@websolutespa/test 3.0.1 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @websolutespa/test
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3f7c21b: - Payload 3.91.0 and Next.js 16.4.2 (React 19.2.9): peer dependencies are now ranges, `payload` / `@payloadcms/*` `^3.91.0`, `next` `^16.3.3`, `react` / `react-dom` `^19.2.1`
8
+ - payload-plugin-bowl: the mixer context is built only for reads by an authenticated user (payload 3.90+ resolves the jwt user with the request query, populating tenants before `req.user` is set); email options typed with payload `SendEmailOptions`, no direct nodemailer dependency
9
+ - payload-plugin-storage: `AZURE_STORAGE_CONTAINER_ACCESS` (`private` default since payload 3.90, `blob`, `container`) for containers created by the plugin
10
+ - mixer web: `images.qualities` includes `IMAGE_QUALITY` (next 16 defaults to `[75]`)
11
+ - e96a9d6: - tsconfig: TypeScript 6, `types: ["node"]` (no longer implicit) and `noUncheckedSideEffectImports: false` in the base config; drop `baseUrl` in consumers (deprecated)
12
+ - test: vitest 5 / vite 8 (native tsconfig paths, `vite-tsconfig-paths` removed), build outputs excluded from the test run, jsdom 30, testing-library jest-dom 7
13
+ - bom-mixer-llm: `isChunkType` guard, narrowing of unknown chunk items under typescript 6
14
+ - node 24 (engines >= 22.13)
15
+ - 12b6e2f: - test: replace the jest presets with shared vitest configurations, `@websolutespa/test/vitest` (`defineNodeConfig`, `defineDomConfig`, `definePayloadConfig`); drop jest dependencies
16
+ - declare every imported package and script binary in the package that uses it (no more reliance on hoisting), drop unused dependencies
17
+ - bom-mixer-checkout: `useCart.add` no longer mutates the previous cart state
18
+
19
+ ### Patch Changes
20
+
21
+ - b320a0f: - payload-db-memory: keep versions when Payload enforces `maxPerDoc`, query drafts on `version.*`, apply static field defaults and `$push` on jobs (queued jobs now run), store `Date` values as ISO strings
22
+ - payload-plugin-bowl: support inline array `src` for static collections, decorate rich text with mixer context (`beforeOperationHook`), create redirects on slug updates, honour `getTranslation` default text, keep the app `config.custom`
23
+ - payload-plugin-bowl-llm: merge `config.custom` instead of replacing it
24
+ - payload-plugin-cron-job: mark failing handlers as failed, log unknown jobs correctly
25
+ - payload-plugin-search: match tab fields, trim slate trailing new lines, return 400 when the query is missing
26
+ - test: `getConfig` / `getContext` accept `{ db: 'memory' | 'mongo' }` (default from `BOM_TEST_DB`)
27
+ - Updated dependencies [b320a0f]
28
+ - Updated dependencies [3f7c21b]
29
+ - Updated dependencies [12b6e2f]
30
+ - @websolutespa/payload-db-memory@3.1.0
31
+
32
+ ## 3.0.2
33
+
34
+ ### Patch Changes
35
+
36
+ - Fixing: payload exports
37
+
3
38
  ## 3.0.1
4
39
 
5
40
  ### Patch Changes
