strapi/packages/strapi-utils/lib/__tests__/sanitize-entity.test.js

361 lines
11 KiB
JavaScript
Raw Normal View History

'use strict';
const _ = require('lodash');
Hide creator fields from public api by default (#8052) * Add model option to hide/show creators fields in public API response Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add content-types util, rework sanitize-entity's private handling Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Update search e2e tests, fix an issue on empty search for the core-api controller (find) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix GraphQL plugin (handle privates attributes on typeDefs + resolver builds) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix sanitizeEntity import Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Move doc update from beta to stable Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix e2e test Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr comments Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Remove creator's field from upload controller routes Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix typedef build for graphql association Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr (comments + several issues) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add tests for search behavior in content-manager Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Rename files variables to meaningful names (upload controllers) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix test with search id matching serialNumber Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com> * Add toHasBeenCalledWith check for config.get (utils/content-types.test.js) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> Co-authored-by: Alexandre Bodin <bodin.alex@gmail.com>
2020-10-01 17:47:08 +02:00
const sanitizeEntity = require('../sanitize-entity');
describe('Sanitize Entity', () => {
const input = {
id: 1,
email: 'foo@bar.com',
firstname: 'foo',
lastname: 'bar',
password: 'qwerty',
};
const article = {
name: 'foobar',
content: 'lorem ipsum',
secret: 'very-secret',
};
const inputWithRelation = {
...input,
article,
};
const inputWithDz = {
...input,
dz: [
{
__component: 'article',
name: 'foo',
content: 'bar',
secret: 'secret-foobar',
},
],
};
const userModel = {
primaryKey: 'id',
options: {
timestamps: ['created_at', 'updated_at'],
},
Hide creator fields from public api by default (#8052) * Add model option to hide/show creators fields in public API response Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add content-types util, rework sanitize-entity's private handling Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Update search e2e tests, fix an issue on empty search for the core-api controller (find) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix GraphQL plugin (handle privates attributes on typeDefs + resolver builds) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix sanitizeEntity import Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Move doc update from beta to stable Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix e2e test Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr comments Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Remove creator's field from upload controller routes Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix typedef build for graphql association Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr (comments + several issues) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add tests for search behavior in content-manager Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Rename files variables to meaningful names (upload controllers) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix test with search id matching serialNumber Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com> * Add toHasBeenCalledWith check for config.get (utils/content-types.test.js) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> Co-authored-by: Alexandre Bodin <bodin.alex@gmail.com>
2020-10-01 17:47:08 +02:00
privateAttributes: ['email'],
attributes: {
email: {
type: 'text',
private: true,
},
firstname: {
type: 'text',
},
lastname: {
type: 'text',
},
password: {
type: 'password',
},
},
};
const userRelModel = {
...userModel,
attributes: {
...userModel.attributes,
article: {
collection: 'article',
},
},
};
const userDzModel = {
...userModel,
attributes: {
...userModel.attributes,
dz: {
type: 'dynamiczone',
components: ['article'],
},
},
};
const articleModel = {
primaryKey: 'id',
options: {
timestamps: ['created_at', 'updated_at'],
},
Hide creator fields from public api by default (#8052) * Add model option to hide/show creators fields in public API response Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add content-types util, rework sanitize-entity's private handling Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Update search e2e tests, fix an issue on empty search for the core-api controller (find) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix GraphQL plugin (handle privates attributes on typeDefs + resolver builds) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix sanitizeEntity import Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Move doc update from beta to stable Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix e2e test Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr comments Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Remove creator's field from upload controller routes Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix typedef build for graphql association Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr (comments + several issues) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add tests for search behavior in content-manager Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Rename files variables to meaningful names (upload controllers) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix test with search id matching serialNumber Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com> * Add toHasBeenCalledWith check for config.get (utils/content-types.test.js) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> Co-authored-by: Alexandre Bodin <bodin.alex@gmail.com>
2020-10-01 17:47:08 +02:00
privateAttributes: ['secret'],
attributes: {
name: {
type: 'text',
},
content: {
type: 'text',
},
secret: {
type: 'text',
private: true,
},
},
};
const models = {
user: userModel,
article: articleModel,
userRel: userRelModel,
userDz: userDzModel,
};
beforeEach(() => {
global.strapi = {
getModel(name) {
return models[name];
},
config: {
get: jest.fn,
},
};
});
describe('Basic', () => {
const tests = [
[
{ withPrivate: false, isOutput: true, includeFields: null },
_.pick(input, ['id', 'firstname', 'lastname']),
],
[{ withPrivate: false, isOutput: false, includeFields: null }, input],
[
{ withPrivate: false, isOutput: true, includeFields: ['firstname'] },
_.pick(input, ['id', 'firstname']),
],
[
{ withPrivate: false, isOutput: true, includeFields: ['email', 'firstname'] },
_.pick(input, ['id', 'firstname']),
],
[{ withPrivate: false, isOutput: true, includeFields: ['password'] }, _.pick(input, ['id'])],
[
{ withPrivate: true, isOutput: true, includeFields: null },
_.pick(input, ['id', 'email', 'firstname', 'lastname']),
],
[{ withPrivate: true, isOutput: false, includeFields: null }, input],
[
{ withPrivate: true, isOutput: true, includeFields: ['firstname'] },
_.pick(input, ['id', 'firstname']),
],
[
{ withPrivate: true, isOutput: true, includeFields: ['email', 'firstname'] },
_.pick(input, ['id', 'email', 'firstname']),
],
[{ withPrivate: true, isOutput: true, includeFields: ['password'] }, _.pick(input, ['id'])],
[
{ withPrivate: true, isOutput: false, includeFields: ['firstname'] },
_.pick(input, ['id', 'firstname']),
],
[
{ withPrivate: true, isOutput: false, includeFields: ['email', 'firstname'] },
_.pick(input, ['id', 'email', 'firstname']),
],
[
{ withPrivate: true, isOutput: false, includeFields: ['password'] },
_.pick(input, ['id', 'password']),
],
];
test.each(tests)(`Test n°%#`, (options, expected) => {
const { user: model } = models;
expect(sanitizeEntity(input, { ...options, model })).toStrictEqual(expected);
});
});
describe('With private attributes', () => {
describe('When options.privateAttributes exists in model, the attributes in options.privateAttributes must be hidden', () => {
const tests = [
[{ withPrivate: false, isOutput: true, includeFields: null }, _.pick(input, ['lastname'])],
[{ withPrivate: false, isOutput: false, includeFields: null }, input],
[{ withPrivate: false, isOutput: true, includeFields: ['firstname'] }, {}],
[{ withPrivate: false, isOutput: true, includeFields: ['email', 'firstname'] }, {}],
[{ withPrivate: false, isOutput: true, includeFields: ['password'] }, {}],
[
{ withPrivate: true, isOutput: true, includeFields: null },
_.pick(input, ['id', 'email', 'firstname', 'lastname']),
],
[{ withPrivate: true, isOutput: false, includeFields: null }, input],
[
{ withPrivate: true, isOutput: true, includeFields: ['firstname'] },
_.pick(input, ['id', 'firstname']),
],
[
{ withPrivate: true, isOutput: true, includeFields: ['email', 'firstname'] },
_.pick(input, ['id', 'email', 'firstname']),
],
[{ withPrivate: true, isOutput: true, includeFields: ['password'] }, _.pick(input, ['id'])],
[
{ withPrivate: true, isOutput: false, includeFields: ['firstname'] },
_.pick(input, ['id', 'firstname']),
],
[
{ withPrivate: true, isOutput: false, includeFields: ['email', 'firstname'] },
_.pick(input, ['id', 'email', 'firstname']),
],
[
{ withPrivate: true, isOutput: false, includeFields: ['password'] },
_.pick(input, ['id', 'password']),
],
];
const model = {
...models.user,
options: {
...models.user.options,
privateAttributes: ['firstname'],
},
Hide creator fields from public api by default (#8052) * Add model option to hide/show creators fields in public API response Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add content-types util, rework sanitize-entity's private handling Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Update search e2e tests, fix an issue on empty search for the core-api controller (find) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix GraphQL plugin (handle privates attributes on typeDefs + resolver builds) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix sanitizeEntity import Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Move doc update from beta to stable Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix e2e test Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr comments Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Remove creator's field from upload controller routes Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix typedef build for graphql association Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix pr (comments + several issues) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Add tests for search behavior in content-manager Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Rename files variables to meaningful names (upload controllers) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> * Fix test with search id matching serialNumber Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com> * Add toHasBeenCalledWith check for config.get (utils/content-types.test.js) Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu> Co-authored-by: Alexandre Bodin <bodin.alex@gmail.com>
2020-10-01 17:47:08 +02:00
privateAttributes: [].concat(models.user.privateAttributes, ['firstname'], ['id']),
};
test.each(tests)(`Test n°%#`, (options, expected) => {
expect(sanitizeEntity(input, { ...options, model })).toStrictEqual(expected);
});
});
});
describe('With relation', () => {
const tests = [
[
inputWithRelation,
{ withPrivate: false, isOutput: true, includeFields: null },
_.pick(inputWithRelation, [
'id',
'firstname',
'lastname',
'article.name',
'article.content',
]),
],
[
inputWithRelation,
{ withPrivate: false, isOutput: true, includeFields: ['firstname', 'lastname'] },
_.pick(inputWithRelation, ['id', 'firstname', 'lastname']),
],
[
inputWithRelation,
{ withPrivate: false, isOutput: true, includeFields: ['article'] },
_.pick(inputWithRelation, ['id', 'article.name', 'article.content']),
],
[
inputWithRelation,
{ withPrivate: false, isOutput: true, includeFields: ['article.name'] },
_.pick(inputWithRelation, ['id', 'article.name']),
],
[
inputWithRelation,
{ withPrivate: true, isOutput: true, includeFields: null },
_.pick(inputWithRelation, ['id', 'email', 'firstname', 'lastname', 'article']),
],
[
{ ...inputWithRelation, article: _.times(3, () => _.clone(article)) },
{ withPrivate: false, isOutput: true, includeFields: null },
{
..._.pick(inputWithRelation, ['id', 'firstname', 'lastname']),
article: _.times(3, () => _.pick(article, ['name', 'content'])),
},
],
];
test.each(tests)(`Test n°%#`, (source, options, expected) => {
const { userRel: model } = models;
expect(sanitizeEntity(source, { ...options, model })).toStrictEqual(expected);
});
});
describe('With Dynamic Zone', () => {
test('Dynamic zone null', () => {
const { userDz: model } = models;
const dataSource = { ...inputWithDz, dz: null };
const expected = _.pick(dataSource, ['id', 'firstname', 'lastname', 'dz']);
expect(sanitizeEntity(dataSource, { model })).toStrictEqual(expected);
});
test('Dynamic zone with a basic component', () => {
const { userDz: model } = models;
const expected = {
..._.pick(inputWithDz, ['id', 'firstname', 'lastname']),
dz: inputWithDz.dz.map(comp => _.pick(comp, ['__component', 'name', 'content'])),
};
expect(sanitizeEntity(inputWithDz, { model })).toStrictEqual(expected);
});
});
describe('Edge cases', () => {
test('It returns the input data if the model is nil and isOutput false', () => {
expect(sanitizeEntity(input, { model: null, isOutput: false })).toEqual(input);
expect(sanitizeEntity(input, { model: undefined, isOutput: false })).toEqual(input);
});
test('It returns null if the model is nil and isOutput true', () => {
expect(sanitizeEntity(input, { model: null })).toBeNull();
expect(sanitizeEntity(input, { model: undefined })).toBeNull();
});
test(`It returns the input data as-is if it's not an object or an array`, () => {
const { user: model } = models;
expect(sanitizeEntity('foobar', { model })).toBe('foobar');
expect(sanitizeEntity(undefined, { model })).toBeUndefined();
expect(sanitizeEntity(null, { model })).toBeNull();
});
test('It sanitizes all entries if the input is an array', () => {
const dataSource = [_.clone(input), _.clone(input)];
const expected = [
_.pick(input, 'id', 'firstname', 'lastname'),
_.pick(input, 'id', 'firstname', 'lastname'),
];
const { user: model } = models;
expect(sanitizeEntity(dataSource, { model })).toStrictEqual(expected);
});
test(`It should put the relation value as-is if it's nil'`, () => {
const dataSource = { ...inputWithRelation, article: null };
const expected = _.omit(dataSource, ['email', 'password']);
const { userRel: model } = models;
expect(sanitizeEntity(dataSource, { model })).toStrictEqual(expected);
});
test(`It should make sure that legacy data parsing returns an object`, () => {
const dataSource = {
toJSON: jest.fn(() => input),
};
const invalidDataSource = {
toJSON: jest.fn(() => null),
};
const { user: model } = models;
expect(sanitizeEntity(dataSource, { model })).toStrictEqual(
_.omit(input, ['email', 'password'])
);
expect(dataSource.toJSON).toHaveBeenCalled();
expect(sanitizeEntity(invalidDataSource, { model })).toBeNull();
expect(invalidDataSource.toJSON).toHaveBeenCalled();
});
test('It should handle custom fields', () => {
const dataSource = { ...input, foo: 'bar' };
const expected = _.omit(dataSource, ['email', 'password']);
const { user: model } = models;
expect(sanitizeEntity(dataSource, { model })).toStrictEqual(expected);
});
});
});