feat: async plugins (#2030)
* feat: async plugins * wip: async config * fix: async config
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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--',
|
||||
|
||||
@@ -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...');
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
];
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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 ?? {},
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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 },
|
||||
});
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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
1
test/plugins/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
media
|
||||
40
test/plugins/config.ts
Normal file
40
test/plugins/config.ts
Normal 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,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
0
test/plugins/e2e.todo-spec.ts
Normal file
0
test/plugins/e2e.todo-spec.ts
Normal file
28
test/plugins/int.spec.ts
Normal file
28
test/plugins/int.spec.ts
Normal 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));
|
||||
});
|
||||
});
|
||||
@@ -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}`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user