|
|
@@ -3,15 +3,14 @@ import {format} from '@e22m4u/js-format';
|
|
|
import {projectData} from './project-data.js';
|
|
|
|
|
|
describe('projectData', function () {
|
|
|
- it('should require the parameter "schemaOrFactory" to be an object or a function', function () {
|
|
|
+ it('should require the parameter "schemaOrSource" to be a valid value', function () {
|
|
|
const throwable = v => () => projectData(v, {});
|
|
|
const error = s =>
|
|
|
format(
|
|
|
- 'Projection schema must be an Object or a Function ' +
|
|
|
- 'that returns a schema object, but %s was given.',
|
|
|
+ 'Projection schema must be an Object, a Function ' +
|
|
|
+ 'or a non-empty String, but %s was given.',
|
|
|
s,
|
|
|
);
|
|
|
- expect(throwable('str')).to.throw(error('"str"'));
|
|
|
expect(throwable('')).to.throw(error('""'));
|
|
|
expect(throwable(10)).to.throw(error('10'));
|
|
|
expect(throwable(0)).to.throw(error('0'));
|
|
|
@@ -20,8 +19,9 @@ describe('projectData', function () {
|
|
|
expect(throwable([])).to.throw(error('Array'));
|
|
|
expect(throwable(null)).to.throw(error('null'));
|
|
|
expect(throwable(undefined)).to.throw(error('undefined'));
|
|
|
- throwable({})();
|
|
|
- throwable(() => ({}))();
|
|
|
+ projectData({}, {});
|
|
|
+ projectData(() => ({}), {});
|
|
|
+ projectData('mySchema', {}, {resolver: () => ({})});
|
|
|
});
|
|
|
|
|
|
it('should require the parameter "options" to be an object', function () {
|
|
|
@@ -72,23 +72,20 @@ describe('projectData', function () {
|
|
|
throwable(undefined)();
|
|
|
});
|
|
|
|
|
|
- it('should throw an error if the schema factory returns an invalid value', function () {
|
|
|
- const throwable = v => () => projectData(() => v, {});
|
|
|
+ it('should require the option "resolver" to be a Function', function () {
|
|
|
+ const throwable = v => () => projectData({}, {}, {resolver: v});
|
|
|
const error = s =>
|
|
|
- format(
|
|
|
- 'Projection schema factory must return an Object, but %s was given.',
|
|
|
- s,
|
|
|
- );
|
|
|
- expect(throwable('str')).to.throw(error('"str"'));
|
|
|
+ format('Option "resolver" must be a Function, but %s was given.', s);
|
|
|
expect(throwable('')).to.throw(error('""'));
|
|
|
expect(throwable(10)).to.throw(error('10'));
|
|
|
expect(throwable(0)).to.throw(error('0'));
|
|
|
expect(throwable(true)).to.throw(error('true'));
|
|
|
expect(throwable(false)).to.throw(error('false'));
|
|
|
expect(throwable([])).to.throw(error('Array'));
|
|
|
+ expect(throwable({})).to.throw(error('Object'));
|
|
|
expect(throwable(null)).to.throw(error('null'));
|
|
|
- expect(throwable(undefined)).to.throw(error('undefined'));
|
|
|
- throwable({})();
|
|
|
+ throwable(() => undefined)();
|
|
|
+ throwable(undefined)();
|
|
|
});
|
|
|
|
|
|
it('should return a non-object and non-array data as is', function () {
|
|
|
@@ -151,6 +148,22 @@ describe('projectData', function () {
|
|
|
});
|
|
|
|
|
|
describe('schema factory', function () {
|
|
|
+ it('should throw an error if the schema factory returns an invalid value', function () {
|
|
|
+ const throwable = v => () => projectData(() => v, {});
|
|
|
+ const error = s =>
|
|
|
+ format('Schema factory must return an Object, but %s was given.', s);
|
|
|
+ expect(throwable('str')).to.throw(error('"str"'));
|
|
|
+ expect(throwable('')).to.throw(error('""'));
|
|
|
+ expect(throwable(10)).to.throw(error('10'));
|
|
|
+ expect(throwable(0)).to.throw(error('0'));
|
|
|
+ expect(throwable(true)).to.throw(error('true'));
|
|
|
+ expect(throwable(false)).to.throw(error('false'));
|
|
|
+ expect(throwable([])).to.throw(error('Array'));
|
|
|
+ expect(throwable(null)).to.throw(error('null'));
|
|
|
+ expect(throwable(undefined)).to.throw(error('undefined'));
|
|
|
+ throwable({})();
|
|
|
+ });
|
|
|
+
|
|
|
it('should resolve a schema object from the given factory', function () {
|
|
|
let invoked = 0;
|
|
|
const factory = () => {
|
|
|
@@ -177,6 +190,60 @@ describe('projectData', function () {
|
|
|
});
|
|
|
});
|
|
|
|
|
|
+ describe('named schema', function () {
|
|
|
+ it('should throw an error if the schema resolver returns an invalid value', function () {
|
|
|
+ const throwable = v => () =>
|
|
|
+ projectData('mySchema', {}, {resolver: () => v});
|
|
|
+ const error = s =>
|
|
|
+ format('Schema resolver must return an Object, but %s was given.', s);
|
|
|
+ expect(throwable('str')).to.throw(error('"str"'));
|
|
|
+ expect(throwable('')).to.throw(error('""'));
|
|
|
+ expect(throwable(10)).to.throw(error('10'));
|
|
|
+ expect(throwable(0)).to.throw(error('0'));
|
|
|
+ expect(throwable(true)).to.throw(error('true'));
|
|
|
+ expect(throwable(false)).to.throw(error('false'));
|
|
|
+ expect(throwable([])).to.throw(error('Array'));
|
|
|
+ expect(throwable(null)).to.throw(error('null'));
|
|
|
+ expect(throwable(undefined)).to.throw(error('undefined'));
|
|
|
+ throwable({})();
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should throw an error if no schema resolver is provided when a schema name is given', function () {
|
|
|
+ const throwable = () => projectData('mySchema', {});
|
|
|
+ expect(throwable).to.throw(
|
|
|
+ 'Unable to resolve the schema "mySchema" without a specified resolver.',
|
|
|
+ );
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should pass the schema name to the schema resolver and project the given data', function () {
|
|
|
+ let invoked = 0;
|
|
|
+ const resolver = name => {
|
|
|
+ expect(name).to.be.eq('mySchema');
|
|
|
+ invoked++;
|
|
|
+ return {foo: true, bar: false};
|
|
|
+ };
|
|
|
+ const res = projectData('mySchema', {foo: 10, bar: 20}, {resolver});
|
|
|
+ expect(res).to.be.eql({foo: 10});
|
|
|
+ expect(invoked).to.be.eq(1);
|
|
|
+ });
|
|
|
+
|
|
|
+ it('should use the schema resolver in the nested schema', function () {
|
|
|
+ let invoked = 0;
|
|
|
+ const resolver = name => {
|
|
|
+ expect(name).to.be.eq('mySchema');
|
|
|
+ invoked++;
|
|
|
+ return {baz: true, qux: false};
|
|
|
+ };
|
|
|
+ const res = projectData(
|
|
|
+ {foo: true, bar: {schema: 'mySchema'}},
|
|
|
+ {foo: 10, bar: {baz: 20, qux: 30}},
|
|
|
+ {resolver},
|
|
|
+ );
|
|
|
+ expect(res).to.be.eql({foo: 10, bar: {baz: 20}});
|
|
|
+ expect(invoked).to.be.eq(1);
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
describe('strict mode', function () {
|
|
|
it('should preserve fields not defined in the schema when the strict option is false', function () {
|
|
|
const res = projectData({}, {foo: 10});
|
|
|
@@ -214,6 +281,15 @@ describe('projectData', function () {
|
|
|
);
|
|
|
expect(res).to.be.eql({bar: {baz: 20}});
|
|
|
});
|
|
|
+
|
|
|
+ it('should ignore prototype properties', function () {
|
|
|
+ const res = projectData(
|
|
|
+ {bar: true, toString: true},
|
|
|
+ {bar: 10},
|
|
|
+ {strict: true},
|
|
|
+ );
|
|
|
+ expect(res).to.be.eql({bar: 10});
|
|
|
+ });
|
|
|
});
|
|
|
|
|
|
describe('projection scope', function () {
|