@labdigital/commercetools-mock 0.9.0 → 0.10.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.
Files changed (95) hide show
  1. package/README.md +8 -0
  2. package/dist/index.d.ts +18 -17
  3. package/dist/index.global.js +1751 -1664
  4. package/dist/index.global.js.map +1 -1
  5. package/dist/index.js +1773 -1684
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +1966 -1877
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +28 -20
  10. package/src/constants.ts +4 -2
  11. package/src/ctMock.ts +19 -84
  12. package/src/helpers.ts +9 -10
  13. package/src/index.test.ts +1 -1
  14. package/src/lib/haversine.ts +2 -2
  15. package/src/lib/masking.ts +3 -1
  16. package/src/lib/predicateParser.test.ts +16 -0
  17. package/src/lib/predicateParser.ts +94 -86
  18. package/src/lib/projectionSearchFilter.test.ts +28 -36
  19. package/src/lib/projectionSearchFilter.ts +86 -102
  20. package/src/oauth/store.ts +3 -3
  21. package/src/priceSelector.test.ts +18 -35
  22. package/src/priceSelector.ts +6 -9
  23. package/src/product-projection-search.ts +51 -57
  24. package/src/repositories/abstract.ts +85 -41
  25. package/src/repositories/cart-discount.ts +1 -1
  26. package/src/repositories/cart.ts +36 -31
  27. package/src/repositories/category.ts +17 -19
  28. package/src/repositories/channel.ts +1 -1
  29. package/src/repositories/custom-object.ts +35 -22
  30. package/src/repositories/customer-group.ts +1 -1
  31. package/src/repositories/customer.ts +39 -1
  32. package/src/repositories/discount-code.ts +1 -1
  33. package/src/repositories/errors.ts +9 -11
  34. package/src/repositories/extension.ts +13 -11
  35. package/src/repositories/helpers.ts +8 -13
  36. package/src/repositories/index.ts +59 -0
  37. package/src/repositories/inventory-entry.ts +1 -1
  38. package/src/repositories/order.ts +6 -6
  39. package/src/repositories/payment.ts +3 -3
  40. package/src/repositories/product-discount.ts +1 -1
  41. package/src/repositories/product-projection.ts +1 -0
  42. package/src/repositories/product-type.ts +29 -34
  43. package/src/repositories/product.ts +124 -80
  44. package/src/repositories/project.ts +10 -27
  45. package/src/repositories/shipping-method.ts +15 -17
  46. package/src/repositories/shopping-list.ts +2 -2
  47. package/src/repositories/state.ts +9 -9
  48. package/src/repositories/store.ts +2 -2
  49. package/src/repositories/subscription.ts +1 -1
  50. package/src/repositories/tax-category.ts +4 -4
  51. package/src/repositories/type.ts +12 -14
  52. package/src/repositories/zone.ts +5 -6
  53. package/src/server.ts +5 -0
  54. package/src/services/abstract.ts +44 -11
  55. package/src/services/cart-discount.ts +2 -3
  56. package/src/services/cart.test.ts +8 -10
  57. package/src/services/cart.ts +8 -11
  58. package/src/services/category.test.ts +1 -2
  59. package/src/services/category.ts +2 -3
  60. package/src/services/channel.ts +2 -3
  61. package/src/services/custom-object.test.ts +5 -5
  62. package/src/services/custom-object.ts +2 -3
  63. package/src/services/customer-group.ts +2 -3
  64. package/src/services/customer.test.ts +136 -0
  65. package/src/services/customer.ts +2 -3
  66. package/src/services/discount-code.ts +2 -3
  67. package/src/services/extension.ts +2 -3
  68. package/src/services/index.ts +74 -0
  69. package/src/services/inventory-entry.test.ts +8 -12
  70. package/src/services/inventory-entry.ts +2 -3
  71. package/src/services/my-cart.ts +3 -4
  72. package/src/services/my-customer.ts +2 -3
  73. package/src/services/my-order.ts +3 -4
  74. package/src/services/my-payment.ts +2 -3
  75. package/src/services/order.test.ts +4 -6
  76. package/src/services/order.ts +2 -3
  77. package/src/services/payment.ts +2 -3
  78. package/src/services/product-discount.ts +2 -3
  79. package/src/services/product-projection.test.ts +76 -8
  80. package/src/services/product-projection.ts +2 -3
  81. package/src/services/product-type.ts +2 -3
  82. package/src/services/product.test.ts +199 -89
  83. package/src/services/product.ts +2 -3
  84. package/src/services/project.ts +3 -3
  85. package/src/services/shipping-method.ts +2 -3
  86. package/src/services/shopping-list.ts +2 -3
  87. package/src/services/state.ts +2 -3
  88. package/src/services/store.test.ts +11 -2
  89. package/src/services/store.ts +2 -3
  90. package/src/services/subscription.ts +2 -3
  91. package/src/services/tax-category.ts +2 -3
  92. package/src/services/type.ts +2 -3
  93. package/src/services/zone.ts +2 -3
  94. package/src/storage.ts +23 -30
  95. package/src/types.ts +46 -6
