Skip to content
This repository was archived by the owner on Mar 28, 2022. It is now read-only.

Commit 4e30b9e

Browse files
committed
Full core Options unit tests coverage
1 parent 2ccf478 commit 4e30b9e

3 files changed

Lines changed: 255 additions & 27 deletions

File tree

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ module.exports = {
4646
"**/test/unit/core/settings/CommandLineArguments.spec.js",
4747
"**/test/unit/core/settings/Options.spec.js"
4848
],
49-
//testMatch: ["**/test/unit/core/settings/CommandLineArguments.spec.js", "**/test/unit/core/settings/Options.spec.js"],
49+
//testMatch: ["**/test/unit/core/settings/Options.spec.js"],
5050

5151
// The test environment that will be used for testing
5252
testEnvironment: "node"

lib/core/settings/Options.js

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,24 @@ class Options {
3939
}
4040

4141
async init(options) {
42-
const baseOptions = {
43-
...DEFAULT_OPTIONS,
44-
...this._customDefaults,
45-
...options
46-
};
47-
if (!this._onlyProgrammaticOptions) {
48-
await this._commandLineArguments.init();
49-
this._options = this._getDefinedOptions(
50-
this._removeDeprecatedOptions({
51-
...baseOptions,
52-
...this._commandLineArguments.options
53-
})
54-
);
55-
} else {
56-
this._options = this._getDefinedOptions(this._removeDeprecatedOptions(baseOptions));
42+
if (!this._initialized) {
43+
this._initialized = true;
44+
const baseOptions = {
45+
...DEFAULT_OPTIONS,
46+
...this._customDefaults,
47+
...options
48+
};
49+
if (!this._onlyProgrammaticOptions) {
50+
await this._commandLineArguments.init();
51+
this._options = this._getDefinedOptions(
52+
this._removeDeprecatedOptions({
53+
...baseOptions,
54+
...this._commandLineArguments.options
55+
})
56+
);
57+
} else {
58+
this._options = this._getDefinedOptions(this._removeDeprecatedOptions(baseOptions));
59+
}
5760
}
5861
return Promise.resolve();
5962
}
@@ -62,29 +65,31 @@ class Options {
6265
return this._options;
6366
}
6467

68+
_rejectCustomOption(errorMessage) {
69+
tracer.error(errorMessage);
70+
throw new Error(errorMessage);
71+
}
72+
6573
addCustom(optionDetails) {
6674
if (this._initialized) {
67-
tracer.error("Options are already initializated. No more options can be added");
68-
return;
75+
this._rejectCustomOption("Options are already initializated. No more options can be added");
6976
}
7077
if (!optionDetails) {
71-
tracer.error("Please provide option details when adding a new option");
72-
return;
78+
this._rejectCustomOption("Please provide option details when adding a new option");
7379
}
7480
if (!optionDetails.name) {
75-
tracer.error("Please provide option name when adding a new option");
76-
return;
81+
this._rejectCustomOption("Please provide option name when adding a new option");
7782
}
7883
if (this._optionsNames.includes(optionDetails.name)) {
79-
tracer.error(`Option with name ${optionDetails.name} is already registered`);
80-
return;
84+
this._rejectCustomOption(`Option with name ${optionDetails.name} is already registered`);
8185
}
8286
if (
8387
!optionDetails.type ||
8488
!["string", "number", "boolean", "booleanString"].includes(optionDetails.type)
8589
) {
86-
tracer.error("Please provide a valid option type between: string, number, boolean");
87-
return;
90+
this._rejectCustomOption(
91+
"Please provide a valid option type between: string, number, boolean"
92+
);
8893
}
8994
if (!optionDetails.description) {
9095
tracer.warn("Please provide option description when adding a new option");

test/unit/core/settings/Options.spec.js

Lines changed: 224 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe("options", () => {
2323

2424
beforeEach(() => {
2525
sandbox = sinon.createSandbox();
26-
sandbox.stub(tracer, "warn");
26+
sandbox.spy(tracer, "warn");
2727
sandbox.stub(tracer, "error");
2828
commandLineArgumentsMocks = new CommandLineArgumentsMocks();
2929
options = new Options();
@@ -40,6 +40,13 @@ describe("options", () => {
4040
expect(commandLineArgumentsMocks.stubs.instance.init.callCount).toEqual(1);
4141
});
4242

43+
it("should call only once to get command line arguments", async () => {
44+
await options.init();
45+
await options.init();
46+
await options.init();
47+
expect(commandLineArgumentsMocks.stubs.instance.init.callCount).toEqual(1);
48+
});
49+
4350
it("should print a warning if --feature option is received", async () => {
4451
commandLineArgumentsMocks.stubs.instance.options = {
4552
feature: "foo-feature",
@@ -64,6 +71,113 @@ describe("options", () => {
6471
});
6572
});
6673

74+
describe("init method when using programmatic options", () => {
75+
it("should not call to get command line arguments", async () => {
76+
options = new Options({
77+
onlyProgrammaticOptions: true
78+
});
79+
await options.init();
80+
expect(commandLineArgumentsMocks.stubs.instance.init.callCount).toEqual(0);
81+
});
82+
});
83+
84+
describe("when adding custom option", () => {
85+
it("should trow an error if options have been already initialized", async () => {
86+
expect.assertions(2);
87+
await options.init();
88+
try {
89+
options.addCustom();
90+
} catch (error) {
91+
const errorMessageContains = "already initializated";
92+
expect(tracer.error.getCall(0).args[0]).toEqual(
93+
expect.stringContaining(errorMessageContains)
94+
);
95+
expect(error.message).toEqual(expect.stringContaining(errorMessageContains));
96+
}
97+
});
98+
99+
it("should trow an error if no option is provided", () => {
100+
expect.assertions(2);
101+
try {
102+
options.addCustom();
103+
} catch (error) {
104+
const errorMessageContains = "provide option details";
105+
expect(tracer.error.getCall(0).args[0]).toEqual(
106+
expect.stringContaining(errorMessageContains)
107+
);
108+
expect(error.message).toEqual(expect.stringContaining(errorMessageContains));
109+
}
110+
});
111+
112+
it("should trow an error if option name is not provided", () => {
113+
expect.assertions(2);
114+
try {
115+
options.addCustom({
116+
description: "foo"
117+
});
118+
} catch (error) {
119+
const errorMessageContains = "provide option name";
120+
expect(tracer.error.getCall(0).args[0]).toEqual(
121+
expect.stringContaining(errorMessageContains)
122+
);
123+
expect(error.message).toEqual(expect.stringContaining(errorMessageContains));
124+
}
125+
});
126+
127+
it("should trow an error if option was already declared", () => {
128+
expect.assertions(2);
129+
try {
130+
options.addCustom({
131+
name: "behaviors"
132+
});
133+
} catch (error) {
134+
const errorMessageContains = "already registered";
135+
expect(tracer.error.getCall(0).args[0]).toEqual(
136+
expect.stringContaining(errorMessageContains)
137+
);
138+
expect(error.message).toEqual(expect.stringContaining(errorMessageContains));
139+
}
140+
});
141+
142+
it("should trow an error if option type is unknown", () => {
143+
expect.assertions(2);
144+
try {
145+
options.addCustom({
146+
name: "foo",
147+
type: "foo"
148+
});
149+
} catch (error) {
150+
const errorMessageContains = "provide a valid option type";
151+
expect(tracer.error.getCall(0).args[0]).toEqual(
152+
expect.stringContaining(errorMessageContains)
153+
);
154+
expect(error.message).toEqual(expect.stringContaining(errorMessageContains));
155+
}
156+
});
157+
158+
it("should print a warning if option description is not provided", () => {
159+
expect.assertions(1);
160+
options.addCustom({
161+
name: "foo",
162+
type: "string"
163+
});
164+
const errorMessageContains = "provide option description";
165+
expect(tracer.warn.getCall(0).args[0]).toEqual(
166+
expect.stringContaining(errorMessageContains)
167+
);
168+
});
169+
170+
it("should not print a warning if option description is not provided", () => {
171+
expect.assertions(1);
172+
options.addCustom({
173+
name: "foo",
174+
type: "string",
175+
description: "foo-description"
176+
});
177+
expect(tracer.warn.callCount).toEqual(0);
178+
});
179+
});
180+
67181
describe("options getter", () => {
68182
it("should only get values from keys defined in default values", async () => {
69183
commandLineArgumentsMocks.stubs.instance.options = {
@@ -171,4 +285,113 @@ describe("options", () => {
171285
});
172286
});
173287
});
288+
289+
describe("options getter when using programmatic options", () => {
290+
beforeEach(() => {
291+
options = new Options({
292+
onlyProgrammaticOptions: true
293+
});
294+
});
295+
296+
it("should only get values from keys defined in default values", async () => {
297+
await options.init({
298+
behavior: "foo-behavior",
299+
cli: true,
300+
behaviors: "foo/behaviors/path",
301+
foo: undefined,
302+
foo2: "foooo"
303+
});
304+
expect(options.options).toEqual({
305+
port: 3100,
306+
host: "0.0.0.0",
307+
log: "info",
308+
delay: 0,
309+
watch: true,
310+
behavior: "foo-behavior",
311+
behaviors: "foo/behaviors/path"
312+
});
313+
});
314+
315+
it("should get values from keys defined in new options", async () => {
316+
options.addCustom({
317+
name: "cli",
318+
type: "boolean"
319+
});
320+
options.addCustom({
321+
name: "foo",
322+
type: "string"
323+
});
324+
await options.init({
325+
behavior: "foo-behavior",
326+
cli: true,
327+
behaviors: "foo/behaviors/path",
328+
foo: "foo"
329+
});
330+
expect(options.options).toEqual({
331+
port: 3100,
332+
host: "0.0.0.0",
333+
log: "info",
334+
cli: true,
335+
foo: "foo",
336+
delay: 0,
337+
watch: true,
338+
behavior: "foo-behavior",
339+
behaviors: "foo/behaviors/path"
340+
});
341+
});
342+
343+
it("should extend default options with user options, ommiting undefined values", async () => {
344+
await options.init({
345+
behavior: "foo-behavior",
346+
cli: true,
347+
behaviors: "foo/behaviors/path",
348+
foo: undefined
349+
});
350+
expect(options.options).toEqual({
351+
port: 3100,
352+
host: "0.0.0.0",
353+
log: "info",
354+
delay: 0,
355+
watch: true,
356+
behavior: "foo-behavior",
357+
behaviors: "foo/behaviors/path"
358+
});
359+
});
360+
361+
it("should convert feature and features options to behavior and behaviors", async () => {
362+
await options.init({
363+
feature: "foo-feature",
364+
cli: true,
365+
features: "foo/features/path"
366+
});
367+
expect(options.options).toEqual({
368+
port: 3100,
369+
host: "0.0.0.0",
370+
log: "info",
371+
delay: 0,
372+
watch: true,
373+
behavior: "foo-feature",
374+
behaviors: "foo/features/path"
375+
});
376+
});
377+
378+
it("should apply behavior and behavior options if feature and features options are received too", async () => {
379+
await options.init({
380+
behavior: "foo-behavior",
381+
feature: "foo-feature",
382+
cli: true,
383+
behaviors: "foo/behaviors/path",
384+
features: "foo-feature"
385+
});
386+
expect(options.options).toEqual({
387+
port: 3100,
388+
host: "0.0.0.0",
389+
log: "info",
390+
delay: 0,
391+
watch: true,
392+
behavior: "foo-behavior",
393+
behaviors: "foo/behaviors/path"
394+
});
395+
});
396+
});
174397
});

0 commit comments

Comments
 (0)