mirror of
https://github.com/strapi/strapi.git
synced 2025-12-10 14:34:22 +00:00
chore(history): add api tests (#20157)
This commit is contained in:
parent
7431ba9b38
commit
bdaafbbb3c
@ -45,18 +45,18 @@ export const VersionHeader = ({ headerId }: VersionHeaderProps) => {
|
||||
|
||||
const mainFieldValue = version.data[mainField];
|
||||
|
||||
const getBackLink = (): To => {
|
||||
const getNextNavigation = (): To => {
|
||||
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
||||
|
||||
if (collectionType === COLLECTION_TYPES) {
|
||||
return {
|
||||
pathname: `../${collectionType}/${version.contentType}/${version.relatedDocumentId}`,
|
||||
pathname: `/content-manager/${collectionType}/${version.contentType}/${version.relatedDocumentId}`,
|
||||
search: pluginsQueryParams,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
pathname: `../${collectionType}/${version.contentType}`,
|
||||
pathname: `/content-manager/${collectionType}/${version.contentType}`,
|
||||
search: pluginsQueryParams,
|
||||
};
|
||||
};
|
||||
@ -64,16 +64,17 @@ export const VersionHeader = ({ headerId }: VersionHeaderProps) => {
|
||||
const handleRestore = async () => {
|
||||
try {
|
||||
const response = await restoreVersion({
|
||||
documentId: version.relatedDocumentId,
|
||||
collectionType,
|
||||
params: {
|
||||
versionId: version.id,
|
||||
documentId: version.relatedDocumentId,
|
||||
contentType: version.contentType,
|
||||
},
|
||||
body: { contentType: version.contentType },
|
||||
});
|
||||
|
||||
if ('data' in response) {
|
||||
navigate(`/content-manager/${collectionType}/${slug}/${response.data.data?.documentId}`);
|
||||
navigate(getNextNavigation());
|
||||
|
||||
toggleNotification({
|
||||
type: 'success',
|
||||
@ -137,7 +138,7 @@ export const VersionHeader = ({ headerId }: VersionHeaderProps) => {
|
||||
startIcon={<ArrowLeft />}
|
||||
as={NavLink}
|
||||
// @ts-expect-error - types are not inferred correctly through the as prop.
|
||||
to={getBackLink()}
|
||||
to={getNextNavigation()}
|
||||
>
|
||||
{formatMessage({
|
||||
id: 'global.back',
|
||||
|
||||
@ -80,7 +80,7 @@ describe('VersionHeader', () => {
|
||||
const backLink = screen.getByRole('link', { name: 'Back' });
|
||||
expect(backLink).toHaveAttribute(
|
||||
'href',
|
||||
'/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr'
|
||||
'/content-manager/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr'
|
||||
);
|
||||
});
|
||||
|
||||
@ -111,7 +111,7 @@ describe('VersionHeader', () => {
|
||||
const backLink = screen.getByRole('link', { name: 'Back' });
|
||||
expect(backLink).toHaveAttribute(
|
||||
'href',
|
||||
'/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr?plugins[i18n][locale]=en'
|
||||
'/content-manager/collection-types/api::kitchensink.kitchensink/pcwmq3rlmp5w0be3cuplhnpr?plugins[i18n][locale]=en'
|
||||
);
|
||||
});
|
||||
|
||||
@ -158,7 +158,10 @@ describe('VersionHeader', () => {
|
||||
expect(await screen.findByText('Test Title (homepage)')).toBeInTheDocument();
|
||||
|
||||
const backLink = screen.getByRole('link', { name: 'Back' });
|
||||
expect(backLink).toHaveAttribute('href', '/single-types/api::homepage.homepage');
|
||||
expect(backLink).toHaveAttribute(
|
||||
'href',
|
||||
'/content-manager/single-types/api::homepage.homepage'
|
||||
);
|
||||
});
|
||||
|
||||
it('should display the correct title and subtitle for a localized entry', async () => {
|
||||
@ -185,7 +188,7 @@ describe('VersionHeader', () => {
|
||||
const backLink = screen.getByRole('link', { name: 'Back' });
|
||||
expect(backLink).toHaveAttribute(
|
||||
'href',
|
||||
'/single-types/api::homepage.homepage?plugins[i18n][locale]=en'
|
||||
'/content-manager/single-types/api::homepage.homepage?plugins[i18n][locale]=en'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
import { Data } from '@strapi/types';
|
||||
|
||||
import {
|
||||
GetHistoryVersions,
|
||||
RestoreHistoryVersion,
|
||||
} from '../../../../shared/contracts/history-versions';
|
||||
import { COLLECTION_TYPES } from '../../constants/collections';
|
||||
import { contentManagerApi } from '../../services/api';
|
||||
|
||||
interface RestoreVersion extends RestoreHistoryVersion.Request {
|
||||
documentId: Data.ID;
|
||||
collectionType?: string;
|
||||
}
|
||||
|
||||
const historyVersionsApi = contentManagerApi.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
getHistoryVersions: builder.query<
|
||||
@ -21,23 +29,27 @@ const historyVersionsApi = contentManagerApi.injectEndpoints({
|
||||
},
|
||||
providesTags: ['HistoryVersion'],
|
||||
}),
|
||||
restoreVersion: builder.mutation<RestoreHistoryVersion.Response, RestoreHistoryVersion.Request>(
|
||||
{
|
||||
query({ params, body }) {
|
||||
return {
|
||||
url: `/content-manager/history-versions/${params.versionId}/restore`,
|
||||
method: 'PUT',
|
||||
data: body,
|
||||
};
|
||||
},
|
||||
invalidatesTags: (_res, _error, { params }) => {
|
||||
return [
|
||||
'HistoryVersion',
|
||||
{ type: 'Document', id: `${params.contentType}_${params.documentId}` },
|
||||
];
|
||||
},
|
||||
}
|
||||
),
|
||||
restoreVersion: builder.mutation<RestoreHistoryVersion.Response, RestoreVersion>({
|
||||
query({ params, body }) {
|
||||
return {
|
||||
url: `/content-manager/history-versions/${params.versionId}/restore`,
|
||||
method: 'PUT',
|
||||
data: body,
|
||||
};
|
||||
},
|
||||
invalidatesTags: (_res, _error, { documentId, collectionType, params }) => {
|
||||
return [
|
||||
'HistoryVersion',
|
||||
{
|
||||
type: 'Document',
|
||||
id:
|
||||
collectionType === COLLECTION_TYPES
|
||||
? `${params.contentType}_${documentId}`
|
||||
: params.contentType,
|
||||
},
|
||||
];
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -1,199 +0,0 @@
|
||||
import { createHistoryVersionController } from '../history-version';
|
||||
|
||||
const mockFindVersionsPage = jest.fn();
|
||||
|
||||
// History utils
|
||||
jest.mock('../../utils', () => ({
|
||||
getService: jest.fn((_strapi, name) => {
|
||||
if (name === 'history') {
|
||||
return {
|
||||
findVersionsPage: mockFindVersionsPage,
|
||||
};
|
||||
}
|
||||
}),
|
||||
}));
|
||||
|
||||
// Content Manager utils
|
||||
jest.mock('../../../utils', () => ({
|
||||
getService: jest.fn((name) => {
|
||||
if (name === 'permission-checker') {
|
||||
return {
|
||||
create: jest.fn(() => ({
|
||||
cannot: {
|
||||
read: jest.fn(() => false),
|
||||
},
|
||||
sanitizeQuery: jest.fn((query) => query),
|
||||
})),
|
||||
};
|
||||
}
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('History version controller', () => {
|
||||
beforeEach(() => {
|
||||
mockFindVersionsPage.mockClear();
|
||||
});
|
||||
|
||||
describe('findMany', () => {
|
||||
it('should require contentType and documentId for collection types', () => {
|
||||
const ctx = {
|
||||
state: {
|
||||
userAbility: {},
|
||||
},
|
||||
query: {},
|
||||
};
|
||||
|
||||
const historyVersionController = createHistoryVersionController({
|
||||
// @ts-expect-error - we're not mocking the entire strapi object
|
||||
strapi: { getModel: jest.fn(() => ({ kind: 'collectionType' })) },
|
||||
});
|
||||
|
||||
// @ts-expect-error partial context
|
||||
expect(historyVersionController.findMany(ctx)).rejects.toThrow(
|
||||
/contentType and documentId are required/
|
||||
);
|
||||
expect(mockFindVersionsPage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should require contentType for single types', () => {
|
||||
const ctx = {
|
||||
state: {
|
||||
userAbility: {},
|
||||
},
|
||||
query: {},
|
||||
};
|
||||
|
||||
const historyVersionController = createHistoryVersionController({
|
||||
// @ts-expect-error - we're not mocking the entire strapi object
|
||||
strapi: { getModel: jest.fn(() => ({ kind: 'singleType' })) },
|
||||
});
|
||||
|
||||
// @ts-expect-error partial context
|
||||
expect(historyVersionController.findMany(ctx)).rejects.toThrow(/contentType is required/);
|
||||
expect(mockFindVersionsPage).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call findVersionsPage for collection types', async () => {
|
||||
const ctx = {
|
||||
state: {
|
||||
userAbility: {},
|
||||
},
|
||||
query: {
|
||||
documentId: 'document-id',
|
||||
contentType: 'api::test.test',
|
||||
},
|
||||
};
|
||||
|
||||
mockFindVersionsPage.mockResolvedValueOnce({
|
||||
results: [{ id: 'history-version-id' }],
|
||||
pagination: {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageCount: 1,
|
||||
total: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const historyVersionController = createHistoryVersionController({
|
||||
// @ts-expect-error - we're not mocking the entire strapi object
|
||||
strapi: { getModel: jest.fn(() => ({ kind: 'collectionType' })) },
|
||||
});
|
||||
|
||||
// @ts-expect-error partial context
|
||||
const response = await historyVersionController.findMany(ctx);
|
||||
|
||||
expect(mockFindVersionsPage).toHaveBeenCalled();
|
||||
expect(response.data.length).toBe(1);
|
||||
expect(response.meta.pagination).toBeDefined();
|
||||
});
|
||||
|
||||
it('should call findVersionsPage for single types', async () => {
|
||||
const ctx = {
|
||||
state: {
|
||||
userAbility: {},
|
||||
},
|
||||
query: {
|
||||
contentType: 'api::test.test',
|
||||
},
|
||||
};
|
||||
|
||||
mockFindVersionsPage.mockResolvedValueOnce({
|
||||
results: [{ id: 'history-version-id' }],
|
||||
pagination: {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageCount: 1,
|
||||
total: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const historyVersionController = createHistoryVersionController({
|
||||
// @ts-expect-error - we're not mocking the entire strapi object
|
||||
strapi: { getModel: jest.fn(() => ({ kind: 'singleType' })) },
|
||||
});
|
||||
|
||||
// @ts-expect-error partial context
|
||||
const response = await historyVersionController.findMany(ctx);
|
||||
|
||||
expect(mockFindVersionsPage).toHaveBeenCalled();
|
||||
expect(response.data.length).toBe(1);
|
||||
expect(response.meta.pagination).toBeDefined();
|
||||
});
|
||||
|
||||
it('applies pagination params', async () => {
|
||||
const ctx = {
|
||||
state: {
|
||||
userAbility: {},
|
||||
},
|
||||
query: {
|
||||
contentType: 'api::test.test',
|
||||
},
|
||||
};
|
||||
|
||||
const historyVersionController = createHistoryVersionController({
|
||||
// @ts-expect-error - we're not mocking the entire strapi object
|
||||
strapi: { getModel: jest.fn(() => ({ kind: 'singleType' })) },
|
||||
});
|
||||
|
||||
/**
|
||||
* Applies default pagination params
|
||||
*/
|
||||
mockFindVersionsPage.mockResolvedValueOnce({
|
||||
results: [],
|
||||
pagination: {
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
},
|
||||
});
|
||||
// @ts-expect-error partial context
|
||||
const mockResponse = await historyVersionController.findMany(ctx);
|
||||
expect(mockFindVersionsPage).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
})
|
||||
);
|
||||
expect(mockResponse.meta.pagination.page).toBe(1);
|
||||
expect(mockResponse.meta.pagination.pageSize).toBe(20);
|
||||
|
||||
/**
|
||||
* Prevents invalid pagination params
|
||||
*/
|
||||
mockFindVersionsPage.mockResolvedValueOnce({
|
||||
results: [],
|
||||
pagination: {},
|
||||
});
|
||||
// @ts-expect-error partial context
|
||||
await historyVersionController.findMany({
|
||||
...ctx,
|
||||
query: { ...ctx.query, page: '-1', pageSize: '1000' },
|
||||
});
|
||||
expect(mockFindVersionsPage).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -37,13 +37,13 @@ const createHistoryVersionController = ({ strapi }: { strapi: Core.Strapi }) =>
|
||||
return {
|
||||
async findMany(ctx) {
|
||||
const contentTypeUid = ctx.query.contentType as UID.ContentType;
|
||||
const isSingleType = strapi.getModel(contentTypeUid).kind === 'singleType';
|
||||
const isSingleType = strapi.getModel(contentTypeUid)?.kind === 'singleType';
|
||||
|
||||
if (isSingleType && !contentTypeUid) {
|
||||
throw new errors.ForbiddenError('contentType is required');
|
||||
}
|
||||
|
||||
if (!contentTypeUid && !ctx.query.documentId) {
|
||||
if (!isSingleType && (!contentTypeUid || !ctx.query.documentId)) {
|
||||
throw new errors.ForbiddenError('contentType and documentId are required');
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,9 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
};
|
||||
|
||||
const localesService = strapi.plugin('i18n')?.service('locales');
|
||||
|
||||
const getDefaultLocale = async () => (localesService ? localesService.getDefaultLocale() : null);
|
||||
|
||||
const getLocaleDictionary = async () => {
|
||||
if (!localesService) return {};
|
||||
|
||||
@ -163,8 +166,9 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
? { documentId: result.documentId, locale: context.params?.locale }
|
||||
: { documentId: context.params.documentId, locale: context.params?.locale };
|
||||
|
||||
const defaultLocale = localesService ? await localesService.getDefaultLocale() : null;
|
||||
const defaultLocale = await getDefaultLocale();
|
||||
const locale = documentContext.locale || defaultLocale;
|
||||
|
||||
const document = await strapi.documents(contentTypeUid).findOne({
|
||||
documentId: documentContext.documentId,
|
||||
locale,
|
||||
@ -251,6 +255,7 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
results: HistoryVersions.HistoryVersionDataResponse[];
|
||||
pagination: HistoryVersions.Pagination;
|
||||
}> {
|
||||
const locale = params.locale || (await getDefaultLocale());
|
||||
const [{ results, pagination }, localeDictionary] = await Promise.all([
|
||||
query.findPage({
|
||||
...params,
|
||||
@ -258,7 +263,7 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
$and: [
|
||||
{ contentType: params.contentType },
|
||||
...(params.documentId ? [{ relatedDocumentId: params.documentId }] : []),
|
||||
...(params.locale ? [{ locale: params.locale }] : []),
|
||||
...(locale ? [{ locale }] : []),
|
||||
],
|
||||
},
|
||||
populate: ['createdBy'],
|
||||
@ -497,6 +502,7 @@ const createHistoryService = ({ strapi }: { strapi: Core.Strapi }) => {
|
||||
const data = omit(['id', ...Object.keys(schemaDiff.removed)], dataWithoutMissingRelations);
|
||||
const restoredDocument = await strapi.documents(version.contentType).update({
|
||||
documentId: version.relatedDocumentId,
|
||||
locale: version.locale,
|
||||
data,
|
||||
});
|
||||
|
||||
|
||||
@ -82,7 +82,6 @@ export declare namespace RestoreHistoryVersion {
|
||||
export interface Request {
|
||||
params: {
|
||||
versionId: Data.ID;
|
||||
documentId: Data.ID;
|
||||
contentType: UID.ContentType;
|
||||
};
|
||||
body: {
|
||||
|
||||
@ -0,0 +1,442 @@
|
||||
import { createStrapiInstance } from 'api-tests/strapi';
|
||||
import { createAuthRequest } from 'api-tests/request';
|
||||
import { createUtils, describeOnCondition } from 'api-tests/utils';
|
||||
import { createTestBuilder } from 'api-tests/builder';
|
||||
|
||||
const edition = process.env.STRAPI_DISABLE_EE === 'true' ? 'CE' : 'EE';
|
||||
|
||||
const collectionTypeUid = 'api::product.product';
|
||||
const collectionTypeModel = {
|
||||
draftAndPublish: true,
|
||||
singularName: 'product',
|
||||
pluralName: 'products',
|
||||
displayName: 'Product',
|
||||
kind: 'collectionType',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: true,
|
||||
},
|
||||
},
|
||||
attributes: {
|
||||
name: {
|
||||
type: 'string',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const singleTypeUid = 'api::homepage.homepage';
|
||||
const singleTypeModel = {
|
||||
draftAndPublish: true,
|
||||
singularName: 'homepage',
|
||||
pluralName: 'homepages',
|
||||
displayName: 'Homepage',
|
||||
kind: 'singleType',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: true,
|
||||
},
|
||||
},
|
||||
attributes: {
|
||||
title: {
|
||||
type: 'string',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
subtitle: {
|
||||
type: 'string',
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
localized: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
interface CreateEntryArgs {
|
||||
uid: string;
|
||||
data: Record<string, unknown>;
|
||||
isCollectionType?: boolean;
|
||||
}
|
||||
|
||||
interface UpdateEntryArgs extends CreateEntryArgs {
|
||||
documentId?: string;
|
||||
locale?: string;
|
||||
}
|
||||
|
||||
describeOnCondition(edition === 'EE')('History API', () => {
|
||||
const builder = createTestBuilder();
|
||||
let strapi;
|
||||
let rq;
|
||||
let collectionTypeDocumentId;
|
||||
let singleTypeDocumentId;
|
||||
|
||||
const createEntry = async ({ uid, data, isCollectionType = true }: CreateEntryArgs) => {
|
||||
const type = isCollectionType ? 'collection-types' : 'single-types';
|
||||
|
||||
const { body } = await rq({
|
||||
method: 'POST',
|
||||
url: `/content-manager/${type}/${uid}`,
|
||||
body: data,
|
||||
});
|
||||
|
||||
return body;
|
||||
};
|
||||
|
||||
const updateEntry = async ({ uid, documentId, data, locale }: UpdateEntryArgs) => {
|
||||
const type = documentId ? 'collection-types' : 'single-types';
|
||||
const params = documentId ? `${type}/${uid}/${documentId}` : `${type}/${uid}`;
|
||||
|
||||
const { body } = await rq({
|
||||
method: 'PUT',
|
||||
url: `/content-manager/${params}`,
|
||||
body: data,
|
||||
qs: { locale },
|
||||
});
|
||||
|
||||
return body;
|
||||
};
|
||||
|
||||
const createUserAndReq = async (
|
||||
userName: string,
|
||||
permissions: { action: string; subject: string }[]
|
||||
) => {
|
||||
const utils = createUtils(strapi);
|
||||
const role = await utils.createRole({
|
||||
name: `role-${userName}`,
|
||||
description: `Role with restricted permissions for ${userName}`,
|
||||
});
|
||||
|
||||
const rolePermissions = await utils.assignPermissionsToRole(role.id, permissions);
|
||||
Object.assign(role, { permissions: rolePermissions });
|
||||
|
||||
const user = await utils.createUser({
|
||||
firstname: userName,
|
||||
lastname: 'User',
|
||||
email: `${userName}.user@strapi.io`,
|
||||
roles: [role.id],
|
||||
});
|
||||
|
||||
const rq = await createAuthRequest({ strapi, userInfo: user });
|
||||
|
||||
return rq;
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
await builder.addContentTypes([collectionTypeModel, singleTypeModel]).build();
|
||||
|
||||
strapi = await createStrapiInstance();
|
||||
rq = await createAuthRequest({ strapi });
|
||||
|
||||
// Create another locale
|
||||
const localeService = strapi.plugin('i18n').service('locales');
|
||||
await localeService.create({ code: 'fr', name: 'French' });
|
||||
|
||||
// Create a collection type to create an initial history version
|
||||
const collectionType = await createEntry({
|
||||
uid: collectionTypeUid,
|
||||
data: {
|
||||
name: 'Product 1',
|
||||
},
|
||||
});
|
||||
|
||||
// Update the single type to create an initial history version
|
||||
const singleType = await updateEntry({
|
||||
uid: singleTypeUid,
|
||||
data: {
|
||||
title: 'Welcome',
|
||||
},
|
||||
isCollectionType: false,
|
||||
});
|
||||
// Set the documentIds to test
|
||||
collectionTypeDocumentId = collectionType.data.documentId;
|
||||
singleTypeDocumentId = singleType.data.documentId;
|
||||
|
||||
// Update to create history versions for entries in different locales
|
||||
await Promise.all([
|
||||
updateEntry({
|
||||
documentId: collectionTypeDocumentId,
|
||||
uid: collectionTypeUid,
|
||||
data: {
|
||||
description: 'Hello',
|
||||
},
|
||||
}),
|
||||
updateEntry({
|
||||
documentId: collectionTypeDocumentId,
|
||||
uid: collectionTypeUid,
|
||||
locale: 'fr',
|
||||
data: {
|
||||
name: 'Produit 1',
|
||||
},
|
||||
}),
|
||||
updateEntry({
|
||||
documentId: collectionTypeDocumentId,
|
||||
uid: collectionTypeUid,
|
||||
locale: 'fr',
|
||||
data: {
|
||||
description: 'Coucou',
|
||||
},
|
||||
}),
|
||||
updateEntry({
|
||||
uid: singleTypeUid,
|
||||
data: {
|
||||
description: 'Wow, amazing!',
|
||||
},
|
||||
isCollectionType: false,
|
||||
}),
|
||||
updateEntry({
|
||||
uid: singleTypeUid,
|
||||
data: {
|
||||
title: 'Bienvenue',
|
||||
},
|
||||
isCollectionType: false,
|
||||
locale: 'fr',
|
||||
}),
|
||||
updateEntry({
|
||||
uid: singleTypeUid,
|
||||
data: {
|
||||
description: 'Super',
|
||||
},
|
||||
isCollectionType: false,
|
||||
locale: 'fr',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await strapi.destroy();
|
||||
await builder.cleanup();
|
||||
});
|
||||
|
||||
describe('Find many history versions', () => {
|
||||
test('A collection type throws with invalid query params', async () => {
|
||||
const noDocumentId = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?contentType=${collectionTypeUid}`,
|
||||
});
|
||||
|
||||
const noContentTypeUid = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?documentId=${collectionTypeDocumentId}`,
|
||||
});
|
||||
|
||||
expect(noDocumentId.statusCode).toBe(403);
|
||||
expect(noContentTypeUid.statusCode).toBe(403);
|
||||
});
|
||||
|
||||
test('A single type throws with invalid query params', async () => {
|
||||
const singleTypeNoContentTypeUid = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/`,
|
||||
});
|
||||
|
||||
expect(singleTypeNoContentTypeUid.statusCode).toBe(403);
|
||||
});
|
||||
|
||||
test('Throws without read permissions', async () => {
|
||||
const restrictedRq = await createUserAndReq('restricted', []);
|
||||
const res = await restrictedRq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}`,
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(403);
|
||||
});
|
||||
|
||||
test('A collection type finds many versions in the default locale', async () => {
|
||||
const collectionType = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}`,
|
||||
});
|
||||
|
||||
expect(collectionType.statusCode).toBe(200);
|
||||
expect(collectionType.body.data).toHaveLength(2);
|
||||
expect(collectionType.body.data[0].relatedDocumentId).toBe(collectionTypeDocumentId);
|
||||
expect(collectionType.body.data[1].relatedDocumentId).toBe(collectionTypeDocumentId);
|
||||
expect(collectionType.body.data[0].locale.code).toBe('en');
|
||||
expect(collectionType.body.data[1].locale.code).toBe('en');
|
||||
expect(collectionType.body.meta.pagination).toEqual({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageCount: 1,
|
||||
total: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test('A collection type finds many versions in the provided locale', async () => {
|
||||
const collectionType = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}&locale=fr`,
|
||||
});
|
||||
|
||||
expect(collectionType.statusCode).toBe(200);
|
||||
expect(collectionType.body.data).toHaveLength(2);
|
||||
expect(collectionType.body.data[0].relatedDocumentId).toBe(collectionTypeDocumentId);
|
||||
expect(collectionType.body.data[1].relatedDocumentId).toBe(collectionTypeDocumentId);
|
||||
expect(collectionType.body.data[0].locale.code).toBe('fr');
|
||||
expect(collectionType.body.data[1].locale.code).toBe('fr');
|
||||
expect(collectionType.body.meta.pagination).toEqual({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageCount: 1,
|
||||
total: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test('A single type finds many versions in the default locale', async () => {
|
||||
const singleType = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?contentType=${singleTypeUid}`,
|
||||
});
|
||||
|
||||
expect(singleType.statusCode).toBe(200);
|
||||
expect(singleType.body.data).toHaveLength(2);
|
||||
expect(singleType.body.data[0].relatedDocumentId).toBe(singleTypeDocumentId);
|
||||
expect(singleType.body.data[1].relatedDocumentId).toBe(singleTypeDocumentId);
|
||||
expect(singleType.body.data[0].locale.code).toBe('en');
|
||||
expect(singleType.body.data[1].locale.code).toBe('en');
|
||||
expect(singleType.body.meta.pagination).toEqual({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageCount: 1,
|
||||
total: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test('A single type finds many versions in the provided locale', async () => {
|
||||
const singleType = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?contentType=${singleTypeUid}&locale=fr`,
|
||||
});
|
||||
|
||||
expect(singleType.statusCode).toBe(200);
|
||||
expect(singleType.body.data).toHaveLength(2);
|
||||
expect(singleType.body.data[0].relatedDocumentId).toBe(singleTypeDocumentId);
|
||||
expect(singleType.body.data[1].relatedDocumentId).toBe(singleTypeDocumentId);
|
||||
expect(singleType.body.data[0].locale.code).toBe('fr');
|
||||
expect(singleType.body.data[1].locale.code).toBe('fr');
|
||||
expect(singleType.body.meta.pagination).toEqual({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
pageCount: 1,
|
||||
total: 2,
|
||||
});
|
||||
});
|
||||
|
||||
test('Applies pagination params', async () => {
|
||||
const collectionType = await rq({
|
||||
method: 'GET',
|
||||
url: `/content-manager/history-versions/?contentType=${collectionTypeUid}&documentId=${collectionTypeDocumentId}&page=1&pageSize=1`,
|
||||
});
|
||||
|
||||
expect(collectionType.body.data).toHaveLength(1);
|
||||
expect(collectionType.body.meta.pagination).toEqual({
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
pageCount: 2,
|
||||
total: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Restore a history version', () => {
|
||||
test('Throws with invalid body', async () => {
|
||||
const res = await rq({
|
||||
method: 'PUT',
|
||||
url: `/content-manager/history-versions/1/restore`,
|
||||
body: {},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
expect(res.body).toMatchObject({
|
||||
data: null,
|
||||
error: {
|
||||
status: 400,
|
||||
name: 'ValidationError',
|
||||
message: 'contentType is required',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Throws without update permissions', async () => {
|
||||
const restrictedRq = await createUserAndReq('read', [
|
||||
{ action: 'plugin::content-manager.explorer.read', subject: collectionTypeUid },
|
||||
]);
|
||||
const res = await restrictedRq({
|
||||
method: 'PUT',
|
||||
url: `/content-manager/history-versions/1/restore`,
|
||||
body: {
|
||||
contentType: collectionTypeUid,
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(403);
|
||||
expect(res.body).toMatchObject({
|
||||
data: null,
|
||||
error: {
|
||||
status: 403,
|
||||
name: 'ForbiddenError',
|
||||
message: 'Forbidden',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Restores a history version in the default locale', async () => {
|
||||
const currentDocument = await strapi
|
||||
.documents(collectionTypeUid)
|
||||
.findOne({ documentId: collectionTypeDocumentId });
|
||||
|
||||
await rq({
|
||||
method: 'PUT',
|
||||
url: `/content-manager/history-versions/1/restore`,
|
||||
body: {
|
||||
contentType: collectionTypeUid,
|
||||
},
|
||||
});
|
||||
|
||||
const restoredDocument = await strapi
|
||||
.documents(collectionTypeUid)
|
||||
.findOne({ documentId: collectionTypeDocumentId });
|
||||
|
||||
expect(currentDocument.description).toBe('Hello');
|
||||
expect(restoredDocument.description).toBe(null);
|
||||
});
|
||||
|
||||
test('Restores a history version in the provided locale', async () => {
|
||||
const currentDocument = await strapi
|
||||
.documents(collectionTypeUid)
|
||||
.findOne({ documentId: collectionTypeDocumentId, locale: 'fr' });
|
||||
|
||||
await rq({
|
||||
method: 'PUT',
|
||||
url: `/content-manager/history-versions/4/restore`,
|
||||
body: {
|
||||
contentType: collectionTypeUid,
|
||||
},
|
||||
});
|
||||
|
||||
const restoredDocument = await strapi
|
||||
.documents(collectionTypeUid)
|
||||
.findOne({ documentId: collectionTypeDocumentId, locale: 'fr' });
|
||||
|
||||
expect(currentDocument.description).toBe('Coucou');
|
||||
expect(restoredDocument.description).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user