Skip to content

Commit

Permalink
feat: add required option in state definition
Browse files Browse the repository at this point in the history
  • Loading branch information
b-ma committed Sep 23, 2024
1 parent 4c17ce1 commit d381f20
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 17 deletions.
19 changes: 17 additions & 2 deletions src/common/ParameterBag.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import equal from 'fast-deep-equal';
export const sharedOptions = {
nullable: false,
event: false, // if event=true, nullable=true
required: false, // if required=true, default is set to init value
metas: {},
filterChange: true,
immediate: false,
Expand Down Expand Up @@ -146,8 +147,13 @@ class ParameterBag {
const required = types[def.type].required;

required.forEach(key => {
if (def.event === true && key === 'default') {
// do nothing, default is always null for `event` params
if ((def.event === true || def.required === true) && key === 'default') {
// do nothing:
// - default is always null for `event` params
// - default is always null for `required` params
if ('default' in def && def.default !== null) {
throw new TypeError(`[StateManager.registerSchema] Invalid schema definition for param ${name} - "default" propaerty is set and not null while the parameter definition is declared as "event" or "required"`);
}
} else if (!Object.prototype.hasOwnProperty.call(def, key)) {
throw new TypeError(`[StateManager.registerSchema] Invalid schema definition - param "${name}" (type "${def.type}"): "${key}" key is required`);
}
Expand Down Expand Up @@ -208,6 +214,15 @@ class ParameterBag {
def.default = null;
}

if (def.required === true) {
// throw if value is not given in init values
if (initValues[name] === undefined || initValues[name] === null) {
throw new Error(`[SharedState.create] Invalid init value for required param "${name}", cannot be null or undefined`);
}

def.default = initValues[name];
}

let initValue;

if (Object.prototype.hasOwnProperty.call(initValues, name)) {
Expand Down
30 changes: 28 additions & 2 deletions tests/states/ParameterBag.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ describe('# [private] ParameterBag', () => {
assert.doesNotThrow(() => ParameterBag.validateSchema({
myBoolean: { type: 'boolean', event: true }
}));
})
});

it(`should allow "default" to not be declared when "required" is true`, () => {
// required: true does not require `default` value
assert.doesNotThrow(() => ParameterBag.validateSchema({
myBoolean: { type: 'boolean', required: true }
}));
});
});

describe('## constructor(schema, initValues)', () => {
Expand All @@ -49,6 +56,18 @@ describe('# [private] ParameterBag', () => {
}, ReferenceError, `[StateManager.create] init value defined for undefined param "myFloat"`);
});

it('should throw if required param is not given at initialization', () => {
let errored = false;
try {
new ParameterBag({ requiredParam: { type: 'boolean', required: true, } });
} catch(err) {
console.log(err.message);
errored = true;
}

if (!errored) { assert.fail('require param should have thrown'); }
});

it('should complete and deeply clone schema', () => {
const schema = {
myBoolean: {
Expand Down Expand Up @@ -115,11 +134,16 @@ describe('# [private] ParameterBag', () => {
default: null,
event: true,
},
required: {
type: 'string',
required: true,
},
};

const params = new ParameterBag(schema, {
bool: true,
int: -4,
required: 'coucou',
});

describe(`## has(name)`, () => {
Expand All @@ -131,7 +155,7 @@ describe('# [private] ParameterBag', () => {

describe(`## getValues()`, () => {
it(`should return current values`, () => {
const expected = { bool: true, int: -2, nullable: {}, event: null };
const expected = { bool: true, int: -2, nullable: {}, event: null, required: 'coucou' };
assert.deepEqual(params.getValues(), expected);
});

Expand All @@ -158,6 +182,7 @@ describe('# [private] ParameterBag', () => {
assert.strictEqual(params.get('int'), -2);
assert.deepEqual(params.get('nullable'), {});
assert.strictEqual(params.get('event'), null);
assert.strictEqual(params.get('required'), 'coucou');
});
});

Expand Down Expand Up @@ -216,6 +241,7 @@ describe('# [private] ParameterBag', () => {
int: 0,
nullable: {},
event: null,
required: 'coucou', // default is set to init value
});
});
});
Expand Down
2 changes: 2 additions & 0 deletions tests/states/StateCollection.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ describe(`# SharedStateCollection`, () => {
"initValue": false,
"metas": {},
"nullable": false,
"required": false,
"type": "boolean",
},
"int": {
Expand All @@ -192,6 +193,7 @@ describe(`# SharedStateCollection`, () => {
"metas": {},
"min": 0,
"nullable": false,
"required": false,
"step": 1,
"type": "integer",
},
Expand Down
2 changes: 2 additions & 0 deletions tests/states/StateManager.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe(`# StateManager`, () => {
immediate: false,
type: 'boolean',
default: false,
required: false,
initValue: false
},
int: {
Expand All @@ -97,6 +98,7 @@ describe(`# StateManager`, () => {
type: 'integer',
default: 0,
step: 1,
required: false,
initValue: 0
}
};
Expand Down
28 changes: 15 additions & 13 deletions tests/states/schema-options.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,18 +281,21 @@ describe('# SharedState - schema options', () => {

it('[immediate=true, event=true] should behave correctly', async () => {
return new Promise(async (resolve, reject) => {
server.stateManager.registerSchema('immediate-test-2', {
immediateValue: {
type: 'integer',
default: 0,
immediate: true,
event: true,
},
normalValue: {
type: 'integer',
default: 0,
}
});
try {
server.stateManager.registerSchema('immediate-test-2', {
immediateValue: {
type: 'integer',
immediate: true,
event: true,
},
normalValue: {
type: 'integer',
default: 0,
}
});
} catch (err) {
console.log(err.message);
}

const state = await client1.stateManager.create('immediate-test-2');
const attached = await client2.stateManager.attach('immediate-test-2');
Expand Down Expand Up @@ -492,7 +495,6 @@ describe('# SharedState - schema options', () => {
try {
result = await owned.set(expected);
} catch (err) {
console.log(err.message);
}
assert.deepEqual(result, expected);
// 1 - for state create request
Expand Down

0 comments on commit d381f20

Please sign in to comment.