mirror of
https://github.com/strapi/strapi.git
synced 2025-09-03 05:39:36 +00:00
Add utils::sanitize-entity tests (#7497)
* Add utils::sanitize-entity tests Signed-off-by: Convly <jean-sebastien.herbaux@epitech.eu>
This commit is contained in:
parent
b39709a6ed
commit
1e67421668
295
packages/strapi-utils/lib/__tests__/sanitize-entity.test.js
Normal file
295
packages/strapi-utils/lib/__tests__/sanitize-entity.test.js
Normal file
@ -0,0 +1,295 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const sanitizeEntity = require('../sanitize-entity');
|
||||
|
||||
describe('Sanitize Entity', () => {
|
||||
const input = {
|
||||
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'],
|
||||
},
|
||||
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'],
|
||||
},
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'text',
|
||||
},
|
||||
content: {
|
||||
type: 'text',
|
||||
},
|
||||
secret: {
|
||||
type: 'text',
|
||||
private: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const models = {
|
||||
user: userModel,
|
||||
article: articleModel,
|
||||
userRel: userRelModel,
|
||||
userDz: userDzModel,
|
||||
};
|
||||
|
||||
global.strapi = {
|
||||
getModel(name) {
|
||||
return models[name];
|
||||
},
|
||||
};
|
||||
|
||||
describe('Basic', () => {
|
||||
const tests = [
|
||||
[
|
||||
{ withPrivate: false, isOutput: true, includeFields: null },
|
||||
_.pick(input, ['firstname', 'lastname']),
|
||||
],
|
||||
[{ withPrivate: false, isOutput: false, includeFields: null }, input],
|
||||
[
|
||||
{ withPrivate: false, isOutput: true, includeFields: ['firstname'] },
|
||||
_.pick(input, ['firstname']),
|
||||
],
|
||||
[
|
||||
{ withPrivate: false, isOutput: true, includeFields: ['email', 'firstname'] },
|
||||
_.pick(input, ['firstname']),
|
||||
],
|
||||
[{ withPrivate: false, isOutput: true, includeFields: ['password'] }, {}],
|
||||
[
|
||||
{ withPrivate: true, isOutput: true, includeFields: null },
|
||||
_.pick(input, ['email', 'firstname', 'lastname']),
|
||||
],
|
||||
[{ withPrivate: true, isOutput: false, includeFields: null }, input],
|
||||
[
|
||||
{ withPrivate: true, isOutput: true, includeFields: ['firstname'] },
|
||||
_.pick(input, ['firstname']),
|
||||
],
|
||||
[
|
||||
{ withPrivate: true, isOutput: true, includeFields: ['email', 'firstname'] },
|
||||
_.pick(input, ['email', 'firstname']),
|
||||
],
|
||||
[{ withPrivate: true, isOutput: true, includeFields: ['password'] }, {}],
|
||||
[
|
||||
{ withPrivate: true, isOutput: false, includeFields: ['firstname'] },
|
||||
_.pick(input, ['firstname']),
|
||||
],
|
||||
[
|
||||
{ withPrivate: true, isOutput: false, includeFields: ['email', 'firstname'] },
|
||||
_.pick(input, ['email', 'firstname']),
|
||||
],
|
||||
[
|
||||
{ withPrivate: true, isOutput: false, includeFields: ['password'] },
|
||||
_.pick(input, ['password']),
|
||||
],
|
||||
];
|
||||
|
||||
test.each(tests)(`Test n°%#`, (options, expected) => {
|
||||
const { user: model } = models;
|
||||
expect(sanitizeEntity(input, { ...options, model })).toStrictEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('With relation', () => {
|
||||
const tests = [
|
||||
[
|
||||
inputWithRelation,
|
||||
{ withPrivate: false, isOutput: true, includeFields: null },
|
||||
{
|
||||
..._.pick(inputWithRelation, ['firstname', 'lastname']),
|
||||
article: _.pick(inputWithRelation.article, ['name', 'content']),
|
||||
},
|
||||
],
|
||||
[
|
||||
inputWithRelation,
|
||||
{ withPrivate: false, isOutput: true, includeFields: ['firstname', 'lastname'] },
|
||||
_.pick(inputWithRelation, ['firstname', 'lastname']),
|
||||
],
|
||||
[
|
||||
inputWithRelation,
|
||||
{ withPrivate: false, isOutput: true, includeFields: ['article'] },
|
||||
{
|
||||
article: _.pick(inputWithRelation.article, ['name', 'content']),
|
||||
},
|
||||
],
|
||||
[
|
||||
inputWithRelation,
|
||||
{ withPrivate: false, isOutput: true, includeFields: ['article.name'] },
|
||||
_.pick(inputWithRelation, ['article.name']),
|
||||
],
|
||||
[
|
||||
inputWithRelation,
|
||||
{ withPrivate: true, isOutput: true, includeFields: null },
|
||||
_.pick(inputWithRelation, ['email', 'firstname', 'lastname', 'article']),
|
||||
],
|
||||
[
|
||||
{ ...inputWithRelation, article: _.times(3, () => _.clone(article)) },
|
||||
{ withPrivate: false, isOutput: true, includeFields: null },
|
||||
{
|
||||
..._.pick(inputWithRelation, '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, ['firstname', 'lastname', 'dz']);
|
||||
|
||||
expect(sanitizeEntity(dataSource, { model })).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
test('Dynamic zone with a basic component', () => {
|
||||
const { userDz: model } = models;
|
||||
|
||||
const expected = {
|
||||
..._.pick(inputWithDz, ['firstname', 'lastname']),
|
||||
dz: inputWithDz.dz.map(comp => _.pick(comp, ['__component', 'name', 'content'])),
|
||||
};
|
||||
|
||||
expect(sanitizeEntity(inputWithDz, { model })).toStrictEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge cases', () => {
|
||||
test('It returns null if the model is nil', () => {
|
||||
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, 'firstname', 'lastname'),
|
||||
_.pick(input, '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);
|
||||
});
|
||||
});
|
||||
});
|
@ -11,10 +11,14 @@ const sanitizeEntity = (dataSource, options) => {
|
||||
|
||||
const data = parseOriginalData(dataSource);
|
||||
|
||||
if (typeof data !== 'object') {
|
||||
if (typeof data !== 'object' || _.isNil(data)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (_.isArray(data)) {
|
||||
return data.map(entity => sanitizeEntity(entity, options));
|
||||
}
|
||||
|
||||
if (_.isNil(model)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ const createCollectionTypeController = ({ model, service }) => {
|
||||
entities = await service.find(ctx.query);
|
||||
}
|
||||
|
||||
return entities.map(entity => sanitizeEntity(entity, { model }));
|
||||
return sanitizeEntity(entities, { model });
|
||||
},
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user