You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
611 lines
18 KiB
611 lines
18 KiB
/** |
|
* @filedescription Object Schema Tests |
|
*/ |
|
/* global it, describe, beforeEach */ |
|
|
|
"use strict"; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Requirements |
|
//----------------------------------------------------------------------------- |
|
|
|
const assert = require("chai").assert; |
|
const { ObjectSchema } = require("../src/"); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Class |
|
//----------------------------------------------------------------------------- |
|
|
|
describe("ObjectSchema", () => { |
|
|
|
let schema; |
|
|
|
describe("new ObjectSchema()", () => { |
|
|
|
it("should add a new key when a strategy is passed", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() {}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
assert.isTrue(schema.hasKey("foo")); |
|
}); |
|
|
|
it("should throw an error when a strategy is missing a merge() method", () => { |
|
assert.throws(() => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
validate() { } |
|
} |
|
}); |
|
}, /Definition for key "foo" must have a merge property/); |
|
}); |
|
|
|
it("should throw an error when a strategy is missing a merge() method", () => { |
|
assert.throws(() => { |
|
schema = new ObjectSchema(); |
|
}, /Schema definitions missing/); |
|
}); |
|
|
|
it("should throw an error when a strategy is missing a validate() method", () => { |
|
assert.throws(() => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { }, |
|
} |
|
}); |
|
}, /Definition for key "foo" must have a validate\(\) method/); |
|
}); |
|
|
|
it("should throw an error when merge is an invalid string", () => { |
|
assert.throws(() => { |
|
new ObjectSchema({ |
|
foo: { |
|
merge: "bar", |
|
validate() { } |
|
} |
|
}); |
|
}, /key "foo" missing valid merge strategy/); |
|
}); |
|
|
|
it("should throw an error when validate is an invalid string", () => { |
|
assert.throws(() => { |
|
new ObjectSchema({ |
|
foo: { |
|
merge: "assign", |
|
validate: "s" |
|
} |
|
}); |
|
}, /key "foo" missing valid validation strategy/); |
|
}); |
|
|
|
}); |
|
|
|
|
|
describe("merge()", () => { |
|
|
|
it("should throw an error when an unexpected key is found", () => { |
|
let schema = new ObjectSchema({}); |
|
|
|
assert.throws(() => { |
|
schema.merge({ foo: true }, { foo: true }); |
|
}, /Unexpected key "foo"/); |
|
}); |
|
|
|
it("should throw an error when merge() throws an error", () => { |
|
let schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
throw new Error("Boom!"); |
|
}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
assert.throws(() => { |
|
schema.merge({ foo: true }, { foo: true }); |
|
}, /Key "foo": Boom!/); |
|
|
|
}); |
|
|
|
it("should call the merge() strategy for one key when called", () => { |
|
|
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
const result = schema.merge({ foo: true }, { foo: false }); |
|
assert.propertyVal(result, "foo", "bar"); |
|
}); |
|
|
|
it("should not call the merge() strategy when both objects don't contain the key", () => { |
|
|
|
let called = false; |
|
|
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
called = true; |
|
}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
schema.merge({}, {}); |
|
assert.isFalse(called, "The merge() strategy should not have been called."); |
|
}); |
|
|
|
it("should omit returning the key when the merge() strategy returns undefined", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return undefined; |
|
}, |
|
validate() { } |
|
} |
|
}); |
|
|
|
const result = schema.merge({ foo: true }, { foo: false }); |
|
assert.notProperty(result, "foo"); |
|
}); |
|
|
|
it("should call the merge() strategy for two keys when called", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() { } |
|
}, |
|
bar: { |
|
merge() { |
|
return "baz"; |
|
}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
const result = schema.merge({ foo: true, bar: 1 }, { foo: true, bar: 2 }); |
|
assert.propertyVal(result, "foo", "bar"); |
|
assert.propertyVal(result, "bar", "baz"); |
|
}); |
|
|
|
it("should call the merge() strategy for two keys when called on three objects", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() { } |
|
}, |
|
bar: { |
|
merge() { |
|
return "baz"; |
|
}, |
|
validate() { } |
|
} |
|
}); |
|
|
|
const result = schema.merge( |
|
{ foo: true, bar: 1 }, |
|
{ foo: true, bar: 3 }, |
|
{ foo: false, bar: 2 } |
|
); |
|
assert.propertyVal(result, "foo", "bar"); |
|
assert.propertyVal(result, "bar", "baz"); |
|
}); |
|
|
|
it("should call the merge() strategy when defined as 'overwrite'", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge: "overwrite", |
|
validate() { } |
|
} |
|
}); |
|
|
|
const result = schema.merge( |
|
{ foo: true }, |
|
{ foo: false } |
|
); |
|
assert.propertyVal(result, "foo", false); |
|
}); |
|
|
|
it("should call the merge() strategy when defined as 'assign'", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge: "assign", |
|
validate() { } |
|
} |
|
}); |
|
|
|
const result = schema.merge( |
|
{ foo: { bar: true } }, |
|
{ foo: { baz: false } } |
|
); |
|
|
|
assert.strictEqual(result.foo.bar, true); |
|
assert.strictEqual(result.foo.baz, false); |
|
}); |
|
|
|
it("should call the merge strategy when there's a subschema", () => { |
|
|
|
schema = new ObjectSchema({ |
|
name: { |
|
schema: { |
|
first: { |
|
merge: "replace", |
|
validate: "string" |
|
}, |
|
last: { |
|
merge: "replace", |
|
validate: "string" |
|
} |
|
} |
|
} |
|
}); |
|
|
|
const result = schema.merge({ |
|
name: { |
|
first: "n", |
|
last: "z" |
|
} |
|
}, { |
|
name: { |
|
first: "g" |
|
} |
|
}); |
|
|
|
assert.strictEqual(result.name.first, "g"); |
|
assert.strictEqual(result.name.last, "z"); |
|
}); |
|
|
|
it("should return separate objects when using subschema", () => { |
|
|
|
schema = new ObjectSchema({ |
|
age: { |
|
merge: "replace", |
|
validate: "number" |
|
}, |
|
address: { |
|
schema: { |
|
street: { |
|
schema: { |
|
number: { |
|
merge: "replace", |
|
validate: "number" |
|
}, |
|
streetName: { |
|
merge: "replace", |
|
validate: "string" |
|
} |
|
} |
|
}, |
|
state: { |
|
merge: "replace", |
|
validate: "string" |
|
} |
|
} |
|
} |
|
}); |
|
|
|
const baseObject = { |
|
address: { |
|
street: { |
|
number: 100, |
|
streetName: "Foo St" |
|
}, |
|
state: "HA" |
|
} |
|
}; |
|
|
|
const result = schema.merge(baseObject, { |
|
age: 29 |
|
}); |
|
|
|
assert.notStrictEqual(result.address.street, baseObject.address.street); |
|
assert.deepStrictEqual(result.address, baseObject.address); |
|
}); |
|
|
|
it("should not error when calling the merge strategy when there's a subschema and no matching key in second object", () => { |
|
|
|
schema = new ObjectSchema({ |
|
name: { |
|
schema: { |
|
first: { |
|
merge: "replace", |
|
validate: "string" |
|
}, |
|
last: { |
|
merge: "replace", |
|
validate: "string" |
|
} |
|
} |
|
} |
|
}); |
|
|
|
const result = schema.merge({ |
|
name: { |
|
first: "n", |
|
last: "z" |
|
} |
|
}, { |
|
}); |
|
|
|
assert.strictEqual(result.name.first, "n"); |
|
assert.strictEqual(result.name.last, "z"); |
|
}); |
|
|
|
it("should not error when calling the merge strategy when there's multiple subschemas and no matching key in second object", () => { |
|
|
|
schema = new ObjectSchema({ |
|
user: { |
|
schema: { |
|
name: { |
|
schema: { |
|
first: { |
|
merge: "replace", |
|
validate: "string" |
|
}, |
|
last: { |
|
merge: "replace", |
|
validate: "string" |
|
} |
|
} |
|
} |
|
|
|
} |
|
} |
|
}); |
|
|
|
const result = schema.merge({ |
|
user: { |
|
name: { |
|
first: "n", |
|
last: "z" |
|
} |
|
} |
|
}, { |
|
}); |
|
|
|
assert.strictEqual(result.user.name.first, "n"); |
|
assert.strictEqual(result.user.name.last, "z"); |
|
}); |
|
|
|
|
|
}); |
|
|
|
describe("validate()", () => { |
|
|
|
it("should throw an error when an unexpected key is found", () => { |
|
let schema = new ObjectSchema({}); |
|
assert.throws(() => { |
|
schema.validate({ foo: true }); |
|
}, /Unexpected key "foo"/); |
|
}); |
|
|
|
it("should not throw an error when an expected key is found", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
schema.validate({ foo: true }); |
|
}); |
|
|
|
it("should pass the property value into validate() when key is found", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate(value) { |
|
assert.isTrue(value); |
|
} |
|
} |
|
}); |
|
|
|
schema.validate({ foo: true }); |
|
}); |
|
|
|
it("should not throw an error when expected keys are found", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() {} |
|
}, |
|
bar: { |
|
merge() { |
|
return "baz"; |
|
}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
schema.validate({ foo: true, bar: true }); |
|
}); |
|
|
|
it("should not throw an error when expected keys are found with required keys", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() { } |
|
}, |
|
bar: { |
|
requires: ["foo"], |
|
merge() { |
|
return "baz"; |
|
}, |
|
validate() { } |
|
} |
|
}); |
|
|
|
schema.validate({ foo: true, bar: true }); |
|
}); |
|
|
|
it("should throw an error when expected keys are found without required keys", () => { |
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() { } |
|
}, |
|
baz: { |
|
merge() { |
|
return "baz"; |
|
}, |
|
validate() { } |
|
}, |
|
bar: { |
|
name: "bar", |
|
requires: ["foo", "baz"], |
|
merge() { }, |
|
validate() { } |
|
} |
|
}); |
|
|
|
assert.throws(() => { |
|
schema.validate({ bar: true }); |
|
}, /Key "bar" requires keys "foo", "baz"./); |
|
}); |
|
|
|
|
|
it("should throw an error when an expected key is found but is invalid", () => { |
|
|
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() { |
|
throw new Error("Invalid key."); |
|
} |
|
} |
|
}); |
|
|
|
assert.throws(() => { |
|
schema.validate({ foo: true }); |
|
}, /Key "foo": Invalid key/); |
|
}); |
|
|
|
it("should throw an error when an expected key is found but is invalid with a string validator", () => { |
|
|
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate: "string" |
|
} |
|
}); |
|
|
|
assert.throws(() => { |
|
schema.validate({ foo: true }); |
|
}, /Key "foo": Expected a string/); |
|
}); |
|
|
|
it("should throw an error when an expected key is found but is invalid with a number validator", () => { |
|
|
|
schema = new ObjectSchema({ |
|
foo: { |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate: "number" |
|
} |
|
}); |
|
|
|
assert.throws(() => { |
|
schema.validate({ foo: true }); |
|
}, /Key "foo": Expected a number/); |
|
}); |
|
|
|
it("should throw an error when a required key is missing", () => { |
|
|
|
schema = new ObjectSchema({ |
|
foo: { |
|
required: true, |
|
merge() { |
|
return "bar"; |
|
}, |
|
validate() {} |
|
} |
|
}); |
|
|
|
assert.throws(() => { |
|
schema.validate({}); |
|
}, /Missing required key "foo"/); |
|
}); |
|
|
|
it("should throw an error when a subschema is provided and the value doesn't validate", () => { |
|
|
|
schema = new ObjectSchema({ |
|
name: { |
|
schema: { |
|
first: { |
|
merge: "replace", |
|
validate: "string" |
|
}, |
|
last: { |
|
merge: "replace", |
|
validate: "string" |
|
} |
|
} |
|
} |
|
}); |
|
|
|
assert.throws(() => { |
|
schema.validate({ |
|
name: { |
|
first: 123, |
|
last: "z" |
|
} |
|
}); |
|
|
|
}, /Key "name": Key "first": Expected a string/); |
|
}); |
|
|
|
it("should not throw an error when a subschema is provided and the value validates", () => { |
|
|
|
schema = new ObjectSchema({ |
|
name: { |
|
schema: { |
|
first: { |
|
merge: "replace", |
|
validate: "string" |
|
}, |
|
last: { |
|
merge: "replace", |
|
validate: "string" |
|
} |
|
} |
|
} |
|
}); |
|
|
|
schema.validate({ |
|
name: { |
|
first: "n", |
|
last: "z" |
|
} |
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
});
|
|
|