feat: async plugins (#2030)

* feat: async plugins

* wip: async config

* fix: async config
This commit is contained in:
Jacob Fletcher
2023-02-13 10:46:55 -05:00
committed by GitHub
parent 11532857d2
commit 9f30553813
25 changed files with 218 additions and 119 deletions

View File

@@ -3,10 +3,29 @@ import { SanitizedConfig } from '../../../../config/types';
const Context = createContext<SanitizedConfig>({} as SanitizedConfig);
export const ConfigProvider: React.FC<{config: SanitizedConfig, children: React.ReactNode}> = ({ children, config }) => (
<Context.Provider value={config}>
{children}
</Context.Provider>
);
export const ConfigProvider: React.FC<{config: SanitizedConfig, children: React.ReactNode}> = ({ children, config: incomingConfig }) => {
const [config, setConfig] = React.useState<SanitizedConfig>();
const hasAwaited = React.useRef(false);
React.useEffect(() => {
if (incomingConfig && !hasAwaited.current) {
hasAwaited.current = true;
const awaitConfig = async () => {
const resolvedConfig = await incomingConfig;
setConfig(resolvedConfig);
};
awaitConfig();
}
}, [incomingConfig]);
if (!config) return null;
return (
<Context.Provider value={config}>
{children}
</Context.Provider>
);
};
export const useConfig = (): SanitizedConfig => useContext(Context);

View File

@@ -9,7 +9,7 @@ const rawConfigPath = findConfig();
export const build = async (): Promise<void> => {
try {
const config = loadConfig();
const config = await loadConfig();
const webpackProdConfig = getWebpackProdConfig(config);

View File

@@ -7,7 +7,7 @@ import payload from '..';
export async function generateGraphQLSchema(): Promise<void> {
const logger = Logger();
const config = loadConfig();
const config = await loadConfig();
await payload.init({
secret: '--unused--',

View File

@@ -32,9 +32,9 @@ function configToJsonSchema(config: SanitizedConfig): JSONSchema4 {
};
}
export function generateTypes(): void {
export async function generateTypes(): Promise<void> {
const logger = Logger();
const config = loadConfig();
const config = await loadConfig();
const outputFile = process.env.PAYLOAD_TS_OUTPUT_PATH || config.typescript.outputFile;
logger.info('Compiling TS types for Collections and Globals...');

View File

@@ -8,14 +8,17 @@ import sanitize from './sanitize';
* @param config Payload Config
* @returns Built and sanitized Payload Config
*/
export function buildConfig(config: Config): SanitizedConfig {
export async function buildConfig(config: Config): Promise<SanitizedConfig> {
if (Array.isArray(config.plugins)) {
const configWithPlugins = config.plugins.reduce(
(updatedConfig, plugin) => plugin(updatedConfig),
config,
const configAfterPlugins = await config.plugins.reduce(
async (acc, plugin) => {
const configAfterPlugin = await acc;
return plugin(configAfterPlugin);
},
Promise.resolve(config),
);
const sanitizedConfig = sanitize(configWithPlugins);
const sanitizedConfig = sanitize(configAfterPlugins);
return sanitizedConfig;
}

View File

@@ -9,7 +9,7 @@ import findConfig from './find';
import validate from './validate';
import { clientFiles } from './clientFiles';
const loadConfig = (logger?: pino.Logger): SanitizedConfig => {
const loadConfig = async (logger?: pino.Logger): Promise<SanitizedConfig> => {
const localLogger = logger ?? Logger();
const configPath = findConfig();
@@ -19,18 +19,18 @@ const loadConfig = (logger?: pino.Logger): SanitizedConfig => {
});
// eslint-disable-next-line @typescript-eslint/no-var-requires
let config = require(configPath);
const configPromise = require(configPath);
if (config.default) config = config.default;
let config = await configPromise;
let validatedConfig = config;
if (config.default) config = await config.default;
if (process.env.NODE_ENV !== 'production') {
validatedConfig = validate(config, localLogger);
config = await validate(config, localLogger);
}
return {
...validatedConfig,
...config,
paths: {
configDir: path.dirname(configPath),
config: configPath,

View File

@@ -27,7 +27,7 @@ type Email = {
};
// eslint-disable-next-line no-use-before-define
export type Plugin = (config: Config) => Config;
export type Plugin = (config: Config) => Promise<Config> | Config;
type GeneratePreviewURLOptions = {
locale: string;

View File

@@ -32,7 +32,7 @@ const validateFields = (context: string, entity: SanitizedCollectionConfig | San
return errors;
};
const validateCollections = (collections: SanitizedCollectionConfig[]): string[] => {
const validateCollections = async (collections: SanitizedCollectionConfig[]): Promise<string[]> => {
const errors: string[] = [];
collections.forEach((collection) => {
const result = collectionSchema.validate(collection, { abortEarly: false });
@@ -62,13 +62,13 @@ const validateGlobals = (globals: SanitizedGlobalConfig[]): string[] => {
return errors;
};
const validateSchema = (config: SanitizedConfig, logger: Logger): SanitizedConfig => {
const validateSchema = async (config: SanitizedConfig, logger: Logger): Promise<SanitizedConfig> => {
const result = schema.validate(config, {
abortEarly: false,
});
const nestedErrors = [
...validateCollections(config.collections),
...await validateCollections(config.collections),
...validateGlobals(config.globals),
];

View File

@@ -181,7 +181,7 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
} else {
// eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
const loadConfig = require('./config/load').default;
this.config = loadConfig(this.logger);
this.config = await loadConfig(this.logger);
}
// Configure email service

View File

@@ -76,7 +76,7 @@ describe('access control', () => {
let existingDoc: ReadOnlyCollection;
beforeAll(async () => {
existingDoc = await payload.create<ReadOnlyCollection>({
existingDoc = await payload.create({
collection: readOnlySlug,
data: {
name: 'name',
@@ -114,7 +114,7 @@ describe('access control', () => {
let existingDoc: ReadOnlyCollection;
beforeAll(async () => {
existingDoc = await payload.create<ReadOnlyCollection>({
existingDoc = await payload.create({
collection: readOnlySlug,
data: {
name: 'name',
@@ -162,7 +162,7 @@ describe('access control', () => {
let existingDoc: RestrictedVersion;
beforeAll(async () => {
existingDoc = await payload.create<RestrictedVersion>({
existingDoc = await payload.create({
collection: restrictedVersionsSlug,
data: {
name: 'name',
@@ -172,7 +172,7 @@ describe('access control', () => {
test('versions sidebar should not show', async () => {
await page.goto(restrictedVersionsUrl.edit(existingDoc.id));
await expect(page.locator('.versions-count')).not.toBeVisible();
await expect(page.locator('.versions-count')).toBeHidden();
});
});

View File

@@ -5,7 +5,7 @@ import { Forbidden } from '../../src/errors';
import type { PayloadRequest } from '../../src/types';
import { initPayloadTest } from '../helpers/configHelpers';
import { relyOnRequestHeadersSlug, requestHeaders, restrictedSlug, siblingDataSlug, slug } from './config';
import type { Restricted, Post, SiblingDatum, RelyOnRequestHeader } from './payload-types';
import type { Restricted, Post, RelyOnRequestHeader } from './payload-types';
import { firstArrayText, secondArrayText } from './shared';
describe('Access Control', () => {
@@ -17,12 +17,12 @@ describe('Access Control', () => {
});
beforeEach(async () => {
post1 = await payload.create<Post>({
post1 = await payload.create({
collection: slug,
data: { name: 'name' },
});
restricted = await payload.create<Restricted>({
restricted = await payload.create({
collection: restrictedSlug,
data: { name: 'restricted' },
});
@@ -37,7 +37,7 @@ describe('Access Control', () => {
it.todo('should properly prevent / allow public users from reading a restricted field');
it('should be able to restrict access based upon siblingData', async () => {
const { id } = await payload.create<SiblingDatum>({
const { id } = await payload.create({
collection: siblingDataSlug,
data: {
array: [
@@ -53,7 +53,7 @@ describe('Access Control', () => {
},
});
const doc = await payload.findByID<SiblingDatum>({
const doc = await payload.findByID({
id,
collection: siblingDataSlug,
overrideAccess: false,
@@ -64,7 +64,7 @@ describe('Access Control', () => {
expect(doc.array?.[1].text).toBeUndefined();
// Retrieve with default of overriding access
const docOverride = await payload.findByID<SiblingDatum>({
const docOverride = await payload.findByID({
id,
collection: siblingDataSlug,
});
@@ -150,7 +150,7 @@ describe('Access Control', () => {
describe('Override Access', () => {
describe('Fields', () => {
it('should allow overrideAccess: false', async () => {
const req = async () => payload.update<Post>({
const req = async () => payload.update({
collection: slug,
id: post1.id,
data: { restrictedField: restricted.id },
@@ -161,7 +161,7 @@ describe('Access Control', () => {
});
it('should allow overrideAccess: true', async () => {
const doc = await payload.update<Post>({
const doc = await payload.update({
collection: slug,
id: post1.id,
data: { restrictedField: restricted.id },
@@ -172,7 +172,7 @@ describe('Access Control', () => {
});
it('should allow overrideAccess by default', async () => {
const doc = await payload.update<Post>({
const doc = await payload.update({
collection: slug,
id: post1.id,
data: { restrictedField: restricted.id },
@@ -221,7 +221,7 @@ describe('Access Control', () => {
});
async function createDoc<Collection>(data: Partial<Collection>, overrideSlug = slug, options?: Partial<CreateOptions<Collection>>): Promise<Collection> {
return payload.create<Collection>({
return payload.create({
...options,
collection: overrideSlug,
data: data ?? {},

View File

@@ -1,13 +1,14 @@
import mongoose from 'mongoose';
import { initPayloadTest } from '../helpers/configHelpers';
import payload from '../../src';
import config from './config';
import type { Array as ArrayCollection } from './payload-types';
import configPromise from './config';
const collection = config.collections[0]?.slug;
let collection: string;
describe('array-update', () => {
beforeAll(async () => {
const config = await configPromise;
collection = config.collections[0]?.slug;
await initPayloadTest({ __dirname });
});
@@ -45,7 +46,7 @@ describe('array-update', () => {
required: updatedText,
};
const updatedDoc = await payload.update<ArrayCollection>({
const updatedDoc = await payload.update({
id: doc.id,
collection,
data: {
@@ -67,7 +68,7 @@ describe('array-update', () => {
optional: 'optional test',
};
const doc = await payload.create<ArrayCollection>({
const doc = await payload.create({
collection,
data: {
array: [
@@ -80,7 +81,7 @@ describe('array-update', () => {
},
});
const updatedDoc = await payload.update<ArrayCollection>({
const updatedDoc = await payload.update({
id: doc.id,
collection,
data: {

View File

@@ -1,7 +1,7 @@
import { Config, SanitizedConfig } from '../src/config/types';
import { buildConfig as buildPayloadConfig } from '../src/config/build';
export function buildConfig(config?: Partial<Config>): SanitizedConfig {
export function buildConfig(config?: Partial<Config>): Promise<SanitizedConfig> {
const [name] = process.argv.slice(2);
const baseConfig: Config = {
telemetry: false,

View File

@@ -1,7 +1,6 @@
import type { CollectionConfig } from '../../src/collections/config/types';
import { devUser } from '../credentials';
import { buildConfig } from '../buildConfig';
import type { Post } from './payload-types';
export interface Relation {
id: string;
@@ -88,20 +87,20 @@ export default buildConfig({
},
});
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'post1',
},
});
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'post2',
},
});
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'with-description',
@@ -109,14 +108,14 @@ export default buildConfig({
},
});
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'numPost1',
number: 1,
},
});
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'numPost2',
@@ -124,13 +123,13 @@ export default buildConfig({
},
});
const rel1 = await payload.create<Relation>({
const rel1 = await payload.create({
collection: relationSlug,
data: {
name: 'name',
},
});
const rel2 = await payload.create<Relation>({
const rel2 = await payload.create({
collection: relationSlug,
data: {
name: 'name2',
@@ -138,14 +137,14 @@ export default buildConfig({
});
// Relation - hasMany
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to hasMany',
relationHasManyField: rel1.id,
},
});
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to hasMany 2',
@@ -154,7 +153,7 @@ export default buildConfig({
});
// Relation - relationTo multi
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to multi',
@@ -166,7 +165,7 @@ export default buildConfig({
});
// Relation - relationTo multi hasMany
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to multi hasMany',

View File

@@ -1,11 +1,11 @@
import mongoose from 'mongoose';
import { GraphQLClient } from 'graphql-request';
import { initPayloadTest } from '../helpers/configHelpers';
import config from './config';
import configPromise from './config';
import payload from '../../src';
import type { Post } from './payload-types';
const slug = config.collections[0]?.slug;
let slug = '';
const title = 'title';
let client: GraphQLClient;
@@ -13,6 +13,8 @@ let client: GraphQLClient;
describe('collections-graphql', () => {
beforeAll(async () => {
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } });
const config = await configPromise;
slug = config.collections[0]?.slug;
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}`;
client = new GraphQLClient(url);
});
@@ -354,7 +356,7 @@ describe('collections-graphql', () => {
});
async function createPost(overrides?: Partial<Post>) {
const doc = await payload.create<Post>({
const doc = await payload.create({
collection: slug,
data: { title: 'title', ...overrides },
});

View File

@@ -1,7 +1,6 @@
import type { CollectionConfig } from '../../src/collections/config/types';
import { devUser } from '../credentials';
import { buildConfig } from '../buildConfig';
import type { Post } from './payload-types';
export interface Relation {
id: string;
@@ -135,13 +134,13 @@ export default buildConfig({
},
});
const rel1 = await payload.create<Relation>({
const rel1 = await payload.create({
collection: relationSlug,
data: {
name: 'name',
},
});
const rel2 = await payload.create<Relation>({
const rel2 = await payload.create({
collection: relationSlug,
data: {
name: 'name2',
@@ -156,14 +155,14 @@ export default buildConfig({
});
// Relation - hasMany
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to hasMany',
relationHasManyField: rel1.id,
},
});
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to hasMany 2',
@@ -172,7 +171,7 @@ export default buildConfig({
});
// Relation - relationTo multi
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to multi',
@@ -184,7 +183,7 @@ export default buildConfig({
});
// Relation - relationTo multi hasMany
await payload.create<Post>({
await payload.create({
collection: slug,
data: {
title: 'rel to multi hasMany',

View File

@@ -1,10 +1,9 @@
import type { IndexDirection, IndexOptions } from 'mongoose';
import { initPayloadTest } from '../helpers/configHelpers';
import { RESTClient } from '../helpers/rest';
import config from '../uploads/config';
import configPromise from '../uploads/config';
import payload from '../../src';
import { pointDoc } from './collections/Point';
import type { ArrayField, GroupField, TabsField } from './payload-types';
import { arrayFieldsSlug, arrayDefaultValue, arrayDoc } from './collections/Array';
import { groupFieldsSlug, groupDefaultChild, groupDefaultValue, groupDoc } from './collections/Group';
import { defaultText } from './collections/Text';
@@ -17,6 +16,7 @@ let client;
describe('Fields', () => {
beforeAll(async () => {
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } });
const config = await configPromise;
client = new RESTClient(config, { serverURL, defaultSlug: 'point-fields' });
await client.login();
});
@@ -268,14 +268,14 @@ describe('Fields', () => {
const collection = arrayFieldsSlug;
beforeAll(async () => {
doc = await payload.create<ArrayField>({
doc = await payload.create({
collection,
data: {},
});
});
it('should return undefined arrays when no data present', async () => {
const document = await payload.create<ArrayField>({
const document = await payload.create({
collection: arrayFieldsSlug,
data: arrayDoc,
});
@@ -284,7 +284,7 @@ describe('Fields', () => {
});
it('should create with ids and nested ids', async () => {
const docWithIDs = await payload.create<GroupField>({
const docWithIDs = await payload.create({
collection: groupFieldsSlug,
data: groupDoc,
});
@@ -300,14 +300,14 @@ describe('Fields', () => {
const localized = [{ text: 'unique' }];
const enText = 'english';
const esText = 'spanish';
const { id } = await payload.create<ArrayField>({
const { id } = await payload.create({
collection,
data: {
localized,
},
});
const enDoc = await payload.update<ArrayField>({
const enDoc = await payload.update({
collection,
id,
locale: 'en',
@@ -316,7 +316,7 @@ describe('Fields', () => {
},
});
const esDoc = await payload.update<ArrayField>({
const esDoc = await payload.update({
collection,
id,
locale: 'es',
@@ -342,7 +342,7 @@ describe('Fields', () => {
let document;
beforeAll(async () => {
document = await payload.create<GroupField>({
document = await payload.create({
collection: groupFieldsSlug,
data: {},
});
@@ -358,7 +358,7 @@ describe('Fields', () => {
let document;
beforeAll(async () => {
document = await payload.create<TabsField>({
document = await payload.create({
collection: tabsSlug,
data: tabsDoc,
});
@@ -395,7 +395,7 @@ describe('Fields', () => {
});
it('should allow hooks on a named tab', async () => {
const newDocument = await payload.create<TabsField>({
const newDocument = await payload.create({
collection: tabsSlug,
data: tabsDoc,
});
@@ -406,7 +406,7 @@ describe('Fields', () => {
});
it('should return empty object for groups when no data present', async () => {
const doc = await payload.create<GroupField>({
const doc = await payload.create({
collection: groupFieldsSlug,
data: groupDoc,
});

View File

@@ -1,6 +1,6 @@
import { GraphQLClient } from 'graphql-request';
import { initPayloadTest } from '../helpers/configHelpers';
import config, { arraySlug, englishLocale, slug, spanishLocale } from './config';
import configPromise, { arraySlug, englishLocale, slug, spanishLocale } from './config';
import payload from '../../src';
import { RESTClient } from '../helpers/rest';
@@ -13,6 +13,7 @@ describe('globals', () => {
describe('REST', () => {
let client: RESTClient;
beforeAll(async () => {
const config = await configPromise;
client = new RESTClient(config, { serverURL, defaultSlug: slug });
});
it('should create', async () => {
@@ -135,6 +136,7 @@ describe('globals', () => {
describe('graphql', () => {
let client: GraphQLClient;
beforeAll(async () => {
const config = await configPromise;
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}`;
client = new GraphQLClient(url);
});

View File

@@ -258,7 +258,7 @@ export class RESTClient {
return { status, doc: result };
}
async endpoint<T = any>(path: string, method = 'get', params = undefined): Promise<{ status: number, data: T }> {
async endpoint<T = any>(path: string, method = 'get', params: any = undefined): Promise<{ status: number, data: T }> {
const response = await fetch(`${this.serverURL}${path}`, {
headers: {
'Content-Type': 'application/json',

View File

@@ -10,7 +10,7 @@ import type {
GlobalArray,
} from './payload-types';
import type { LocalizedPostAllLocale } from './config';
import config, { relationshipLocalizedSlug, slug, withLocalizedRelSlug, withRequiredLocalizedFields } from './config';
import configPromise, { relationshipLocalizedSlug, slug, withLocalizedRelSlug, withRequiredLocalizedFields } from './config';
import {
defaultLocale,
englishTitle,
@@ -23,8 +23,10 @@ import {
} from './shared';
import type { Where } from '../../src/types';
import { arrayCollectionSlug } from './collections/Array';
import type { Config } from '../../src/config/types';
const collection = slug;
let config: Config;
let serverURL;
@@ -34,6 +36,7 @@ describe('Localization', () => {
beforeAll(async () => {
({ serverURL } = await initPayloadTest({ __dirname, init: { local: false } }));
config = await configPromise;
post1 = await payload.create({
collection,
@@ -49,7 +52,7 @@ describe('Localization', () => {
},
});
await payload.update<LocalizedPost>({
await payload.update({
collection,
id: postWithLocalizedData.id,
locale: spanishLocale,
@@ -67,7 +70,7 @@ describe('Localization', () => {
describe('localized text', () => {
it('create english', async () => {
const allDocs = await payload.find<LocalizedPost>({
const allDocs = await payload.find({
collection,
where: {
title: { equals: post1.title },
@@ -77,7 +80,7 @@ describe('Localization', () => {
});
it('add spanish translation', async () => {
const updated = await payload.update<LocalizedPost>({
const updated = await payload.update({
collection,
id: post1.id,
locale: spanishLocale,
@@ -88,7 +91,7 @@ describe('Localization', () => {
expect(updated.title).toEqual(spanishTitle);
const localized = await payload.findByID<LocalizedPostAllLocale>({
const localized = await payload.findByID({
collection,
id: post1.id,
locale: 'all',
@@ -99,7 +102,7 @@ describe('Localization', () => {
});
it('should fallback to english translation when empty', async () => {
const updated = await payload.update<LocalizedPost>({
const updated = await payload.update({
collection,
id: post1.id,
locale: spanishLocale,
@@ -110,7 +113,7 @@ describe('Localization', () => {
expect(updated.title).toEqual(englishTitle);
const localizedFallback = await payload.findByID<LocalizedPostAllLocale>({
const localizedFallback = await payload.findByID({
collection,
id: post1.id,
locale: 'all',
@@ -123,14 +126,14 @@ describe('Localization', () => {
describe('querying', () => {
let localizedPost: LocalizedPost;
beforeEach(async () => {
const { id } = await payload.create<LocalizedPost>({
const { id } = await payload.create({
collection,
data: {
title: englishTitle,
},
});
localizedPost = await payload.update<LocalizedPost>({
localizedPost = await payload.update({
collection,
id,
locale: spanishLocale,
@@ -170,7 +173,7 @@ describe('Localization', () => {
});
it('all locales', async () => {
const localized = await payload.findByID<LocalizedPostAllLocale>({
const localized = await payload.findByID({
collection,
locale: 'all',
id: localizedPost.id,
@@ -181,7 +184,7 @@ describe('Localization', () => {
});
it('by localized field value - default locale', async () => {
const result = await payload.find<LocalizedPost>({
const result = await payload.find({
collection,
where: {
title: {
@@ -194,7 +197,7 @@ describe('Localization', () => {
});
it('by localized field value - alternate locale', async () => {
const result = await payload.find<LocalizedPost>({
const result = await payload.find({
collection,
locale: spanishLocale,
where: {
@@ -208,7 +211,7 @@ describe('Localization', () => {
});
it('by localized field value - opposite locale???', async () => {
const result = await payload.find<LocalizedPost>({
const result = await payload.find({
collection,
locale: 'all',
where: {
@@ -258,7 +261,7 @@ describe('Localization', () => {
describe('regular relationship', () => {
it('can query localized relationship', async () => {
const result = await payload.find<WithLocalizedRelationship>({
const result = await payload.find({
collection: withLocalizedRelSlug,
where: {
'localizedRelationship.title': {
@@ -271,7 +274,7 @@ describe('Localization', () => {
});
it('specific locale', async () => {
const result = await payload.find<WithLocalizedRelationship>({
const result = await payload.find({
collection: withLocalizedRelSlug,
locale: spanishLocale,
where: {
@@ -285,7 +288,7 @@ describe('Localization', () => {
});
it('all locales', async () => {
const result = await payload.find<WithLocalizedRelationship>({
const result = await payload.find({
collection: withLocalizedRelSlug,
locale: 'all',
where: {
@@ -300,7 +303,7 @@ describe('Localization', () => {
it('populates relationships with all locales', async () => {
// the relationship fields themselves are localized on this collection
const result = await payload.find<RelationshipLocalized>({
const result = await payload.find({
collection: relationshipLocalizedSlug,
locale: 'all',
depth: 1,
@@ -314,7 +317,7 @@ describe('Localization', () => {
describe('relationship - hasMany', () => {
it('default locale', async () => {
const result = await payload.find<WithLocalizedRelationship>({
const result = await payload.find({
collection: withLocalizedRelSlug,
where: {
'localizedRelationHasManyField.title': {
@@ -326,7 +329,7 @@ describe('Localization', () => {
expect(result.docs[0].id).toEqual(withRelationship.id);
// Second relationship
const result2 = await payload.find<WithLocalizedRelationship>({
const result2 = await payload.find({
collection: withLocalizedRelSlug,
where: {
'localizedRelationHasManyField.title': {
@@ -339,7 +342,7 @@ describe('Localization', () => {
});
it('specific locale', async () => {
const result = await payload.find<WithLocalizedRelationship>({
const result = await payload.find({
collection: withLocalizedRelSlug,
locale: spanishLocale,
where: {
@@ -352,7 +355,7 @@ describe('Localization', () => {
expect(result.docs[0].id).toEqual(withRelationship.id);
// Second relationship
const result2 = await payload.find<WithLocalizedRelationship>({
const result2 = await payload.find({
collection: withLocalizedRelSlug,
locale: spanishLocale,
where: {
@@ -366,7 +369,7 @@ describe('Localization', () => {
});
it('relationship population uses locale', async () => {
const result = await payload.findByID<WithLocalizedRelationship>({
const result = await payload.findByID({
collection: withLocalizedRelSlug,
depth: 1,
id: withRelationship.id,
@@ -377,7 +380,7 @@ describe('Localization', () => {
it('all locales', async () => {
const queryRelation = (where: Where) => {
return payload.find<WithLocalizedRelationship>({
return payload.find({
collection: withLocalizedRelSlug,
locale: 'all',
where,
@@ -423,7 +426,7 @@ describe('Localization', () => {
describe('relationTo multi', () => {
it('by id', async () => {
const result = await payload.find<WithLocalizedRelationship>({
const result = await payload.find({
collection: withLocalizedRelSlug,
where: {
'localizedRelationMultiRelationTo.value': {
@@ -435,7 +438,7 @@ describe('Localization', () => {
expect(result.docs[0].id).toEqual(withRelationship.id);
// Second relationship
const result2 = await payload.find<WithLocalizedRelationship>({
const result2 = await payload.find({
collection: withLocalizedRelSlug,
locale: spanishLocale,
where: {
@@ -451,7 +454,7 @@ describe('Localization', () => {
describe('relationTo multi hasMany', () => {
it('by id', async () => {
const result = await payload.find<WithLocalizedRelationship>({
const result = await payload.find({
collection: withLocalizedRelSlug,
where: {
'localizedRelationMultiRelationToHasMany.value': {
@@ -463,7 +466,7 @@ describe('Localization', () => {
expect(result.docs[0].id).toEqual(withRelationship.id);
// First relationship - spanish locale
const result2 = await payload.find<WithLocalizedRelationship>({
const result2 = await payload.find({
collection: withLocalizedRelSlug,
locale: spanishLocale,
where: {
@@ -476,7 +479,7 @@ describe('Localization', () => {
expect(result2.docs[0].id).toEqual(withRelationship.id);
// Second relationship
const result3 = await payload.find<WithLocalizedRelationship>({
const result3 = await payload.find({
collection: withLocalizedRelSlug,
where: {
'localizedRelationMultiRelationToHasMany.value': {
@@ -488,7 +491,7 @@ describe('Localization', () => {
expect(result3.docs[0].id).toEqual(withRelationship.id);
// Second relationship - spanish locale
const result4 = await payload.find<WithLocalizedRelationship>({
const result4 = await payload.find({
collection: withLocalizedRelSlug,
where: {
'localizedRelationMultiRelationToHasMany.value': {
@@ -504,7 +507,7 @@ describe('Localization', () => {
describe('Localized - arrays with nested localized fields', () => {
it('should allow moving rows and retain existing row locale data', async () => {
const globalArray = await payload.findGlobal<GlobalArray>({
const globalArray = await payload.findGlobal({
slug: 'global-array',
});
@@ -553,7 +556,7 @@ describe('Localization', () => {
},
});
const updatedDoc = await payload.update<LocalizedRequired>({
const updatedDoc = await payload.update({
collection: withRequiredLocalizedFields,
id: newDoc.id,
data: {
@@ -577,7 +580,7 @@ describe('Localization', () => {
let token;
it('should allow user to login and retrieve populated localized field', async () => {
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}?locale=en`;
const url = `${serverURL}${config?.routes?.api}${config?.routes?.graphQL}?locale=en`;
const client = new GraphQLClient(url);
const query = `mutation {
@@ -602,7 +605,7 @@ describe('Localization', () => {
it('should allow retrieval of populated localized fields within meUser', async () => {
// Defining locale=en in graphQL string should not break JWT strategy
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}?locale=en`;
const url = `${serverURL}${config?.routes?.api}${config?.routes?.graphQL}?locale=en`;
const client = new GraphQLClient(url);
const query = `query {
@@ -626,7 +629,7 @@ describe('Localization', () => {
});
it('should create and update collections', async () => {
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}`;
const url = `${serverURL}${config?.routes?.api}${config?.routes?.graphQL}`;
const client = new GraphQLClient(url);
const create = `mutation {
@@ -749,14 +752,14 @@ async function createLocalizedPost(data: {
[spanishLocale]: string;
};
}): Promise<LocalizedPost> {
const localizedRelation = await payload.create<LocalizedPost>({
const localizedRelation = await payload.create({
collection,
data: {
title: data.title.en,
},
});
await payload.update<LocalizedPost>({
await payload.update({
collection,
id: localizedRelation.id,
locale: spanishLocale,

1
test/plugins/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
media

40
test/plugins/config.ts Normal file
View File

@@ -0,0 +1,40 @@
import { buildConfig } from '../buildConfig';
import { devUser } from '../credentials';
export const pagesSlug = 'pages';
export default buildConfig({
collections: [
{
slug: 'users',
auth: true,
fields: [],
},
],
plugins: [
async (config) => ({
...config,
collections: [
...config.collections || [],
{
slug: pagesSlug,
fields: [
{
name: 'title',
type: 'text',
},
],
},
],
}),
],
onInit: async (payload) => {
await payload.create({
collection: 'users',
data: {
email: devUser.email,
password: devUser.password,
},
});
},
});

View File

28
test/plugins/int.spec.ts Normal file
View File

@@ -0,0 +1,28 @@
import { initPayloadTest } from '../helpers/configHelpers';
import { RESTClient } from '../helpers/rest';
import configPromise, { pagesSlug } from './config';
import payload from '../../src';
require('isomorphic-fetch');
let client;
describe('Collections - Plugins', () => {
beforeAll(async () => {
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } });
const config = await configPromise;
client = new RESTClient(config, { serverURL, defaultSlug: pagesSlug });
await client.login();
});
it('created pages collection', async () => {
const { id } = await payload.create({
collection: pagesSlug,
data: {
title: 'Test Page',
},
});
expect(id).toEqual(expect.any(String));
});
});

View File

@@ -1,7 +1,7 @@
import { request, GraphQLClient } from 'graphql-request';
import { initPayloadTest } from '../helpers/configHelpers';
import payload from '../../src';
import config from './config';
import configPromise from './config';
import AutosavePosts from './collections/Autosave';
import AutosaveGlobal from './globals/Autosave';
import { devUser } from '../credentials';
@@ -27,6 +27,8 @@ const globalGraphQLOriginalTitle = 'updated global title';
describe('Versions', () => {
beforeAll(async () => {
const config = await configPromise;
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } });
graphQLURL = `${serverURL}${config.routes.api}${config.routes.graphQL}`;