@@ -31,7 +31,7 @@ export const matchesPredicate = (
31
31
  }
32
32
 
33
33
  if (Array.isArray(predicate)) {
34
- return predicate.every(item => {
34
+ return predicate.every((item) => {
35
35
  const func = generateMatchFunc(item)
36
36
  return func(target, variables || {})
37
37
  })
@@ -45,22 +45,21 @@ export const parseQueryExpression = (
45
45
  predicate: string | string[]
46
46
  ): MatchFunc => {
47
47
  if (Array.isArray(predicate)) {
48
- const callbacks = predicate.map(item => generateMatchFunc(item))
49
- return (target: any, variables: VariableMap) => {
50
- return callbacks.every(callback => callback(target, variables))
51
- }
48
+ const callbacks = predicate.map((item) => generateMatchFunc(item))
49
+ return (target: any, variables: VariableMap) =>
50
+ callbacks.every((callback) => callback(target, variables))
52
51
  } else {
53
52
  return generateMatchFunc(predicate)
54
53
  }
55
54
  }
56
55
 
57
- type Symbol = {
56
+ type TypeSymbol = {
58
57
  type: 'var' | 'boolean' | 'string' | 'float' | 'int' | 'identifier'
59
58
  value: any
60
59
  pos?: ITokenPosition
61
60
  }
62
61
 
63
- const validateSymbol = (val: Symbol) => {
62
+ const validateSymbol = (val: TypeSymbol) => {
64
63
  if (!val.type) {
65
64
  throw new PredicateError('Internal error')
66
65
  }
@@ -76,7 +75,7 @@ const validateSymbol = (val: Symbol) => {
76
75
  }
77
76
  }
78
77
 
79
- const resolveSymbol = (val: Symbol, vars: VariableMap): any => {
78
+ const resolveSymbol = (val: TypeSymbol, vars: VariableMap): any => {
80
79
  if (val.type === 'var') {
81
80
  if (!(val.value in vars)) {
82
81
  throw new PredicateError(`Missing parameter value for ${val.value}`)
@@ -87,7 +86,7 @@ const resolveSymbol = (val: Symbol, vars: VariableMap): any => {
87
86
  return val.value
88
87
  }
89
88
 
90
- const resolveValue = (obj: any, val: Symbol): any => {
89
+ const resolveValue = (obj: any, val: TypeSymbol): any => {
91
90
  if (val.type !== 'identifier') {
92
91
  throw new PredicateError('Internal error')
93
92
  }
@@ -95,8 +94,8 @@ const resolveValue = (obj: any, val: Symbol): any => {
95
94
  if (!(val.value in obj)) {
96
95
  if (Array.isArray(obj)) {
97
96
  return Object.values(obj)
98
- .filter(v => val.value in v)
99
- .map(v => v[val.value])
97
+ .filter((v) => val.value in v)
98
+ .map((v) => v[val.value])
100
99
  }
101
100
  throw new PredicateError(`The field '${val.value}' does not exist.`)
102
101
  }
@@ -104,8 +103,8 @@ const resolveValue = (obj: any, val: Symbol): any => {
104
103
  return obj[val.value]
105
104
  }
106
105
 
107
- const getLexer = (value: string) => {
108
- return new perplex(value)
106
+ const getLexer = (value: string) =>
107
+ new perplex(value)
109
108
 
110
109
  .token('AND', /and(?![-_a-z0-9]+)/i)
111
110
  .token('OR', /or(?![-_a-z0-9]+)/i)
@@ -124,6 +123,7 @@ const getLexer = (value: string) => {
124
123
  .token('FLOAT', /\d+\.\d+/)
125
124
  .token('INT', /\d+/)
126
125
  .token('VARIABLE', /:([-_A-Za-z0-9]+)/)
126
+ .token('BOOLEAN', /(true|false)/)
127
127
  .token('IDENTIFIER', /[-_A-Za-z0-9]+/)
128
128
  .token('STRING', /"((?:\\.|[^"\\])*)"/)
129
129
  .token('STRING', /'((?:\\.|[^'\\])*)'/)
@@ -139,7 +139,6 @@ const getLexer = (value: string) => {
139
139
  .token('=', '=')
140
140
  .token('"', '"')
141
141
  .token('WS', /\s+/, true) // skip
142
- }
143
142
 
144
143
  /**
145
144
  * This function converts a query expression in to a callable which returns a
@@ -152,67 +151,82 @@ const generateMatchFunc = (predicate: string): MatchFunc => {
152
151
  const lexer = getLexer(predicate)
153
152
  const parser = new Parser(lexer)
154
153
  .builder()
155
- .nud('IDENTIFIER', 100, t => {
156
- return {
157
- type: 'identifier',
158
- value: t.token.match,
159
- pos: t.token.strpos(),
160
- } as Symbol
161
- })
162
- .nud('VARIABLE', 100, t => {
163
- return {
164
- type: 'var',
165
- // @ts-ignore
166
- value: t.token.groups[1],
167
- pos: t.token.strpos(),
168
- } as Symbol
169
- })
170
- .nud('STRING', 100, t => {
171
- return {
172
- type: 'string',
173
- // @ts-ignore
174
- value: t.token.groups[1],
175
- pos: t.token.strpos(),
176
- } as Symbol
177
- })
178
- .nud('INT', 1, t => {
179
- return {
180
- type: 'int',
181
- value: parseInt(t.token.match, 10),
182
- pos: t.token.strpos(),
183
- } as Symbol
184
- })
185
- .nud('FLOAT', 1, t => {
186
- return {
187
- type: 'float',
188
- value: parseFloat(t.token.match),
189
- pos: t.token.strpos(),
190
- } as Symbol
191
- })
154
+ .nud(
155
+ 'IDENTIFIER',
156
+ 100,
157
+ (t) =>
158
+ ({
159
+ type: 'identifier',
160
+ value: t.token.match,
161
+ pos: t.token.strpos(),
162
+ } as TypeSymbol)
163
+ )
164
+ .nud(
165
+ 'BOOLEAN',
166
+ 1,
167
+ (t) =>
168
+ ({
169
+ type: 'boolean',
170
+ value: t.token.match === 'true' ? true : false,
171
+ pos: t.token.strpos(),
172
+ } as TypeSymbol)
173
+ )
174
+ .nud(
175
+ 'VARIABLE',
176
+ 100,
177
+ (t) =>
178
+ ({
179
+ type: 'var',
180
+ // @ts-ignore
181
+ value: t.token.groups[1],
182
+ pos: t.token.strpos(),
183
+ } as TypeSymbol)
184
+ )
185
+ .nud(
186
+ 'STRING',
187
+ 100,
188
+ (t) =>
189
+ ({
190
+ type: 'string',
191
+ // @ts-ignore
192
+ value: t.token.groups[1],
193
+ pos: t.token.strpos(),
194
+ } as TypeSymbol)
195
+ )
196
+ .nud(
197
+ 'INT',
198
+ 1,
199
+ (t) =>
200
+ ({
201
+ type: 'int',
202
+ value: parseInt(t.token.match, 10),
203
+ pos: t.token.strpos(),
204
+ } as TypeSymbol)
205
+ )
206
+ .nud(
207
+ 'FLOAT',
208
+ 1,
209
+ (t) =>
210
+ ({
211
+ type: 'float',
212
+ value: parseFloat(t.token.match),
213
+ pos: t.token.strpos(),
214
+ } as TypeSymbol)
215
+ )
192
216
  .nud('NOT', 100, ({ bp }) => {
193
217
  const expr = parser.parse({ terminals: [bp - 1] })
194
- return (obj: any) => {
195
- return !expr(obj)
196
- }
197
- })
198
- .nud('EMPTY', 10, ({ bp }) => {
199
- return 'empty'
200
- })
201
- .nud('DEFINED', 10, ({ bp }) => {
202
- return 'defined'
218
+ return (obj: any) => !expr(obj)
203
219
  })
220
+ .nud('EMPTY', 10, ({ bp }) => 'empty')
221
+ .nud('DEFINED', 10, ({ bp }) => 'defined')
204
222
 
205
223
  .led('AND', 5, ({ left, bp }) => {
206
224
  const expr = parser.parse({ terminals: [bp - 1] })
207
- return (obj: any) => {
208
- return left(obj) && expr(obj)
209
- }
225
+ return (obj: any) => left(obj) && expr(obj)
210
226
  })
211
227
  .led('OR', 5, ({ left, token, bp }) => {
212
228
  const expr = parser.parse({ terminals: [bp - 1] })
213
- return (obj: any, vars: object) => {
214
- return left(obj, vars) || expr(obj, vars)
215
- }
229
+ return (obj: any, vars: object) => left(obj, vars) || expr(obj, vars)
216
230
  })
217
231
  .led('COMMA', 1, ({ left, token, bp }) => {
218
232
  const expr: any = parser.parse({ terminals: [bp - 1] })
@@ -222,7 +236,7 @@ const generateMatchFunc = (predicate: string): MatchFunc => {
222
236
  return [left, expr]
223
237
  }
224
238
  })
225
- .nud('(', 100, t => {
239
+ .nud('(', 100, (t) => {
226
240
  const expr: any = parser.parse({ terminals: [')'] })
227
241
  return expr
228
242
  })
@@ -246,7 +260,7 @@ const generateMatchFunc = (predicate: string): MatchFunc => {
246
260
  const resolvedValue = resolveValue(obj, left)
247
261
  const resolvedSymbol = resolveSymbol(expr, vars)
248
262
  if (Array.isArray(resolvedValue)) {
249
- return !!resolvedValue.some(elem => elem === resolvedSymbol)
263
+ return !!resolvedValue.some((elem) => elem === resolvedSymbol)
250
264
  }
251
265
  return resolvedValue === resolvedSymbol
252
266
  }
@@ -254,42 +268,36 @@ const generateMatchFunc = (predicate: string): MatchFunc => {
254
268
  .led('!=', 20, ({ left, bp }) => {
255
269
  const expr = parser.parse({ terminals: [bp - 1] })
256
270
  validateSymbol(expr)
257
-
258
- return (obj: any, vars: VariableMap) => {
259
- return resolveValue(obj, left) !== resolveSymbol(expr, vars)
260
- }
271
+ return (obj: any, vars: VariableMap) =>
272
+ resolveValue(obj, left) !== resolveSymbol(expr, vars)
261
273
  })
262
274
  .led('>', 20, ({ left, bp }) => {
263
275
  const expr = parser.parse({ terminals: [bp - 1] })
264
276
  validateSymbol(expr)
265
277
 
266
- return (obj: any, vars: object) => {
267
- return resolveValue(obj, left) > resolveSymbol(expr, vars)
268
- }
278
+ return (obj: any, vars: object) =>
279
+ resolveValue(obj, left) > resolveSymbol(expr, vars)
269
280
  })
270
281
  .led('>=', 20, ({ left, bp }) => {
271
282
  const expr = parser.parse({ terminals: [bp - 1] })
272
283
  validateSymbol(expr)
273
284
 
274
- return (obj: any, vars: object) => {
275
- return resolveValue(obj, left) >= resolveSymbol(expr, vars)
276
- }
285
+ return (obj: any, vars: object) =>
286
+ resolveValue(obj, left) >= resolveSymbol(expr, vars)
277
287
  })
278
288
  .led('<', 20, ({ left, bp }) => {
279
289
  const expr = parser.parse({ terminals: [bp - 1] })
280
290
  validateSymbol(expr)
281
291
 
282
- return (obj: any, vars: object) => {
283
- return resolveValue(obj, left) < resolveSymbol(expr, vars)
284
- }
292
+ return (obj: any, vars: object) =>
293
+ resolveValue(obj, left) < resolveSymbol(expr, vars)
285
294
  })
286
295
  .led('<=', 20, ({ left, bp }) => {
287
296
  const expr = parser.parse({ terminals: [bp - 1] })
288
297
  validateSymbol(expr)
289
298
 
290
- return (obj: any, vars: object) => {
291
- return resolveValue(obj, left) <= resolveSymbol(expr, vars)
292
- }
299
+ return (obj: any, vars: object) =>
300
+ resolveValue(obj, left) <= resolveSymbol(expr, vars)
293
301
  })
294
302
  .led('IS', 20, ({ left, bp }) => {
295
303
  let invert = false
@@ -343,7 +351,7 @@ const generateMatchFunc = (predicate: string): MatchFunc => {
343
351
  symbols = [expr]
344
352
  }
345
353
 
346
- const inValues = symbols.map((item: Symbol) =>
354
+ const inValues = symbols.map((item: TypeSymbol) =>
347
355
  resolveSymbol(item, vars)
348
356
  )
349
357
  return inValues.includes(resolveValue(obj, left))
@@ -412,7 +420,7 @@ const generateMatchFunc = (predicate: string): MatchFunc => {
412
420
  )
413
421
  }
414
422
 
415
- const array = expr.map((item: Symbol) => resolveSymbol(item, vars))
423
+ const array = expr.map((item: TypeSymbol) => resolveSymbol(item, vars))
416
424
  if (keyword.type === 'ALL') {
417
425
  return array.every((item: any) => value.includes(item))
418
426
  } else {
@@ -1,9 +1,19 @@
1
- import { Product, ProductData } from '@commercetools/platform-sdk'
1
+ import { ProductProjection } from '@commercetools/platform-sdk'
2
+ import { cloneObject } from '../helpers'
2
3
  import { applyPriceSelector } from '../priceSelector'
3
4
  import { parseFilterExpression } from './projectionSearchFilter'
4
5
 
5
6
  describe('Search filter', () => {
6
- const productData: ProductData = {
7
+ const exampleProduct: ProductProjection = {
8
+ id: '7401d82f-1378-47ba-996a-85beeb87ac87',
9
+ version: 2,
10
+ createdAt: '2022-07-22T10:02:40.851Z',
11
+ lastModifiedAt: '2022-07-22T10:02:44.427Z',
12
+ key: 'test-product',
13
+ productType: {
14
+ typeId: 'product-type',
15
+ id: 'b9b4b426-938b-4ccb-9f36-c6f933e8446e',
16
+ },
7
17
  name: {
8
18
  'nl-NL': 'test',
9
19
  },
@@ -47,27 +57,9 @@ describe('Search filter', () => {
47
57
  },
48
58
  }
49
59
 
50
- const exampleProduct: Product = {
51
- id: '7401d82f-1378-47ba-996a-85beeb87ac87',
52
- version: 2,
53
- createdAt: '2022-07-22T10:02:40.851Z',
54
- lastModifiedAt: '2022-07-22T10:02:44.427Z',
55
- key: 'test-product',
56
- productType: {
57
- typeId: 'product-type',
58
- id: 'b9b4b426-938b-4ccb-9f36-c6f933e8446e',
59
- },
60
- masterData: {
61
- current: productData,
62
- staged: productData,
63
- published: true,
64
- hasStagedChanges: false,
65
- },
66
- }
67
-
68
- const match = (pattern: string, product?: Product) => {
69
- const matchFunc = parseFilterExpression(pattern, false)
70
- const clone = JSON.parse(JSON.stringify(product ?? exampleProduct))
60
+ const match = (pattern: string, product?: ProductProjection) => {
61
+ const matchFunc = parseFilterExpression(pattern)
62
+ const clone = cloneObject(product ?? exampleProduct)
71
63
  return {
72
64
  isMatch: matchFunc(clone, false),
73
65
  product: clone,
@@ -81,7 +73,9 @@ describe('Search filter', () => {
81
73
  })
82
74
 
83
75
  test('by product type id', async () => {
84
- expect(match(`productType.id:"b9b4b426-938b-4ccb-9f36-c6f933e8446e"`).isMatch).toBeTruthy()
76
+ expect(
77
+ match(`productType.id:"b9b4b426-938b-4ccb-9f36-c6f933e8446e"`).isMatch
78
+ ).toBeTruthy()
85
79
  })
86
80
 
87
81
  test('by SKU', async () => {
@@ -129,20 +123,22 @@ describe('Search filter', () => {
129
123
 
130
124
  test('by price range - or', async () => {
131
125
  expect(
132
- match(`variants.price.centAmount:range (2 TO 1500 ), (1500 TO 3000), (3000 TO 6000)`).isMatch
126
+ match(
127
+ `variants.price.centAmount:range (2 TO 1500 ), (1500 TO 3000), (3000 TO 6000)`
128
+ ).isMatch
133
129
  ).toBeTruthy()
134
130
  })
135
131
 
136
132
  test('by scopedPrice range', async () => {
137
133
  let result
138
- let products: Product[]
134
+ let products: ProductProjection[]
139
135
 
140
136
  // No currency given
141
137
  result = match(`variants.scopedPrice.value.centAmount:range (1500 TO 2000)`)
142
138
  expect(result.isMatch).toBeFalsy()
143
139
 
144
140
  // Currency match
145
- products = [JSON.parse(JSON.stringify(exampleProduct))]
141
+ products = [cloneObject(exampleProduct)]
146
142
  applyPriceSelector(products, { currency: 'EUR' })
147
143
 
148
144
  result = match(
@@ -151,18 +147,14 @@ describe('Search filter', () => {
151
147
  )
152
148
  expect(result.isMatch).toBeTruthy()
153
149
  expect(result.product).toMatchObject({
154
- masterData: {
155
- current: {
156
- masterVariant: {
157
- sku: 'MYSKU',
158
- scopedPrice: { value: { centAmount: 1789 } },
159
- },
160
- },
150
+ masterVariant: {
151
+ sku: 'MYSKU',
152
+ scopedPrice: { value: { centAmount: 1789 } },
161
153
  },
162
154
  })
163
155
 
164
156
  // Currency mismatch
165
- products = [JSON.parse(JSON.stringify(exampleProduct))]
157
+ products = [cloneObject(exampleProduct)]
166
158
  applyPriceSelector(products, { currency: 'USD' })
167
159
 
168
160
  result = match(
@@ -172,7 +164,7 @@ describe('Search filter', () => {
172
164
  expect(result.isMatch).toBeFalsy()
173
165
 
174
166
  // Price has no country so mismatch
175
- products = [JSON.parse(JSON.stringify(exampleProduct))]
167
+ products = [cloneObject(exampleProduct)]
176
168
  applyPriceSelector(products, { currency: 'EUR', country: 'NL' })
177
169
  result = match(
178
170
  `variants.scopedPrice.value.centAmount:range (1500 TO 2000)`,