test: refactor all test directories into one
This commit is contained in:
@@ -2,8 +2,9 @@ module.exports = {
|
||||
verbose: true,
|
||||
testEnvironment: 'node',
|
||||
testMatch: [
|
||||
'**/test/int/**/*spec.ts',
|
||||
'**/test/**/*int.spec.ts',
|
||||
],
|
||||
globalSetup: './test/jest.setup.ts',
|
||||
testTimeout: 15000,
|
||||
moduleNameMapper: {
|
||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/src/webpack/mocks/fileMock.js',
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
const config: PlaywrightTestConfig = {
|
||||
// Look for test files in the "tests" directory, relative to this configuration file
|
||||
testDir: 'test',
|
||||
testMatch: 'e2e.spec.ts',
|
||||
testMatch: '*e2e.spec.ts',
|
||||
workers: 999,
|
||||
timeout: 600000,
|
||||
};
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { APIError } from '.';
|
||||
|
||||
describe('Errors', () => {
|
||||
describe('APIError', () => {
|
||||
it('should handle an error message', () => {
|
||||
const error = new APIError('my message', 400, false);
|
||||
expect(error.message).toStrictEqual('my message');
|
||||
});
|
||||
|
||||
// it('should handle an array', () => {
|
||||
// const errors = [
|
||||
// {
|
||||
// error: 'some error description',
|
||||
// },
|
||||
// {
|
||||
// error: 'some error description 2',
|
||||
// },
|
||||
// ];
|
||||
// const error = new APIError(errors, 400, false);
|
||||
// expect(error.message).toStrictEqual(JSON.stringify(errors));
|
||||
// });
|
||||
|
||||
// it('should handle an object', () => {
|
||||
// const myFancyErrorObject = { someProp: 'someDetail ' };
|
||||
// const error = new APIError(myFancyErrorObject, 400, false);
|
||||
// expect(error.message).toStrictEqual(JSON.stringify(myFancyErrorObject));
|
||||
// });
|
||||
});
|
||||
});
|
||||
@@ -1,55 +0,0 @@
|
||||
import merge from 'deepmerge';
|
||||
import path from 'path';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { CollectionConfig } from '../../collections/config/types';
|
||||
import { Config, SanitizedConfig, InitOptions } from '../../config/types';
|
||||
import { buildConfig } from '../../config/build';
|
||||
import payload from '../..';
|
||||
|
||||
|
||||
const Admins: CollectionConfig = {
|
||||
slug: 'admins',
|
||||
auth: true,
|
||||
fields: [
|
||||
// Email added by default
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const baseConfig: Config = {
|
||||
serverURL: 'http://localhost:3000',
|
||||
admin: {
|
||||
user: Admins.slug,
|
||||
},
|
||||
collections: [
|
||||
Admins,
|
||||
],
|
||||
};
|
||||
|
||||
export function generateTestConfig(overrides?: Partial<Config>): SanitizedConfig {
|
||||
return buildConfig(merge(baseConfig, overrides));
|
||||
}
|
||||
|
||||
type InitPayloadTestOptions = { initOptions?: Partial<InitOptions> }
|
||||
export function initPayloadTest(dirName: string, initOptions?: InitPayloadTestOptions): void {
|
||||
process.env.PAYLOAD_CONFIG_PATH = path.resolve(dirName, './payload.config.ts');
|
||||
|
||||
payload.init({
|
||||
local: true,
|
||||
mongoURL: `mongodb://localhost/${uuid()}`,
|
||||
secret: uuid(),
|
||||
// TODO: Figure out how to handle express
|
||||
...initOptions,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export const openAccess: CollectionConfig['access'] = {
|
||||
read: () => true,
|
||||
create: () => true,
|
||||
delete: () => true,
|
||||
update: () => true,
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
import { devUser } from '../../credentials';
|
||||
import { devUser } from '../credentials';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
import type { ReadOnlyCollection } from './payload-types';
|
||||
|
||||
export const slug = 'access-controls';
|
||||
export const readOnlySlug = 'read-only-collection';
|
||||
export const restrictedSlug = 'restricted';
|
||||
export const restrictedVersionsSlug = 'restricted-versions';
|
||||
|
||||
export default buildConfig({
|
||||
collections: [
|
||||
@@ -45,6 +45,19 @@ export default buildConfig({
|
||||
delete: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: restrictedVersionsSlug,
|
||||
versions: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
readVersions: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
@@ -62,11 +75,18 @@ export default buildConfig({
|
||||
},
|
||||
});
|
||||
|
||||
await payload.create<ReadOnlyCollection>({
|
||||
await payload.create({
|
||||
collection: readOnlySlug,
|
||||
data: {
|
||||
name: 'read-only',
|
||||
},
|
||||
});
|
||||
|
||||
await payload.create({
|
||||
collection: restrictedVersionsSlug,
|
||||
data: {
|
||||
name: 'versioned',
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -1,16 +1,15 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import payload from '../../../src';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../../helpers/configHelpers';
|
||||
import payload from '../../src';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../helpers/configHelpers';
|
||||
import { login } from '../helpers';
|
||||
import { readOnlySlug, restrictedSlug, slug } from './config';
|
||||
import type { ReadOnlyCollection } from './payload-types';
|
||||
import { restrictedVersionsSlug, readOnlySlug, restrictedSlug, slug } from './config';
|
||||
import type { ReadOnlyCollection, RestrictedVersion } from './payload-types';
|
||||
|
||||
/**
|
||||
* TODO: Access Control
|
||||
* prevent user from logging in (canAccessAdmin)
|
||||
* no version controls is no access
|
||||
*
|
||||
* FSK: 'should properly prevent / allow public users from reading a restricted field'
|
||||
*
|
||||
@@ -24,6 +23,7 @@ describe('access control', () => {
|
||||
let url: AdminUrlUtil;
|
||||
let restrictedUrl: AdminUrlUtil;
|
||||
let readoOnlyUrl: AdminUrlUtil;
|
||||
let restrictedVersionsUrl: AdminUrlUtil;
|
||||
|
||||
beforeAll(async ({ browser }) => {
|
||||
const { serverURL } = await initPayloadE2E(__dirname);
|
||||
@@ -31,6 +31,7 @@ describe('access control', () => {
|
||||
url = new AdminUrlUtil(serverURL, slug);
|
||||
restrictedUrl = new AdminUrlUtil(serverURL, restrictedSlug);
|
||||
readoOnlyUrl = new AdminUrlUtil(serverURL, readOnlySlug);
|
||||
restrictedVersionsUrl = new AdminUrlUtil(serverURL, restrictedVersionsSlug);
|
||||
|
||||
const context = await browser.newContext();
|
||||
page = await context.newPage();
|
||||
@@ -121,7 +122,7 @@ describe('access control', () => {
|
||||
await expect(page.locator(`#card-${readOnlySlug}`)).not.toHaveClass('card__actions');
|
||||
});
|
||||
|
||||
test('edit view should not have buttons', async () => {
|
||||
test('edit view should not have actions buttons', async () => {
|
||||
await page.goto(readoOnlyUrl.edit(existingDoc.id));
|
||||
await expect(page.locator('.collection-edit__collection-actions li')).toHaveCount(0);
|
||||
});
|
||||
@@ -131,6 +132,24 @@ describe('access control', () => {
|
||||
await expect(page.locator('#field-name')).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('readVersions', () => {
|
||||
let existingDoc: RestrictedVersion;
|
||||
|
||||
beforeAll(async () => {
|
||||
existingDoc = await payload.create<RestrictedVersion>({
|
||||
collection: restrictedVersionsSlug,
|
||||
data: {
|
||||
name: 'name',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('versions sidebar should not show', async () => {
|
||||
await page.goto(restrictedVersionsUrl.edit(existingDoc.id));
|
||||
await expect(page.locator('.versions-count')).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function createDoc(data: any): Promise<{ id: string }> {
|
||||
@@ -35,6 +35,16 @@ export interface ReadOnlyCollection {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "restricted-versions".
|
||||
*/
|
||||
export interface RestrictedVersion {
|
||||
id: string;
|
||||
name?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "users".
|
||||
@@ -1,6 +1,6 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import payload from '../../../src';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import payload from '../../src';
|
||||
import config from './config';
|
||||
import type { Array as ArrayCollection } from './payload-types';
|
||||
|
||||
69
test/auth/e2e.spec.ts
Normal file
69
test/auth/e2e.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import { firstRegister } from '../helpers';
|
||||
import { slug } from './config';
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Auth
|
||||
* change password
|
||||
* unlock
|
||||
* generate api key
|
||||
* log out
|
||||
*/
|
||||
|
||||
const { beforeAll, describe } = test;
|
||||
let url: AdminUrlUtil;
|
||||
|
||||
// describe('authentication', () => {
|
||||
// let page: Page;
|
||||
|
||||
// beforeAll(async ({ browser }) => {
|
||||
// const { serverURL } = await initPayloadTest({
|
||||
// __dirname,
|
||||
// init: {
|
||||
// local: false,
|
||||
// },
|
||||
// });
|
||||
// // await clearDocs(); // Clear any seeded data from onInit
|
||||
|
||||
// url = new AdminUrlUtil(serverURL, slug);
|
||||
|
||||
// const context = await browser.newContext();
|
||||
// page = await context.newPage();
|
||||
|
||||
// await firstRegister({ page, serverURL });
|
||||
// });
|
||||
|
||||
// describe('Authentication', () => {
|
||||
// test(should login and logout', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should logout', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should allow change password', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should reset password', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should lockout after reaching max login attempts', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should prevent login for locked user', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should unlock user', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should not login without verify', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// test(should allow generate api keys', () => {
|
||||
// expect(1).toEqual(1);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
37
test/buildConfig.ts
Normal file
37
test/buildConfig.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import merge from 'deepmerge';
|
||||
import { Config, SanitizedConfig } from '../src/config/types';
|
||||
import { buildConfig as buildPayloadConfig } from '../src/config/build';
|
||||
|
||||
|
||||
const baseConfig: Config = {
|
||||
typescript: {
|
||||
outputFile: process.env.PAYLOAD_TS_OUTPUT_PATH,
|
||||
},
|
||||
};
|
||||
|
||||
export function buildConfig(overrides?: Partial<Config>): SanitizedConfig {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
baseConfig.admin = {
|
||||
...baseConfig.admin || {},
|
||||
webpack: (config) => {
|
||||
const existingConfig = typeof overrides?.admin?.webpack === 'function' ? overrides.admin.webpack(config) : config;
|
||||
return {
|
||||
...existingConfig,
|
||||
cache: {
|
||||
type: 'memory',
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
console.log(process.env.PAYLOAD_DISABLE_ADMIN);
|
||||
if (process.env.PAYLOAD_DISABLE_ADMIN === 'true') {
|
||||
console.log('disabling admin');
|
||||
if (typeof baseConfig.admin !== 'object') baseConfig.admin = {};
|
||||
baseConfig.admin.disable = true;
|
||||
}
|
||||
|
||||
|
||||
return buildPayloadConfig(merge(baseConfig, overrides || {}));
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import config from './config';
|
||||
import payload from '../../../src';
|
||||
import { RESTClient } from '../../helpers/rest';
|
||||
import payload from '../../src';
|
||||
import { RESTClient } from '../helpers/rest';
|
||||
import type { Post } from './payload-types';
|
||||
|
||||
const collection = config.collections[0]?.slug;
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { CollectionConfig } from '../../../src/collections/config/types';
|
||||
import { devUser } from '../../credentials';
|
||||
import type { CollectionConfig } from '../../src/collections/config/types';
|
||||
import { devUser } from '../credentials';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
import type { Post } from './payload-types';
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import mongoose from 'mongoose';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import type { Relation } from './config';
|
||||
import config, { slug, relationSlug } from './config';
|
||||
import payload from '../../../src';
|
||||
import { RESTClient } from '../../helpers/rest';
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import payload from '../../src';
|
||||
import { RESTClient } from '../helpers/rest';
|
||||
import type { Post } from './payload-types';
|
||||
import { mapAsync } from '../../src/utilities/mapAsync';
|
||||
|
||||
let client: RESTClient;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import { devUser } from '../../credentials';
|
||||
import { mapAsync } from '../../src/utilities/mapAsync';
|
||||
import { devUser } from '../credentials';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
|
||||
export const slug = 'posts';
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import payload from '../../../src';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../../helpers/configHelpers';
|
||||
import payload from '../../src';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../helpers/configHelpers';
|
||||
import { login, saveDocAndAssert } from '../helpers';
|
||||
import type { Post } from './config';
|
||||
import { slug } from './config';
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import wait from '../../../src/utilities/wait';
|
||||
import { mapAsync } from '../../src/utilities/mapAsync';
|
||||
import wait from '../../src/utilities/wait';
|
||||
|
||||
const { afterEach, beforeAll, beforeEach, describe } = test;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable no-console */
|
||||
import express from 'express';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import payload from '../../src';
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import { firstRegister } from '../helpers';
|
||||
import { slug } from './config';
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Auth
|
||||
* change password
|
||||
* unlock
|
||||
* generate api key
|
||||
* log out
|
||||
*/
|
||||
|
||||
const { beforeAll, describe } = test;
|
||||
let url: AdminUrlUtil;
|
||||
|
||||
describe('authentication', () => {
|
||||
let page: Page;
|
||||
|
||||
beforeAll(async ({ browser }) => {
|
||||
const { serverURL } = await initPayloadTest({
|
||||
__dirname,
|
||||
init: {
|
||||
local: false,
|
||||
},
|
||||
});
|
||||
// await clearDocs(); // Clear any seeded data from onInit
|
||||
|
||||
url = new AdminUrlUtil(serverURL, slug);
|
||||
|
||||
const context = await browser.newContext();
|
||||
page = await context.newPage();
|
||||
|
||||
await firstRegister({ page, serverURL });
|
||||
});
|
||||
|
||||
describe('Authentication', () => {
|
||||
test('should login and logout', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should logout', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should allow change password', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should reset password', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should lockout after reaching max login attempts', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should prevent login for locked user', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should unlock user', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should not login without verify', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
test('should allow generate api keys', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
import merge from 'deepmerge';
|
||||
import { buildConfig as buildPayloadConfig } from '../../src/config/build';
|
||||
import type { Config, SanitizedConfig } from '../../src/config/types';
|
||||
|
||||
export function buildConfig(overrides?: Partial<Config>): SanitizedConfig {
|
||||
const baseConfig: Config = {
|
||||
typescript: {
|
||||
outputFile: process.env.PAYLOAD_TS_OUTPUT_PATH,
|
||||
},
|
||||
};
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
baseConfig.admin = {
|
||||
webpack: (config) => ({
|
||||
...config,
|
||||
cache: {
|
||||
type: 'memory',
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return buildPayloadConfig(merge(baseConfig, overrides || {}));
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import wait from '../../../src/utilities/wait';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import wait from '../../src/utilities/wait';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import { firstRegister } from '../helpers';
|
||||
import { slug } from './config';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CollectionConfig } from '../../../src/collections/config/types';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
import { devUser } from '../../credentials';
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import { devUser } from '../credentials';
|
||||
import { mapAsync } from '../../src/utilities/mapAsync';
|
||||
|
||||
export const slug = 'fields-relationship';
|
||||
|
||||
@@ -14,7 +14,7 @@ export interface FieldsRelationship {
|
||||
id: string;
|
||||
relationship: RelationOne;
|
||||
relationshipHasMany: RelationOne[];
|
||||
relationshipHasManyMultiple: Array<RelationOne | RelationTwo | { relationTo: string, value: string}>;
|
||||
relationshipHasManyMultiple: Array<RelationOne | RelationTwo | { relationTo: string, value: string }>;
|
||||
relationshipMultiple: Array<RelationOne | RelationTwo>;
|
||||
relationshipRestricted: RelationRestricted;
|
||||
relationshipWithTitle: RelationWithTitle;
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import payload from '../../../src';
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E, initPayloadTest } from '../../helpers/configHelpers';
|
||||
import payload from '../../src';
|
||||
import { mapAsync } from '../../src/utilities/mapAsync';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../helpers/configHelpers';
|
||||
import { login, saveDocAndAssert } from '../helpers';
|
||||
import type {
|
||||
FieldsRelationship as CollectionWithRelationships,
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
relationWithTitleSlug,
|
||||
slug,
|
||||
} from './config';
|
||||
import wait from '../../../src/utilities/wait';
|
||||
import wait from '../../src/utilities/wait';
|
||||
|
||||
const { beforeAll, describe } = test;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionConfig } from '../../../../../src/collections/config/types';
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const ArrayFields: CollectionConfig = {
|
||||
slug: 'array-fields',
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionConfig } from '../../../../../src/collections/config/types';
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const BlockFields: CollectionConfig = {
|
||||
slug: 'block-fields',
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionConfig } from '../../../../../src/collections/config/types';
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const CollapsibleFields: CollectionConfig = {
|
||||
slug: 'collapsible-fields',
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionConfig } from '../../../../../src/collections/config/types';
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const RichTextFields: CollectionConfig = {
|
||||
slug: 'rich-text-fields',
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionConfig } from '../../../../../src/collections/config/types';
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const SelectFields: CollectionConfig = {
|
||||
slug: 'select-fields',
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionConfig } from '../../../../../src/collections/config/types';
|
||||
import type { CollectionConfig } from '../../../../src/collections/config/types';
|
||||
|
||||
const TextFields: CollectionConfig = {
|
||||
slug: 'text-fields',
|
||||
@@ -1,5 +1,5 @@
|
||||
import { buildConfig } from '../buildConfig';
|
||||
import { devUser } from '../../credentials';
|
||||
import { devUser } from '../credentials';
|
||||
import ArrayFields, { arrayDoc } from './collections/Array';
|
||||
import BlockFields, { blocksDoc } from './collections/Blocks';
|
||||
import CollapsibleFields, { collapsibleDoc } from './collections/Collapsible';
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../../helpers/configHelpers';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../helpers/configHelpers';
|
||||
import { login } from '../helpers';
|
||||
import { textDoc } from './collections/Text';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect } from '@playwright/test';
|
||||
import wait from '../../src/utilities/wait';
|
||||
import { devUser } from '../credentials';
|
||||
import wait from '../src/utilities/wait';
|
||||
import { devUser } from './credentials';
|
||||
|
||||
type FirstRegisterArgs = {
|
||||
page: Page,
|
||||
@@ -28,6 +28,7 @@ export async function initPayloadTest(options: Options): Promise<{ serverURL: st
|
||||
...options.init || {},
|
||||
};
|
||||
|
||||
process.env.PAYLOAD_DISABLE_ADMIN = 'true';
|
||||
process.env.PAYLOAD_CONFIG_PATH = path.resolve(options.__dirname, './config.ts');
|
||||
|
||||
const port = await getPort();
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import merge from 'deepmerge';
|
||||
import { buildConfig as buildPayloadConfig } from '../../src/config/build';
|
||||
import type { Config, SanitizedConfig } from '../../src/config/types';
|
||||
|
||||
export function buildConfig(overrides?: Partial<Config>): SanitizedConfig {
|
||||
const baseConfig: Config = {
|
||||
typescript: {
|
||||
outputFile: process.env.PAYLOAD_TS_OUTPUT_PATH,
|
||||
},
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
baseConfig.admin = {
|
||||
disable: true,
|
||||
};
|
||||
}
|
||||
|
||||
return buildPayloadConfig(merge(baseConfig, overrides || {}));
|
||||
}
|
||||
@@ -1,438 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import FormData from 'form-data';
|
||||
import { GraphQLClient } from 'graphql-request';
|
||||
import { promisify } from 'util';
|
||||
import getConfig from '../../config/load';
|
||||
import { email, password } from '../../mongoose/testCredentials';
|
||||
|
||||
const stat = promisify(fs.stat);
|
||||
|
||||
require('isomorphic-fetch');
|
||||
|
||||
const config = getConfig();
|
||||
const api = `${config.serverURL}${config.routes.api}`;
|
||||
|
||||
let client;
|
||||
let token;
|
||||
let headers;
|
||||
|
||||
describe('Collections - Uploads', () => {
|
||||
beforeAll(async (done) => {
|
||||
const response = await fetch(`${api}/admins/login`, {
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password,
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
({ token } = data);
|
||||
headers = {
|
||||
Authorization: `JWT ${token}`,
|
||||
};
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
describe('REST', () => {
|
||||
const mediaDir = path.join(__dirname, '../../../demo', 'media');
|
||||
beforeAll(async () => {
|
||||
// Clear demo/media directory
|
||||
const mediaDirExists = await fileExists(mediaDir);
|
||||
if (!mediaDirExists) return;
|
||||
fs.readdir(mediaDir, (err, files) => {
|
||||
if (err) throw err;
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const file of files) {
|
||||
fs.unlink(path.join(mediaDir, file), (unlinkErr) => {
|
||||
if (unlinkErr) throw unlinkErr;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it('creates', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
const response = await fetch(`${api}/media`, {
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
// Check for files
|
||||
expect(await fileExists(path.join(mediaDir, 'image.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'image-16x16.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'image-320x240.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'image-640x480.png'))).toBe(true);
|
||||
|
||||
// Check api response
|
||||
expect(data).toMatchObject({
|
||||
doc: {
|
||||
alt: 'test media',
|
||||
filename: 'image.png',
|
||||
mimeType: 'image/png',
|
||||
sizes: {
|
||||
icon: {
|
||||
filename: 'image-16x16.png',
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
mobile: {
|
||||
filename: 'image-320x240.png',
|
||||
width: 320,
|
||||
height: 240,
|
||||
},
|
||||
tablet: {
|
||||
filename: 'image-640x480.png',
|
||||
width: 640,
|
||||
height: 480,
|
||||
},
|
||||
},
|
||||
|
||||
// We have a hook to check if upload sizes
|
||||
// are properly bound to the Payload `req`.
|
||||
// This field should be automatically set
|
||||
// if they are found.
|
||||
foundUploadSizes: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('creates images that do not require all sizes', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/small.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
const response = await fetch(`${api}/media`, {
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
expect(await fileExists(path.join(mediaDir, 'small.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'small-16x16.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'small-320x240.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'small-640x480.png'))).toBe(false);
|
||||
|
||||
// Check api response
|
||||
expect(data).toMatchObject({
|
||||
doc: {
|
||||
alt: 'test media',
|
||||
filename: 'small.png',
|
||||
mimeType: 'image/png',
|
||||
sizes: {
|
||||
icon: {
|
||||
filename: 'small-16x16.png',
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
},
|
||||
|
||||
// We have a hook to check if upload sizes
|
||||
// are properly bound to the Payload `req`.
|
||||
// This field should be automatically set
|
||||
// if they are found.
|
||||
foundUploadSizes: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('creates media without storing a file', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const response = await fetch(`${api}/unstored-media`, {
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
// Check for files
|
||||
expect(await !fileExists(path.join(mediaDir, 'image.png'))).toBe(false);
|
||||
expect(await !fileExists(path.join(mediaDir, 'image-640x480.png'))).toBe(false);
|
||||
|
||||
// Check api response
|
||||
expect(data).toMatchObject({
|
||||
doc: {
|
||||
alt: 'test media',
|
||||
filename: 'image.png',
|
||||
mimeType: 'image/png',
|
||||
sizes: {
|
||||
tablet: {
|
||||
filename: 'image-640x480.png',
|
||||
width: 640,
|
||||
height: 480,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('creates with same name', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/samename.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const firstResponse = await fetch(`${api}/media`, {
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
expect(firstResponse.status).toBe(201);
|
||||
|
||||
const sameForm = new FormData();
|
||||
sameForm.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/samename.png')),
|
||||
);
|
||||
sameForm.append('alt', 'test media');
|
||||
sameForm.append('locale', 'en');
|
||||
|
||||
const response = await fetch(`${api}/media`, {
|
||||
body: sameForm as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
const data = await response.json();
|
||||
|
||||
// Check for files
|
||||
expect(await fileExists(path.join(mediaDir, 'samename-1.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'samename-1-16x16.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'samename-1-320x240.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'samename-1-640x480.png'))).toBe(true);
|
||||
|
||||
expect(data).toMatchObject({
|
||||
doc: {
|
||||
alt: 'test media',
|
||||
filename: 'samename-1.png',
|
||||
mimeType: 'image/png',
|
||||
sizes: {
|
||||
icon: {
|
||||
filename: 'samename-1-16x16.png',
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
mobile: {
|
||||
filename: 'samename-1-320x240.png',
|
||||
width: 320,
|
||||
height: 240,
|
||||
},
|
||||
tablet: {
|
||||
filename: 'samename-1-640x480.png',
|
||||
width: 640,
|
||||
height: 480,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('update', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/update.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const response = await fetch(`${api}/media`, {
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
expect(response.status).toBe(201);
|
||||
|
||||
const updateFormData = new FormData();
|
||||
const newAlt = 'my new alt';
|
||||
|
||||
updateFormData.append('filename', data.doc.filename);
|
||||
updateFormData.append('alt', newAlt);
|
||||
const updateResponse = await fetch(`${api}/media/${data.doc.id}`, {
|
||||
body: updateFormData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'put',
|
||||
});
|
||||
|
||||
|
||||
const updateResponseData = await updateResponse.json();
|
||||
expect(updateResponse.status).toBe(200);
|
||||
|
||||
// Check that files weren't affected
|
||||
expect(await fileExists(path.join(mediaDir, 'update.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'update-16x16.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'update-320x240.png'))).toBe(true);
|
||||
expect(await fileExists(path.join(mediaDir, 'update-640x480.png'))).toBe(true);
|
||||
|
||||
// Check api response
|
||||
expect(updateResponseData).toMatchObject({
|
||||
doc: {
|
||||
alt: newAlt,
|
||||
filename: 'update.png',
|
||||
mimeType: 'image/png',
|
||||
sizes: {
|
||||
icon: {
|
||||
filename: 'update-16x16.png',
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
mobile: {
|
||||
filename: 'update-320x240.png',
|
||||
width: 320,
|
||||
height: 240,
|
||||
},
|
||||
tablet: {
|
||||
filename: 'update-640x480.png',
|
||||
width: 640,
|
||||
height: 480,
|
||||
},
|
||||
maintainedAspectRatio: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('delete', async () => {
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/delete.png')),
|
||||
);
|
||||
formData.append('alt', 'test media');
|
||||
formData.append('locale', 'en');
|
||||
|
||||
const createResponse = await fetch(`${api}/media`, {
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
|
||||
const createData = await createResponse.json();
|
||||
expect(createResponse.status).toBe(201);
|
||||
const docId = createData.doc.id;
|
||||
|
||||
const response = await fetch(`${api}/media/${docId}`, {
|
||||
headers,
|
||||
method: 'delete',
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
expect(response.status).toBe(200);
|
||||
expect(data.id).toBe(docId);
|
||||
|
||||
const imageExists = await fileExists(path.join(mediaDir, 'delete.png'));
|
||||
expect(imageExists).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GraphQL', () => {
|
||||
// graphql cannot submit formData to create files, we only need to test getting relationship data on upload fields
|
||||
let media;
|
||||
let image;
|
||||
const alt = 'alt text';
|
||||
beforeAll(async (done) => {
|
||||
client = new GraphQLClient(`${api}${config.routes.graphQL}`, {
|
||||
headers: { Authorization: `JWT ${token}` },
|
||||
});
|
||||
|
||||
// create media using REST
|
||||
const formData = new FormData();
|
||||
formData.append(
|
||||
'file',
|
||||
fs.createReadStream(path.join(__dirname, '../../..', 'tests/api/assets/image.png')),
|
||||
);
|
||||
formData.append('alt', alt);
|
||||
formData.append('locale', 'en');
|
||||
const mediaResponse = await fetch(`${api}/media`, {
|
||||
body: formData as unknown as BodyInit,
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
const mediaData = await mediaResponse.json();
|
||||
media = mediaData.doc;
|
||||
|
||||
// create image that relates to media
|
||||
headers['Content-Type'] = 'application/json';
|
||||
const imageResponse = await fetch(`${api}/images`, {
|
||||
body: JSON.stringify({
|
||||
upload: media.id,
|
||||
}),
|
||||
headers,
|
||||
method: 'post',
|
||||
});
|
||||
const data = await imageResponse.json();
|
||||
image = data.doc;
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should query uploads relationship fields', async () => {
|
||||
// language=graphQL
|
||||
const query = `query {
|
||||
Image(id: "${image.id}") {
|
||||
id
|
||||
upload {
|
||||
alt
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
const response = await client.request(query);
|
||||
expect(response.Image.upload.alt).toStrictEqual(alt);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function fileExists(fileName: string): Promise<boolean> {
|
||||
try {
|
||||
await stat(fileName);
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
3
test/jest.setup.ts
Normal file
3
test/jest.setup.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = () => {
|
||||
process.env.PAYLOAD_DISABLE_ADMIN = 'true';
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import { mapAsync } from '../../src/utilities/mapAsync';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
|
||||
export const slug = 'localized-posts';
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import payload from '../../../src';
|
||||
import type { TypeWithTimestamps } from '../../../src/collections/config/types';
|
||||
import { mapAsync } from '../../../src/utilities/mapAsync';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import payload from '../../src';
|
||||
import type { TypeWithTimestamps } from '../../src/collections/config/types';
|
||||
import { mapAsync } from '../../src/utilities/mapAsync';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import { firstRegister, saveDocAndAssert } from '../helpers';
|
||||
import type { LocalizedPost } from './config';
|
||||
import { slug } from './config';
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { buildConfig } from '../e2e/buildConfig';
|
||||
import { buildConfig } from '../buildConfig';
|
||||
import { devUser } from '../credentials';
|
||||
import getFileByPath from '../../src/uploads/getFileByPath';
|
||||
|
||||
@@ -17,7 +17,7 @@ export default buildConfig({
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
alias: {
|
||||
...config.resolve.alias,
|
||||
...config?.resolve?.alias,
|
||||
fs: mockModulePath,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { Media } from './payload-types';
|
||||
import payload from '../../src';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadE2E } from '../helpers/configHelpers';
|
||||
import { login, saveDocAndAssert } from '../e2e/helpers';
|
||||
import { login, saveDocAndAssert } from '../helpers';
|
||||
import wait from '../../src/utilities/wait';
|
||||
|
||||
const { beforeAll, describe } = test;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { AdminUrlUtil } from '../../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../../helpers/configHelpers';
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil';
|
||||
import { initPayloadTest } from '../helpers/configHelpers';
|
||||
import { firstRegister } from '../helpers';
|
||||
import { slug } from './config';
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('suite name', () => {
|
||||
// });
|
||||
|
||||
describe('feature', () => {
|
||||
test('testname', () => {
|
||||
it('testname', () => {
|
||||
expect(1).toEqual(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user