@webiny/api-headless-cms-testing 6.6.0-alpha.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Webiny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @webiny/api-headless-cms-testing
2
+
3
+ > [!NOTE]
4
+ > This package is part of the [Webiny](https://www.webiny.com) monorepo.
5
+ > It’s **included in every Webiny project by default** and is not meant to be used as a standalone package.
6
+
7
+ πŸ“˜ **Documentation:** [https://www.webiny.com/docs](https://www.webiny.com/docs)
8
+
9
+ ---
10
+
11
+ _This README file is automatically generated during the publish process._
@@ -0,0 +1,64 @@
1
+ import type { Container } from "@webiny/di";
2
+ import type { IdentityData } from "@webiny/api-core/features/security/IdentityContext/index.js";
3
+ import type { SecurityPermission } from "@webiny/api-core/types/security.js";
4
+ import type { DecryptedWcpProjectLicense } from "@webiny/wcp/types.js";
5
+ export interface CmsTestHandlerParams {
6
+ /** Identity for the request. `undefined` β†’ a default admin; `null` β†’ anonymous. */
7
+ identity?: IdentityData | null;
8
+ permissions?: SecurityPermission[];
9
+ testProjectLicense?: DecryptedWcpProjectLicense;
10
+ /** CMS endpoint type to build. Defaults to "manage". */
11
+ cmsType?: "manage" | "read" | "preview";
12
+ /** Plugins forwarded to `HeadlessCmsFeature.register` as `extraPlugins` (e.g. CMS model plugins). */
13
+ extraCmsPlugins?: any[];
14
+ /**
15
+ * Legacy escape hatch (being retired β€” prefer `setup`). A mixed array, dispatched like the old
16
+ * `useContextHandler`:
17
+ * - RegisterExtensionPlugins are applied at register() time (DI registration);
18
+ * - static plugins (CmsModelPlugin, GraphQLSchemaPlugin, …) are forwarded to HeadlessCmsFeature
19
+ * as extraPlugins so their models reach the container before any initializer caches them;
20
+ * - plain `container => {}` functions run LAST (after `setup`), so they can override defaults.
21
+ */
22
+ legacyPlugins?: any;
23
+ /**
24
+ * Register the consuming package's own features here (e.g. AcoFeature, FileModel, plus its own
25
+ * getStorageOps presets via processLegacyPlugins). Runs in the request phase AFTER ApiCore + CMS
26
+ * storage + HeadlessCmsFeature, and BEFORE the GraphQL engine β€” i.e. before any initializer or
27
+ * resolver, the same window the real app handler uses.
28
+ */
29
+ setup?: (container: Container) => void | Promise<void>;
30
+ }
31
+ export interface InvokeParams {
32
+ httpMethod?: "POST";
33
+ type?: string;
34
+ body: {
35
+ query: string;
36
+ variables?: Record<string, any>;
37
+ };
38
+ headers?: Record<string, string>;
39
+ }
40
+ /**
41
+ * Shared integration test handler that wires the real CMS base (ApiCore + HeadlessCms + GraphQL
42
+ * engine + the CMS manage route) the same way the AWS app handler does β€” auth via Test
43
+ * authenticator/authorizer, root tenant seeded, storage via getStorageOps. Consuming packages add
44
+ * their own features through `params.setup` and build their SDKs on top of `invoke`/`invokeCms`,
45
+ * or grab the fully-initialized request context via `getContext()`.
46
+ */
47
+ export declare const createCmsTestHandler: (params?: CmsTestHandlerParams) => {
48
+ handler: (request: Partial<import("@webiny/event-handler-core/index.js").IHttpRequest> & {
49
+ method: string;
50
+ path: string;
51
+ }) => Promise<import("@webiny/event-handler-core/index.js").IHttpResponse>;
52
+ invoke: ({ httpMethod, body, headers }: InvokeParams) => Promise<readonly [any, import("@webiny/event-handler-core/index.js").IHttpResponse]>;
53
+ invokeCms: ({ httpMethod, type, body, headers }: InvokeParams) => Promise<readonly [any, import("@webiny/event-handler-core/index.js").IHttpResponse]>;
54
+ getContext: <C extends Record<string, any> = Record<string, any>>() => Promise<C>;
55
+ createQuery: <T extends Record<string, any> = Record<string, any>>(query: string) => (variables?: Record<string, any>, headers?: Record<string, string>) => Promise<readonly [T, any]>;
56
+ createMutation: <T extends Record<string, any> = Record<string, any>>(mutation: string) => (variables?: Record<string, any>, headers?: Record<string, string>) => Promise<readonly [T, any]>;
57
+ introspect: () => Promise<readonly [any, import("@webiny/event-handler-core/index.js").IHttpResponse]>;
58
+ identity: IdentityData | null;
59
+ tenant: {
60
+ id: string;
61
+ name: string;
62
+ parent: null;
63
+ };
64
+ };
@@ -0,0 +1,165 @@
1
+ import { createTestHttpHandler } from "@webiny/event-handler-core/features/testing";
2
+ import { ApiCoreFeature, registerApiCoreStorageOperations } from "@webiny/api-core";
3
+ import { GraphQLContextualSchema, GraphQLEngineFeature } from "@webiny/api-graphql";
4
+ import { loadWcpLicense } from "@webiny/api-core/features/wcp/loadWcpLicense.js";
5
+ import { getStorageOps } from "@webiny/project-utils/testing/environment/index.js";
6
+ import { createTestWcpLicense } from "@webiny/wcp/testing/createTestWcpLicense.js";
7
+ import { buildSchema, getIntrospectionQuery } from "graphql";
8
+ import { HeadlessCmsFeature } from "@webiny/api-headless-cms/HeadlessCmsFeature.js";
9
+ import { AuthTriggerHandler, RootTenantInitializer, TestAuthenticator, TestAuthorizer, TestIdentity, TestPermissions } from "@webiny/api-core-testing";
10
+ import { processLegacyPlugins } from "./processLegacyPlugins.js";
11
+ const DEFAULT_IDENTITY = {
12
+ id: "id-12345678",
13
+ type: "admin",
14
+ displayName: "John Doe"
15
+ };
16
+ const STUB_SCHEMA = buildSchema("type Query { _empty: String }");
17
+ const createCmsTestHandler = (params = {})=>{
18
+ const apiCoreStorage = getStorageOps("apiCore");
19
+ const cmsStorage = getStorageOps("cms");
20
+ const identity = void 0 === params.identity ? DEFAULT_IDENTITY : params.identity;
21
+ const permissions = void 0 === params.permissions ? [
22
+ {
23
+ name: "*"
24
+ }
25
+ ] : params.permissions;
26
+ const cmsType = params.cmsType ?? "manage";
27
+ const setupRoot = (container)=>{
28
+ container.registerInstance(TestIdentity, identity);
29
+ container.registerInstance(TestPermissions, {
30
+ list: permissions
31
+ });
32
+ container.register(TestAuthenticator);
33
+ container.register(TestAuthorizer);
34
+ container.registerDecorator(AuthTriggerHandler);
35
+ container.registerDecorator(RootTenantInitializer);
36
+ };
37
+ const setupRequest = async (container)=>{
38
+ const wcpLicense = await loadWcpLicense(params.testProjectLicense ?? createTestWcpLicense());
39
+ registerApiCoreStorageOperations(container, apiCoreStorage.storageOperations);
40
+ ApiCoreFeature.register(container, {
41
+ wcpLicense
42
+ });
43
+ processLegacyPlugins(container, cmsStorage.plugins);
44
+ const legacyItems = [
45
+ params.legacyPlugins
46
+ ].flat(1 / 0).filter(Boolean);
47
+ const isFn = (p)=>"function" == typeof p && !p.prototype;
48
+ const legacyObjects = legacyItems.filter((p)=>!isFn(p));
49
+ processLegacyPlugins(container, legacyObjects);
50
+ const staticPlugins = legacyObjects.filter((p)=>"function" != typeof p.apply && "function" != typeof p);
51
+ HeadlessCmsFeature.register(container, {
52
+ type: cmsType,
53
+ extraPlugins: [
54
+ ...params.extraCmsPlugins ?? [],
55
+ ...staticPlugins
56
+ ]
57
+ });
58
+ await params.setup?.(container);
59
+ for (const plugin of legacyItems.filter(isFn))plugin(container);
60
+ };
61
+ const handler = createTestHttpHandler({
62
+ root: setupRoot,
63
+ request: async (container)=>{
64
+ await setupRequest(container);
65
+ GraphQLEngineFeature.register(container);
66
+ }
67
+ });
68
+ const invoke = async ({ httpMethod = "POST", body, headers = {} })=>{
69
+ const response = await handler({
70
+ method: httpMethod,
71
+ path: "/graphql",
72
+ headers: {
73
+ "x-tenant": "root",
74
+ "content-type": "application/json",
75
+ ...headers
76
+ },
77
+ body
78
+ });
79
+ return [
80
+ response.body,
81
+ response
82
+ ];
83
+ };
84
+ const invokeCms = async ({ httpMethod = "POST", type = "manage", body, headers = {} })=>{
85
+ const response = await handler({
86
+ method: httpMethod,
87
+ path: `/cms/${type}`,
88
+ headers: {
89
+ "x-tenant": "root",
90
+ "content-type": "application/json",
91
+ ...headers
92
+ },
93
+ body
94
+ });
95
+ return [
96
+ response.body,
97
+ response
98
+ ];
99
+ };
100
+ const getContext = async ()=>{
101
+ const captured = {};
102
+ const ctxHandler = createTestHttpHandler({
103
+ root: setupRoot,
104
+ request: async (container)=>{
105
+ await setupRequest(container);
106
+ container.registerInstance(GraphQLContextualSchema, {
107
+ async build (ctx) {
108
+ captured.value = ctx;
109
+ return STUB_SCHEMA;
110
+ }
111
+ });
112
+ GraphQLEngineFeature.register(container);
113
+ }
114
+ });
115
+ await ctxHandler({
116
+ method: "POST",
117
+ path: "/graphql",
118
+ headers: {
119
+ "x-tenant": "root",
120
+ "content-type": "application/json"
121
+ },
122
+ body: {
123
+ query: "{ __typename }"
124
+ }
125
+ });
126
+ return captured.value;
127
+ };
128
+ const createQuery = (query)=>(variables, headers = {})=>invoke({
129
+ body: {
130
+ query,
131
+ variables: variables || void 0
132
+ },
133
+ headers
134
+ });
135
+ const createMutation = (mutation)=>(variables, headers = {})=>invoke({
136
+ body: {
137
+ query: mutation,
138
+ variables: variables || void 0
139
+ },
140
+ headers
141
+ });
142
+ const introspect = ()=>invoke({
143
+ body: {
144
+ query: getIntrospectionQuery()
145
+ }
146
+ });
147
+ return {
148
+ handler,
149
+ invoke,
150
+ invokeCms,
151
+ getContext,
152
+ createQuery,
153
+ createMutation,
154
+ introspect,
155
+ identity,
156
+ tenant: {
157
+ id: "root",
158
+ name: "Root",
159
+ parent: null
160
+ }
161
+ };
162
+ };
163
+ export { createCmsTestHandler };
164
+
165
+ //# sourceMappingURL=createCmsTestHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createCmsTestHandler.js","sources":["../src/createCmsTestHandler.ts"],"sourcesContent":["import { createTestHttpHandler } from \"@webiny/event-handler-core/features/testing\";\nimport type { Container } from \"@webiny/di\";\nimport { ApiCoreFeature, registerApiCoreStorageOperations } from \"@webiny/api-core\";\nimport { GraphQLEngineFeature, GraphQLContextualSchema } from \"@webiny/api-graphql\";\nimport { loadWcpLicense } from \"@webiny/api-core/features/wcp/loadWcpLicense.js\";\nimport { getStorageOps } from \"@webiny/project-utils/testing/environment/index.js\";\nimport { createTestWcpLicense } from \"@webiny/wcp/testing/createTestWcpLicense.js\";\nimport { buildSchema, getIntrospectionQuery } from \"graphql\";\nimport type { GraphQLSchema } from \"graphql\";\nimport type { ApiCoreStorageOperations } from \"@webiny/api-core/types/core.js\";\nimport type { IdentityData } from \"@webiny/api-core/features/security/IdentityContext/index.js\";\nimport type { SecurityPermission } from \"@webiny/api-core/types/security.js\";\nimport type { DecryptedWcpProjectLicense } from \"@webiny/wcp/types.js\";\nimport { HeadlessCmsFeature } from \"@webiny/api-headless-cms/HeadlessCmsFeature.js\";\nimport { TestIdentity, TestAuthenticator } from \"@webiny/api-core-testing\";\nimport { TestPermissions, TestAuthorizer } from \"@webiny/api-core-testing\";\nimport { AuthTriggerHandler } from \"@webiny/api-core-testing\";\nimport { RootTenantInitializer } from \"@webiny/api-core-testing\";\nimport { processLegacyPlugins } from \"./processLegacyPlugins.js\";\n\nconst DEFAULT_IDENTITY: IdentityData = {\n id: \"id-12345678\",\n type: \"admin\",\n displayName: \"John Doe\"\n};\n\nconst STUB_SCHEMA: GraphQLSchema = buildSchema(\"type Query { _empty: String }\");\n\nexport interface CmsTestHandlerParams {\n /** Identity for the request. `undefined` β†’ a default admin; `null` β†’ anonymous. */\n identity?: IdentityData | null;\n permissions?: SecurityPermission[];\n testProjectLicense?: DecryptedWcpProjectLicense;\n /** CMS endpoint type to build. Defaults to \"manage\". */\n cmsType?: \"manage\" | \"read\" | \"preview\";\n /** Plugins forwarded to `HeadlessCmsFeature.register` as `extraPlugins` (e.g. CMS model plugins). */\n extraCmsPlugins?: any[];\n /**\n * Legacy escape hatch (being retired β€” prefer `setup`). A mixed array, dispatched like the old\n * `useContextHandler`:\n * - RegisterExtensionPlugins are applied at register() time (DI registration);\n * - static plugins (CmsModelPlugin, GraphQLSchemaPlugin, …) are forwarded to HeadlessCmsFeature\n * as extraPlugins so their models reach the container before any initializer caches them;\n * - plain `container => {}` functions run LAST (after `setup`), so they can override defaults.\n */\n legacyPlugins?: any;\n /**\n * Register the consuming package's own features here (e.g. AcoFeature, FileModel, plus its own\n * getStorageOps presets via processLegacyPlugins). Runs in the request phase AFTER ApiCore + CMS\n * storage + HeadlessCmsFeature, and BEFORE the GraphQL engine β€” i.e. before any initializer or\n * resolver, the same window the real app handler uses.\n */\n setup?: (container: Container) => void | Promise<void>;\n}\n\nexport interface InvokeParams {\n httpMethod?: \"POST\";\n type?: string;\n body: { query: string; variables?: Record<string, any> };\n headers?: Record<string, string>;\n}\n\n/**\n * Shared integration test handler that wires the real CMS base (ApiCore + HeadlessCms + GraphQL\n * engine + the CMS manage route) the same way the AWS app handler does β€” auth via Test\n * authenticator/authorizer, root tenant seeded, storage via getStorageOps. Consuming packages add\n * their own features through `params.setup` and build their SDKs on top of `invoke`/`invokeCms`,\n * or grab the fully-initialized request context via `getContext()`.\n */\nexport const createCmsTestHandler = (params: CmsTestHandlerParams = {}) => {\n const apiCoreStorage = getStorageOps<ApiCoreStorageOperations>(\"apiCore\");\n const cmsStorage = getStorageOps(\"cms\");\n\n const identity = params.identity === undefined ? DEFAULT_IDENTITY : params.identity;\n const permissions = params.permissions === undefined ? [{ name: \"*\" }] : params.permissions;\n const cmsType = params.cmsType ?? \"manage\";\n\n const setupRoot = (container: Container) => {\n container.registerInstance(TestIdentity, identity);\n container.registerInstance(TestPermissions, { list: permissions });\n container.register(TestAuthenticator);\n container.register(TestAuthorizer);\n container.registerDecorator(AuthTriggerHandler);\n container.registerDecorator(RootTenantInitializer);\n };\n\n // Everything up to (but not including) the GraphQL engine β€” shared by the HTTP handler and the\n // context-capture handler.\n const setupRequest = async (container: Container) => {\n const wcpLicense = await loadWcpLicense(\n params.testProjectLicense ?? createTestWcpLicense()\n );\n\n registerApiCoreStorageOperations(container, apiCoreStorage.storageOperations);\n ApiCoreFeature.register(container, { wcpLicense });\n\n // CMS storage preset. All storage presets are RegisterExtensionPlugins (registerDynamoDBCore,\n // registerCmsOpenSearchStorageOperations, dbPlugins, ...); processLegacyPlugins runs them at\n // register() time β€” before HeadlessCmsFeature builds storage, mirroring the real app's\n // registerExtensions.\n processLegacyPlugins(container, cmsStorage.plugins);\n\n // `legacyPlugins` is a mixed bag: plain `container => {}` functions (called last, after\n // `setup`) plus legacy plugin objects β€” RegisterExtensionPlugins (register-time) or static\n // Plugins (extraPlugins).\n const legacyItems = [params.legacyPlugins].flat(Infinity as 1).filter(Boolean);\n const isFn = (p: any) => typeof p === \"function\" && !p.prototype;\n\n const legacyObjects = legacyItems.filter(p => !isFn(p));\n processLegacyPlugins(container, legacyObjects);\n const staticPlugins = legacyObjects.filter(\n p => typeof (p as any).apply !== \"function\" && typeof p !== \"function\"\n );\n HeadlessCmsFeature.register(container, {\n type: cmsType,\n extraPlugins: [...(params.extraCmsPlugins ?? []), ...staticPlugins]\n });\n\n await params.setup?.(container);\n\n // Function plugins in `legacyPlugins` run LAST β€” after the consuming package's own `setup` β€”\n // so they can override defaults it registered (last-wins).\n for (const plugin of legacyItems.filter(isFn)) {\n (plugin as (container: any) => void)(container);\n }\n };\n\n const handler = createTestHttpHandler({\n root: setupRoot,\n request: async container => {\n await setupRequest(container);\n GraphQLEngineFeature.register(container);\n }\n });\n\n const invoke = async ({ httpMethod = \"POST\", body, headers = {} }: InvokeParams) => {\n const response = await handler({\n method: httpMethod,\n path: \"/graphql\",\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\", ...headers },\n body\n });\n return [response.body, response] as const;\n };\n\n const invokeCms = async ({\n httpMethod = \"POST\",\n type = \"manage\",\n body,\n headers = {}\n }: InvokeParams) => {\n const response = await handler({\n method: httpMethod,\n path: `/cms/${type}`,\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\", ...headers },\n body\n });\n return [response.body, response] as const;\n };\n\n /**\n * Build the request once and return the fully-initialized context (after auth, tenant, CMS and\n * all consumer features). Uses the same GraphQLContextualSchema.build(ctx) capture trick the\n * legacy `useContextHandler` does β€” for tests that resolve services directly off the context\n * rather than issuing GraphQL queries.\n */\n const getContext = async <\n C extends Record<string, any> = Record<string, any>\n >(): Promise<C> => {\n const captured: { value?: Record<string, any> } = {};\n\n const ctxHandler = createTestHttpHandler({\n root: setupRoot,\n request: async container => {\n await setupRequest(container);\n container.registerInstance(GraphQLContextualSchema, {\n async build(ctx: Record<string, any>): Promise<GraphQLSchema> {\n captured.value = ctx;\n return STUB_SCHEMA;\n }\n });\n GraphQLEngineFeature.register(container);\n }\n });\n\n await ctxHandler({\n method: \"POST\",\n path: \"/graphql\",\n headers: { \"x-tenant\": \"root\", \"content-type\": \"application/json\" },\n body: { query: \"{ __typename }\" }\n });\n\n return captured.value as C;\n };\n\n // Convenience wrappers mirroring the retired `useGraphQLHandler` β€” thin builders over `invoke`\n // (the main `/graphql` endpoint) so consumers can issue typed queries/mutations directly.\n const createQuery = <T extends Record<string, any> = Record<string, any>>(query: string) => {\n return (variables?: Record<string, any>, headers: Record<string, string> = {}) =>\n invoke({ body: { query, variables: variables || undefined }, headers }) as Promise<\n readonly [T, any]\n >;\n };\n\n const createMutation = <T extends Record<string, any> = Record<string, any>>(\n mutation: string\n ) => {\n return (variables?: Record<string, any>, headers: Record<string, string> = {}) =>\n invoke({\n body: { query: mutation, variables: variables || undefined },\n headers\n }) as Promise<readonly [T, any]>;\n };\n\n const introspect = () => invoke({ body: { query: getIntrospectionQuery() } });\n\n return {\n handler,\n invoke,\n invokeCms,\n getContext,\n createQuery,\n createMutation,\n introspect,\n identity,\n tenant: { id: \"root\", name: \"Root\", parent: null }\n };\n};\n"],"names":["DEFAULT_IDENTITY","STUB_SCHEMA","buildSchema","createCmsTestHandler","params","apiCoreStorage","getStorageOps","cmsStorage","identity","undefined","permissions","cmsType","setupRoot","container","TestIdentity","TestPermissions","TestAuthenticator","TestAuthorizer","AuthTriggerHandler","RootTenantInitializer","setupRequest","wcpLicense","loadWcpLicense","createTestWcpLicense","registerApiCoreStorageOperations","ApiCoreFeature","processLegacyPlugins","legacyItems","Infinity","Boolean","isFn","p","legacyObjects","staticPlugins","HeadlessCmsFeature","plugin","handler","createTestHttpHandler","GraphQLEngineFeature","invoke","httpMethod","body","headers","response","invokeCms","type","getContext","captured","ctxHandler","GraphQLContextualSchema","ctx","createQuery","query","variables","createMutation","mutation","introspect","getIntrospectionQuery"],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export { createCmsTestHandler } from "./createCmsTestHandler.js";
2
+ export type { CmsTestHandlerParams, InvokeParams } from "./createCmsTestHandler.js";
3
+ export { processLegacyPlugins } from "./processLegacyPlugins.js";
4
+ export { TestIdentity, TestAuthenticator } from "@webiny/api-core-testing";
5
+ export { TestPermissions, TestAuthorizer } from "@webiny/api-core-testing";
6
+ export { AuthTriggerHandler } from "@webiny/api-core-testing";
7
+ export { RootTenantInitializer } from "@webiny/api-core-testing";
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { createCmsTestHandler } from "./createCmsTestHandler.js";
2
+ export { processLegacyPlugins } from "./processLegacyPlugins.js";
3
+ export { AuthTriggerHandler, RootTenantInitializer, TestAuthenticator, TestAuthorizer, TestIdentity, TestPermissions } from "@webiny/api-core-testing";
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@webiny/api-headless-cms-testing",
3
+ "version": "6.6.0-alpha.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": "./index.js",
7
+ "./*": "./*"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/webiny/webiny-js.git",
12
+ "directory": "packages/api-headless-cms-testing"
13
+ },
14
+ "description": "Shared Headless CMS integration test handler (createCmsTestHandler) for Webiny API packages.",
15
+ "author": "Webiny Ltd.",
16
+ "license": "MIT",
17
+ "dependencies": {
18
+ "@webiny/api-core": "6.6.0-alpha.0",
19
+ "@webiny/api-core-testing": "6.6.0-alpha.0",
20
+ "@webiny/api-graphql": "6.6.0-alpha.0",
21
+ "@webiny/api-headless-cms": "6.6.0-alpha.0",
22
+ "@webiny/di": "1.0.2",
23
+ "@webiny/event-handler-core": "6.6.0-alpha.0",
24
+ "@webiny/project-utils": "6.6.0-alpha.0",
25
+ "@webiny/wcp": "6.6.0-alpha.0",
26
+ "graphql": "16.14.2"
27
+ },
28
+ "devDependencies": {
29
+ "@webiny/build-tools": "6.6.0-alpha.0",
30
+ "rimraf": "6.1.3",
31
+ "typescript": "7.0.2"
32
+ },
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "webiny": {
37
+ "publishFrom": "dist"
38
+ }
39
+ }
@@ -0,0 +1,12 @@
1
+ import type { Container } from "@webiny/di";
2
+ /**
3
+ * Apply legacy RegisterExtensionPlugins (e.g. the storage-operations presets returned by
4
+ * getStorageOps(...).plugins) against the request container β€” the test-time equivalent of how the
5
+ * app registers them.
6
+ *
7
+ * Detection is by `plugin.type` rather than `instanceof RegisterExtensionPlugin`: a consumer's
8
+ * dependency tree can resolve a second copy of `@webiny/handler`, giving the storage-preset plugins
9
+ * a different class identity than the one this (shipped) module imports, which would make an
10
+ * `instanceof` check silently miss them.
11
+ */
12
+ export declare function processLegacyPlugins(container: Container, plugins: any[]): void;
@@ -0,0 +1,12 @@
1
+ const REGISTER_EXTENSION_TYPE = "handler.register.extension";
2
+ function processLegacyPlugins(container, plugins) {
3
+ const flat = [
4
+ plugins
5
+ ].flat(1 / 0);
6
+ for (const plugin of flat)if (plugin && plugin.type === REGISTER_EXTENSION_TYPE && "function" == typeof plugin.apply) plugin.apply({
7
+ container
8
+ });
9
+ }
10
+ export { processLegacyPlugins };
11
+
12
+ //# sourceMappingURL=processLegacyPlugins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processLegacyPlugins.js","sources":["../src/processLegacyPlugins.ts"],"sourcesContent":["import type { Container } from \"@webiny/di\";\n\nconst REGISTER_EXTENSION_TYPE = \"handler.register.extension\";\n\n/**\n * Apply legacy RegisterExtensionPlugins (e.g. the storage-operations presets returned by\n * getStorageOps(...).plugins) against the request container β€” the test-time equivalent of how the\n * app registers them.\n *\n * Detection is by `plugin.type` rather than `instanceof RegisterExtensionPlugin`: a consumer's\n * dependency tree can resolve a second copy of `@webiny/handler`, giving the storage-preset plugins\n * a different class identity than the one this (shipped) module imports, which would make an\n * `instanceof` check silently miss them.\n */\nexport function processLegacyPlugins(container: Container, plugins: any[]): void {\n const flat = [plugins].flat(Infinity as 1);\n for (const plugin of flat) {\n if (\n plugin &&\n plugin.type === REGISTER_EXTENSION_TYPE &&\n typeof plugin.apply === \"function\"\n ) {\n plugin.apply({ container } as any);\n }\n }\n}\n"],"names":["REGISTER_EXTENSION_TYPE","processLegacyPlugins","container","plugins","flat","Infinity","plugin"],"mappings":"AAEA,MAAMA,0BAA0B;AAYzB,SAASC,qBAAqBC,SAAoB,EAAEC,OAAc;IACrE,MAAMC,OAAO;QAACD;KAAQ,CAAC,IAAI,CAACE;IAC5B,KAAK,MAAMC,UAAUF,KACjB,IACIE,UACAA,OAAO,IAAI,KAAKN,2BAChB,AAAwB,cAAxB,OAAOM,OAAO,KAAK,EAEnBA,OAAO,KAAK,CAAC;QAAEJ;IAAU;AAGrC"}