Skip to content

Commit

Permalink
Merge pull request #1654 from hapijs/lab-bump
Browse files Browse the repository at this point in the history
Bump to lab@18. Fixes #1653.
  • Loading branch information
Marsup committed Nov 19, 2018
2 parents 4653c3c + bb7d80d commit dc42412
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 8 deletions.
4 changes: 2 additions & 2 deletions lib/errors.js
Expand Up @@ -146,7 +146,7 @@ exports.create = function (type, context, state, options, flags, message, templa

exports.process = function (errors, object) {

if (!errors || !errors.length) {
if (!errors) {
return null;
}

Expand Down Expand Up @@ -176,7 +176,7 @@ exports.process = function (errors, object) {

// Do not push intermediate errors, we're only interested in leafs

if (item.context.reason && item.context.reason.length) {
if (item.context.reason) {
const override = processErrors(item.context.reason, item.path, item.type === 'override' ? item.message : null);
if (override) {
return override;
Expand Down
4 changes: 2 additions & 2 deletions lib/types/alternatives/index.js
Expand Up @@ -137,11 +137,11 @@ internals.Alternatives = class extends Any {
obj._refs.push(...item.is._refs);
}

if (item.then && item.then._refs) {
if (item.then && item.then._refs.length) {
obj._refs.push(...item.then._refs);
}

if (item.otherwise && item.otherwise._refs) {
if (item.otherwise && item.otherwise._refs.length) {
obj._refs.push(...item.otherwise._refs);
}

Expand Down
3 changes: 1 addition & 2 deletions lib/types/any/index.js
Expand Up @@ -617,8 +617,7 @@ module.exports = internals.Any = class {

if (this._invalids.has(value, state, options, this._flags.insensitive)) {
errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', { value, invalids: this._invalids.values({ stripUndefined: true }) }, state, options));
if (options.abortEarly ||
value === undefined) { // No reason to keep validating missing value
if (options.abortEarly) {

return this._finalizeValue(value, originalValue, errors, state, options);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/types/date/index.js
Expand Up @@ -82,7 +82,7 @@ internals.Date = class extends Any {
if (isIsoDate) {
date = format.test(value) ? new Date(value.toString()) : internals.invalidDate;
}
else if (timestamp && multiplier) {
else if (timestamp) {
date = /^\s*$/.test(value) ? internals.invalidDate : new Date(value * multiplier);
}
else {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -18,7 +18,7 @@
"devDependencies": {
"code": "5.x.x",
"hapitoc": "1.x.x",
"lab": "17.x.x"
"lab": "18.x.x"
},
"scripts": {
"test": "lab -t 100 -a code -L",
Expand Down
8 changes: 8 additions & 0 deletions test/set.js
Expand Up @@ -96,6 +96,14 @@ describe('Set', () => {
set.add('x');
expect(set.values({ stripUndefined: true })).to.not.include(undefined).and.to.equal(['x']);
});

it('ignores absent stripUndefined', () => {

const set = new Set();
set.add(undefined);
set.add('x');
expect(set.values({})).to.equal([undefined, 'x']);
});
});

describe('add()', () => {
Expand Down
42 changes: 42 additions & 0 deletions test/types/alternatives.js
Expand Up @@ -623,6 +623,48 @@ describe('alternatives', () => {
]);
});


it('validates when is has either ref pointing to a complex type or value', () => {

const date = new Date(42);
const now = Date.now();

const schema = {
a: Joi.alternatives().when('b', {
is: Joi.valid(
new Date(+date), // Intentional cloning of the date to change the reference
Joi.ref('c')
),
then: 'x'
}),
b: Joi.date(),
c: Joi.date()
};

Helper.validate(schema, [
[{ a: 'x', b: date, c: date }, true],
[{ a: 'x', b: date, c: now }, true, null, { a: 'x', b: date, c: new Date(now) }],
[{ a: 'y', b: date, c: date }, false, null, {
message: 'child "a" fails because ["a" must be one of [x]]',
details: [{
message: '"a" must be one of [x]',
path: ['a'],
type: 'any.allowOnly',
context: { value: 'y', valids: ['x'], label: 'a', key: 'a' }
}]
}],
[{ a: 'y' }, false, null, {
message: 'child "a" fails because ["a" must be one of [x]]',
details: [{
message: '"a" must be one of [x]',
path: ['a'],
type: 'any.allowOnly',
context: { value: 'y', valids: ['x'], label: 'a', key: 'a' }
}]
}]
]);
});

it('validates when then has ref', () => {

const ref = Joi.ref('c');
Expand Down
118 changes: 118 additions & 0 deletions test/types/any.js
Expand Up @@ -1667,6 +1667,124 @@ describe('any', () => {
});
});

it('merges two schemas (flags with empty on one side)', () => {

const a = Joi.string().valid('a').empty('');
const b = Joi.string().insensitive();

Helper.validate(a, [
['a', true],
['A', false, null, {
message: '"value" must be one of [a]',
details: [{
message: '"value" must be one of [a]',
path: [],
type: 'any.allowOnly',
context: { value: 'A', valids: ['a'], label: 'value', key: undefined }
}]
}],
['b', false, null, {
message: '"value" must be one of [a]',
details: [{
message: '"value" must be one of [a]',
path: [],
type: 'any.allowOnly',
context: { value: 'b', valids: ['a'], label: 'value', key: undefined }
}]
}],
['', true, null, undefined],
[' ', false, null, {
message: '"value" must be one of [a]',
details: [{
message: '"value" must be one of [a]',
path: [],
type: 'any.allowOnly',
context: { value: ' ', valids: ['a'], label: 'value', key: undefined }
}]
}]
]);

const ab = a.concat(b);
Helper.validate(ab, [
['a', true, null, 'a'],
['A', true, null, 'a'],
['b', false, null, {
message: '"value" must be one of [a]',
details: [{
message: '"value" must be one of [a]',
path: [],
type: 'any.allowOnly',
context: { value: 'b', valids: ['a'], label: 'value', key: undefined }
}]
}],
['', true, null, undefined],
[' ', false, null, {
message: '"value" must be one of [a]',
details: [{
message: '"value" must be one of [a]',
path: [],
type: 'any.allowOnly',
context: { value: ' ', valids: ['a'], label: 'value', key: undefined }
}]
}]
]);

expect(ab.describe()).to.equal({
type: 'string',
flags: {
allowOnly: true,
empty: {
type: 'string',
flags: { allowOnly: true },
valids: ['']
},
insensitive: true
},
valids: ['a'],
invalids: ['']
});

const ba = b.concat(a);
Helper.validate(ba, [
['a', true, null, 'a'],
['A', true, null, 'a'],
['b', false, null, {
message: '"value" must be one of [a]',
details: [{
message: '"value" must be one of [a]',
path: [],
type: 'any.allowOnly',
context: { value: 'b', valids: ['a'], label: 'value', key: undefined }
}]
}],
['', true, null, undefined],
[' ', false, null, {
message: '"value" must be one of [a]',
details: [{
message: '"value" must be one of [a]',
path: [],
type: 'any.allowOnly',
context: { value: ' ', valids: ['a'], label: 'value', key: undefined }
}]
}]
]);

expect(ba.describe()).to.equal({
type: 'string',
flags: {
allowOnly: true,
empty: {
type: 'string',
flags: { allowOnly: true },
valids: ['']
},
insensitive: true
},
valids: ['a'],
invalids: ['']
});
});

it('overrides and append information', () => {

const a = Joi.description('a').unit('a').tags('a').example('a');
Expand Down
11 changes: 11 additions & 0 deletions test/types/binary.js
Expand Up @@ -97,6 +97,17 @@ describe('binary', () => {
const value = await Joi.binary().validate(Buffer.from('hello world'));
expect(value.toString('utf8')).to.equal('hello world');
});

it('accepts a buffer object in strict mode', async () => {

const value = await Joi.binary().strict().validate(Buffer.from('hello world'));
expect(value.toString('utf8')).to.equal('hello world');
});

it('rejects strings in strict mode', async () => {

await expect(Joi.binary().strict().validate('hello world')).to.reject('"value" must be a buffer or a string');
});
});

describe('encoding()', () => {
Expand Down
1 change: 1 addition & 0 deletions test/types/lazy.js
Expand Up @@ -61,6 +61,7 @@ describe('lazy', () => {
expect(() => Joi.lazy(() => {}, { oce: true })).to.throw('Options contain unknown keys: oce');
expect(() => Joi.lazy(() => {}, { once: 'foo' })).to.throw('Option "once" must be a boolean');
expect(() => Joi.lazy(() => {}, {})).to.not.throw();
expect(() => Joi.lazy(() => {}, { once: true })).to.not.throw();
});
});

Expand Down
36 changes: 36 additions & 0 deletions test/types/object.js
Expand Up @@ -31,6 +31,11 @@ describe('object', () => {
expect(value.hi).to.equal(true);
});

it('fails on json string in strict mode', async () => {

await expect(Joi.object().strict().validate('{"hi":true}')).to.reject('"value" must be an object');
});

it('errors on non-object string', async () => {

const err = await expect(Joi.object().validate('a string')).to.reject('"value" must be an object');
Expand Down Expand Up @@ -1191,6 +1196,24 @@ describe('object', () => {
expect(value).to.equal({ a: 'something' });
});

it('should delete a key with override and ignoredUndefined if from exists', async () => {

const regex = /^b$/i;

const schema = Joi.object().keys({
c: Joi.any(),
a: Joi.any()
}).rename(regex, 'a', { ignoreUndefined: true, override: true });

const input = {
a: 'something',
b: 'something else'
};

const value = await schema.validate(input);
expect(value).to.equal({ a: 'something else' });
});

it('should fulfill describe() with non-defaults', () => {

const regex = /^b$/i;
Expand Down Expand Up @@ -1506,6 +1529,19 @@ describe('object', () => {
expect(value).to.equal({ a: 'something' });
});

it('should delete a key with override and ignoredUndefined if from exists', async () => {

const schema = Joi.object().rename('b', 'a', { ignoreUndefined: true, override: true });

const input = {
a: 'something',
b: 'something else'
};

const value = await schema.validate(input);
expect(value).to.equal({ a: 'something else' });
});

it('should fulfill describe() with defaults', () => {

const schema = Joi.object().rename('b', 'a');
Expand Down

0 comments on commit dc42412

Please sign in to comment.