@payloadcms/plugin-ecommerce 3.67.0-internal.87c53da → 3.67.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/dist/collections/addresses/createAddressesCollection.d.ts +1 -5
- package/dist/collections/addresses/createAddressesCollection.d.ts.map +1 -1
- package/dist/collections/addresses/createAddressesCollection.js +7 -6
- package/dist/collections/addresses/createAddressesCollection.js.map +1 -1
- package/dist/collections/carts/beforeChange.d.ts.map +1 -1
- package/dist/collections/carts/beforeChange.js +13 -1
- package/dist/collections/carts/beforeChange.js.map +1 -1
- package/dist/collections/carts/createCartsCollection.d.ts +6 -4
- package/dist/collections/carts/createCartsCollection.d.ts.map +1 -1
- package/dist/collections/carts/createCartsCollection.js +36 -5
- package/dist/collections/carts/createCartsCollection.js.map +1 -1
- package/dist/collections/carts/hasCartSecretAccess.d.ts +10 -0
- package/dist/collections/carts/hasCartSecretAccess.d.ts.map +1 -0
- package/dist/collections/carts/hasCartSecretAccess.js +24 -0
- package/dist/collections/carts/hasCartSecretAccess.js.map +1 -0
- package/dist/collections/orders/createOrdersCollection.d.ts +1 -5
- package/dist/collections/orders/createOrdersCollection.d.ts.map +1 -1
- package/dist/collections/orders/createOrdersCollection.js +9 -8
- package/dist/collections/orders/createOrdersCollection.js.map +1 -1
- package/dist/collections/products/createProductsCollection.d.ts +1 -4
- package/dist/collections/products/createProductsCollection.d.ts.map +1 -1
- package/dist/collections/products/createProductsCollection.js +5 -5
- package/dist/collections/products/createProductsCollection.js.map +1 -1
- package/dist/collections/transactions/createTransactionsCollection.d.ts +1 -3
- package/dist/collections/transactions/createTransactionsCollection.d.ts.map +1 -1
- package/dist/collections/transactions/createTransactionsCollection.js +5 -5
- package/dist/collections/transactions/createTransactionsCollection.js.map +1 -1
- package/dist/collections/variants/createVariantOptionsCollection.d.ts +1 -4
- package/dist/collections/variants/createVariantOptionsCollection.d.ts.map +1 -1
- package/dist/collections/variants/createVariantOptionsCollection.js +5 -5
- package/dist/collections/variants/createVariantOptionsCollection.js.map +1 -1
- package/dist/collections/variants/createVariantTypesCollection.d.ts +1 -4
- package/dist/collections/variants/createVariantTypesCollection.d.ts.map +1 -1
- package/dist/collections/variants/createVariantTypesCollection.js +5 -5
- package/dist/collections/variants/createVariantTypesCollection.js.map +1 -1
- package/dist/collections/variants/createVariantsCollection/index.d.ts +1 -4
- package/dist/collections/variants/createVariantsCollection/index.d.ts.map +1 -1
- package/dist/collections/variants/createVariantsCollection/index.js +5 -5
- package/dist/collections/variants/createVariantsCollection/index.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -33
- package/dist/index.js.map +1 -1
- package/dist/react/provider/index.d.ts +3 -0
- package/dist/react/provider/index.d.ts.map +1 -1
- package/dist/react/provider/index.js +261 -156
- package/dist/react/provider/index.js.map +1 -1
- package/dist/translations/en.d.ts.map +1 -1
- package/dist/translations/en.js +1 -0
- package/dist/translations/en.js.map +1 -1
- package/dist/types/index.d.ts +43 -25
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utilities/accessComposition.d.ts +55 -0
- package/dist/utilities/accessComposition.d.ts.map +1 -0
- package/dist/utilities/accessComposition.js +103 -0
- package/dist/utilities/accessComposition.js.map +1 -0
- package/dist/utilities/accessComposition.spec.js +803 -0
- package/dist/utilities/accessComposition.spec.js.map +1 -0
- package/dist/utilities/defaultProductsValidation.spec.js +383 -0
- package/dist/utilities/defaultProductsValidation.spec.js.map +1 -0
- package/dist/utilities/getCollectionSlugMap.spec.js +159 -0
- package/dist/utilities/getCollectionSlugMap.spec.js.map +1 -0
- package/dist/utilities/sanitizePluginConfig.d.ts.map +1 -1
- package/dist/utilities/sanitizePluginConfig.js +10 -2
- package/dist/utilities/sanitizePluginConfig.js.map +1 -1
- package/dist/utilities/sanitizePluginConfig.spec.js +515 -0
- package/dist/utilities/sanitizePluginConfig.spec.js.map +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/accessComposition.spec.ts"],"sourcesContent":["import type { Access, AccessArgs, Where } from 'payload'\n\nimport { accessAND, conditional, accessOR } from './accessComposition'\n\n// Mock access args for testing\nconst mockArgs: AccessArgs = {\n req: {\n user: null,\n headers: new Headers(),\n payload: {} as any,\n context: {},\n } as any,\n}\n\nconst mockArgsWithUser: AccessArgs = {\n req: {\n user: { id: '123', email: 'test@example.com' },\n headers: new Headers(),\n payload: {} as any,\n context: {},\n } as any,\n}\n\ndescribe('Access Composition Utilities', () => {\n describe('or', () => {\n it('should return true when first checker returns true', async () => {\n const checker1: Access = async () => true\n const checker2: Access = async () => false\n\n const result = await accessOR(checker1, checker2)(mockArgs)\n\n expect(result).toBe(true)\n })\n\n it('should return true when any checker returns true', async () => {\n const checker1: Access = async () => false\n const checker2: Access = async () => true\n const checker3: Access = async () => false\n\n const result = await accessOR(checker1, checker2, checker3)(mockArgs)\n\n expect(result).toBe(true)\n })\n\n it('should return false when all checkers return false', async () => {\n const checker1: Access = async () => false\n const checker2: Access = async () => false\n const checker3: Access = async () => false\n\n const result = await accessOR(checker1, checker2, checker3)(mockArgs)\n\n expect(result).toBe(false)\n })\n\n it('should combine Where queries with OR logic', async () => {\n const checker1: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker2: Access = async () => ({\n status: { equals: 'published' },\n })\n\n const result = await accessOR(checker1, checker2)(mockArgs)\n\n expect(result).toEqual({\n or: [{ customer: { equals: '123' } }, { status: { equals: 'published' } }],\n })\n })\n\n it('should return true when one checker returns true and others return Where queries', async () => {\n const checker1: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker2: Access = async () => true\n\n const result = await accessOR(checker1, checker2)(mockArgs)\n\n expect(result).toBe(true)\n })\n\n it('should ignore false values when combining Where queries', async () => {\n const checker1: Access = async () => false\n const checker2: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker3: Access = async () => false\n const checker4: Access = async () => ({\n status: { equals: 'published' },\n })\n\n const result = await accessOR(checker1, checker2, checker3, checker4)(mockArgs)\n\n expect(result).toEqual({\n or: [{ customer: { equals: '123' } }, { status: { equals: 'published' } }],\n })\n })\n\n it('should return a single Where query when only one checker returns a Where query', async () => {\n const checker1: Access = async () => false\n const checker2: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker3: Access = async () => false\n\n const result = await accessOR(checker1, checker2, checker3)(mockArgs)\n\n expect(result).toEqual({\n or: [{ customer: { equals: '123' } }],\n })\n })\n\n it('should short-circuit on first true result for performance', async () => {\n let secondCheckerCalled = false\n\n const checker1: Access = async () => true\n const checker2: Access = async () => {\n secondCheckerCalled = true\n return false\n }\n\n await accessOR(checker1, checker2)(mockArgs)\n\n expect(secondCheckerCalled).toBe(false)\n })\n\n it('should handle empty checkers array', async () => {\n const result = await accessOR()(mockArgs)\n\n expect(result).toBe(false)\n })\n\n it('should handle complex nested Where queries', async () => {\n const checker1: Access = async () =>\n ({\n and: [{ customer: { equals: '123' } }, { status: { equals: 'active' } }],\n }) as Where\n const checker2: Access = async () => ({\n role: { equals: 'admin' },\n })\n\n const result = await accessOR(checker1, checker2)(mockArgs)\n\n expect(result).toEqual({\n or: [\n { and: [{ customer: { equals: '123' } }, { status: { equals: 'active' } }] },\n { role: { equals: 'admin' } },\n ],\n })\n })\n })\n\n describe('and', () => {\n it('should return false when any checker returns false', async () => {\n const checker1: Access = async () => true\n const checker2: Access = async () => false\n\n const result = await accessAND(checker1, checker2)(mockArgs)\n\n expect(result).toBe(false)\n })\n\n it('should return true when all checkers return true', async () => {\n const checker1: Access = async () => true\n const checker2: Access = async () => true\n const checker3: Access = async () => true\n\n const result = await accessAND(checker1, checker2, checker3)(mockArgs)\n\n expect(result).toBe(true)\n })\n\n it('should combine Where queries with AND logic', async () => {\n const checker1: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker2: Access = async () => ({\n status: { equals: 'published' },\n })\n\n const result = await accessAND(checker1, checker2)(mockArgs)\n\n expect(result).toEqual({\n and: [{ customer: { equals: '123' } }, { status: { equals: 'published' } }],\n })\n })\n\n it('should return false when one checker returns false and others return Where queries', async () => {\n const checker1: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker2: Access = async () => false\n\n const result = await accessAND(checker1, checker2)(mockArgs)\n\n expect(result).toBe(false)\n })\n\n it('should return Where query when all checkers return Where queries except one returns true', async () => {\n const checker1: Access = async () => true\n const checker2: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker3: Access = async () => ({\n status: { equals: 'published' },\n })\n\n const result = await accessAND(checker1, checker2, checker3)(mockArgs)\n\n expect(result).toEqual({\n and: [{ customer: { equals: '123' } }, { status: { equals: 'published' } }],\n })\n })\n\n it('should short-circuit on first false result for performance', async () => {\n let secondCheckerCalled = false\n\n const checker1: Access = async () => false\n const checker2: Access = async () => {\n secondCheckerCalled = true\n return true\n }\n\n await accessAND(checker1, checker2)(mockArgs)\n\n expect(secondCheckerCalled).toBe(false)\n })\n\n it('should handle empty checkers array', async () => {\n const result = await accessAND()(mockArgs)\n\n expect(result).toBe(true)\n })\n\n it('should return a single Where query when only one checker returns a Where query', async () => {\n const checker1: Access = async () => true\n const checker2: Access = async () => ({\n customer: { equals: '123' },\n })\n const checker3: Access = async () => true\n\n const result = await accessAND(checker1, checker2, checker3)(mockArgs)\n\n expect(result).toEqual({\n and: [{ customer: { equals: '123' } }],\n })\n })\n\n it('should handle complex nested Where queries', async () => {\n const checker1: Access = async () => ({\n or: [{ customer: { equals: '123' } }, { customer: { equals: '456' } }],\n })\n const checker2: Access = async () => ({\n status: { equals: 'active' },\n })\n\n const result = await accessAND(checker1, checker2)(mockArgs)\n\n expect(result).toEqual({\n and: [\n { or: [{ customer: { equals: '123' } }, { customer: { equals: '456' } }] },\n { status: { equals: 'active' } },\n ],\n })\n })\n\n it('should return false immediately when first checker returns false', async () => {\n const checker1: Access = async () => false\n const checker2: Access = async () => {\n throw new Error('Should not be called')\n }\n\n const result = await accessAND(checker1, checker2)(mockArgs)\n\n expect(result).toBe(false)\n })\n })\n\n describe('conditional', () => {\n it('should apply checker when condition is true', async () => {\n const checker: Access = async () => true\n\n const result = await conditional(true, checker)(mockArgs)\n\n expect(result).toBe(true)\n })\n\n it('should return false when condition is false', async () => {\n const checker: Access = async () => true\n\n const result = await conditional(false, checker)(mockArgs)\n\n expect(result).toBe(false)\n })\n\n it('should apply checker when condition function returns true', async () => {\n const condition = ({ req }: AccessArgs) => !!req.user\n const checker: Access = async () => true\n\n const result = await conditional(condition, checker)(mockArgsWithUser)\n\n expect(result).toBe(true)\n })\n\n it('should return false when condition function returns false', async () => {\n const condition = ({ req }: AccessArgs) => !!req.user\n const checker: Access = async () => true\n\n const result = await conditional(condition, checker)(mockArgs)\n\n expect(result).toBe(false)\n })\n\n it('should pass Where query through when condition is true', async () => {\n const checker: Access = async () => ({\n customer: { equals: '123' },\n })\n\n const result = await conditional(true, checker)(mockArgs)\n\n expect(result).toEqual({\n customer: { equals: '123' },\n })\n })\n\n it('should not call checker when condition is false', async () => {\n let checkerCalled = false\n\n const checker: Access = async () => {\n checkerCalled = true\n return true\n }\n\n await conditional(false, checker)(mockArgs)\n\n expect(checkerCalled).toBe(false)\n })\n\n it('should evaluate condition function each time', async () => {\n const condition = ({ req }: AccessArgs) => !!req.user\n const checker: Access = async () => true\n\n // First call without user\n const result1 = await conditional(condition, checker)(mockArgs)\n expect(result1).toBe(false)\n\n // Second call with user\n const result2 = await conditional(condition, checker)(mockArgsWithUser)\n expect(result2).toBe(true)\n })\n\n it('should work with false checker result when condition is true', async () => {\n const checker: Access = async () => false\n\n const result = await conditional(true, checker)(mockArgs)\n\n expect(result).toBe(false)\n })\n })\n\n describe('combined composition', () => {\n it('should compose or, and, and conditional together', async () => {\n const isAdmin: Access = async ({ req }) => req.user?.role === 'admin'\n const isOwner: Access = async ({ req }) => ({\n customer: { equals: req.user?.id },\n })\n const isGuest: Access = async ({ req }) => !req.user\n\n const allowGuestCarts = true\n\n const access = accessOR(isAdmin, accessAND(isOwner), conditional(allowGuestCarts, isGuest))\n\n // Guest user (no user)\n const guestResult = await access(mockArgs)\n expect(guestResult).toBe(true)\n\n // Admin user\n const adminResult = await access({\n req: {\n user: { id: '123', role: 'admin' },\n headers: new Headers(),\n payload: {} as any,\n context: {},\n } as any,\n })\n expect(adminResult).toBe(true)\n\n // Regular user (owner)\n const ownerResult = await access({\n req: {\n user: { id: '123', role: 'customer' },\n headers: new Headers(),\n payload: {} as any,\n context: {},\n } as any,\n })\n expect(ownerResult).toEqual({\n or: [{ and: [{ customer: { equals: '123' } }] }],\n })\n })\n\n it('should handle complex nested compositions', async () => {\n const checker1: Access = async () => ({\n status: { equals: 'published' },\n })\n const checker2: Access = async () => ({\n visibility: { equals: 'public' },\n })\n const checker3: Access = async ({ req }) => !!req.user\n const checker4: Access = async () => ({\n customer: { equals: '123' },\n })\n\n // ((published AND public) OR (authenticated AND customer=123))\n const access = accessOR(accessAND(checker1, checker2), accessAND(checker3, checker4))\n\n // Without user\n const result1 = await access(mockArgs)\n expect(result1).toEqual({\n or: [\n {\n and: [{ status: { equals: 'published' } }, { visibility: { equals: 'public' } }],\n },\n ],\n })\n\n // With user\n const result2 = await access(mockArgsWithUser)\n expect(result2).toEqual({\n or: [\n {\n and: [{ status: { equals: 'published' } }, { visibility: { equals: 'public' } }],\n },\n {\n and: [{ customer: { equals: '123' } }],\n },\n ],\n })\n })\n\n it('should handle conditional inside or composition', async () => {\n const isAdmin: Access = async () => false\n const isGuest: Access = async () => true\n const allowGuestAccess = true\n\n const access = accessOR(isAdmin, conditional(allowGuestAccess, isGuest))\n\n const result = await access(mockArgs)\n expect(result).toBe(true)\n })\n\n it('should handle conditional inside and composition', async () => {\n const hasPermission: Access = async () => ({\n permissions: { contains: 'read' },\n })\n const isActiveUser: Access = async () => true\n const featureFlagEnabled = true\n\n const access = accessAND(hasPermission, conditional(featureFlagEnabled, isActiveUser))\n\n const result = await access(mockArgs)\n expect(result).toEqual({\n and: [{ permissions: { contains: 'read' } }],\n })\n })\n\n it('should correctly handle multiple levels of nesting', async () => {\n const a: Access = async () => true\n const b: Access = async () => false\n const c: Access = async () => ({ field1: { equals: 'value1' } })\n const d: Access = async () => ({ field2: { equals: 'value2' } })\n\n // (a AND (b OR (c AND d)))\n const access = accessAND(a, accessOR(b, accessAND(c, d)))\n\n const result = await access(mockArgs)\n expect(result).toEqual({\n and: [\n { or: [{ and: [{ field1: { equals: 'value1' } }, { field2: { equals: 'value2' } }] }] },\n ],\n })\n })\n })\n\n describe('edge cases and failure scenarios', () => {\n it('should handle checker that throws an error', async () => {\n const checker1: Access = async () => {\n throw new Error('Access check failed')\n }\n const checker2: Access = async () => true\n\n await expect(accessOR(checker1, checker2)(mockArgs)).rejects.toThrow('Access check failed')\n })\n\n it('should handle null or undefined returns gracefully', async () => {\n const checker1: Access = async () => null as any\n const checker2: Access = async () => undefined as any\n const checker3: Access = async () => true\n\n const result = await accessOR(checker1, checker2, checker3)(mockArgs)\n expect(result).toBe(true)\n })\n\n it('should handle deeply nested Where queries', async () => {\n const checker: Access = async () =>\n ({\n and: [\n {\n or: [\n { field1: { equals: 'value1' } },\n {\n and: [{ field2: { equals: 'value2' } }, { field3: { equals: 'value3' } }],\n },\n ],\n },\n { field4: { not_equals: 'value4' } },\n ],\n }) as Where\n\n const result = await accessOR(checker)(mockArgs)\n\n expect(result).toEqual({\n or: [\n {\n and: [\n {\n or: [\n { field1: { equals: 'value1' } },\n {\n and: [{ field2: { equals: 'value2' } }, { field3: { equals: 'value3' } }],\n },\n ],\n },\n { field4: { not_equals: 'value4' } },\n ],\n },\n ],\n })\n })\n\n it('should handle async checker that takes time', async () => {\n const checker1: Access = async () => {\n await new Promise((resolve) => setTimeout(resolve, 10))\n return false\n }\n const checker2: Access = async () => {\n await new Promise((resolve) => setTimeout(resolve, 10))\n return true\n }\n\n const start = Date.now()\n const result = await accessOR(checker1, checker2)(mockArgs)\n const duration = Date.now() - start\n\n expect(result).toBe(true)\n expect(duration).toBeGreaterThanOrEqual(20)\n })\n\n it('should handle all checkers returning null/undefined', async () => {\n const checker1: Access = async () => null as any\n const checker2: Access = async () => undefined as any\n\n const result = await accessOR(checker1, checker2)(mockArgs)\n\n // null and undefined should be treated as false\n expect(result).toBe(false)\n })\n\n it('should handle Where query with empty object', async () => {\n const checker: Access = async () => ({}) as Where\n\n const result = await accessOR(checker)(mockArgs)\n\n expect(result).toEqual({})\n })\n\n it('should handle conditional with complex condition function', async () => {\n const condition = ({ req }: AccessArgs): boolean => {\n return !!(req.user && req.user.email && req.user.email.endsWith('@admin.com'))\n }\n\n const checker: Access = async () => true\n\n // Non-admin email\n const result1 = await conditional(\n condition,\n checker,\n )({\n req: {\n user: { id: '123', email: 'user@example.com' },\n headers: new Headers(),\n payload: {} as any,\n context: {},\n } as any,\n })\n expect(result1).toBe(false)\n\n // Admin email\n const result2 = await conditional(\n condition,\n checker,\n )({\n req: {\n user: { id: '123', email: 'admin@admin.com' },\n headers: new Headers(),\n payload: {} as any,\n context: {},\n } as any,\n })\n expect(result2).toBe(true)\n })\n\n it('should handle very large number of checkers in or', async () => {\n const checkers: Access[] = Array.from({ length: 100 }, (_, i) => async () => ({\n field: { equals: `value${i}` },\n }))\n\n const result = await accessOR(...checkers)(mockArgs)\n\n expect(result).toHaveProperty('or')\n expect((result as any).or).toHaveLength(100)\n })\n\n it('should handle very large number of checkers in and', async () => {\n const checkers: Access[] = Array.from({ length: 100 }, (_, i) => async () => ({\n field: { equals: `value${i}` },\n }))\n\n const result = await accessAND(...checkers)(mockArgs)\n\n expect(result).toHaveProperty('and')\n expect((result as any).and).toHaveLength(100)\n })\n\n it('should handle alternating true/false in or correctly', async () => {\n const checkers: Access[] = [\n async () => false,\n async () => false,\n async () => false,\n async () => true, // This should cause short-circuit\n async () => {\n throw new Error('Should not be called')\n },\n ]\n\n const result = await accessOR(...checkers)(mockArgs)\n\n expect(result).toBe(true)\n })\n\n it('should handle alternating true/false in and correctly', async () => {\n const checkers: Access[] = [\n async () => true,\n async () => true,\n async () => false, // This should cause short-circuit\n async () => {\n throw new Error('Should not be called')\n },\n ]\n\n const result = await accessAND(...checkers)(mockArgs)\n\n expect(result).toBe(false)\n })\n })\n})\n"],"names":["accessAND","conditional","accessOR","mockArgs","req","user","headers","Headers","payload","context","mockArgsWithUser","id","email","describe","it","checker1","checker2","result","expect","toBe","checker3","customer","equals","status","toEqual","or","checker4","secondCheckerCalled","and","role","Error","checker","condition","checkerCalled","result1","result2","isAdmin","isOwner","isGuest","allowGuestCarts","access","guestResult","adminResult","ownerResult","visibility","allowGuestAccess","hasPermission","permissions","contains","isActiveUser","featureFlagEnabled","a","b","c","field1","d","field2","rejects","toThrow","undefined","field3","field4","not_equals","Promise","resolve","setTimeout","start","Date","now","duration","toBeGreaterThanOrEqual","endsWith","checkers","Array","from","length","_","i","field","toHaveProperty","toHaveLength"],"mappings":"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"}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import { EUR, USD } from '../currencies/index.js';
|
|
2
|
+
import { defaultProductsValidation } from './defaultProductsValidation';
|
|
3
|
+
import { MissingPrice, OutOfStock } from './errorCodes';
|
|
4
|
+
describe('defaultProductsValidation', ()=>{
|
|
5
|
+
const currenciesConfig = {
|
|
6
|
+
defaultCurrency: 'USD',
|
|
7
|
+
supportedCurrencies: [
|
|
8
|
+
USD,
|
|
9
|
+
EUR
|
|
10
|
+
]
|
|
11
|
+
};
|
|
12
|
+
describe('currency validation', ()=>{
|
|
13
|
+
it('should throw error when currency is not provided', ()=>{
|
|
14
|
+
const product = {
|
|
15
|
+
id: 'product-1',
|
|
16
|
+
priceInUSD: 1000
|
|
17
|
+
};
|
|
18
|
+
expect(()=>{
|
|
19
|
+
defaultProductsValidation({
|
|
20
|
+
currenciesConfig,
|
|
21
|
+
currency: '',
|
|
22
|
+
product: product,
|
|
23
|
+
quantity: 1
|
|
24
|
+
});
|
|
25
|
+
}).toThrow('Currency must be provided for product validation.');
|
|
26
|
+
});
|
|
27
|
+
it('should throw error when currency is undefined', ()=>{
|
|
28
|
+
const product = {
|
|
29
|
+
id: 'product-1',
|
|
30
|
+
priceInUSD: 1000
|
|
31
|
+
};
|
|
32
|
+
expect(()=>{
|
|
33
|
+
defaultProductsValidation({
|
|
34
|
+
currenciesConfig,
|
|
35
|
+
currency: undefined,
|
|
36
|
+
product: product,
|
|
37
|
+
quantity: 1
|
|
38
|
+
});
|
|
39
|
+
}).toThrow('Currency must be provided for product validation.');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('variant validation', ()=>{
|
|
43
|
+
it('should validate variant price exists', ()=>{
|
|
44
|
+
const variant = {
|
|
45
|
+
id: 'variant-1',
|
|
46
|
+
priceInEUR: 900,
|
|
47
|
+
inventory: 10
|
|
48
|
+
};
|
|
49
|
+
expect(()=>{
|
|
50
|
+
defaultProductsValidation({
|
|
51
|
+
currenciesConfig,
|
|
52
|
+
currency: 'usd',
|
|
53
|
+
product: {},
|
|
54
|
+
quantity: 1,
|
|
55
|
+
variant: variant
|
|
56
|
+
});
|
|
57
|
+
}).toThrow('Variant with ID variant-1 does not have a price in usd.');
|
|
58
|
+
});
|
|
59
|
+
it('should pass when variant has price in requested currency', ()=>{
|
|
60
|
+
const variant = {
|
|
61
|
+
id: 'variant-1',
|
|
62
|
+
priceInUSD: 1000,
|
|
63
|
+
inventory: 10
|
|
64
|
+
};
|
|
65
|
+
expect(()=>{
|
|
66
|
+
defaultProductsValidation({
|
|
67
|
+
currenciesConfig,
|
|
68
|
+
currency: 'usd',
|
|
69
|
+
product: {},
|
|
70
|
+
quantity: 1,
|
|
71
|
+
variant: variant
|
|
72
|
+
});
|
|
73
|
+
}).not.toThrow();
|
|
74
|
+
});
|
|
75
|
+
it('should handle case-insensitive currency codes', ()=>{
|
|
76
|
+
const variant = {
|
|
77
|
+
id: 'variant-1',
|
|
78
|
+
priceInUSD: 1000,
|
|
79
|
+
inventory: 10
|
|
80
|
+
};
|
|
81
|
+
expect(()=>{
|
|
82
|
+
defaultProductsValidation({
|
|
83
|
+
currenciesConfig,
|
|
84
|
+
currency: 'USD',
|
|
85
|
+
product: {},
|
|
86
|
+
quantity: 1,
|
|
87
|
+
variant: variant
|
|
88
|
+
});
|
|
89
|
+
}).not.toThrow();
|
|
90
|
+
});
|
|
91
|
+
it('should throw error when variant inventory is 0', ()=>{
|
|
92
|
+
const variant = {
|
|
93
|
+
id: 'variant-1',
|
|
94
|
+
priceInUSD: 1000,
|
|
95
|
+
inventory: 0
|
|
96
|
+
};
|
|
97
|
+
expect(()=>{
|
|
98
|
+
defaultProductsValidation({
|
|
99
|
+
currenciesConfig,
|
|
100
|
+
currency: 'usd',
|
|
101
|
+
product: {},
|
|
102
|
+
quantity: 1,
|
|
103
|
+
variant: variant
|
|
104
|
+
});
|
|
105
|
+
}).toThrow('Variant with ID variant-1 is out of stock or does not have enough inventory.');
|
|
106
|
+
});
|
|
107
|
+
it('should throw error when variant inventory is less than quantity', ()=>{
|
|
108
|
+
const variant = {
|
|
109
|
+
id: 'variant-1',
|
|
110
|
+
priceInUSD: 1000,
|
|
111
|
+
inventory: 5
|
|
112
|
+
};
|
|
113
|
+
expect(()=>{
|
|
114
|
+
defaultProductsValidation({
|
|
115
|
+
currenciesConfig,
|
|
116
|
+
currency: 'usd',
|
|
117
|
+
product: {},
|
|
118
|
+
quantity: 10,
|
|
119
|
+
variant: variant
|
|
120
|
+
});
|
|
121
|
+
}).toThrow('Variant with ID variant-1 is out of stock or does not have enough inventory.');
|
|
122
|
+
});
|
|
123
|
+
it('should pass when variant inventory equals quantity', ()=>{
|
|
124
|
+
const variant = {
|
|
125
|
+
id: 'variant-1',
|
|
126
|
+
priceInUSD: 1000,
|
|
127
|
+
inventory: 5
|
|
128
|
+
};
|
|
129
|
+
expect(()=>{
|
|
130
|
+
defaultProductsValidation({
|
|
131
|
+
currenciesConfig,
|
|
132
|
+
currency: 'usd',
|
|
133
|
+
product: {},
|
|
134
|
+
quantity: 5,
|
|
135
|
+
variant: variant
|
|
136
|
+
});
|
|
137
|
+
}).not.toThrow();
|
|
138
|
+
});
|
|
139
|
+
it('should pass when variant inventory is greater than quantity', ()=>{
|
|
140
|
+
const variant = {
|
|
141
|
+
id: 'variant-1',
|
|
142
|
+
priceInUSD: 1000,
|
|
143
|
+
inventory: 10
|
|
144
|
+
};
|
|
145
|
+
expect(()=>{
|
|
146
|
+
defaultProductsValidation({
|
|
147
|
+
currenciesConfig,
|
|
148
|
+
currency: 'usd',
|
|
149
|
+
product: {},
|
|
150
|
+
quantity: 5,
|
|
151
|
+
variant: variant
|
|
152
|
+
});
|
|
153
|
+
}).not.toThrow();
|
|
154
|
+
});
|
|
155
|
+
it('should pass when variant has no inventory field (unlimited stock)', ()=>{
|
|
156
|
+
const variant = {
|
|
157
|
+
id: 'variant-1',
|
|
158
|
+
priceInUSD: 1000
|
|
159
|
+
};
|
|
160
|
+
expect(()=>{
|
|
161
|
+
defaultProductsValidation({
|
|
162
|
+
currenciesConfig,
|
|
163
|
+
currency: 'usd',
|
|
164
|
+
product: {},
|
|
165
|
+
quantity: 100,
|
|
166
|
+
variant: variant
|
|
167
|
+
});
|
|
168
|
+
}).not.toThrow();
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
describe('product validation', ()=>{
|
|
172
|
+
it('should validate product price exists', ()=>{
|
|
173
|
+
const product = {
|
|
174
|
+
id: 'product-1',
|
|
175
|
+
priceInEUR: 900,
|
|
176
|
+
inventory: 10
|
|
177
|
+
};
|
|
178
|
+
expect(()=>{
|
|
179
|
+
defaultProductsValidation({
|
|
180
|
+
currenciesConfig,
|
|
181
|
+
currency: 'usd',
|
|
182
|
+
product: product,
|
|
183
|
+
quantity: 1
|
|
184
|
+
});
|
|
185
|
+
}).toThrow('Product does not have a price in.');
|
|
186
|
+
});
|
|
187
|
+
it('should include error cause with MissingPrice code', ()=>{
|
|
188
|
+
const product = {
|
|
189
|
+
id: 'product-1',
|
|
190
|
+
priceInEUR: 900,
|
|
191
|
+
inventory: 10
|
|
192
|
+
};
|
|
193
|
+
try {
|
|
194
|
+
defaultProductsValidation({
|
|
195
|
+
currenciesConfig,
|
|
196
|
+
currency: 'usd',
|
|
197
|
+
product: product,
|
|
198
|
+
quantity: 1
|
|
199
|
+
});
|
|
200
|
+
} catch (error) {
|
|
201
|
+
expect(error.cause).toEqual({
|
|
202
|
+
code: MissingPrice,
|
|
203
|
+
codes: [
|
|
204
|
+
'product-1',
|
|
205
|
+
'usd'
|
|
206
|
+
]
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
it('should pass when product has price in requested currency', ()=>{
|
|
211
|
+
const product = {
|
|
212
|
+
id: 'product-1',
|
|
213
|
+
priceInUSD: 1000,
|
|
214
|
+
inventory: 10
|
|
215
|
+
};
|
|
216
|
+
expect(()=>{
|
|
217
|
+
defaultProductsValidation({
|
|
218
|
+
currenciesConfig,
|
|
219
|
+
currency: 'usd',
|
|
220
|
+
product: product,
|
|
221
|
+
quantity: 1
|
|
222
|
+
});
|
|
223
|
+
}).not.toThrow();
|
|
224
|
+
});
|
|
225
|
+
it('should throw error when product inventory is 0', ()=>{
|
|
226
|
+
const product = {
|
|
227
|
+
id: 'product-1',
|
|
228
|
+
priceInUSD: 1000,
|
|
229
|
+
inventory: 0
|
|
230
|
+
};
|
|
231
|
+
expect(()=>{
|
|
232
|
+
defaultProductsValidation({
|
|
233
|
+
currenciesConfig,
|
|
234
|
+
currency: 'usd',
|
|
235
|
+
product: product,
|
|
236
|
+
quantity: 1
|
|
237
|
+
});
|
|
238
|
+
}).toThrow('Product is out of stock or does not have enough inventory.');
|
|
239
|
+
});
|
|
240
|
+
it('should include error cause with OutOfStock code', ()=>{
|
|
241
|
+
const product = {
|
|
242
|
+
id: 'product-1',
|
|
243
|
+
priceInUSD: 1000,
|
|
244
|
+
inventory: 0
|
|
245
|
+
};
|
|
246
|
+
try {
|
|
247
|
+
defaultProductsValidation({
|
|
248
|
+
currenciesConfig,
|
|
249
|
+
currency: 'usd',
|
|
250
|
+
product: product,
|
|
251
|
+
quantity: 1
|
|
252
|
+
});
|
|
253
|
+
} catch (error) {
|
|
254
|
+
expect(error.cause).toEqual({
|
|
255
|
+
code: OutOfStock,
|
|
256
|
+
codes: [
|
|
257
|
+
'product-1'
|
|
258
|
+
]
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
it('should throw error when product inventory is less than quantity', ()=>{
|
|
263
|
+
const product = {
|
|
264
|
+
id: 'product-1',
|
|
265
|
+
priceInUSD: 1000,
|
|
266
|
+
inventory: 5
|
|
267
|
+
};
|
|
268
|
+
expect(()=>{
|
|
269
|
+
defaultProductsValidation({
|
|
270
|
+
currenciesConfig,
|
|
271
|
+
currency: 'usd',
|
|
272
|
+
product: product,
|
|
273
|
+
quantity: 10
|
|
274
|
+
});
|
|
275
|
+
}).toThrow('Product is out of stock or does not have enough inventory.');
|
|
276
|
+
});
|
|
277
|
+
it('should pass when product inventory equals quantity', ()=>{
|
|
278
|
+
const product = {
|
|
279
|
+
id: 'product-1',
|
|
280
|
+
priceInUSD: 1000,
|
|
281
|
+
inventory: 5
|
|
282
|
+
};
|
|
283
|
+
expect(()=>{
|
|
284
|
+
defaultProductsValidation({
|
|
285
|
+
currenciesConfig,
|
|
286
|
+
currency: 'usd',
|
|
287
|
+
product: product,
|
|
288
|
+
quantity: 5
|
|
289
|
+
});
|
|
290
|
+
}).not.toThrow();
|
|
291
|
+
});
|
|
292
|
+
it('should pass when product inventory is greater than quantity', ()=>{
|
|
293
|
+
const product = {
|
|
294
|
+
id: 'product-1',
|
|
295
|
+
priceInUSD: 1000,
|
|
296
|
+
inventory: 10
|
|
297
|
+
};
|
|
298
|
+
expect(()=>{
|
|
299
|
+
defaultProductsValidation({
|
|
300
|
+
currenciesConfig,
|
|
301
|
+
currency: 'usd',
|
|
302
|
+
product: product,
|
|
303
|
+
quantity: 5
|
|
304
|
+
});
|
|
305
|
+
}).not.toThrow();
|
|
306
|
+
});
|
|
307
|
+
it('should pass when product has no inventory field (unlimited stock)', ()=>{
|
|
308
|
+
const product = {
|
|
309
|
+
id: 'product-1',
|
|
310
|
+
priceInUSD: 1000
|
|
311
|
+
};
|
|
312
|
+
expect(()=>{
|
|
313
|
+
defaultProductsValidation({
|
|
314
|
+
currenciesConfig,
|
|
315
|
+
currency: 'usd',
|
|
316
|
+
product: product,
|
|
317
|
+
quantity: 100
|
|
318
|
+
});
|
|
319
|
+
}).not.toThrow();
|
|
320
|
+
});
|
|
321
|
+
it('should default quantity to 1 when not provided', ()=>{
|
|
322
|
+
const product = {
|
|
323
|
+
id: 'product-1',
|
|
324
|
+
priceInUSD: 1000,
|
|
325
|
+
inventory: 1
|
|
326
|
+
};
|
|
327
|
+
expect(()=>{
|
|
328
|
+
defaultProductsValidation({
|
|
329
|
+
currenciesConfig,
|
|
330
|
+
currency: 'usd',
|
|
331
|
+
product: product
|
|
332
|
+
});
|
|
333
|
+
}).not.toThrow();
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
describe('variant priority over product', ()=>{
|
|
337
|
+
it('should only validate variant when both product and variant are provided', ()=>{
|
|
338
|
+
const product = {
|
|
339
|
+
id: 'product-1',
|
|
340
|
+
priceInEUR: 900,
|
|
341
|
+
inventory: 0
|
|
342
|
+
};
|
|
343
|
+
const variant = {
|
|
344
|
+
id: 'variant-1',
|
|
345
|
+
priceInUSD: 1000,
|
|
346
|
+
inventory: 10
|
|
347
|
+
};
|
|
348
|
+
// Should not throw because variant validation takes priority
|
|
349
|
+
expect(()=>{
|
|
350
|
+
defaultProductsValidation({
|
|
351
|
+
currenciesConfig,
|
|
352
|
+
currency: 'usd',
|
|
353
|
+
product: product,
|
|
354
|
+
quantity: 1,
|
|
355
|
+
variant: variant
|
|
356
|
+
});
|
|
357
|
+
}).not.toThrow();
|
|
358
|
+
});
|
|
359
|
+
it('should not validate product inventory when variant is provided', ()=>{
|
|
360
|
+
const product = {
|
|
361
|
+
id: 'product-1',
|
|
362
|
+
priceInUSD: 1000,
|
|
363
|
+
inventory: 0
|
|
364
|
+
};
|
|
365
|
+
const variant = {
|
|
366
|
+
id: 'variant-1',
|
|
367
|
+
priceInUSD: 1000,
|
|
368
|
+
inventory: 10
|
|
369
|
+
};
|
|
370
|
+
expect(()=>{
|
|
371
|
+
defaultProductsValidation({
|
|
372
|
+
currenciesConfig,
|
|
373
|
+
currency: 'usd',
|
|
374
|
+
product: product,
|
|
375
|
+
quantity: 1,
|
|
376
|
+
variant: variant
|
|
377
|
+
});
|
|
378
|
+
}).not.toThrow();
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
//# sourceMappingURL=defaultProductsValidation.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/defaultProductsValidation.spec.ts"],"sourcesContent":["import type { CurrenciesConfig } from '../types/index.js'\n\nimport { EUR, USD } from '../currencies/index.js'\nimport { defaultProductsValidation } from './defaultProductsValidation'\nimport { MissingPrice, OutOfStock } from './errorCodes'\n\ndescribe('defaultProductsValidation', () => {\n const currenciesConfig: CurrenciesConfig = {\n defaultCurrency: 'USD',\n supportedCurrencies: [USD, EUR],\n }\n\n describe('currency validation', () => {\n it('should throw error when currency is not provided', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: '',\n product: product as any,\n quantity: 1,\n })\n }).toThrow('Currency must be provided for product validation.')\n })\n\n it('should throw error when currency is undefined', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: undefined as any,\n product: product as any,\n quantity: 1,\n })\n }).toThrow('Currency must be provided for product validation.')\n })\n })\n\n describe('variant validation', () => {\n it('should validate variant price exists', () => {\n const variant = {\n id: 'variant-1',\n priceInEUR: 900,\n inventory: 10,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: {} as any,\n quantity: 1,\n variant: variant as any,\n })\n }).toThrow('Variant with ID variant-1 does not have a price in usd.')\n })\n\n it('should pass when variant has price in requested currency', () => {\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 10,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: {} as any,\n quantity: 1,\n variant: variant as any,\n })\n }).not.toThrow()\n })\n\n it('should handle case-insensitive currency codes', () => {\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 10,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'USD',\n product: {} as any,\n quantity: 1,\n variant: variant as any,\n })\n }).not.toThrow()\n })\n\n it('should throw error when variant inventory is 0', () => {\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 0,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: {} as any,\n quantity: 1,\n variant: variant as any,\n })\n }).toThrow('Variant with ID variant-1 is out of stock or does not have enough inventory.')\n })\n\n it('should throw error when variant inventory is less than quantity', () => {\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 5,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: {} as any,\n quantity: 10,\n variant: variant as any,\n })\n }).toThrow('Variant with ID variant-1 is out of stock or does not have enough inventory.')\n })\n\n it('should pass when variant inventory equals quantity', () => {\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 5,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: {} as any,\n quantity: 5,\n variant: variant as any,\n })\n }).not.toThrow()\n })\n\n it('should pass when variant inventory is greater than quantity', () => {\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 10,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: {} as any,\n quantity: 5,\n variant: variant as any,\n })\n }).not.toThrow()\n })\n\n it('should pass when variant has no inventory field (unlimited stock)', () => {\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: {} as any,\n quantity: 100,\n variant: variant as any,\n })\n }).not.toThrow()\n })\n })\n\n describe('product validation', () => {\n it('should validate product price exists', () => {\n const product = {\n id: 'product-1',\n priceInEUR: 900,\n inventory: 10,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 1,\n })\n }).toThrow('Product does not have a price in.')\n })\n\n it('should include error cause with MissingPrice code', () => {\n const product = {\n id: 'product-1',\n priceInEUR: 900,\n inventory: 10,\n }\n\n try {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 1,\n })\n } catch (error: any) {\n expect(error.cause).toEqual({\n code: MissingPrice,\n codes: ['product-1', 'usd'],\n })\n }\n })\n\n it('should pass when product has price in requested currency', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 10,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 1,\n })\n }).not.toThrow()\n })\n\n it('should throw error when product inventory is 0', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 0,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 1,\n })\n }).toThrow('Product is out of stock or does not have enough inventory.')\n })\n\n it('should include error cause with OutOfStock code', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 0,\n }\n\n try {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 1,\n })\n } catch (error: any) {\n expect(error.cause).toEqual({\n code: OutOfStock,\n codes: ['product-1'],\n })\n }\n })\n\n it('should throw error when product inventory is less than quantity', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 5,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 10,\n })\n }).toThrow('Product is out of stock or does not have enough inventory.')\n })\n\n it('should pass when product inventory equals quantity', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 5,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 5,\n })\n }).not.toThrow()\n })\n\n it('should pass when product inventory is greater than quantity', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 10,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 5,\n })\n }).not.toThrow()\n })\n\n it('should pass when product has no inventory field (unlimited stock)', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 100,\n })\n }).not.toThrow()\n })\n\n it('should default quantity to 1 when not provided', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 1,\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n })\n }).not.toThrow()\n })\n })\n\n describe('variant priority over product', () => {\n it('should only validate variant when both product and variant are provided', () => {\n const product = {\n id: 'product-1',\n priceInEUR: 900, // Missing USD price\n inventory: 0, // Out of stock\n }\n\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 10,\n }\n\n // Should not throw because variant validation takes priority\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 1,\n variant: variant as any,\n })\n }).not.toThrow()\n })\n\n it('should not validate product inventory when variant is provided', () => {\n const product = {\n id: 'product-1',\n priceInUSD: 1000,\n inventory: 0, // Product out of stock\n }\n\n const variant = {\n id: 'variant-1',\n priceInUSD: 1000,\n inventory: 10, // But variant has stock\n }\n\n expect(() => {\n defaultProductsValidation({\n currenciesConfig,\n currency: 'usd',\n product: product as any,\n quantity: 1,\n variant: variant as any,\n })\n }).not.toThrow()\n })\n })\n})\n"],"names":["EUR","USD","defaultProductsValidation","MissingPrice","OutOfStock","describe","currenciesConfig","defaultCurrency","supportedCurrencies","it","product","id","priceInUSD","expect","currency","quantity","toThrow","undefined","variant","priceInEUR","inventory","not","error","cause","toEqual","code","codes"],"mappings":"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"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { USD } from '../currencies/index.js';
|
|
2
|
+
import { getCollectionSlugMap } from './getCollectionSlugMap';
|
|
3
|
+
describe('getCollectionSlugMap', ()=>{
|
|
4
|
+
const mockAccessConfig = {
|
|
5
|
+
adminOnlyFieldAccess: jest.fn(),
|
|
6
|
+
adminOrPublishedStatus: jest.fn(),
|
|
7
|
+
customerOnlyFieldAccess: jest.fn(),
|
|
8
|
+
isAdmin: jest.fn(),
|
|
9
|
+
isAuthenticated: jest.fn(),
|
|
10
|
+
isDocumentOwner: jest.fn(),
|
|
11
|
+
publicAccess: jest.fn()
|
|
12
|
+
};
|
|
13
|
+
const baseConfig = {
|
|
14
|
+
access: mockAccessConfig,
|
|
15
|
+
addresses: {
|
|
16
|
+
addressFields: []
|
|
17
|
+
},
|
|
18
|
+
carts: true,
|
|
19
|
+
currencies: {
|
|
20
|
+
defaultCurrency: 'USD',
|
|
21
|
+
supportedCurrencies: [
|
|
22
|
+
USD
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
customers: {
|
|
26
|
+
slug: 'users'
|
|
27
|
+
},
|
|
28
|
+
orders: true,
|
|
29
|
+
payments: {
|
|
30
|
+
paymentMethods: []
|
|
31
|
+
},
|
|
32
|
+
products: true,
|
|
33
|
+
transactions: true
|
|
34
|
+
};
|
|
35
|
+
it('should return default slug map when no overrides are provided', ()=>{
|
|
36
|
+
const result = getCollectionSlugMap({
|
|
37
|
+
sanitizedPluginConfig: baseConfig
|
|
38
|
+
});
|
|
39
|
+
expect(result).toEqual({
|
|
40
|
+
addresses: 'addresses',
|
|
41
|
+
carts: 'carts',
|
|
42
|
+
customers: 'users',
|
|
43
|
+
orders: 'orders',
|
|
44
|
+
products: 'products',
|
|
45
|
+
transactions: 'transactions',
|
|
46
|
+
variantOptions: 'variantOptions',
|
|
47
|
+
variants: 'variants',
|
|
48
|
+
variantTypes: 'variantTypes'
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
it('should use custom customers slug when provided', ()=>{
|
|
52
|
+
const config = {
|
|
53
|
+
...baseConfig,
|
|
54
|
+
customers: {
|
|
55
|
+
slug: 'custom-users'
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const result = getCollectionSlugMap({
|
|
59
|
+
sanitizedPluginConfig: config
|
|
60
|
+
});
|
|
61
|
+
expect(result.customers).toBe('custom-users');
|
|
62
|
+
});
|
|
63
|
+
it('should apply slugMap overrides', ()=>{
|
|
64
|
+
const config = {
|
|
65
|
+
...baseConfig,
|
|
66
|
+
slugMap: {
|
|
67
|
+
products: 'custom-products',
|
|
68
|
+
variants: 'custom-variants',
|
|
69
|
+
orders: 'custom-orders'
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const result = getCollectionSlugMap({
|
|
73
|
+
sanitizedPluginConfig: config
|
|
74
|
+
});
|
|
75
|
+
expect(result.products).toBe('custom-products');
|
|
76
|
+
expect(result.variants).toBe('custom-variants');
|
|
77
|
+
expect(result.orders).toBe('custom-orders');
|
|
78
|
+
// Other slugs should remain default
|
|
79
|
+
expect(result.addresses).toBe('addresses');
|
|
80
|
+
expect(result.carts).toBe('carts');
|
|
81
|
+
});
|
|
82
|
+
it('should prioritize slugMap overrides over customers slug', ()=>{
|
|
83
|
+
const config = {
|
|
84
|
+
...baseConfig,
|
|
85
|
+
customers: {
|
|
86
|
+
slug: 'my-users'
|
|
87
|
+
},
|
|
88
|
+
slugMap: {
|
|
89
|
+
customers: 'overridden-users'
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const result = getCollectionSlugMap({
|
|
93
|
+
sanitizedPluginConfig: config
|
|
94
|
+
});
|
|
95
|
+
expect(result.customers).toBe('overridden-users');
|
|
96
|
+
});
|
|
97
|
+
it('should handle partial slugMap overrides', ()=>{
|
|
98
|
+
const config = {
|
|
99
|
+
...baseConfig,
|
|
100
|
+
slugMap: {
|
|
101
|
+
products: 'items'
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const result = getCollectionSlugMap({
|
|
105
|
+
sanitizedPluginConfig: config
|
|
106
|
+
});
|
|
107
|
+
expect(result.products).toBe('items');
|
|
108
|
+
expect(result.addresses).toBe('addresses');
|
|
109
|
+
expect(result.carts).toBe('carts');
|
|
110
|
+
expect(result.customers).toBe('users');
|
|
111
|
+
expect(result.orders).toBe('orders');
|
|
112
|
+
expect(result.transactions).toBe('transactions');
|
|
113
|
+
expect(result.variants).toBe('variants');
|
|
114
|
+
expect(result.variantOptions).toBe('variantOptions');
|
|
115
|
+
expect(result.variantTypes).toBe('variantTypes');
|
|
116
|
+
});
|
|
117
|
+
it('should handle empty slugMap', ()=>{
|
|
118
|
+
const config = {
|
|
119
|
+
...baseConfig,
|
|
120
|
+
slugMap: {}
|
|
121
|
+
};
|
|
122
|
+
const result = getCollectionSlugMap({
|
|
123
|
+
sanitizedPluginConfig: config
|
|
124
|
+
});
|
|
125
|
+
expect(result).toEqual({
|
|
126
|
+
addresses: 'addresses',
|
|
127
|
+
carts: 'carts',
|
|
128
|
+
customers: 'users',
|
|
129
|
+
orders: 'orders',
|
|
130
|
+
products: 'products',
|
|
131
|
+
transactions: 'transactions',
|
|
132
|
+
variantOptions: 'variantOptions',
|
|
133
|
+
variants: 'variants',
|
|
134
|
+
variantTypes: 'variantTypes'
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
it('should handle undefined slugMap', ()=>{
|
|
138
|
+
const config = {
|
|
139
|
+
...baseConfig,
|
|
140
|
+
slugMap: undefined
|
|
141
|
+
};
|
|
142
|
+
const result = getCollectionSlugMap({
|
|
143
|
+
sanitizedPluginConfig: config
|
|
144
|
+
});
|
|
145
|
+
expect(result).toEqual({
|
|
146
|
+
addresses: 'addresses',
|
|
147
|
+
carts: 'carts',
|
|
148
|
+
customers: 'users',
|
|
149
|
+
orders: 'orders',
|
|
150
|
+
products: 'products',
|
|
151
|
+
transactions: 'transactions',
|
|
152
|
+
variantOptions: 'variantOptions',
|
|
153
|
+
variants: 'variants',
|
|
154
|
+
variantTypes: 'variantTypes'
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
//# sourceMappingURL=getCollectionSlugMap.spec.js.map
|