convex-cms 0.0.1
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/dist/cli/commands/admin.d.ts +16 -0
- package/dist/cli/commands/admin.d.ts.map +1 -0
- package/dist/cli/commands/admin.js +88 -0
- package/dist/cli/commands/admin.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/detectConvexUrl.d.ts +13 -0
- package/dist/cli/utils/detectConvexUrl.d.ts.map +1 -0
- package/dist/cli/utils/detectConvexUrl.js +48 -0
- package/dist/cli/utils/detectConvexUrl.js.map +1 -0
- package/dist/cli/utils/openBrowser.d.ts +7 -0
- package/dist/cli/utils/openBrowser.d.ts.map +1 -0
- package/dist/cli/utils/openBrowser.js +17 -0
- package/dist/cli/utils/openBrowser.js.map +1 -0
- package/dist/client/admin-config.d.ts +126 -0
- package/dist/client/admin-config.d.ts.map +1 -0
- package/dist/client/admin-config.js +117 -0
- package/dist/client/admin-config.js.map +1 -0
- package/dist/client/adminApi.d.ts +2273 -0
- package/dist/client/adminApi.d.ts.map +1 -0
- package/dist/client/adminApi.js +716 -0
- package/dist/client/adminApi.js.map +1 -0
- package/dist/client/agentTools.d.ts +933 -0
- package/dist/client/agentTools.d.ts.map +1 -0
- package/dist/client/agentTools.js +1004 -0
- package/dist/client/agentTools.js.map +1 -0
- package/dist/client/argTypes.d.ts +212 -0
- package/dist/client/argTypes.d.ts.map +1 -0
- package/dist/client/argTypes.js +5 -0
- package/dist/client/argTypes.js.map +1 -0
- package/dist/client/field-types.d.ts +55 -0
- package/dist/client/field-types.d.ts.map +1 -0
- package/dist/client/field-types.js +152 -0
- package/dist/client/field-types.js.map +1 -0
- package/dist/client/index.d.ts +189 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +668 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/queryBuilder.d.ts +765 -0
- package/dist/client/queryBuilder.d.ts.map +1 -0
- package/dist/client/queryBuilder.js +970 -0
- package/dist/client/queryBuilder.js.map +1 -0
- package/dist/client/schema/codegen.d.ts +128 -0
- package/dist/client/schema/codegen.d.ts.map +1 -0
- package/dist/client/schema/codegen.js +318 -0
- package/dist/client/schema/codegen.js.map +1 -0
- package/dist/client/schema/defineContentType.d.ts +221 -0
- package/dist/client/schema/defineContentType.d.ts.map +1 -0
- package/dist/client/schema/defineContentType.js +380 -0
- package/dist/client/schema/defineContentType.js.map +1 -0
- package/dist/client/schema/index.d.ts +85 -0
- package/dist/client/schema/index.d.ts.map +1 -0
- package/dist/client/schema/index.js +92 -0
- package/dist/client/schema/index.js.map +1 -0
- package/dist/client/schema/schemaDrift.d.ts +199 -0
- package/dist/client/schema/schemaDrift.d.ts.map +1 -0
- package/dist/client/schema/schemaDrift.js +340 -0
- package/dist/client/schema/schemaDrift.js.map +1 -0
- package/dist/client/schema/typedClient.d.ts +401 -0
- package/dist/client/schema/typedClient.d.ts.map +1 -0
- package/dist/client/schema/typedClient.js +269 -0
- package/dist/client/schema/typedClient.js.map +1 -0
- package/dist/client/schema/types.d.ts +477 -0
- package/dist/client/schema/types.d.ts.map +1 -0
- package/dist/client/schema/types.js +39 -0
- package/dist/client/schema/types.js.map +1 -0
- package/dist/client/types.d.ts +449 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +149 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/workflows.d.ts +51 -0
- package/dist/client/workflows.d.ts.map +1 -0
- package/dist/client/workflows.js +103 -0
- package/dist/client/workflows.js.map +1 -0
- package/dist/client/wrapper.d.ts +2198 -0
- package/dist/client/wrapper.d.ts.map +1 -0
- package/dist/client/wrapper.js +2651 -0
- package/dist/client/wrapper.js.map +1 -0
- package/dist/component/_generated/api.d.ts +124 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +4321 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/auditLog.d.ts +410 -0
- package/dist/component/auditLog.d.ts.map +1 -0
- package/dist/component/auditLog.js +607 -0
- package/dist/component/auditLog.js.map +1 -0
- package/dist/component/authorization.d.ts +323 -0
- package/dist/component/authorization.d.ts.map +1 -0
- package/dist/component/authorization.js +464 -0
- package/dist/component/authorization.js.map +1 -0
- package/dist/component/authorizationHooks.d.ts +184 -0
- package/dist/component/authorizationHooks.d.ts.map +1 -0
- package/dist/component/authorizationHooks.js +521 -0
- package/dist/component/authorizationHooks.js.map +1 -0
- package/dist/component/bulkOperations.d.ts +200 -0
- package/dist/component/bulkOperations.d.ts.map +1 -0
- package/dist/component/bulkOperations.js +568 -0
- package/dist/component/bulkOperations.js.map +1 -0
- package/dist/component/contentEntries.d.ts +719 -0
- package/dist/component/contentEntries.d.ts.map +1 -0
- package/dist/component/contentEntries.js +1617 -0
- package/dist/component/contentEntries.js.map +1 -0
- package/dist/component/contentEntryMutations.d.ts +505 -0
- package/dist/component/contentEntryMutations.d.ts.map +1 -0
- package/dist/component/contentEntryMutations.js +1009 -0
- package/dist/component/contentEntryMutations.js.map +1 -0
- package/dist/component/contentEntryValidation.d.ts +115 -0
- package/dist/component/contentEntryValidation.d.ts.map +1 -0
- package/dist/component/contentEntryValidation.js +546 -0
- package/dist/component/contentEntryValidation.js.map +1 -0
- package/dist/component/contentLock.d.ts +328 -0
- package/dist/component/contentLock.d.ts.map +1 -0
- package/dist/component/contentLock.js +471 -0
- package/dist/component/contentLock.js.map +1 -0
- package/dist/component/contentTypeMigration.d.ts +411 -0
- package/dist/component/contentTypeMigration.d.ts.map +1 -0
- package/dist/component/contentTypeMigration.js +805 -0
- package/dist/component/contentTypeMigration.js.map +1 -0
- package/dist/component/contentTypeMutations.d.ts +975 -0
- package/dist/component/contentTypeMutations.d.ts.map +1 -0
- package/dist/component/contentTypeMutations.js +768 -0
- package/dist/component/contentTypeMutations.js.map +1 -0
- package/dist/component/contentTypes.d.ts +538 -0
- package/dist/component/contentTypes.d.ts.map +1 -0
- package/dist/component/contentTypes.js +304 -0
- package/dist/component/contentTypes.js.map +1 -0
- package/dist/component/convex.config.d.ts +42 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +43 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/documentTypes.d.ts +186 -0
- package/dist/component/documentTypes.d.ts.map +1 -0
- package/dist/component/documentTypes.js +23 -0
- package/dist/component/documentTypes.js.map +1 -0
- package/dist/component/eventEmitter.d.ts +281 -0
- package/dist/component/eventEmitter.d.ts.map +1 -0
- package/dist/component/eventEmitter.js +300 -0
- package/dist/component/eventEmitter.js.map +1 -0
- package/dist/component/exportImport.d.ts +1120 -0
- package/dist/component/exportImport.d.ts.map +1 -0
- package/dist/component/exportImport.js +931 -0
- package/dist/component/exportImport.js.map +1 -0
- package/dist/component/index.d.ts +28 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +142 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/lib/deepReferenceResolver.d.ts +252 -0
- package/dist/component/lib/deepReferenceResolver.d.ts.map +1 -0
- package/dist/component/lib/deepReferenceResolver.js +601 -0
- package/dist/component/lib/deepReferenceResolver.js.map +1 -0
- package/dist/component/lib/errors.d.ts +306 -0
- package/dist/component/lib/errors.d.ts.map +1 -0
- package/dist/component/lib/errors.js +407 -0
- package/dist/component/lib/errors.js.map +1 -0
- package/dist/component/lib/index.d.ts +10 -0
- package/dist/component/lib/index.d.ts.map +1 -0
- package/dist/component/lib/index.js +33 -0
- package/dist/component/lib/index.js.map +1 -0
- package/dist/component/lib/mediaReferenceResolver.d.ts +217 -0
- package/dist/component/lib/mediaReferenceResolver.d.ts.map +1 -0
- package/dist/component/lib/mediaReferenceResolver.js +326 -0
- package/dist/component/lib/mediaReferenceResolver.js.map +1 -0
- package/dist/component/lib/metadataExtractor.d.ts +245 -0
- package/dist/component/lib/metadataExtractor.d.ts.map +1 -0
- package/dist/component/lib/metadataExtractor.js +548 -0
- package/dist/component/lib/metadataExtractor.js.map +1 -0
- package/dist/component/lib/mutationAuth.d.ts +95 -0
- package/dist/component/lib/mutationAuth.d.ts.map +1 -0
- package/dist/component/lib/mutationAuth.js +146 -0
- package/dist/component/lib/mutationAuth.js.map +1 -0
- package/dist/component/lib/queries.d.ts +17 -0
- package/dist/component/lib/queries.d.ts.map +1 -0
- package/dist/component/lib/queries.js +49 -0
- package/dist/component/lib/queries.js.map +1 -0
- package/dist/component/lib/ragContentChunker.d.ts +423 -0
- package/dist/component/lib/ragContentChunker.d.ts.map +1 -0
- package/dist/component/lib/ragContentChunker.js +897 -0
- package/dist/component/lib/ragContentChunker.js.map +1 -0
- package/dist/component/lib/referenceResolver.d.ts +175 -0
- package/dist/component/lib/referenceResolver.d.ts.map +1 -0
- package/dist/component/lib/referenceResolver.js +293 -0
- package/dist/component/lib/referenceResolver.js.map +1 -0
- package/dist/component/lib/slugGenerator.d.ts +71 -0
- package/dist/component/lib/slugGenerator.d.ts.map +1 -0
- package/dist/component/lib/slugGenerator.js +207 -0
- package/dist/component/lib/slugGenerator.js.map +1 -0
- package/dist/component/lib/slugUniqueness.d.ts +131 -0
- package/dist/component/lib/slugUniqueness.d.ts.map +1 -0
- package/dist/component/lib/slugUniqueness.js +229 -0
- package/dist/component/lib/slugUniqueness.js.map +1 -0
- package/dist/component/lib/softDelete.d.ts +18 -0
- package/dist/component/lib/softDelete.d.ts.map +1 -0
- package/dist/component/lib/softDelete.js +29 -0
- package/dist/component/lib/softDelete.js.map +1 -0
- package/dist/component/localeFallbackChain.d.ts +410 -0
- package/dist/component/localeFallbackChain.d.ts.map +1 -0
- package/dist/component/localeFallbackChain.js +467 -0
- package/dist/component/localeFallbackChain.js.map +1 -0
- package/dist/component/localeFields.d.ts +508 -0
- package/dist/component/localeFields.d.ts.map +1 -0
- package/dist/component/localeFields.js +592 -0
- package/dist/component/localeFields.js.map +1 -0
- package/dist/component/mediaAssetMutations.d.ts +235 -0
- package/dist/component/mediaAssetMutations.d.ts.map +1 -0
- package/dist/component/mediaAssetMutations.js +558 -0
- package/dist/component/mediaAssetMutations.js.map +1 -0
- package/dist/component/mediaAssets.d.ts +168 -0
- package/dist/component/mediaAssets.d.ts.map +1 -0
- package/dist/component/mediaAssets.js +618 -0
- package/dist/component/mediaAssets.js.map +1 -0
- package/dist/component/mediaFolderMutations.d.ts +642 -0
- package/dist/component/mediaFolderMutations.d.ts.map +1 -0
- package/dist/component/mediaFolderMutations.js +849 -0
- package/dist/component/mediaFolderMutations.js.map +1 -0
- package/dist/component/mediaUploadMutations.d.ts +136 -0
- package/dist/component/mediaUploadMutations.d.ts.map +1 -0
- package/dist/component/mediaUploadMutations.js +205 -0
- package/dist/component/mediaUploadMutations.js.map +1 -0
- package/dist/component/mediaVariantMutations.d.ts +468 -0
- package/dist/component/mediaVariantMutations.d.ts.map +1 -0
- package/dist/component/mediaVariantMutations.js +737 -0
- package/dist/component/mediaVariantMutations.js.map +1 -0
- package/dist/component/mediaVariants.d.ts +525 -0
- package/dist/component/mediaVariants.d.ts.map +1 -0
- package/dist/component/mediaVariants.js +661 -0
- package/dist/component/mediaVariants.js.map +1 -0
- package/dist/component/ragContentIndexer.d.ts +595 -0
- package/dist/component/ragContentIndexer.d.ts.map +1 -0
- package/dist/component/ragContentIndexer.js +794 -0
- package/dist/component/ragContentIndexer.js.map +1 -0
- package/dist/component/rateLimitHooks.d.ts +266 -0
- package/dist/component/rateLimitHooks.d.ts.map +1 -0
- package/dist/component/rateLimitHooks.js +412 -0
- package/dist/component/rateLimitHooks.js.map +1 -0
- package/dist/component/roles.d.ts +649 -0
- package/dist/component/roles.d.ts.map +1 -0
- package/dist/component/roles.js +884 -0
- package/dist/component/roles.js.map +1 -0
- package/dist/component/scheduledPublish.d.ts +182 -0
- package/dist/component/scheduledPublish.d.ts.map +1 -0
- package/dist/component/scheduledPublish.js +304 -0
- package/dist/component/scheduledPublish.js.map +1 -0
- package/dist/component/schema.d.ts +4114 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +469 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/component/taxonomies.d.ts +476 -0
- package/dist/component/taxonomies.d.ts.map +1 -0
- package/dist/component/taxonomies.js +785 -0
- package/dist/component/taxonomies.js.map +1 -0
- package/dist/component/taxonomyMutations.d.ts +206 -0
- package/dist/component/taxonomyMutations.d.ts.map +1 -0
- package/dist/component/taxonomyMutations.js +1001 -0
- package/dist/component/taxonomyMutations.js.map +1 -0
- package/dist/component/trash.d.ts +265 -0
- package/dist/component/trash.d.ts.map +1 -0
- package/dist/component/trash.js +621 -0
- package/dist/component/trash.js.map +1 -0
- package/dist/component/types.d.ts +4 -0
- package/dist/component/types.d.ts.map +1 -0
- package/dist/component/types.js +2 -0
- package/dist/component/types.js.map +1 -0
- package/dist/component/userContext.d.ts +508 -0
- package/dist/component/userContext.d.ts.map +1 -0
- package/dist/component/userContext.js +615 -0
- package/dist/component/userContext.js.map +1 -0
- package/dist/component/validation.d.ts +387 -0
- package/dist/component/validation.d.ts.map +1 -0
- package/dist/component/validation.js +1052 -0
- package/dist/component/validation.js.map +1 -0
- package/dist/component/validators.d.ts +4645 -0
- package/dist/component/validators.d.ts.map +1 -0
- package/dist/component/validators.js +641 -0
- package/dist/component/validators.js.map +1 -0
- package/dist/component/versionMutations.d.ts +216 -0
- package/dist/component/versionMutations.d.ts.map +1 -0
- package/dist/component/versionMutations.js +321 -0
- package/dist/component/versionMutations.js.map +1 -0
- package/dist/component/webhookTrigger.d.ts +770 -0
- package/dist/component/webhookTrigger.d.ts.map +1 -0
- package/dist/component/webhookTrigger.js +1413 -0
- package/dist/component/webhookTrigger.js.map +1 -0
- package/dist/react/index.d.ts +316 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +558 -0
- package/dist/react/index.js.map +1 -0
- package/dist/test.d.ts +2230 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +1107 -0
- package/dist/test.js.map +1 -0
- package/package.json +95 -0
- package/src/cli/commands/admin.ts +104 -0
- package/src/cli/index.ts +21 -0
- package/src/cli/utils/detectConvexUrl.ts +54 -0
- package/src/cli/utils/openBrowser.ts +16 -0
- package/src/client/admin-config.ts +138 -0
- package/src/client/adminApi.ts +942 -0
- package/src/client/agentTools.ts +1311 -0
- package/src/client/argTypes.ts +316 -0
- package/src/client/field-types.ts +187 -0
- package/src/client/index.ts +1301 -0
- package/src/client/queryBuilder.ts +1100 -0
- package/src/client/schema/codegen.ts +500 -0
- package/src/client/schema/defineContentType.ts +501 -0
- package/src/client/schema/index.ts +169 -0
- package/src/client/schema/schemaDrift.ts +574 -0
- package/src/client/schema/typedClient.ts +688 -0
- package/src/client/schema/types.ts +666 -0
- package/src/client/types.ts +723 -0
- package/src/client/workflows.ts +141 -0
- package/src/client/wrapper.ts +4304 -0
- package/src/component/_generated/api.ts +140 -0
- package/src/component/_generated/component.ts +5029 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/authorization.ts +647 -0
- package/src/component/authorizationHooks.ts +668 -0
- package/src/component/bulkOperations.ts +687 -0
- package/src/component/contentEntries.ts +1976 -0
- package/src/component/contentEntryMutations.ts +1223 -0
- package/src/component/contentEntryValidation.ts +707 -0
- package/src/component/contentLock.ts +550 -0
- package/src/component/contentTypeMigration.ts +1064 -0
- package/src/component/contentTypeMutations.ts +969 -0
- package/src/component/contentTypes.ts +346 -0
- package/src/component/convex.config.ts +44 -0
- package/src/component/documentTypes.ts +240 -0
- package/src/component/eventEmitter.ts +485 -0
- package/src/component/exportImport.ts +1169 -0
- package/src/component/index.ts +491 -0
- package/src/component/lib/deepReferenceResolver.ts +999 -0
- package/src/component/lib/errors.ts +816 -0
- package/src/component/lib/index.ts +145 -0
- package/src/component/lib/mediaReferenceResolver.ts +495 -0
- package/src/component/lib/metadataExtractor.ts +792 -0
- package/src/component/lib/mutationAuth.ts +199 -0
- package/src/component/lib/queries.ts +79 -0
- package/src/component/lib/ragContentChunker.ts +1371 -0
- package/src/component/lib/referenceResolver.ts +430 -0
- package/src/component/lib/slugGenerator.ts +262 -0
- package/src/component/lib/slugUniqueness.ts +333 -0
- package/src/component/lib/softDelete.ts +44 -0
- package/src/component/localeFallbackChain.ts +673 -0
- package/src/component/localeFields.ts +896 -0
- package/src/component/mediaAssetMutations.ts +725 -0
- package/src/component/mediaAssets.ts +932 -0
- package/src/component/mediaFolderMutations.ts +1046 -0
- package/src/component/mediaUploadMutations.ts +224 -0
- package/src/component/mediaVariantMutations.ts +900 -0
- package/src/component/mediaVariants.ts +793 -0
- package/src/component/ragContentIndexer.ts +1067 -0
- package/src/component/rateLimitHooks.ts +572 -0
- package/src/component/roles.ts +1360 -0
- package/src/component/scheduledPublish.ts +358 -0
- package/src/component/schema.ts +617 -0
- package/src/component/taxonomies.ts +949 -0
- package/src/component/taxonomyMutations.ts +1210 -0
- package/src/component/trash.ts +724 -0
- package/src/component/userContext.ts +898 -0
- package/src/component/validation.ts +1388 -0
- package/src/component/validators.ts +949 -0
- package/src/component/versionMutations.ts +392 -0
- package/src/component/webhookTrigger.ts +1922 -0
- package/src/react/index.ts +898 -0
- package/src/test.ts +1580 -0
package/dist/test.js
ADDED
|
@@ -0,0 +1,1107 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
/**
|
|
3
|
+
* Test helpers for the Convex CMS component.
|
|
4
|
+
*
|
|
5
|
+
* This module provides utilities for testing applications that use the Convex CMS component:
|
|
6
|
+
* - Component registration helpers for convex-test
|
|
7
|
+
* - Mock data factories for content types, entries, and media assets
|
|
8
|
+
* - Assertion utilities for validating CMS-specific structures
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { convexTest } from "convex-test";
|
|
13
|
+
* import { describe, it, expect } from "vitest";
|
|
14
|
+
* import {
|
|
15
|
+
* register,
|
|
16
|
+
* contentTypeFactory,
|
|
17
|
+
* contentEntryFactory,
|
|
18
|
+
* assertContentType,
|
|
19
|
+
* } from "@convex-cms/core/test";
|
|
20
|
+
* import schema from "./schema";
|
|
21
|
+
*
|
|
22
|
+
* const modules = import.meta.glob("./**\/*.ts");
|
|
23
|
+
*
|
|
24
|
+
* describe("my CMS tests", () => {
|
|
25
|
+
* it("creates content types correctly", async () => {
|
|
26
|
+
* const t = convexTest(schema, modules);
|
|
27
|
+
* register(t, "convexCms");
|
|
28
|
+
*
|
|
29
|
+
* // Create test data using factories
|
|
30
|
+
* const blogPostType = contentTypeFactory.blogPost();
|
|
31
|
+
*
|
|
32
|
+
* // Insert into test database
|
|
33
|
+
* const typeId = await t.run(async (ctx) => {
|
|
34
|
+
* return await ctx.db.insert("contentTypes", blogPostType);
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* // Assert the structure is correct
|
|
38
|
+
* const result = await t.run(async (ctx) => {
|
|
39
|
+
* return await ctx.db.get(typeId);
|
|
40
|
+
* });
|
|
41
|
+
* assertContentType(result);
|
|
42
|
+
* });
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @module
|
|
47
|
+
*/
|
|
48
|
+
import schema from "./component/schema.js";
|
|
49
|
+
// Import all component modules for testing
|
|
50
|
+
const modules = import.meta.glob("./component/**/*.ts");
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// Component Registration
|
|
53
|
+
// =============================================================================
|
|
54
|
+
/**
|
|
55
|
+
* Register the Convex CMS component with a convex-test instance.
|
|
56
|
+
*
|
|
57
|
+
* @param t - The test convex instance from calling `convexTest()`
|
|
58
|
+
* @param name - The name of the component as registered in convex.config.ts
|
|
59
|
+
* Defaults to "convexCms"
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* import { convexTest } from "convex-test";
|
|
64
|
+
* import { register } from "@convex-cms/core/test";
|
|
65
|
+
* import schema from "./schema";
|
|
66
|
+
*
|
|
67
|
+
* const modules = import.meta.glob("./**\/*.ts");
|
|
68
|
+
*
|
|
69
|
+
* test("my test", async () => {
|
|
70
|
+
* const t = convexTest(schema, modules);
|
|
71
|
+
* register(t, "convexCms");
|
|
72
|
+
* // Your tests here
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function register(t, name = "convexCms") {
|
|
77
|
+
t.registerComponent(name, schema, modules);
|
|
78
|
+
}
|
|
79
|
+
// =============================================================================
|
|
80
|
+
// Field Factories
|
|
81
|
+
// =============================================================================
|
|
82
|
+
/**
|
|
83
|
+
* Factory functions for creating common field definitions.
|
|
84
|
+
* These produce valid field structures for use in content type definitions.
|
|
85
|
+
*/
|
|
86
|
+
export const fieldFactory = {
|
|
87
|
+
/**
|
|
88
|
+
* Create a text field definition.
|
|
89
|
+
*/
|
|
90
|
+
text(name, label, options = {}) {
|
|
91
|
+
return {
|
|
92
|
+
name,
|
|
93
|
+
label,
|
|
94
|
+
type: "text",
|
|
95
|
+
required: options.required ?? false,
|
|
96
|
+
searchable: options.searchable,
|
|
97
|
+
localized: options.localized,
|
|
98
|
+
description: options.description,
|
|
99
|
+
defaultValue: options.defaultValue,
|
|
100
|
+
options: options.minLength !== undefined ||
|
|
101
|
+
options.maxLength !== undefined ||
|
|
102
|
+
options.pattern !== undefined
|
|
103
|
+
? {
|
|
104
|
+
minLength: options.minLength,
|
|
105
|
+
maxLength: options.maxLength,
|
|
106
|
+
pattern: options.pattern,
|
|
107
|
+
}
|
|
108
|
+
: undefined,
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* Create a rich text field definition.
|
|
113
|
+
*/
|
|
114
|
+
richText(name, label, options = {}) {
|
|
115
|
+
return {
|
|
116
|
+
name,
|
|
117
|
+
label,
|
|
118
|
+
type: "richText",
|
|
119
|
+
required: options.required ?? false,
|
|
120
|
+
searchable: options.searchable,
|
|
121
|
+
localized: options.localized,
|
|
122
|
+
description: options.description,
|
|
123
|
+
options: options.allowedBlocks !== undefined ||
|
|
124
|
+
options.allowedMarks !== undefined
|
|
125
|
+
? {
|
|
126
|
+
allowedBlocks: options.allowedBlocks,
|
|
127
|
+
allowedMarks: options.allowedMarks,
|
|
128
|
+
}
|
|
129
|
+
: undefined,
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
/**
|
|
133
|
+
* Create a number field definition.
|
|
134
|
+
*/
|
|
135
|
+
number(name, label, options = {}) {
|
|
136
|
+
return {
|
|
137
|
+
name,
|
|
138
|
+
label,
|
|
139
|
+
type: "number",
|
|
140
|
+
required: options.required ?? false,
|
|
141
|
+
description: options.description,
|
|
142
|
+
defaultValue: options.defaultValue,
|
|
143
|
+
options: options.min !== undefined ||
|
|
144
|
+
options.max !== undefined ||
|
|
145
|
+
options.step !== undefined ||
|
|
146
|
+
options.precision !== undefined
|
|
147
|
+
? {
|
|
148
|
+
min: options.min,
|
|
149
|
+
max: options.max,
|
|
150
|
+
step: options.step,
|
|
151
|
+
precision: options.precision,
|
|
152
|
+
}
|
|
153
|
+
: undefined,
|
|
154
|
+
};
|
|
155
|
+
},
|
|
156
|
+
/**
|
|
157
|
+
* Create a boolean field definition.
|
|
158
|
+
*/
|
|
159
|
+
boolean(name, label, options = {}) {
|
|
160
|
+
return {
|
|
161
|
+
name,
|
|
162
|
+
label,
|
|
163
|
+
type: "boolean",
|
|
164
|
+
required: options.required ?? false,
|
|
165
|
+
description: options.description,
|
|
166
|
+
defaultValue: options.defaultValue,
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
/**
|
|
170
|
+
* Create a date field definition.
|
|
171
|
+
*/
|
|
172
|
+
date(name, label, options = {}) {
|
|
173
|
+
return {
|
|
174
|
+
name,
|
|
175
|
+
label,
|
|
176
|
+
type: "date",
|
|
177
|
+
required: options.required ?? false,
|
|
178
|
+
description: options.description,
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
/**
|
|
182
|
+
* Create a datetime field definition.
|
|
183
|
+
*/
|
|
184
|
+
datetime(name, label, options = {}) {
|
|
185
|
+
return {
|
|
186
|
+
name,
|
|
187
|
+
label,
|
|
188
|
+
type: "datetime",
|
|
189
|
+
required: options.required ?? false,
|
|
190
|
+
description: options.description,
|
|
191
|
+
};
|
|
192
|
+
},
|
|
193
|
+
/**
|
|
194
|
+
* Create a reference field definition.
|
|
195
|
+
*/
|
|
196
|
+
reference(name, label, options = {}) {
|
|
197
|
+
return {
|
|
198
|
+
name,
|
|
199
|
+
label,
|
|
200
|
+
type: "reference",
|
|
201
|
+
required: options.required ?? false,
|
|
202
|
+
description: options.description,
|
|
203
|
+
options: {
|
|
204
|
+
allowedContentTypes: options.allowedContentTypes,
|
|
205
|
+
multiple: options.multiple,
|
|
206
|
+
minItems: options.minItems,
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
/**
|
|
211
|
+
* Create a media field definition.
|
|
212
|
+
*/
|
|
213
|
+
media(name, label, options = {}) {
|
|
214
|
+
return {
|
|
215
|
+
name,
|
|
216
|
+
label,
|
|
217
|
+
type: "media",
|
|
218
|
+
required: options.required ?? false,
|
|
219
|
+
description: options.description,
|
|
220
|
+
options: {
|
|
221
|
+
allowedMimeTypes: options.allowedMimeTypes,
|
|
222
|
+
maxFileSize: options.maxFileSize,
|
|
223
|
+
multiple: options.multiple,
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
},
|
|
227
|
+
/**
|
|
228
|
+
* Create a JSON field definition.
|
|
229
|
+
*/
|
|
230
|
+
json(name, label, options = {}) {
|
|
231
|
+
return {
|
|
232
|
+
name,
|
|
233
|
+
label,
|
|
234
|
+
type: "json",
|
|
235
|
+
required: options.required ?? false,
|
|
236
|
+
description: options.description,
|
|
237
|
+
defaultValue: options.defaultValue,
|
|
238
|
+
};
|
|
239
|
+
},
|
|
240
|
+
/**
|
|
241
|
+
* Create a select field definition.
|
|
242
|
+
*/
|
|
243
|
+
select(name, label, selectOptions, options = {}) {
|
|
244
|
+
return {
|
|
245
|
+
name,
|
|
246
|
+
label,
|
|
247
|
+
type: "select",
|
|
248
|
+
required: options.required ?? false,
|
|
249
|
+
description: options.description,
|
|
250
|
+
defaultValue: options.defaultValue,
|
|
251
|
+
options: {
|
|
252
|
+
options: selectOptions,
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
/**
|
|
257
|
+
* Create a multi-select field definition.
|
|
258
|
+
*/
|
|
259
|
+
multiSelect(name, label, selectOptions, options = {}) {
|
|
260
|
+
return {
|
|
261
|
+
name,
|
|
262
|
+
label,
|
|
263
|
+
type: "multiSelect",
|
|
264
|
+
required: options.required ?? false,
|
|
265
|
+
description: options.description,
|
|
266
|
+
defaultValue: options.defaultValue,
|
|
267
|
+
options: {
|
|
268
|
+
options: selectOptions,
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
// =============================================================================
|
|
274
|
+
// Content Type Factories
|
|
275
|
+
// =============================================================================
|
|
276
|
+
/**
|
|
277
|
+
* Factory functions for creating test content type data.
|
|
278
|
+
* All factories return data suitable for inserting into the contentTypes table.
|
|
279
|
+
*/
|
|
280
|
+
export const contentTypeFactory = {
|
|
281
|
+
/**
|
|
282
|
+
* Create a minimal valid content type.
|
|
283
|
+
*/
|
|
284
|
+
minimal(name = "test_type") {
|
|
285
|
+
return {
|
|
286
|
+
name,
|
|
287
|
+
displayName: name
|
|
288
|
+
.split("_")
|
|
289
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
290
|
+
.join(" "),
|
|
291
|
+
createdBy: "test-user",
|
|
292
|
+
fields: [],
|
|
293
|
+
isActive: true,
|
|
294
|
+
};
|
|
295
|
+
},
|
|
296
|
+
/**
|
|
297
|
+
* Create a blog post content type with common fields.
|
|
298
|
+
*/
|
|
299
|
+
blogPost(overrides = {}) {
|
|
300
|
+
return {
|
|
301
|
+
name: "blog_post",
|
|
302
|
+
displayName: "Blog Post",
|
|
303
|
+
description: "A blog post content type for testing",
|
|
304
|
+
createdBy: "test-user",
|
|
305
|
+
fields: [
|
|
306
|
+
fieldFactory.text("title", "Title", {
|
|
307
|
+
required: true,
|
|
308
|
+
searchable: true,
|
|
309
|
+
maxLength: 200,
|
|
310
|
+
}),
|
|
311
|
+
fieldFactory.text("slug", "Slug", { required: true }),
|
|
312
|
+
fieldFactory.richText("content", "Content", {
|
|
313
|
+
required: true,
|
|
314
|
+
searchable: true,
|
|
315
|
+
localized: true,
|
|
316
|
+
}),
|
|
317
|
+
fieldFactory.text("excerpt", "Excerpt", {
|
|
318
|
+
searchable: true,
|
|
319
|
+
maxLength: 500,
|
|
320
|
+
}),
|
|
321
|
+
fieldFactory.media("featuredImage", "Featured Image", {
|
|
322
|
+
allowedMimeTypes: ["image/*"],
|
|
323
|
+
}),
|
|
324
|
+
fieldFactory.reference("author", "Author", {
|
|
325
|
+
allowedContentTypes: ["author"],
|
|
326
|
+
}),
|
|
327
|
+
fieldFactory.multiSelect("tags", "Tags", [
|
|
328
|
+
{ value: "tech", label: "Technology" },
|
|
329
|
+
{ value: "news", label: "News" },
|
|
330
|
+
{ value: "tutorial", label: "Tutorial" },
|
|
331
|
+
], {}),
|
|
332
|
+
fieldFactory.datetime("publishedAt", "Published At"),
|
|
333
|
+
],
|
|
334
|
+
icon: "📝",
|
|
335
|
+
slugField: "title",
|
|
336
|
+
titleField: "title",
|
|
337
|
+
isActive: true,
|
|
338
|
+
...overrides,
|
|
339
|
+
};
|
|
340
|
+
},
|
|
341
|
+
/**
|
|
342
|
+
* Create a product content type for e-commerce testing.
|
|
343
|
+
*/
|
|
344
|
+
product(overrides = {}) {
|
|
345
|
+
return {
|
|
346
|
+
name: "product",
|
|
347
|
+
displayName: "Product",
|
|
348
|
+
description: "A product content type for testing",
|
|
349
|
+
createdBy: "test-user",
|
|
350
|
+
fields: [
|
|
351
|
+
fieldFactory.text("name", "Product Name", {
|
|
352
|
+
required: true,
|
|
353
|
+
searchable: true,
|
|
354
|
+
}),
|
|
355
|
+
fieldFactory.text("sku", "SKU", { required: true }),
|
|
356
|
+
fieldFactory.richText("description", "Description", {
|
|
357
|
+
searchable: true,
|
|
358
|
+
}),
|
|
359
|
+
fieldFactory.number("price", "Price", {
|
|
360
|
+
required: true,
|
|
361
|
+
min: 0,
|
|
362
|
+
precision: 2,
|
|
363
|
+
}),
|
|
364
|
+
fieldFactory.number("stock", "Stock Quantity", { min: 0 }),
|
|
365
|
+
fieldFactory.media("images", "Product Images", {
|
|
366
|
+
allowedMimeTypes: ["image/*"],
|
|
367
|
+
multiple: true,
|
|
368
|
+
}),
|
|
369
|
+
fieldFactory.reference("category", "Category", {
|
|
370
|
+
allowedContentTypes: ["category"],
|
|
371
|
+
}),
|
|
372
|
+
fieldFactory.select("status", "Status", [
|
|
373
|
+
{ value: "active", label: "Active" },
|
|
374
|
+
{ value: "discontinued", label: "Discontinued" },
|
|
375
|
+
{ value: "out_of_stock", label: "Out of Stock" },
|
|
376
|
+
], { required: true, defaultValue: "active" }),
|
|
377
|
+
fieldFactory.json("metadata", "Metadata"),
|
|
378
|
+
],
|
|
379
|
+
slugField: "name",
|
|
380
|
+
titleField: "name",
|
|
381
|
+
isActive: true,
|
|
382
|
+
...overrides,
|
|
383
|
+
};
|
|
384
|
+
},
|
|
385
|
+
/**
|
|
386
|
+
* Create an author content type.
|
|
387
|
+
*/
|
|
388
|
+
author(overrides = {}) {
|
|
389
|
+
return {
|
|
390
|
+
name: "author",
|
|
391
|
+
displayName: "Author",
|
|
392
|
+
description: "An author content type for testing",
|
|
393
|
+
createdBy: "test-user",
|
|
394
|
+
fields: [
|
|
395
|
+
fieldFactory.text("name", "Name", { required: true, searchable: true }),
|
|
396
|
+
fieldFactory.text("email", "Email"),
|
|
397
|
+
fieldFactory.richText("bio", "Biography"),
|
|
398
|
+
fieldFactory.media("avatar", "Avatar", {
|
|
399
|
+
allowedMimeTypes: ["image/*"],
|
|
400
|
+
}),
|
|
401
|
+
fieldFactory.json("socialLinks", "Social Links"),
|
|
402
|
+
],
|
|
403
|
+
slugField: "name",
|
|
404
|
+
titleField: "name",
|
|
405
|
+
isActive: true,
|
|
406
|
+
...overrides,
|
|
407
|
+
};
|
|
408
|
+
},
|
|
409
|
+
/**
|
|
410
|
+
* Create a category content type.
|
|
411
|
+
*/
|
|
412
|
+
category(overrides = {}) {
|
|
413
|
+
return {
|
|
414
|
+
name: "category",
|
|
415
|
+
displayName: "Category",
|
|
416
|
+
description: "A category content type for testing",
|
|
417
|
+
createdBy: "test-user",
|
|
418
|
+
fields: [
|
|
419
|
+
fieldFactory.text("name", "Name", { required: true, searchable: true }),
|
|
420
|
+
fieldFactory.text("description", "Description"),
|
|
421
|
+
fieldFactory.media("icon", "Icon", { allowedMimeTypes: ["image/*"] }),
|
|
422
|
+
fieldFactory.reference("parent", "Parent Category", {
|
|
423
|
+
allowedContentTypes: ["category"],
|
|
424
|
+
}),
|
|
425
|
+
fieldFactory.number("sortOrder", "Sort Order", { defaultValue: 0 }),
|
|
426
|
+
],
|
|
427
|
+
slugField: "name",
|
|
428
|
+
titleField: "name",
|
|
429
|
+
isActive: true,
|
|
430
|
+
...overrides,
|
|
431
|
+
};
|
|
432
|
+
},
|
|
433
|
+
/**
|
|
434
|
+
* Create a page content type (singleton-compatible).
|
|
435
|
+
*/
|
|
436
|
+
page(overrides = {}) {
|
|
437
|
+
return {
|
|
438
|
+
name: "page",
|
|
439
|
+
displayName: "Page",
|
|
440
|
+
description: "A page content type for testing",
|
|
441
|
+
createdBy: "test-user",
|
|
442
|
+
fields: [
|
|
443
|
+
fieldFactory.text("title", "Title", {
|
|
444
|
+
required: true,
|
|
445
|
+
searchable: true,
|
|
446
|
+
}),
|
|
447
|
+
fieldFactory.richText("content", "Content", {
|
|
448
|
+
required: true,
|
|
449
|
+
localized: true,
|
|
450
|
+
}),
|
|
451
|
+
fieldFactory.text("metaTitle", "Meta Title"),
|
|
452
|
+
fieldFactory.text("metaDescription", "Meta Description", {
|
|
453
|
+
maxLength: 160,
|
|
454
|
+
}),
|
|
455
|
+
fieldFactory.media("ogImage", "Open Graph Image", {
|
|
456
|
+
allowedMimeTypes: ["image/*"],
|
|
457
|
+
}),
|
|
458
|
+
],
|
|
459
|
+
slugField: "title",
|
|
460
|
+
titleField: "title",
|
|
461
|
+
isActive: true,
|
|
462
|
+
...overrides,
|
|
463
|
+
};
|
|
464
|
+
},
|
|
465
|
+
/**
|
|
466
|
+
* Create a singleton content type (e.g., for site settings).
|
|
467
|
+
*/
|
|
468
|
+
siteSettings(overrides = {}) {
|
|
469
|
+
return {
|
|
470
|
+
name: "site_settings",
|
|
471
|
+
displayName: "Site Settings",
|
|
472
|
+
description: "Global site settings (singleton)",
|
|
473
|
+
createdBy: "test-user",
|
|
474
|
+
fields: [
|
|
475
|
+
fieldFactory.text("siteName", "Site Name", { required: true }),
|
|
476
|
+
fieldFactory.text("tagline", "Tagline"),
|
|
477
|
+
fieldFactory.media("logo", "Logo", { allowedMimeTypes: ["image/*"] }),
|
|
478
|
+
fieldFactory.media("favicon", "Favicon", {
|
|
479
|
+
allowedMimeTypes: ["image/*"],
|
|
480
|
+
}),
|
|
481
|
+
fieldFactory.json("socialLinks", "Social Links"),
|
|
482
|
+
fieldFactory.json("analytics", "Analytics Config"),
|
|
483
|
+
],
|
|
484
|
+
singleton: true,
|
|
485
|
+
titleField: "siteName",
|
|
486
|
+
isActive: true,
|
|
487
|
+
...overrides,
|
|
488
|
+
};
|
|
489
|
+
},
|
|
490
|
+
/**
|
|
491
|
+
* Create a content type with all supported field types.
|
|
492
|
+
* Useful for comprehensive testing.
|
|
493
|
+
*/
|
|
494
|
+
allFieldTypes(overrides = {}) {
|
|
495
|
+
return {
|
|
496
|
+
name: "all_fields",
|
|
497
|
+
displayName: "All Field Types",
|
|
498
|
+
description: "A content type with every supported field type",
|
|
499
|
+
createdBy: "test-user",
|
|
500
|
+
fields: [
|
|
501
|
+
fieldFactory.text("textField", "Text Field", { required: true }),
|
|
502
|
+
fieldFactory.richText("richTextField", "Rich Text Field"),
|
|
503
|
+
fieldFactory.number("numberField", "Number Field"),
|
|
504
|
+
fieldFactory.boolean("booleanField", "Boolean Field"),
|
|
505
|
+
fieldFactory.date("dateField", "Date Field"),
|
|
506
|
+
fieldFactory.datetime("datetimeField", "Datetime Field"),
|
|
507
|
+
fieldFactory.reference("referenceField", "Reference Field"),
|
|
508
|
+
fieldFactory.media("mediaField", "Media Field"),
|
|
509
|
+
fieldFactory.json("jsonField", "JSON Field"),
|
|
510
|
+
fieldFactory.select("selectField", "Select Field", [
|
|
511
|
+
{ value: "option1", label: "Option 1" },
|
|
512
|
+
{ value: "option2", label: "Option 2" },
|
|
513
|
+
]),
|
|
514
|
+
fieldFactory.multiSelect("multiSelectField", "Multi Select Field", [
|
|
515
|
+
{ value: "choice1", label: "Choice 1" },
|
|
516
|
+
{ value: "choice2", label: "Choice 2" },
|
|
517
|
+
{ value: "choice3", label: "Choice 3" },
|
|
518
|
+
]),
|
|
519
|
+
],
|
|
520
|
+
slugField: "textField",
|
|
521
|
+
titleField: "textField",
|
|
522
|
+
isActive: true,
|
|
523
|
+
...overrides,
|
|
524
|
+
};
|
|
525
|
+
},
|
|
526
|
+
/**
|
|
527
|
+
* Create a custom content type with specified fields.
|
|
528
|
+
*/
|
|
529
|
+
custom(name, displayName, fields, overrides = {}) {
|
|
530
|
+
return {
|
|
531
|
+
name,
|
|
532
|
+
displayName,
|
|
533
|
+
createdBy: "test-user",
|
|
534
|
+
fields,
|
|
535
|
+
isActive: true,
|
|
536
|
+
...overrides,
|
|
537
|
+
};
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
// =============================================================================
|
|
541
|
+
// Content Entry Factories
|
|
542
|
+
// =============================================================================
|
|
543
|
+
let entryCounter = 0;
|
|
544
|
+
/**
|
|
545
|
+
* Factory functions for creating test content entry data.
|
|
546
|
+
* All factories return data suitable for inserting into the contentEntries table.
|
|
547
|
+
*
|
|
548
|
+
* Note: You'll need to provide a valid contentTypeId when inserting into the database.
|
|
549
|
+
*/
|
|
550
|
+
export const contentEntryFactory = {
|
|
551
|
+
/**
|
|
552
|
+
* Reset the internal counter used for generating unique slugs.
|
|
553
|
+
* Call this in beforeEach() if you need predictable slug values.
|
|
554
|
+
*/
|
|
555
|
+
resetCounter() {
|
|
556
|
+
entryCounter = 0;
|
|
557
|
+
},
|
|
558
|
+
/**
|
|
559
|
+
* Create a minimal valid content entry.
|
|
560
|
+
*/
|
|
561
|
+
minimal(contentTypeId, overrides = {}) {
|
|
562
|
+
entryCounter++;
|
|
563
|
+
return {
|
|
564
|
+
contentTypeId,
|
|
565
|
+
slug: `test-entry-${entryCounter}`,
|
|
566
|
+
status: "draft",
|
|
567
|
+
data: {},
|
|
568
|
+
version: 1,
|
|
569
|
+
...overrides,
|
|
570
|
+
};
|
|
571
|
+
},
|
|
572
|
+
/**
|
|
573
|
+
* Create a draft content entry.
|
|
574
|
+
*/
|
|
575
|
+
draft(contentTypeId, data, overrides = {}) {
|
|
576
|
+
entryCounter++;
|
|
577
|
+
return {
|
|
578
|
+
contentTypeId,
|
|
579
|
+
slug: `draft-${entryCounter}`,
|
|
580
|
+
status: "draft",
|
|
581
|
+
data,
|
|
582
|
+
version: 1,
|
|
583
|
+
...overrides,
|
|
584
|
+
};
|
|
585
|
+
},
|
|
586
|
+
/**
|
|
587
|
+
* Create a published content entry.
|
|
588
|
+
*/
|
|
589
|
+
published(contentTypeId, data, overrides = {}) {
|
|
590
|
+
entryCounter++;
|
|
591
|
+
const now = Date.now();
|
|
592
|
+
return {
|
|
593
|
+
contentTypeId,
|
|
594
|
+
slug: `published-${entryCounter}`,
|
|
595
|
+
status: "published",
|
|
596
|
+
data,
|
|
597
|
+
version: 1,
|
|
598
|
+
firstPublishedAt: now,
|
|
599
|
+
lastPublishedAt: now,
|
|
600
|
+
...overrides,
|
|
601
|
+
};
|
|
602
|
+
},
|
|
603
|
+
/**
|
|
604
|
+
* Create an archived content entry.
|
|
605
|
+
*/
|
|
606
|
+
archived(contentTypeId, data, overrides = {}) {
|
|
607
|
+
entryCounter++;
|
|
608
|
+
return {
|
|
609
|
+
contentTypeId,
|
|
610
|
+
slug: `archived-${entryCounter}`,
|
|
611
|
+
status: "archived",
|
|
612
|
+
data,
|
|
613
|
+
version: 1,
|
|
614
|
+
...overrides,
|
|
615
|
+
};
|
|
616
|
+
},
|
|
617
|
+
/**
|
|
618
|
+
* Create a scheduled content entry.
|
|
619
|
+
*/
|
|
620
|
+
scheduled(contentTypeId, data, scheduledPublishAt, overrides = {}) {
|
|
621
|
+
entryCounter++;
|
|
622
|
+
return {
|
|
623
|
+
contentTypeId,
|
|
624
|
+
slug: `scheduled-${entryCounter}`,
|
|
625
|
+
status: "scheduled",
|
|
626
|
+
data,
|
|
627
|
+
version: 1,
|
|
628
|
+
scheduledPublishAt,
|
|
629
|
+
...overrides,
|
|
630
|
+
};
|
|
631
|
+
},
|
|
632
|
+
/**
|
|
633
|
+
* Create a soft-deleted content entry.
|
|
634
|
+
*/
|
|
635
|
+
deleted(contentTypeId, data, overrides = {}) {
|
|
636
|
+
entryCounter++;
|
|
637
|
+
return {
|
|
638
|
+
contentTypeId,
|
|
639
|
+
slug: `deleted-${entryCounter}`,
|
|
640
|
+
status: "draft",
|
|
641
|
+
data,
|
|
642
|
+
version: 1,
|
|
643
|
+
deletedAt: Date.now(),
|
|
644
|
+
...overrides,
|
|
645
|
+
};
|
|
646
|
+
},
|
|
647
|
+
/**
|
|
648
|
+
* Create a localized content entry variant.
|
|
649
|
+
*/
|
|
650
|
+
localized(contentTypeId, primaryEntryId, locale, data, overrides = {}) {
|
|
651
|
+
entryCounter++;
|
|
652
|
+
return {
|
|
653
|
+
contentTypeId,
|
|
654
|
+
slug: `localized-${locale}-${entryCounter}`,
|
|
655
|
+
status: "draft",
|
|
656
|
+
data,
|
|
657
|
+
locale,
|
|
658
|
+
primaryEntryId,
|
|
659
|
+
version: 1,
|
|
660
|
+
...overrides,
|
|
661
|
+
};
|
|
662
|
+
},
|
|
663
|
+
/**
|
|
664
|
+
* Create a blog post entry with typical data.
|
|
665
|
+
*/
|
|
666
|
+
blogPost(contentTypeId, overrides = {}) {
|
|
667
|
+
entryCounter++;
|
|
668
|
+
return {
|
|
669
|
+
contentTypeId,
|
|
670
|
+
slug: `blog-post-${entryCounter}`,
|
|
671
|
+
status: "draft",
|
|
672
|
+
data: {
|
|
673
|
+
title: `Test Blog Post ${entryCounter}`,
|
|
674
|
+
content: `<p>This is the content of test blog post ${entryCounter}.</p>`,
|
|
675
|
+
excerpt: `A brief excerpt for blog post ${entryCounter}.`,
|
|
676
|
+
tags: ["tech", "tutorial"],
|
|
677
|
+
},
|
|
678
|
+
version: 1,
|
|
679
|
+
searchText: `Test Blog Post ${entryCounter} content excerpt`,
|
|
680
|
+
...overrides,
|
|
681
|
+
};
|
|
682
|
+
},
|
|
683
|
+
/**
|
|
684
|
+
* Create a product entry with typical data.
|
|
685
|
+
*/
|
|
686
|
+
product(contentTypeId, overrides = {}) {
|
|
687
|
+
entryCounter++;
|
|
688
|
+
const price = Math.floor(Math.random() * 10000) / 100 + 9.99;
|
|
689
|
+
return {
|
|
690
|
+
contentTypeId,
|
|
691
|
+
slug: `product-${entryCounter}`,
|
|
692
|
+
status: "draft",
|
|
693
|
+
data: {
|
|
694
|
+
name: `Test Product ${entryCounter}`,
|
|
695
|
+
sku: `SKU-${entryCounter.toString().padStart(6, "0")}`,
|
|
696
|
+
description: `<p>Description for test product ${entryCounter}.</p>`,
|
|
697
|
+
price,
|
|
698
|
+
stock: Math.floor(Math.random() * 100),
|
|
699
|
+
status: "active",
|
|
700
|
+
},
|
|
701
|
+
version: 1,
|
|
702
|
+
searchText: `Test Product ${entryCounter}`,
|
|
703
|
+
...overrides,
|
|
704
|
+
};
|
|
705
|
+
},
|
|
706
|
+
/**
|
|
707
|
+
* Create multiple entries at once.
|
|
708
|
+
*/
|
|
709
|
+
batch(contentTypeId, count, factory = () => ({})) {
|
|
710
|
+
return Array.from({ length: count }, (_, index) => {
|
|
711
|
+
const custom = factory(contentTypeId, index);
|
|
712
|
+
return contentEntryFactory.minimal(contentTypeId, custom);
|
|
713
|
+
});
|
|
714
|
+
},
|
|
715
|
+
};
|
|
716
|
+
// =============================================================================
|
|
717
|
+
// Media Asset Factories
|
|
718
|
+
// =============================================================================
|
|
719
|
+
let mediaCounter = 0;
|
|
720
|
+
/**
|
|
721
|
+
* Factory functions for creating test media asset data.
|
|
722
|
+
* All factories return data suitable for inserting into the mediaAssets table.
|
|
723
|
+
*
|
|
724
|
+
* Note: You'll need to provide a valid storageId when inserting into the database.
|
|
725
|
+
*/
|
|
726
|
+
export const mediaAssetFactory = {
|
|
727
|
+
/**
|
|
728
|
+
* Reset the internal counter used for generating unique filenames.
|
|
729
|
+
*/
|
|
730
|
+
resetCounter() {
|
|
731
|
+
mediaCounter = 0;
|
|
732
|
+
},
|
|
733
|
+
/**
|
|
734
|
+
* Create a minimal valid media asset.
|
|
735
|
+
*/
|
|
736
|
+
minimal(storageId, overrides = {}) {
|
|
737
|
+
mediaCounter++;
|
|
738
|
+
const name = `file-${mediaCounter}.bin`;
|
|
739
|
+
return {
|
|
740
|
+
kind: "asset",
|
|
741
|
+
storageId,
|
|
742
|
+
name,
|
|
743
|
+
path: `/${name}`,
|
|
744
|
+
mimeType: "application/octet-stream",
|
|
745
|
+
size: 1024,
|
|
746
|
+
...overrides,
|
|
747
|
+
};
|
|
748
|
+
},
|
|
749
|
+
/**
|
|
750
|
+
* Create an image asset.
|
|
751
|
+
*/
|
|
752
|
+
image(storageId, overrides = {}) {
|
|
753
|
+
mediaCounter++;
|
|
754
|
+
const name = `image-${mediaCounter}.jpg`;
|
|
755
|
+
return {
|
|
756
|
+
kind: "asset",
|
|
757
|
+
storageId,
|
|
758
|
+
name,
|
|
759
|
+
path: `/${name}`,
|
|
760
|
+
mimeType: "image/jpeg",
|
|
761
|
+
size: 102400,
|
|
762
|
+
width: 1920,
|
|
763
|
+
height: 1080,
|
|
764
|
+
title: `Test Image ${mediaCounter}`,
|
|
765
|
+
altText: `Alt text for test image ${mediaCounter}`,
|
|
766
|
+
searchText: `Test Image ${mediaCounter}`,
|
|
767
|
+
...overrides,
|
|
768
|
+
};
|
|
769
|
+
},
|
|
770
|
+
/**
|
|
771
|
+
* Create a PNG image asset.
|
|
772
|
+
*/
|
|
773
|
+
png(storageId, overrides = {}) {
|
|
774
|
+
mediaCounter++;
|
|
775
|
+
const name = `image-${mediaCounter}.png`;
|
|
776
|
+
return {
|
|
777
|
+
kind: "asset",
|
|
778
|
+
storageId,
|
|
779
|
+
name,
|
|
780
|
+
path: `/${name}`,
|
|
781
|
+
mimeType: "image/png",
|
|
782
|
+
size: 204800,
|
|
783
|
+
width: 800,
|
|
784
|
+
height: 600,
|
|
785
|
+
...overrides,
|
|
786
|
+
};
|
|
787
|
+
},
|
|
788
|
+
/**
|
|
789
|
+
* Create a video asset.
|
|
790
|
+
*/
|
|
791
|
+
video(storageId, overrides = {}) {
|
|
792
|
+
mediaCounter++;
|
|
793
|
+
const name = `video-${mediaCounter}.mp4`;
|
|
794
|
+
return {
|
|
795
|
+
kind: "asset",
|
|
796
|
+
storageId,
|
|
797
|
+
name,
|
|
798
|
+
path: `/${name}`,
|
|
799
|
+
mimeType: "video/mp4",
|
|
800
|
+
size: 10485760, // 10MB
|
|
801
|
+
width: 1920,
|
|
802
|
+
height: 1080,
|
|
803
|
+
duration: 120, // 2 minutes
|
|
804
|
+
title: `Test Video ${mediaCounter}`,
|
|
805
|
+
searchText: `Test Video ${mediaCounter}`,
|
|
806
|
+
...overrides,
|
|
807
|
+
};
|
|
808
|
+
},
|
|
809
|
+
/**
|
|
810
|
+
* Create an audio asset.
|
|
811
|
+
*/
|
|
812
|
+
audio(storageId, overrides = {}) {
|
|
813
|
+
mediaCounter++;
|
|
814
|
+
const name = `audio-${mediaCounter}.mp3`;
|
|
815
|
+
return {
|
|
816
|
+
kind: "asset",
|
|
817
|
+
storageId,
|
|
818
|
+
name,
|
|
819
|
+
path: `/${name}`,
|
|
820
|
+
mimeType: "audio/mpeg",
|
|
821
|
+
size: 5242880, // 5MB
|
|
822
|
+
duration: 180, // 3 minutes
|
|
823
|
+
title: `Test Audio ${mediaCounter}`,
|
|
824
|
+
searchText: `Test Audio ${mediaCounter}`,
|
|
825
|
+
...overrides,
|
|
826
|
+
};
|
|
827
|
+
},
|
|
828
|
+
/**
|
|
829
|
+
* Create a document asset (PDF).
|
|
830
|
+
*/
|
|
831
|
+
document(storageId, overrides = {}) {
|
|
832
|
+
mediaCounter++;
|
|
833
|
+
const name = `document-${mediaCounter}.pdf`;
|
|
834
|
+
return {
|
|
835
|
+
kind: "asset",
|
|
836
|
+
storageId,
|
|
837
|
+
name,
|
|
838
|
+
path: `/${name}`,
|
|
839
|
+
mimeType: "application/pdf",
|
|
840
|
+
size: 1048576, // 1MB
|
|
841
|
+
title: `Test Document ${mediaCounter}`,
|
|
842
|
+
searchText: `Test Document ${mediaCounter}`,
|
|
843
|
+
...overrides,
|
|
844
|
+
};
|
|
845
|
+
},
|
|
846
|
+
/**
|
|
847
|
+
* Create a soft-deleted media asset.
|
|
848
|
+
*/
|
|
849
|
+
deleted(storageId, overrides = {}) {
|
|
850
|
+
const asset = mediaAssetFactory.image(storageId, overrides);
|
|
851
|
+
return {
|
|
852
|
+
...asset,
|
|
853
|
+
deletedAt: Date.now(),
|
|
854
|
+
};
|
|
855
|
+
},
|
|
856
|
+
/**
|
|
857
|
+
* Create multiple assets at once.
|
|
858
|
+
*/
|
|
859
|
+
batch(storageIds, factory = () => ({})) {
|
|
860
|
+
return storageIds.map((storageId, index) => {
|
|
861
|
+
const custom = factory(storageId, index);
|
|
862
|
+
return mediaAssetFactory.minimal(storageId, custom);
|
|
863
|
+
});
|
|
864
|
+
},
|
|
865
|
+
};
|
|
866
|
+
// =============================================================================
|
|
867
|
+
// Media Folder Factories
|
|
868
|
+
// =============================================================================
|
|
869
|
+
let _folderCounter = 0;
|
|
870
|
+
/**
|
|
871
|
+
* Factory functions for creating test media folder data.
|
|
872
|
+
*/
|
|
873
|
+
export const mediaFolderFactory = {
|
|
874
|
+
/**
|
|
875
|
+
* Reset the internal counter used for generating unique folder names.
|
|
876
|
+
*/
|
|
877
|
+
resetCounter() {
|
|
878
|
+
_folderCounter = 0;
|
|
879
|
+
},
|
|
880
|
+
/**
|
|
881
|
+
* Create a root-level folder.
|
|
882
|
+
*/
|
|
883
|
+
root(name, overrides = {}) {
|
|
884
|
+
return {
|
|
885
|
+
kind: "folder",
|
|
886
|
+
name,
|
|
887
|
+
path: `/${name}`,
|
|
888
|
+
...overrides,
|
|
889
|
+
};
|
|
890
|
+
},
|
|
891
|
+
/**
|
|
892
|
+
* Create a child folder.
|
|
893
|
+
*/
|
|
894
|
+
child(name, parentId, parentPath, overrides = {}) {
|
|
895
|
+
return {
|
|
896
|
+
kind: "folder",
|
|
897
|
+
name,
|
|
898
|
+
parentId,
|
|
899
|
+
path: `${parentPath}/${name}`,
|
|
900
|
+
...overrides,
|
|
901
|
+
};
|
|
902
|
+
},
|
|
903
|
+
/**
|
|
904
|
+
* Create a common folder structure for testing.
|
|
905
|
+
*/
|
|
906
|
+
common() {
|
|
907
|
+
return {
|
|
908
|
+
images: mediaFolderFactory.root("images"),
|
|
909
|
+
videos: mediaFolderFactory.root("videos"),
|
|
910
|
+
documents: mediaFolderFactory.root("documents"),
|
|
911
|
+
};
|
|
912
|
+
},
|
|
913
|
+
};
|
|
914
|
+
// =============================================================================
|
|
915
|
+
// Assertion Utilities
|
|
916
|
+
// =============================================================================
|
|
917
|
+
/**
|
|
918
|
+
* Assert that a value is a valid content type document.
|
|
919
|
+
* Throws an error if the assertion fails.
|
|
920
|
+
*/
|
|
921
|
+
export function assertContentType(value, message) {
|
|
922
|
+
if (!value || typeof value !== "object") {
|
|
923
|
+
throw new Error(message ?? "Expected a content type object");
|
|
924
|
+
}
|
|
925
|
+
const obj = value;
|
|
926
|
+
if (typeof obj.name !== "string") {
|
|
927
|
+
throw new Error(message ?? "Content type missing required 'name' field");
|
|
928
|
+
}
|
|
929
|
+
if (typeof obj.displayName !== "string") {
|
|
930
|
+
throw new Error(message ?? "Content type missing required 'displayName' field");
|
|
931
|
+
}
|
|
932
|
+
if (!Array.isArray(obj.fields)) {
|
|
933
|
+
throw new Error(message ?? "Content type missing required 'fields' array");
|
|
934
|
+
}
|
|
935
|
+
if (typeof obj.isActive !== "boolean") {
|
|
936
|
+
throw new Error(message ?? "Content type missing required 'isActive' field");
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Assert that a value is a valid content entry document.
|
|
941
|
+
* Throws an error if the assertion fails.
|
|
942
|
+
*/
|
|
943
|
+
export function assertContentEntry(value, message) {
|
|
944
|
+
if (!value || typeof value !== "object") {
|
|
945
|
+
throw new Error(message ?? "Expected a content entry object");
|
|
946
|
+
}
|
|
947
|
+
const obj = value;
|
|
948
|
+
if (!obj.contentTypeId) {
|
|
949
|
+
throw new Error(message ?? "Content entry missing required 'contentTypeId' field");
|
|
950
|
+
}
|
|
951
|
+
if (typeof obj.slug !== "string") {
|
|
952
|
+
throw new Error(message ?? "Content entry missing required 'slug' field");
|
|
953
|
+
}
|
|
954
|
+
if (typeof obj.status !== "string") {
|
|
955
|
+
throw new Error(message ?? "Content entry missing required 'status' field");
|
|
956
|
+
}
|
|
957
|
+
const validStatuses = ["draft", "published", "archived", "scheduled"];
|
|
958
|
+
if (!validStatuses.includes(obj.status)) {
|
|
959
|
+
throw new Error(message ?? `Content entry has invalid status '${obj.status}'`);
|
|
960
|
+
}
|
|
961
|
+
if (typeof obj.version !== "number") {
|
|
962
|
+
throw new Error(message ?? "Content entry missing required 'version' field");
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Assert that a value is a valid media asset document.
|
|
967
|
+
* Throws an error if the assertion fails.
|
|
968
|
+
*/
|
|
969
|
+
export function assertMediaAsset(value, message) {
|
|
970
|
+
if (!value || typeof value !== "object") {
|
|
971
|
+
throw new Error(message ?? "Expected a media asset object");
|
|
972
|
+
}
|
|
973
|
+
const obj = value;
|
|
974
|
+
if (obj.kind !== "asset") {
|
|
975
|
+
throw new Error(message ?? "Media asset missing required kind: 'asset'");
|
|
976
|
+
}
|
|
977
|
+
if (!obj.storageId) {
|
|
978
|
+
throw new Error(message ?? "Media asset missing required 'storageId' field");
|
|
979
|
+
}
|
|
980
|
+
if (typeof obj.name !== "string") {
|
|
981
|
+
throw new Error(message ?? "Media asset missing required 'name' field");
|
|
982
|
+
}
|
|
983
|
+
if (typeof obj.mimeType !== "string") {
|
|
984
|
+
throw new Error(message ?? "Media asset missing required 'mimeType' field");
|
|
985
|
+
}
|
|
986
|
+
if (typeof obj.path !== "string") {
|
|
987
|
+
throw new Error(message ?? "Media asset missing required 'path' field");
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Assert that a content entry has a specific status.
|
|
992
|
+
*/
|
|
993
|
+
export function assertStatus(entry, expectedStatus, message) {
|
|
994
|
+
if (entry.status !== expectedStatus) {
|
|
995
|
+
throw new Error(message ??
|
|
996
|
+
`Expected entry status to be '${expectedStatus}', but got '${entry.status}'`);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Assert that a content entry is published.
|
|
1001
|
+
*/
|
|
1002
|
+
export function assertPublished(entry, message) {
|
|
1003
|
+
assertStatus(entry, "published", message);
|
|
1004
|
+
if (!entry.lastPublishedAt) {
|
|
1005
|
+
throw new Error(message ?? "Published entry should have 'lastPublishedAt' set");
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Assert that a document is soft-deleted.
|
|
1010
|
+
*/
|
|
1011
|
+
export function assertDeleted(doc, message) {
|
|
1012
|
+
if (!doc.deletedAt) {
|
|
1013
|
+
throw new Error(message ?? "Expected document to be soft-deleted");
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Assert that a document is not soft-deleted.
|
|
1018
|
+
*/
|
|
1019
|
+
export function assertNotDeleted(doc, message) {
|
|
1020
|
+
if (doc.deletedAt) {
|
|
1021
|
+
throw new Error(message ?? "Expected document to not be soft-deleted");
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Assert that a field definition has expected properties.
|
|
1026
|
+
*/
|
|
1027
|
+
export function assertField(fields, fieldName, expectations, message) {
|
|
1028
|
+
const field = fields.find((f) => f.name === fieldName);
|
|
1029
|
+
if (!field) {
|
|
1030
|
+
throw new Error(message ?? `Field '${fieldName}' not found`);
|
|
1031
|
+
}
|
|
1032
|
+
for (const [key, expectedValue] of Object.entries(expectations)) {
|
|
1033
|
+
const actualValue = field[key];
|
|
1034
|
+
if (JSON.stringify(actualValue) !== JSON.stringify(expectedValue)) {
|
|
1035
|
+
throw new Error(message ??
|
|
1036
|
+
`Field '${fieldName}' expected ${key} to be ${JSON.stringify(expectedValue)}, but got ${JSON.stringify(actualValue)}`);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
// =============================================================================
|
|
1041
|
+
// Test Data Helpers
|
|
1042
|
+
// =============================================================================
|
|
1043
|
+
/**
|
|
1044
|
+
* Generate a unique slug for testing.
|
|
1045
|
+
*/
|
|
1046
|
+
export function uniqueSlug(prefix = "test") {
|
|
1047
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Generate a unique name for testing.
|
|
1051
|
+
*/
|
|
1052
|
+
export function uniqueName(prefix = "test") {
|
|
1053
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Create a timestamp in the past.
|
|
1057
|
+
*/
|
|
1058
|
+
export function pastTimestamp(daysAgo) {
|
|
1059
|
+
return Date.now() - daysAgo * 24 * 60 * 60 * 1000;
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Create a timestamp in the future.
|
|
1063
|
+
*/
|
|
1064
|
+
export function futureTimestamp(daysFromNow) {
|
|
1065
|
+
return Date.now() + daysFromNow * 24 * 60 * 60 * 1000;
|
|
1066
|
+
}
|
|
1067
|
+
// =============================================================================
|
|
1068
|
+
// Exports
|
|
1069
|
+
// =============================================================================
|
|
1070
|
+
/**
|
|
1071
|
+
* Export schema and modules for advanced testing scenarios.
|
|
1072
|
+
*/
|
|
1073
|
+
export { schema, modules };
|
|
1074
|
+
/**
|
|
1075
|
+
* Re-export type constants for convenience.
|
|
1076
|
+
*/
|
|
1077
|
+
export { fieldTypes, contentStatuses, mediaTypes, variantTypes, variantStatuses, variantFormats, } from "./component/schema.js";
|
|
1078
|
+
/**
|
|
1079
|
+
* Default export for convenient importing.
|
|
1080
|
+
*/
|
|
1081
|
+
export default {
|
|
1082
|
+
// Registration
|
|
1083
|
+
register,
|
|
1084
|
+
schema,
|
|
1085
|
+
modules,
|
|
1086
|
+
// Factories
|
|
1087
|
+
fieldFactory,
|
|
1088
|
+
contentTypeFactory,
|
|
1089
|
+
contentEntryFactory,
|
|
1090
|
+
mediaAssetFactory,
|
|
1091
|
+
mediaFolderFactory,
|
|
1092
|
+
// Assertions
|
|
1093
|
+
assertContentType,
|
|
1094
|
+
assertContentEntry,
|
|
1095
|
+
assertMediaAsset,
|
|
1096
|
+
assertStatus,
|
|
1097
|
+
assertPublished,
|
|
1098
|
+
assertDeleted,
|
|
1099
|
+
assertNotDeleted,
|
|
1100
|
+
assertField,
|
|
1101
|
+
// Helpers
|
|
1102
|
+
uniqueSlug,
|
|
1103
|
+
uniqueName,
|
|
1104
|
+
pastTimestamp,
|
|
1105
|
+
futureTimestamp,
|
|
1106
|
+
};
|
|
1107
|
+
//# sourceMappingURL=test.js.map
|