package/README.md CHANGED
@@ -9,3 +9,27 @@ Test shared config of the [BOM Repository](https://github.com/websolutespa/bom)
9
9
  ---
10
10
 
11
11
  ##### *this library is for internal usage and not production ready*
12
+
13
+ ---
14
+
15
+ ### Vitest configurations
16
+
17
+ ```ts
18
+ // vitest.config.ts
19
+ import { definePayloadConfig } from '@websolutespa/test/vitest';
20
+
21
+ export default definePayloadConfig();
22
+ ```
23
+
24
+ | factory | environment | use |
25
+ | --- | --- | --- |
26
+ | `defineNodeConfig` | node | libraries, server code |
27
+ | `defineDomConfig` | jsdom + `@testing-library/jest-dom` matchers | react components and hooks |
28
+ | `definePayloadConfig` | node, `BOM_TEST_DB=memory` by default | Payload suites built with `@websolutespa/test/payload` |
29
+
30
+ Each factory accepts a vitest config, deep merged over the defaults.
31
+
32
+ ### Payload test context
33
+
34
+ `getContext(config, { db })` builds a Payload instance on `@websolutespa/payload-db-memory` (`db: 'memory'`, the default with `definePayloadConfig`)
35
+ or on a mongo memory replica set (`db: 'mongo'`, or `BOM_TEST_DB=mongo`).
@@ -0,0 +1,162 @@
1
+ import { CollectionSlug, Config, JoinQuery, Payload, PopulateType, SanitizedConfig, SelectType, Where } from "payload";
2
+
3
+ //#region src/payload/client.d.ts
4
+ type ValidPath = `/${string}`;
5
+ type FileArg = {
6
+ file?: Omit<File, 'webkitRelativePath'>;
7
+ };
8
+ type RequestQuery = {
9
+ [key: string]: unknown;
10
+ } & {
11
+ depth?: number;
12
+ fallbackLocale?: string;
13
+ joins?: JoinQuery;
14
+ limit?: number;
15
+ locale?: string;
16
+ page?: number;
17
+ populate?: PopulateType;
18
+ select?: SelectType;
19
+ sort?: string;
20
+ where?: Where;
21
+ };
22
+ type RequestOptions = {
23
+ auth?: boolean;
24
+ query?: RequestQuery;
25
+ };
26
+ type ClientRequestOptions = FileArg & RequestInit & RequestOptions;
27
+ type NextRoute = (request: Request, args: {
28
+ params: Promise<{
29
+ slug: string[];
30
+ }>;
31
+ }) => Promise<Response>;
32
+ declare class RestClient {
33
+ private readonly config;
34
+ serverURL: string;
35
+ private token;
36
+ private getRest_;
37
+ private postRest_;
38
+ private putRest_;
39
+ private patchRest_;
40
+ private deleteRest_;
41
+ private postGraphql_;
42
+ constructor(config: SanitizedConfig);
43
+ private getHeaders;
44
+ private getPathParts;
45
+ GET(path: ValidPath, options?: Omit<ClientRequestOptions, 'body' | 'file'>): Promise<Response>;
46
+ POST(path: ValidPath, options?: ClientRequestOptions): Promise<Response>;
47
+ PUT(path: ValidPath, options?: ClientRequestOptions): Promise<Response>;
48
+ PATCH(path: ValidPath, options?: ClientRequestOptions): Promise<Response>;
49
+ DELETE(path: ValidPath, options?: Omit<ClientRequestOptions, 'file'>): Promise<Response>;
50
+ GRAPHQL_POST(options?: Omit<ClientRequestOptions, 'file'>): Promise<Response>;
51
+ get(path: string, options?: Omit<ClientRequestOptions, 'body' | 'file'>): Promise<{
52
+ [key: string]: any;
53
+ }>;
54
+ post(path: string, body: any, options?: ClientRequestOptions): Promise<{
55
+ [key: string]: any;
56
+ }>;
57
+ patch(path: string, body: any, options?: ClientRequestOptions): Promise<{
58
+ [key: string]: any;
59
+ }>;
60
+ delete(path: string, options?: Omit<ClientRequestOptions, 'body' | 'file'>): Promise<{
61
+ [key: string]: any;
62
+ }>;
63
+ getToken(slug?: CollectionSlug, credentials?: {
64
+ email: string;
65
+ password: string;
66
+ }): Promise<string>;
67
+ login({
68
+ slug,
69
+ credentials
70
+ }: {
71
+ slug: string;
72
+ credentials?: {
73
+ email: string;
74
+ password: string;
75
+ };
76
+ }): Promise<{
77
+ [key: string]: any;
78
+ }>;
79
+ }
80
+ //#endregion
81
+ //#region src/payload/config.d.ts
82
+ type TestDatabase = 'mongo' | 'memory';
83
+ type TestConfigOptions = {
84
+ /**
85
+ * Database backing the test payload.
86
+ * - 'mongo' (default): MongoMemoryReplSet + mongooseAdapter, Slate editor.
87
+ * - 'memory': @websolutespa/payload-db-memory, Lexical editor (no replica set, no DATABASE_URL).
88
+ * Defaults to the BOM_TEST_DB environment variable when set.
89
+ */
90
+ db?: TestDatabase;
91
+ };
92
+ declare function getConfig(config: Partial<Config>, options?: TestConfigOptions): Promise<SanitizedConfig>;
93
+ //#endregion
94
+ //#region src/payload/context.d.ts
95
+ /**
96
+ * Local Payload API surface for integration suites that register collections
97
+ * at runtime and therefore cannot use an application's generated schema.
98
+ * It is an intersection with Payload, so it stays assignable to Payload.
99
+ */
100
+ type TestPayload = Payload & {
101
+ create: (options: unknown) => Promise<any>;
102
+ find: (options: unknown) => Promise<any>;
103
+ findByID: (options: unknown) => Promise<any>;
104
+ update: (options: unknown) => Promise<any>;
105
+ };
106
+ type TestContext = {
107
+ payload: TestPayload;
108
+ client: RestClient;
109
+ };
110
+ declare function getContext(userConfig: Partial<Config>, options?: TestConfigOptions): Promise<TestContext>;
111
+ declare function clearContext(context?: TestContext): Promise<void>;
112
+ //#endregion
113
+ //#region src/payload/seed.d.ts
114
+ /**
115
+ * Defaults user roles and endUser roles available on the bowl plugin configuration:
116
+ *
117
+ * admin: user role with super powers.
118
+ * contributor: user role with minor powers.
119
+ * editor: user role with content editing powers.
120
+ * guest: endUser role with application reading capabilities.
121
+ * user: endUser authenticated role with reserved data.
122
+ *
123
+ */
124
+ declare const roles: {
125
+ readonly Admin: "admin";
126
+ readonly Contributor: "contributor";
127
+ readonly Editor: "editor";
128
+ readonly Guest: "guest";
129
+ readonly User: "user";
130
+ };
131
+ declare const users: {
132
+ admin: {
133
+ email: string;
134
+ password: string;
135
+ roles: "admin"[];
136
+ };
137
+ editor: {
138
+ email: string;
139
+ password: string;
140
+ roles: "editor"[];
141
+ };
142
+ api: {
143
+ email: string;
144
+ password: string;
145
+ roles: "guest"[];
146
+ enableAPIKey: boolean;
147
+ apiKey: string;
148
+ };
149
+ };
150
+ declare const endUsers: {
151
+ user: {
152
+ email: string;
153
+ password: string;
154
+ roles: ("guest" | "user")[];
155
+ };
156
+ };
157
+ declare const seedUsers: (payload: TestPayload) => Promise<void>;
158
+ declare const seedEndUsers: (payload: TestPayload) => Promise<void>;
159
+ declare const seed: (payload: TestPayload) => Promise<void>;
160
+ //#endregion
161
+ export { ClientRequestOptions, FileArg, NextRoute, RequestOptions, RequestQuery, RestClient, TestConfigOptions, TestContext, TestDatabase, TestPayload, ValidPath, clearContext, endUsers, getConfig, getContext, roles, seed, seedEndUsers, seedUsers, users };
162
+ //# sourceMappingURL=payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.d.ts","names":[],"sources":["../../src/payload/client.ts","../../src/payload/config.ts","../../src/payload/context.ts","../../src/payload/seed.ts"],"mappings":"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"}
@@ -0,0 +1,354 @@
1
+ import { GRAPHQL_POST, REST_DELETE, REST_GET, REST_PATCH, REST_POST, REST_PUT } from "@payloadcms/next/routes";
2
+ import * as qs from "qs-esm";
3
+ import { uuidv4 } from "@websolutespa/bom-core";
4
+ import { mongooseAdapter } from "@payloadcms/db-mongodb";
5
+ import { lexicalEditor } from "@payloadcms/richtext-lexical";
6
+ import { slateEditor } from "@payloadcms/richtext-slate";
7
+ import { memoryAdapter } from "@websolutespa/payload-db-memory";
8
+ import { MongoMemoryReplSet } from "mongodb-memory-server";
9
+ import path from "path";
10
+ import { buildConfig, getPayload } from "payload";
11
+ import sharp from "sharp";
12
+ import { fileURLToPath } from "url";
13
+ //#region src/payload/seed.ts
14
+ /**
15
+ * Defaults user roles and endUser roles available on the bowl plugin configuration:
16
+ *
17
+ * admin: user role with super powers.
18
+ * contributor: user role with minor powers.
19
+ * editor: user role with content editing powers.
20
+ * guest: endUser role with application reading capabilities.
21
+ * user: endUser authenticated role with reserved data.
22
+ *
23
+ */
24
+ const roles = {
25
+ Admin: "admin",
26
+ Contributor: "contributor",
27
+ Editor: "editor",
28
+ Guest: "guest",
29
+ User: "user"
30
+ };
31
+ const users = {
32
+ admin: {
33
+ email: "admin@payload.com",
34
+ password: "admin@payload.com",
35
+ roles: [roles.Admin]
36
+ },
37
+ editor: {
38
+ email: "editor@payload.com",
39
+ password: "editor@payload.com",
40
+ roles: [roles.Editor]
41
+ },
42
+ api: {
43
+ email: "api@payload.com",
44
+ password: "api@payload.com",
45
+ roles: [roles.Guest],
46
+ enableAPIKey: true,
47
+ apiKey: uuidv4()
48
+ }
49
+ };
50
+ const endUsers = { user: {
51
+ email: "user@payload.com",
52
+ password: "user@payload.com",
53
+ roles: [roles.Guest, roles.User]
54
+ } };
55
+ const seedUsers = async (payload) => {
56
+ const { totalDocs } = await payload.count({ collection: "users" });
57
+ if (totalDocs === 0) for (const entry of Object.entries(users)) {
58
+ const user = entry[1];
59
+ await payload.create({
60
+ collection: "users",
61
+ data: user
62
+ });
63
+ }
64
+ };
65
+ const seedEndUsers = async (payload) => {
66
+ const { totalDocs } = await payload.count({ collection: "end_users" });
67
+ if (totalDocs === 0) for (const entry of Object.entries(endUsers)) {
68
+ const user = entry[1];
69
+ await payload.create({
70
+ collection: "end_users",
71
+ data: user,
72
+ draft: false
73
+ });
74
+ }
75
+ };
76
+ const seed = async (payload) => {
77
+ if (payload.collections["users"] !== void 0) await seedUsers(payload);
78
+ if (payload.collections["end_users"] !== void 0) await seedEndUsers(payload);
79
+ };
80
+ //#endregion
81
+ //#region src/payload/client.ts
82
+ function asValidPath(path) {
83
+ if (!path.match(/^\//)) path = `/${path}`;
84
+ return path;
85
+ }
86
+ function getQueryString(query, params) {
87
+ return qs.stringify({
88
+ ...params || {},
89
+ ...query || {}
90
+ }, { addQueryPrefix: true });
91
+ }
92
+ var RestClient = class {
93
+ config;
94
+ serverURL = "http://localhost:3000";
95
+ token = "";
96
+ getRest_;
97
+ postRest_;
98
+ putRest_;
99
+ patchRest_;
100
+ deleteRest_;
101
+ postGraphql_;
102
+ constructor(config) {
103
+ this.config = config;
104
+ if (config?.serverURL) this.serverURL = config.serverURL;
105
+ this.getRest_ = REST_GET(config);
106
+ this.postRest_ = REST_POST(config);
107
+ this.putRest_ = REST_PUT(config);
108
+ this.patchRest_ = REST_PATCH(config);
109
+ this.deleteRest_ = REST_DELETE(config);
110
+ this.postGraphql_ = GRAPHQL_POST(config);
111
+ }
112
+ getHeaders(options) {
113
+ const headers = new Headers({
114
+ ...options?.file ? { "Content-Length": options.file.size.toString() } : { "Content-Type": "application/json" },
115
+ ...options?.headers || {}
116
+ });
117
+ if (options.auth !== false && this.token) headers.set("Authorization", `JWT ${this.token}`);
118
+ if (options.auth === false) headers.set("DisableAutologin", "true");
119
+ return headers;
120
+ }
121
+ getPathParts(path) {
122
+ const [slugs, params] = path.slice(1).split("?");
123
+ const url = `${this.serverURL}${this.config.routes.api}/${slugs}`;
124
+ return {
125
+ slug: slugs.split("/"),
126
+ params: params ? qs.parse(params) : void 0,
127
+ url
128
+ };
129
+ }
130
+ async GET(path, options = {}) {
131
+ const { slug, params, url } = this.getPathParts(path);
132
+ const { query, ...rest } = options || {};
133
+ const queryParams = getQueryString(query, params);
134
+ const request = new Request(`${url}${queryParams}`, {
135
+ ...rest,
136
+ headers: this.getHeaders(options),
137
+ method: "GET"
138
+ });
139
+ return this.getRest_(request, { params: Promise.resolve({ slug }) });
140
+ }
141
+ async POST(path, options = {}) {
142
+ const { slug, params, url } = this.getPathParts(path);
143
+ const queryParams = getQueryString({}, params);
144
+ const request = new Request(`${url}${queryParams}`, {
145
+ ...options,
146
+ headers: this.getHeaders(options),
147
+ method: "POST"
148
+ });
149
+ return this.postRest_(request, { params: Promise.resolve({ slug }) });
150
+ }
151
+ async PUT(path, options = {}) {
152
+ const { slug, params, url } = this.getPathParts(path);
153
+ const { query, ...rest } = options;
154
+ const queryParams = getQueryString(query, params);
155
+ const request = new Request(`${url}${queryParams}`, {
156
+ ...rest,
157
+ headers: this.getHeaders(options),
158
+ method: "PUT"
159
+ });
160
+ return this.putRest_(request, { params: Promise.resolve({ slug }) });
161
+ }
162
+ async PATCH(path, options = {}) {
163
+ const { slug, params, url } = this.getPathParts(path);
164
+ const { query, ...rest } = options;
165
+ const queryParams = getQueryString(query, params);
166
+ const request = new Request(`${url}${queryParams}`, {
167
+ ...rest,
168
+ headers: this.getHeaders(options),
169
+ method: "PATCH"
170
+ });
171
+ return this.patchRest_(request, { params: Promise.resolve({ slug }) });
172
+ }
173
+ async DELETE(path, options = {}) {
174
+ const { slug, params, url } = this.getPathParts(path);
175
+ const { query, ...rest } = options || {};
176
+ const queryParams = getQueryString(query, params);
177
+ const request = new Request(`${url}${queryParams}`, {
178
+ ...rest,
179
+ headers: this.getHeaders(options),
180
+ method: "DELETE"
181
+ });
182
+ return this.deleteRest_(request, { params: Promise.resolve({ slug }) });
183
+ }
184
+ async GRAPHQL_POST(options = {}) {
185
+ const { query, ...rest } = options;
186
+ const queryParams = getQueryString(query, {});
187
+ const request = new Request(`${this.serverURL}${this.config.routes.api}${this.config.routes.graphQL}${queryParams}`, {
188
+ ...rest,
189
+ headers: this.getHeaders(options),
190
+ method: "POST"
191
+ });
192
+ return this.postGraphql_(request);
193
+ }
194
+ async get(path, options = {}) {
195
+ try {
196
+ const response = await this.GET(asValidPath(path), options);
197
+ if (!response.ok) throw response;
198
+ return await response.json();
199
+ } catch (error) {
200
+ console.log("RestClient.get.error", path, "json" in error ? await error.json() : error);
201
+ throw error;
202
+ }
203
+ }
204
+ async post(path, body, options = {}) {
205
+ try {
206
+ options = {
207
+ ...options,
208
+ body: JSON.stringify(body)
209
+ };
210
+ const response = await this.POST(asValidPath(path), options);
211
+ if (!response.ok) throw response;
212
+ return await response.json();
213
+ } catch (error) {
214
+ console.log("RestClient.post.error", path, error);
215
+ throw error;
216
+ }
217
+ }
218
+ async patch(path, body, options = {}) {
219
+ try {
220
+ options = {
221
+ ...options,
222
+ body: JSON.stringify(body)
223
+ };
224
+ const response = await this.PATCH(asValidPath(path), options);
225
+ if (!response.ok) throw response;
226
+ return await response.json();
227
+ } catch (error) {
228
+ console.log("RestClient.patch.error", path, error);
229
+ throw error;
230
+ }
231
+ }
232
+ async delete(path, options = {}) {
233
+ try {
234
+ const response = await this.DELETE(asValidPath(path), options);
235
+ if (!response.ok) throw response;
236
+ return await response.json();
237
+ } catch (error) {
238
+ console.log("RestClient.delete.error", path, error);
239
+ throw error;
240
+ }
241
+ }
242
+ async getToken(slug = "users", credentials = users.admin) {
243
+ return (await this.post(`/${slug}/login`, {
244
+ email: credentials.email,
245
+ password: credentials.password
246
+ })).token;
247
+ }
248
+ async login({ slug, credentials }) {
249
+ const response = await this.POST(`/${slug}/login`, { body: JSON.stringify(credentials ? { ...credentials } : {
250
+ email: users.admin.email,
251
+ password: users.admin.password
252
+ }) });
253
+ const result = await response.json();
254
+ this.token = result.token;
255
+ if (!result.token) this.token = (response.headers.get("Set-Cookie")?.match(/payload-token=(?<token>.+?);/))?.groups?.token || "";
256
+ return result;
257
+ }
258
+ };
259
+ //#endregion
260
+ //#region src/payload/email.adapter.ts
261
+ const testEmailAdapter = ({ payload }) => ({
262
+ name: "test-email-adapter",
263
+ defaultFromAddress: "dev@payloadcms.com",
264
+ defaultFromName: "Payload Test",
265
+ sendEmail: async (message) => {
266
+ const res = `Test email to: '${getStringifiedToAddress(message)}', Subject: '${message.subject}'`;
267
+ payload.logger.info({
268
+ content: message,
269
+ msg: res
270
+ });
271
+ return Promise.resolve();
272
+ }
273
+ });
274
+ function getAddress(to) {
275
+ if (typeof to === "string") return to;
276
+ if (to && typeof to === "object" && "address" in to && typeof to.address === "string") return to.address;
277
+ return "";
278
+ }
279
+ function getStringifiedToAddress(message) {
280
+ if (!message.to) return;
281
+ return Array.isArray(message.to) ? message.to.map(getAddress).join(", ") : getAddress(message.to) || void 0;
282
+ }
283
+ //#endregion
284
+ //#region src/payload/config.ts
285
+ function resolveDatabase(options) {
286
+ return options?.db || (process.env.BOM_TEST_DB === "memory" ? "memory" : "mongo");
287
+ }
288
+ const filename = fileURLToPath(import.meta.url);
289
+ const dirname = path.dirname(filename);
290
+ if (!process.env.ROOT_DIR) process.env.ROOT_DIR = dirname;
291
+ const buildConfigWithMemoryDB = async (config, options) => {
292
+ const memory = resolveDatabase(options) === "memory";
293
+ if (!memory && process.env.NODE_ENV === "test") {
294
+ const memoryDB = await MongoMemoryReplSet.create({ replSet: {
295
+ count: 3,
296
+ dbName: "payloadmemory"
297
+ } });
298
+ process.env.DATABASE_URL = `${memoryDB.getUri()}&retryWrites=true`;
299
+ }
300
+ return buildConfig({
301
+ ...config,
302
+ admin: {
303
+ ...config.admin,
304
+ importMap: { baseDir: path.resolve(dirname) }
305
+ },
306
+ db: memory ? memoryAdapter() : mongooseAdapter({
307
+ ensureIndexes: true,
308
+ url: process.env.DATABASE_URL || ""
309
+ }),
310
+ editor: memory ? config.editor || lexicalEditor() : slateEditor({}),
311
+ email: testEmailAdapter,
312
+ i18n: {
313
+ ...config.i18n,
314
+ fallbackLanguage: "en"
315
+ },
316
+ localization: {
317
+ locales: ["en", "it"],
318
+ defaultLocale: "en",
319
+ fallback: true
320
+ },
321
+ maxDepth: 10,
322
+ onInit: async (payload) => {
323
+ await seed(payload);
324
+ },
325
+ serverURL: "http://localhost:3000",
326
+ secret: process.env.PAYLOAD_SECRET || "test-secret_key",
327
+ sharp,
328
+ typescript: {
329
+ declare: false,
330
+ outputFile: path.resolve(dirname, "payload-types.ts")
331
+ }
332
+ });
333
+ };
334
+ async function getConfig(config, options) {
335
+ return await buildConfigWithMemoryDB(config, options);
336
+ }
337
+ //#endregion
338
+ //#region src/payload/context.ts
339
+ let CONTEXT = void 0;
340
+ async function getContext(userConfig, options) {
341
+ if (CONTEXT) return CONTEXT;
342
+ const payload = await getPayload({ config: await getConfig(userConfig, options) });
343
+ const context = {
344
+ payload,
345
+ client: new RestClient(payload.config)
346
+ };
347
+ CONTEXT = context;
348
+ return context;
349
+ }
350
+ async function clearContext(context) {}
351
+ //#endregion
352
+ export { RestClient, clearContext, endUsers, getConfig, getContext, roles, seed, seedEndUsers, seedUsers, users };
353
+
354
+ //# sourceMappingURL=payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.js","names":[],"sources":["../../src/payload/seed.ts","../../src/payload/client.ts","../../src/payload/email.adapter.ts","../../src/payload/config.ts","../../src/payload/context.ts"],"sourcesContent":["import { uuidv4 } from '@websolutespa/bom-core';\r\nimport type { TestPayload } from './context';\r\n\r\n/**\r\n * Defaults user roles and endUser roles available on the bowl plugin configuration:\r\n *\r\n * admin: user role with super powers.\r\n * contributor: user role with minor powers.\r\n * editor: user role with content editing powers.\r\n * guest: endUser role with application reading capabilities.\r\n * user: endUser authenticated role with reserved data.\r\n *\r\n */\r\nexport const roles = {\r\n Admin: 'admin',\r\n Contributor: 'contributor',\r\n Editor: 'editor',\r\n Guest: 'guest', // api requests (from Oven) will be made with this role if the user didn't authenticate\r\n User: 'user',\r\n} as const;\r\n\r\nexport const users = {\r\n admin: {\r\n email: 'admin@payload.com',\r\n password: 'admin@payload.com',\r\n roles: [roles.Admin],\r\n },\r\n editor: {\r\n email: 'editor@payload.com',\r\n password: 'editor@payload.com',\r\n roles: [roles.Editor],\r\n },\r\n api: {\r\n email: 'api@payload.com',\r\n password: 'api@payload.com',\r\n roles: [roles.Guest],\r\n enableAPIKey: true,\r\n apiKey: uuidv4(),\r\n },\r\n};\r\n\r\nexport const endUsers = {\r\n user: {\r\n email: 'user@payload.com',\r\n password: 'user@payload.com',\r\n roles: [roles.Guest, roles.User],\r\n },\r\n};\r\n\r\nexport const seedUsers = async (payload: TestPayload) => {\r\n const { totalDocs } = await payload.count({\r\n collection: 'users',\r\n });\r\n if (totalDocs === 0) {\r\n for (const entry of Object.entries(users)) {\r\n const user = entry[1];\r\n await payload.create({\r\n collection: 'users',\r\n data: user,\r\n });\r\n }\r\n }\r\n};\r\n\r\nexport const seedEndUsers = async (payload: TestPayload) => {\r\n const { totalDocs } = await payload.count({\r\n collection: 'end_users',\r\n });\r\n if (totalDocs === 0) {\r\n for (const entry of Object.entries(endUsers)) {\r\n const user = entry[1];\r\n await payload.create({\r\n collection: 'end_users',\r\n data: user,\r\n draft: false,\r\n });\r\n }\r\n }\r\n};\r\n\r\nexport const seed = async (payload: TestPayload) => {\r\n if (payload.collections['users'] !== undefined) {\r\n await seedUsers(payload);\r\n }\r\n if (payload.collections['end_users'] !== undefined) {\r\n await seedEndUsers(payload);\r\n }\r\n};\r\n","import { GRAPHQL_POST, REST_DELETE, REST_GET, REST_PATCH, REST_POST, REST_PUT } from '@payloadcms/next/routes';\r\nimport type { CollectionSlug, JoinQuery, PopulateType, SanitizedConfig, SelectType, Where } from 'payload';\r\nimport type { ParsedQs } from 'qs-esm';\r\nimport * as qs from 'qs-esm';\r\nimport { users } from './seed';\r\n\r\nexport type ValidPath = `/${string}`;\r\n\r\nexport type FileArg = {\r\n file?: Omit<File, 'webkitRelativePath'>;\r\n};\r\n\r\nexport type RequestQuery = {\r\n [key: string]: unknown;\r\n} & {\r\n depth?: number;\r\n fallbackLocale?: string;\r\n joins?: JoinQuery;\r\n limit?: number;\r\n locale?: string;\r\n page?: number;\r\n populate?: PopulateType;\r\n select?: SelectType;\r\n sort?: string;\r\n where?: Where;\r\n};\r\n\r\nexport type RequestOptions = {\r\n auth?: boolean;\r\n query?: RequestQuery;\r\n};\r\n\r\nexport type ClientRequestOptions = FileArg & RequestInit & RequestOptions;\r\n\r\nexport type NextRoute = (request: Request, args: { params: Promise<{ slug: string[] }> }) => Promise<Response>;\r\n\r\nfunction asValidPath(path: string): ValidPath {\r\n if (!path.match(/^\\//)) {\r\n path = `/${path}`;\r\n }\r\n return path as ValidPath;\r\n}\r\n\r\nfunction getQueryString(query?: RequestQuery, params?: ParsedQs): string {\r\n return qs.stringify(\r\n {\r\n ...(params || {}),\r\n ...(query || {}),\r\n },\r\n {\r\n addQueryPrefix: true,\r\n },\r\n )\r\n}\r\n\r\nexport class RestClient {\r\n\r\n private readonly config: SanitizedConfig;\r\n serverURL: string = 'http://localhost:3000';\r\n private token: string = '';\r\n\r\n private getRest_: NextRoute;\r\n private postRest_: NextRoute;\r\n private putRest_: NextRoute;\r\n private patchRest_: NextRoute;\r\n private deleteRest_: NextRoute;\r\n private postGraphql_: (request: Request) => Promise<Response>;\r\n\r\n constructor(config: SanitizedConfig) {\r\n this.config = config;\r\n if (config?.serverURL) {\r\n this.serverURL = config.serverURL;\r\n }\r\n this.getRest_ = REST_GET(config);\r\n this.postRest_ = REST_POST(config);\r\n this.putRest_ = REST_PUT(config);\r\n this.patchRest_ = REST_PATCH(config);\r\n this.deleteRest_ = REST_DELETE(config);\r\n this.postGraphql_ = GRAPHQL_POST(config);\r\n }\r\n\r\n private getHeaders(options: ClientRequestOptions): Headers {\r\n const defaultHeaders = {\r\n 'Content-Type': 'application/json',\r\n };\r\n const headers = new Headers({\r\n ...(options?.file ? {\r\n 'Content-Length': options.file.size.toString(),\r\n } : defaultHeaders),\r\n ...(options?.headers || {}),\r\n });\r\n if (options.auth !== false && this.token) {\r\n headers.set('Authorization', `JWT ${this.token}`);\r\n }\r\n if (options.auth === false) {\r\n headers.set('DisableAutologin', 'true');\r\n }\r\n return headers;\r\n }\r\n\r\n private getPathParts(path: ValidPath): {\r\n params?: ParsedQs;\r\n slug: string[];\r\n url: string;\r\n } {\r\n const [slugs, params] = path.slice(1).split('?');\r\n const url = `${this.serverURL}${this.config.routes.api}/${slugs}`;\r\n return {\r\n slug: slugs.split('/'),\r\n params: params ? qs.parse(params) : undefined,\r\n url,\r\n }\r\n }\r\n\r\n async GET(path: ValidPath, options: Omit<ClientRequestOptions, 'body' | 'file'> = {}): Promise<Response> {\r\n const { slug, params, url } = this.getPathParts(path);\r\n const { query, ...rest } = options || {};\r\n const queryParams = getQueryString(query, params);\r\n const request = new Request(`${url}${queryParams}`, {\r\n ...rest,\r\n headers: this.getHeaders(options),\r\n method: 'GET',\r\n });\r\n return this.getRest_(request, { params: Promise.resolve({ slug }) });\r\n }\r\n\r\n async POST(path: ValidPath, options: ClientRequestOptions = {}): Promise<Response> {\r\n const { slug, params, url } = this.getPathParts(path);\r\n const queryParams = getQueryString({}, params);\r\n const request = new Request(`${url}${queryParams}`, {\r\n ...options,\r\n headers: this.getHeaders(options),\r\n method: 'POST',\r\n });\r\n return this.postRest_(request, { params: Promise.resolve({ slug }) });\r\n }\r\n\r\n async PUT(path: ValidPath, options: ClientRequestOptions = {}): Promise<Response> {\r\n const { slug, params, url } = this.getPathParts(path);\r\n const { query, ...rest } = options;\r\n const queryParams = getQueryString(query, params);\r\n const request = new Request(`${url}${queryParams}`, {\r\n ...rest,\r\n headers: this.getHeaders(options),\r\n method: 'PUT',\r\n });\r\n return this.putRest_(request, { params: Promise.resolve({ slug }) });\r\n }\r\n\r\n async PATCH(path: ValidPath, options: ClientRequestOptions = {}): Promise<Response> {\r\n const { slug, params, url } = this.getPathParts(path);\r\n const { query, ...rest } = options;\r\n const queryParams = getQueryString(query, params);\r\n const request = new Request(`${url}${queryParams}`, {\r\n ...rest,\r\n headers: this.getHeaders(options),\r\n method: 'PATCH',\r\n });\r\n return this.patchRest_(request, { params: Promise.resolve({ slug }) });\r\n }\r\n\r\n async DELETE(path: ValidPath, options: Omit<ClientRequestOptions, 'file'> = {}): Promise<Response> {\r\n const { slug, params, url } = this.getPathParts(path);\r\n const { query, ...rest } = options || {};\r\n const queryParams = getQueryString(query, params);\r\n const request = new Request(`${url}${queryParams}`, {\r\n ...rest,\r\n headers: this.getHeaders(options),\r\n method: 'DELETE',\r\n });\r\n return this.deleteRest_(request, { params: Promise.resolve({ slug }) });\r\n }\r\n\r\n async GRAPHQL_POST(options: Omit<ClientRequestOptions, 'file'> = {}): Promise<Response> {\r\n const { query, ...rest } = options;\r\n const queryParams = getQueryString(query, {});\r\n const request = new Request(`${this.serverURL}${this.config.routes.api}${this.config.routes.graphQL}${queryParams}`, {\r\n ...rest,\r\n headers: this.getHeaders(options),\r\n method: 'POST',\r\n });\r\n return this.postGraphql_(request);\r\n }\r\n\r\n async get(path: string, options: Omit<ClientRequestOptions, 'body' | 'file'> = {}): Promise<{ [key: string]: any }> {\r\n try {\r\n const response = await this.GET(asValidPath(path), options);\r\n if (!response.ok) {\r\n throw response;\r\n }\r\n const data = await response.json();\r\n return data;\r\n } catch (error: any) {\r\n console.log('RestClient.get.error', path, 'json' in error ? await error.json() : error);\r\n throw (error);\r\n }\r\n }\r\n\r\n async post(path: string, body: any, options: ClientRequestOptions = {}): Promise<{ [key: string]: any }> {\r\n try {\r\n options = {\r\n ...options,\r\n body: JSON.stringify(body),\r\n };\r\n const response = await this.POST(asValidPath(path), options);\r\n if (!response.ok) {\r\n throw response;\r\n }\r\n const data = await response.json();\r\n return data;\r\n } catch (error: any) {\r\n console.log('RestClient.post.error', path, error);\r\n throw (error);\r\n }\r\n }\r\n\r\n async patch(path: string, body: any, options: ClientRequestOptions = {}): Promise<{ [key: string]: any }> {\r\n try {\r\n options = {\r\n ...options,\r\n body: JSON.stringify(body),\r\n };\r\n const response = await this.PATCH(asValidPath(path), options);\r\n if (!response.ok) {\r\n throw response;\r\n }\r\n const data = await response.json();\r\n return data;\r\n } catch (error: any) {\r\n console.log('RestClient.patch.error', path, error);\r\n throw (error);\r\n }\r\n }\r\n\r\n async delete(path: string, options: Omit<ClientRequestOptions, 'body' | 'file'> = {}): Promise<{ [key: string]: any }> {\r\n try {\r\n const response = await this.DELETE(asValidPath(path), options);\r\n if (!response.ok) {\r\n throw response;\r\n }\r\n const data = await response.json();\r\n return data;\r\n } catch (error: any) {\r\n console.log('RestClient.delete.error', path, error);\r\n throw (error);\r\n }\r\n }\r\n\r\n async getToken(slug: CollectionSlug = 'users', credentials: { email: string, password: string } = users.admin): Promise<string> {\r\n const result = await this.post(`/${slug}/login`, {\r\n email: credentials.email,\r\n password: credentials.password,\r\n });\r\n return result.token as string;\r\n }\r\n\r\n async login({\r\n slug,\r\n credentials,\r\n }: {\r\n slug: string;\r\n credentials?: {\r\n email: string;\r\n password: string;\r\n };\r\n }): Promise<{ [key: string]: any }> {\r\n const response = await this.POST(`/${slug}/login`, {\r\n body: JSON.stringify(\r\n credentials ? {\r\n ...credentials\r\n } : {\r\n email: users.admin.email,\r\n password: users.admin.password\r\n },\r\n ),\r\n });\r\n const result = await response.json();\r\n this.token = result.token;\r\n if (!result.token) {\r\n // If the token is not in the response body, then we can extract it from the cookies\r\n const setCookie = response.headers.get('Set-Cookie');\r\n const tokenMatchResult = setCookie?.match(/payload-token=(?<token>.+?);/);\r\n this.token = tokenMatchResult?.groups?.token || '';\r\n }\r\n return result;\r\n }\r\n\r\n}\r\n","import type { EmailAdapter, SendEmailOptions } from 'payload';\r\n\r\nexport const testEmailAdapter: EmailAdapter<void> = ({ payload }) => ({\r\n name: 'test-email-adapter',\r\n defaultFromAddress: 'dev@payloadcms.com',\r\n defaultFromName: 'Payload Test',\r\n sendEmail: async (message) => {\r\n const stringifiedTo = getStringifiedToAddress(message)\r\n const res = `Test email to: '${stringifiedTo}', Subject: '${message.subject}'`\r\n payload.logger.info({ content: message, msg: res })\r\n return Promise.resolve()\r\n },\r\n})\r\n\r\nfunction getAddress(to: unknown): string {\r\n if (typeof to === 'string') {\r\n return to;\r\n }\r\n if (to && typeof to === 'object' && 'address' in to && typeof to.address === 'string') {\r\n return to.address;\r\n }\r\n return '';\r\n}\r\n\r\nfunction getStringifiedToAddress(message: SendEmailOptions): string | undefined {\r\n if (!message.to) {\r\n return undefined;\r\n }\r\n return Array.isArray(message.to) ?\r\n message.to.map(getAddress).join(', ') :\r\n getAddress(message.to) || undefined;\r\n}\r\n","import { mongooseAdapter } from '@payloadcms/db-mongodb';\r\nimport { lexicalEditor } from '@payloadcms/richtext-lexical';\r\nimport { slateEditor } from '@payloadcms/richtext-slate';\r\nimport { memoryAdapter } from '@websolutespa/payload-db-memory';\r\nimport { MongoMemoryReplSet } from 'mongodb-memory-server';\r\nimport path from 'path';\r\nimport { buildConfig, Config, SanitizedConfig } from 'payload';\r\nimport sharp from 'sharp';\r\nimport { fileURLToPath } from 'url';\r\nimport { testEmailAdapter } from './email.adapter';\r\nimport type { TestPayload } from './context';\r\nimport { seed } from './seed';\r\n\r\nconst SLATE = true;\r\n\r\nexport type TestDatabase = 'mongo' | 'memory';\r\n\r\nexport type TestConfigOptions = {\r\n /**\r\n * Database backing the test payload.\r\n * - 'mongo' (default): MongoMemoryReplSet + mongooseAdapter, Slate editor.\r\n * - 'memory': @websolutespa/payload-db-memory, Lexical editor (no replica set, no DATABASE_URL).\r\n * Defaults to the BOM_TEST_DB environment variable when set.\r\n */\r\n db?: TestDatabase;\r\n};\r\n\r\nfunction resolveDatabase(options?: TestConfigOptions): TestDatabase {\r\n return options?.db || (process.env.BOM_TEST_DB === 'memory' ? 'memory' : 'mongo');\r\n}\r\n\r\nconst filename = fileURLToPath(import.meta.url);\r\nconst dirname = path.dirname(filename);\r\n\r\nif (!process.env.ROOT_DIR) {\r\n process.env.ROOT_DIR = dirname;\r\n}\r\n\r\nconst buildConfigWithMemoryDB = async (config: Partial<Config>, options?: TestConfigOptions) => {\r\n const memory = resolveDatabase(options) === 'memory';\r\n if (!memory && process.env.NODE_ENV === 'test') {\r\n const memoryDB = await MongoMemoryReplSet.create({\r\n replSet: {\r\n count: 3,\r\n dbName: 'payloadmemory',\r\n },\r\n });\r\n process.env.DATABASE_URL = `${memoryDB.getUri()}&retryWrites=true`;\r\n }\r\n // console.log('NODE_ENV', process.env.NODE_ENV, process.env.DATABASE_URL);\r\n return buildConfig({\r\n ...config,\r\n admin: {\r\n ...config.admin,\r\n importMap: {\r\n baseDir: path.resolve(dirname),\r\n },\r\n },\r\n db: memory ?\r\n memoryAdapter() :\r\n mongooseAdapter({\r\n ensureIndexes: true,\r\n url: process.env.DATABASE_URL || '',\r\n }),\r\n editor: memory ?\r\n (config.editor || lexicalEditor()) :\r\n SLATE ? slateEditor({}) : lexicalEditor(),\r\n email: testEmailAdapter,\r\n i18n: {\r\n ...config.i18n,\r\n fallbackLanguage: 'en',\r\n },\r\n // indexSortableFields: true\r\n localization: {\r\n locales: ['en', 'it'],\r\n defaultLocale: 'en',\r\n fallback: true,\r\n },\r\n maxDepth: 10,\r\n onInit: async (payload) => {\r\n await seed(payload as TestPayload);\r\n },\r\n serverURL: 'http://localhost:3000',\r\n secret: process.env.PAYLOAD_SECRET || 'test-secret_key',\r\n sharp,\r\n typescript: {\r\n declare: false,\r\n outputFile: path.resolve(dirname, 'payload-types.ts'),\r\n },\r\n });\r\n};\r\n\r\nexport async function getConfig(config: Partial<Config>, options?: TestConfigOptions): Promise<SanitizedConfig> {\r\n return await buildConfigWithMemoryDB(config, options);\r\n}\r\n","\r\nimport type { Config, Payload } from 'payload';\r\nimport { getPayload } from 'payload';\r\nimport { RestClient } from './client';\r\nimport { getConfig, type TestConfigOptions } from './config';\r\n\r\n/**\r\n * Local Payload API surface for integration suites that register collections\r\n * at runtime and therefore cannot use an application's generated schema.\r\n * It is an intersection with Payload, so it stays assignable to Payload.\r\n */\r\nexport type TestPayload = Payload & {\r\n create: (options: unknown) => Promise<any>;\r\n find: (options: unknown) => Promise<any>;\r\n findByID: (options: unknown) => Promise<any>;\r\n update: (options: unknown) => Promise<any>;\r\n};\r\n\r\nexport type TestContext = {\r\n payload: TestPayload;\r\n client: RestClient;\r\n}\r\n\r\nlet CONTEXT: TestContext | undefined = undefined;\r\n\r\nexport async function getContext(userConfig: Partial<Config>, options?: TestConfigOptions): Promise<TestContext> {\r\n if (CONTEXT) {\r\n return CONTEXT;\r\n }\r\n const config = await getConfig(userConfig, options);\r\n const payload = await getPayload({ config });\r\n const client = new RestClient(payload.config);\r\n const context: TestContext = {\r\n payload: payload as TestPayload,\r\n client,\r\n };\r\n CONTEXT = context;\r\n // onTestFinished(async () => await clearContext(context));\r\n return context;\r\n}\r\n\r\nexport async function clearContext(context?: TestContext) {\r\n /*\r\n if (context?.payload) {\r\n await context.payload.destroy();\r\n }\r\n */\r\n}\r\n\r\n/*\r\nexport default function setup(project: TestProject) {\r\n project.onTestsRerun(async () => {\r\n const context = await getContext();\r\n });\r\n}\r\n*/\r\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,11 @@
1
+ import "@testing-library/jest-dom/vitest";
2
+ import { cleanup } from "@testing-library/react";
3
+ import { afterEach } from "vitest";
4
+ //#region src/exports/vitest-setup-dom.ts
5
+ afterEach(() => {
6
+ cleanup();
7
+ });
8
+ //#endregion
9
+ export {};
10
+
11
+ //# sourceMappingURL=vitest-setup-dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest-setup-dom.js","names":[],"sources":["../../src/exports/vitest-setup-dom.ts"],"sourcesContent":["// vitest setup of `defineDomConfig`: `@testing-library/jest-dom` matchers and dom cleanup between tests\nimport '@testing-library/jest-dom/vitest';\nimport { cleanup } from '@testing-library/react';\nimport { afterEach } from 'vitest';\n\nafterEach(() => {\n cleanup();\n});\n"],"mappings":";;;;AAKA,gBAAgB;AACd,UAAS;EACT"}