Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow access to parent schema (and unlimited ancestors!) in test context #556

Merged
merged 12 commits into from
May 20, 2020
1 change: 1 addition & 0 deletions src/array.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ inherits(ArraySchema, MixedSchema, {
path,
strict: true,
parent: value,
index: idx,
originalValue: originalValue[idx],
};

Expand Down
6 changes: 5 additions & 1 deletion src/mixed.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@ const proto = (SchemaType.prototype = {
originalValue,
sync,
};

if (options.from) {
validationParams.from = options.from;
}

let initialTests = [];

if (this._typeError) initialTests.push(this._typeError(validationParams));
Expand Down Expand Up @@ -550,7 +555,6 @@ for (const method of ['validate', 'validateSync'])
value,
options.context,
);

return schema[method](parent && parent[parentPath], {
...options,
parent,
Expand Down
11 changes: 10 additions & 1 deletion src/object.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,12 @@ inherits(ObjectSchema, MixedSchema, {
let originalValue =
opts.originalValue != null ? opts.originalValue : _value;

let from = [{ schema: this, value: originalValue }, ...(opts.from || [])];

endEarly = this._option('abortEarly', opts);
recursive = this._option('recursive', opts);

opts = { ...opts, __validating: true, originalValue };
opts = { ...opts, __validating: true, originalValue, from };

return MixedSchema.prototype._validate
.call(this, _value, opts)
Expand All @@ -143,6 +145,12 @@ inherits(ObjectSchema, MixedSchema, {
return value;
}

from = originalValue
? [...from]
: [
{ schema: this, value: originalValue || value },
...(opts.from || []),
];
originalValue = originalValue || value;

let validations = this._nodes.map(key => {
Expand All @@ -155,6 +163,7 @@ inherits(ObjectSchema, MixedSchema, {
let innerOptions = {
...opts,
path,
from,
parent: value,
originalValue: originalValue[key],
};
Expand Down
40 changes: 40 additions & 0 deletions test/mixed.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,46 @@ describe('Mixed Types ', () => {
called.should.equal(true);
});

it('tests should be able to access nested parent', async () => {
let finalFrom,finalOptions;
let testFixture = {
firstField: 'test',
second: [
{
thirdField: 'test3',
},
{
thirdField: 'test4',
},
],
};

let third = object({
thirdField: mixed().test({
test() {
finalFrom = this.from;
finalOptions = this.options;
return true;
},
}),
});

let second = array().of(third);

let first = object({
firstField: mixed(),
second,
});

await first.validate(testFixture);

finalFrom[0].value.should.eql(testFixture.second[finalOptions.index]);
finalFrom[0].schema.should.equal(third);
finalFrom[1].value.should.equal(testFixture);
finalFrom[1].schema.should.equal(first);

});

it('tests can return an error', () => {
let inst = mixed().test({
message: 'invalid ${path}',
Expand Down