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

fix(checkSchema): check all locations if in is not specified. #1070

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/context.spec.ts
Expand Up @@ -157,7 +157,7 @@ describe('#getData()', () => {

context.addFieldInstances(data);

expect(context.getData()).toEqual([data[0]]);
expect(context.getData()).toEqual(data);
});

it('does not filter out second undefined when it contains a wildcard', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/context.ts
Expand Up @@ -43,12 +43,12 @@ export class Context {
const locations = _.uniqBy(instances, 'location');

// #331 - When multiple locations are involved, all of them must pass the validation.
// If none of the locations contain the field, we at least include one for error reporting.
// checkSchema: If `in` option is not specified, try to check all locations by default.
// #458, #531 - Wildcards are an exception though: they may yield 0..* instances with different
// paths, so we may want to skip this filtering.
if (instances.length > 1 && locations.length > 1 && !group.includes('*')) {
const withValue = instances.filter(instance => instance.value !== undefined);
return withValue.length ? withValue : [instances[0]];
return withValue.length ? withValue : instances;
fedeci marked this conversation as resolved.
Show resolved Hide resolved
}

return instances;
Expand Down
92 changes: 90 additions & 2 deletions src/middlewares/schema.spec.ts
Expand Up @@ -183,12 +183,49 @@ describe('on each field', () => {
const { context } = await chain.run({ params: { foo: '' } });
expect(context.errors).toHaveLength(1);
});

it('use default config when specified', async () => {
const chain = checkSchema({
undef: {
default: {
options: 10,
},
},
})[0];

const req = { query: { undef: undefined }, body: {}, params: {}, headers: {}, cookies: {} };
const { context } = await chain.run(req);

expect(context.getData().every(instance => instance.value === 10)).toBe(true);
expect(req.query.undef).toBe(10);
nikli2009 marked this conversation as resolved.
Show resolved Hide resolved
expect((req as any).body.undef).toBe(10);
expect((req as any).headers.undef).toBe(10);
expect((req as any).params.undef).toBe(10);
expect((req as any).cookies.undef).toBe(10);
});
});

describe('when ParamSchema location not specified', () => {
it('should validate locations only in which the field can be found', async () => {
const schema = checkSchema({
foo: {
isInt: true,
toInt: true,
},
});
const { context } = await schema[0].run({
query: { foo: 'foo' },
params: { foo: 'true' },
});

expect(context.errors).toHaveLength(2);
});
});
describe('on schema that contains fields with bail methods', () => {
it('stops validation chain with only one error', async () => {
it('stops validation chain with only one error with specified location', async () => {
const schema = checkSchema({
foo: {
in: ['params'],
fedeci marked this conversation as resolved.
Show resolved Hide resolved
exists: {
bail: true,
},
Expand All @@ -200,7 +237,57 @@ describe('on schema that contains fields with bail methods', () => {
},
});

const { context } = await schema[0].run({ params: {} });
const { context } = await schema[0].run({ query: {} });
expect(context.errors).toHaveLength(1);
});

it('stops validation chain if any validation fails with "exist" validator', async () => {
const allLocations = ['body', 'cookies', 'headers', 'params', 'query'];
const schema = checkSchema({
foo: {
exists: {
bail: true,
errorMessage: 'exists checking failed',
},
isLength: {
options: {
min: 5,
},
},
},
});

const { context } = await schema[0].run({ query: {} });
// when location is not specified, checking each location one by one,
// if the expected field does not show up at all in any location, then there will be 5 errors.
// finally bails.
expect(context.errors).toHaveLength(allLocations.length);
// context.errors should not contain any error from next validator -> isLength.
expect(context.errors.every(err => err.msg === 'exists checking failed')).toBe(true);
});

it('stops validation chain if any validation fails with sanitizer', async () => {
const schema = checkSchema({
foo: {
toInt: true,
isInt: {
bail: true,
},
isLength: {
options: {
min: 5,
},
},
},
});

const { context } = await schema[0].run({ query: { foo: 'true' } });
const {
errors: [firstError],
} = context;

// simply make sure it's sanitizer-result-caused error.
expect(firstError.value).toBe(NaN);
expect(context.errors).toHaveLength(1);
});

Expand All @@ -225,6 +312,7 @@ describe('on schema that contains fields with bail methods', () => {
it('bails with message', async () => {
const schema = checkSchema({
foo: {
in: ['params'],
exists: {
bail: true,
errorMessage: 'Value not exists',
Expand Down
17 changes: 17 additions & 0 deletions src/middlewares/validation-chain-builders.spec.ts
Expand Up @@ -48,6 +48,23 @@ describe('buildCheckFunction()', () => {
value: 'asd',
});
});

describe('when at least 1 locations specified', () => {
// for #1010
it('should apply default value to each specified location if default option is not empty', async () => {
const custom = buildCheckFunction(['cookies', 'headers']);
const chain = custom('bar').default(10);

await chain.run(req);

expect(req.cookies).toHaveProperty('bar', 10);
expect(req.headers).toHaveProperty('bar', 10);

expect(req.body).not.toHaveProperty('bar');
expect(req.params).not.toHaveProperty('bar');
expect(req.query).not.toHaveProperty('bar');
});
});
});

describe('check()', () => {
Expand Down