feat: e2e test upload (#755)

This commit is contained in:
Dan Ribbens
2022-07-14 18:43:19 -04:00
committed by GitHub
parent f7a81d70ac
commit 11600930b7
15 changed files with 565 additions and 9 deletions

View File

@@ -38,13 +38,13 @@
"demo:generate:graphqlschema": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.ts node dist/bin/generateGraphQLSchema",
"demo:serve": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.ts NODE_ENV=production nodemon",
"dev": "nodemon",
"dev:generatetypes": "node ./test/dev/generateTypes.js",
"test": "yarn test:int && yarn test:components",
"test:int": "cross-env NODE_ENV=test DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
"test:e2e": "cross-env NODE_ENV=test DISABLE_LOGGING=true playwright test",
"test:e2e:headed": "cross-env NODE_ENV=test DISABLE_LOGGING=true playwright test --headed",
"test:e2e:debug": "cross-env PWDEBUG=1 NODE_ENV=test DISABLE_LOGGING=true playwright test",
"test:components": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.ts NODE_ENV=test jest --config=jest.components.config.js",
"generatetypes": "node ./test/dev/generateTypes.js",
"clean": "rimraf dist",
"release": "release-it",
"release:patch": "release-it patch",

View File

@@ -70,7 +70,7 @@ const Email: React.FC<Props> = (props) => {
/>
<Label
htmlFor={path}
label={`field-${path}`}
label={label}
required={required}
/>
<input

View File

@@ -0,0 +1,27 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
enableAPIKey?: boolean;
apiKey?: string;
apiKeyIndex?: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
_verified?: boolean;
_verificationToken?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}

View File

@@ -0,0 +1,33 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts".
*/
export interface Post {
id: string;
title?: string;
description?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}

View File

@@ -0,0 +1,35 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "fields-array".
*/
export interface FieldsArray {
id: string;
readOnlyArray?: {
text?: string;
id?: string;
}[];
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}

View File

@@ -3,7 +3,7 @@ import { expect, test } from '@playwright/test';
import payload from '../../../src';
import { mapAsync } from '../../../src/utilities/mapAsync';
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
import { initPayloadTest } from '../../helpers/configHelpers';
import { initPayloadE2E, initPayloadTest } from '../../helpers/configHelpers';
import { login, saveDocAndAssert } from '../helpers';
import type {
FieldsRelationship as CollectionWithRelationships,
@@ -36,12 +36,7 @@ describe('fields - relationship', () => {
let relationWithTitle: RelationWithTitle;
beforeAll(async ({ browser }) => {
const { serverURL } = await initPayloadTest({
__dirname,
init: {
local: false,
},
});
const { serverURL } = await initPayloadE2E(__dirname);
await clearAllDocs();
url = new AdminUrlUtil(serverURL, slug);

View File

@@ -0,0 +1,94 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "fields-relationship".
*/
export interface FieldsRelationship {
id: string;
relationship?: string | RelationOne;
relationshipHasMany?: (string | RelationOne)[];
relationshipMultiple?:
| {
value: string | RelationOne;
relationTo: 'relation-one';
}
| {
value: string | RelationTwo;
relationTo: 'relation-two';
};
relationshipHasManyMultiple?: (
| {
value: string | RelationOne;
relationTo: 'relation-one';
}
| {
value: string | RelationTwo;
relationTo: 'relation-two';
}
)[];
relationshipRestricted?: string | RelationRestricted;
relationshipWithTitle?: string | RelationWithTitle;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "relation-one".
*/
export interface RelationOne {
id: string;
name?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "relation-two".
*/
export interface RelationTwo {
id: string;
name?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "relation-restricted".
*/
export interface RelationRestricted {
id: string;
name?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "relation-with-title".
*/
export interface RelationWithTitle {
id: string;
name?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}

View File

@@ -0,0 +1,32 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "text-fields".
*/
export interface TextField {
id: string;
text: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}

View File

@@ -0,0 +1,33 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "localized-posts".
*/
export interface LocalizedPost {
id: string;
title?: string;
description?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}

1
test/e2e/uploads/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/media

102
test/e2e/uploads/config.ts Normal file
View File

@@ -0,0 +1,102 @@
import path from 'path';
import fs from 'fs';
import { buildConfig } from '../buildConfig';
import { devUser } from '../../credentials';
import getFileByPath from '../../../src/uploads/getFileByPath';
export const mediaSlug = 'media';
export const relationSlug = 'relation';
const mockModulePath = path.resolve(__dirname, './mocks/mockFSModule.js');
export default buildConfig({
admin: {
webpack: (config) => ({
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
fs: mockModulePath,
},
},
}),
},
// upload: {},
collections: [
{
slug: relationSlug,
fields: [
{
name: 'image',
type: 'upload',
relationTo: 'media',
},
],
},
{
slug: mediaSlug,
upload: {
staticURL: '/media',
staticDir: './media',
imageSizes: [
{
name: 'maintainedAspectRatio',
width: 1024,
height: null,
crop: 'center',
},
{
name: 'tablet',
width: 640,
height: 480,
crop: 'left top',
},
{
name: 'mobile',
width: 320,
height: 240,
crop: 'left top',
},
{
name: 'icon',
width: 16,
height: 16,
},
],
},
fields: [
],
},
],
onInit: async (payload) => {
// delete files in /media
const mediaDir = path.resolve(__dirname, './media');
fs.readdirSync(mediaDir).forEach((f) => fs.rmSync(`${mediaDir}/${f}`));
await payload.create({
collection: 'users',
data: {
email: devUser.email,
password: devUser.password,
},
});
// Create image
const filePath = path.resolve(__dirname, './image.png');
const file = getFileByPath(filePath);
const { id: uploadedImage } = await payload.create({
collection: mediaSlug,
data: {},
file,
});
await payload.create({
collection: relationSlug,
data: {
image: uploadedImage,
},
});
},
});

View File

@@ -0,0 +1,88 @@
import type { Page } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
import { initPayloadE2E } from '../../helpers/configHelpers';
import { login, saveDocAndAssert } from '../helpers';
import { relationSlug, mediaSlug } from './config';
import type { Media } from './payload-types';
import wait from '../../../src/utilities/wait';
import payload from '../../../src';
const { beforeAll, describe } = test;
let mediaURL: AdminUrlUtil;
let relationURL: AdminUrlUtil;
describe('uploads', () => {
let page: Page;
let mediaDoc: Media;
beforeAll(async ({ browser }) => {
const { serverURL } = await initPayloadE2E(__dirname);
mediaURL = new AdminUrlUtil(serverURL, mediaSlug);
relationURL = new AdminUrlUtil(serverURL, relationSlug);
const context = await browser.newContext();
page = await context.newPage();
const findMedia = await payload.find({
collection: mediaSlug,
depth: 0,
pagination: false,
});
mediaDoc = findMedia.docs[0] as Media;
await login({ page, serverURL });
});
test('should see upload filename in relation list', async () => {
await page.goto(relationURL.list);
await wait(110);
const field = page.locator('.cell-image');
await expect(field).toContainText('image.png');
});
test('should show upload filename in upload collection list', async () => {
await page.goto(mediaURL.list);
const media = page.locator('.upload-card__filename');
await wait(110);
await expect(media).toHaveText('image.png');
});
test('should create file upload', async () => {
await page.goto(mediaURL.create);
await page.setInputFiles('input[type="file"]', './image.png');
const filename = page.locator('.file-field__filename');
await expect(filename).toContainText('.png');
await page.locator('.form-submit button').click();
await saveDocAndAssert(page);
});
test('should show resized images', async () => {
await page.goto(mediaURL.edit(mediaDoc.id));
await page.locator('.btn.file-details__toggle-more-info').click();
const maintainedAspectRatioMeta = page.locator('.file-details__sizes .file-meta').nth(0);
await expect(maintainedAspectRatioMeta).toContainText('1024x1024');
const tabletMeta = page.locator('.file-details__sizes .file-meta').nth(1);
await expect(tabletMeta).toContainText('640x480');
const mobileMeta = page.locator('.file-details__sizes .file-meta').nth(2);
await expect(mobileMeta).toContainText('320x240');
const iconMeta = page.locator('.file-details__sizes .file-meta').nth(3);
await expect(iconMeta).toContainText('16x16');
});
});

View File

@@ -0,0 +1,4 @@
export default {
readdirSync: () => {},
rmSync: () => {},
};

View File

@@ -0,0 +1,81 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "relation".
*/
export interface Relation {
id: string;
image?: string | Media;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "media".
*/
export interface Media {
id: string;
url?: string;
filename?: string;
mimeType?: string;
filesize?: number;
width?: number;
height?: number;
sizes?: {
maintainedAspectRatio?: {
url?: string;
width?: number;
height?: number;
mimeType?: string;
filesize?: number;
filename?: string;
};
tablet?: {
url?: string;
width?: number;
height?: number;
mimeType?: string;
filesize?: number;
filename?: string;
};
mobile?: {
url?: string;
width?: number;
height?: number;
mimeType?: string;
filesize?: number;
filename?: string;
};
icon?: {
url?: string;
width?: number;
height?: number;
mimeType?: string;
filesize?: number;
filename?: string;
};
};
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}

View File

@@ -0,0 +1,31 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload CMS.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "slugname".
*/
export interface Slugname {
id: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}