@labdigital/commercetools-mock 0.7.0 → 0.9.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.
@@ -65,8 +65,18 @@ export abstract class AbstractRepository {
65
65
  if (!deepEqual(modifiedResource, resource)) {
66
66
  this.save(context, modifiedResource)
67
67
  }
68
- return modifiedResource
68
+
69
+ const result = this.postProcessResource(modifiedResource)
70
+ if (!result) {
71
+ throw new Error("invalid post process action")
72
+ }
73
+ return result
74
+ }
75
+
76
+ postProcessResource(resource: BaseResource | null): BaseResource | null {
77
+ return resource
69
78
  }
79
+
70
80
  }
71
81
 
72
82
  export abstract class AbstractResourceRepository extends AbstractRepository {
@@ -79,12 +89,17 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
79
89
  }
80
90
 
81
91
  query(context: RepositoryContext, params: QueryParams = {}) {
82
- return this._storage.query(context.projectKey, this.getTypeId(), {
92
+ const result = this._storage.query(context.projectKey, this.getTypeId(), {
83
93
  expand: params.expand,
84
94
  where: params.where,
85
95
  offset: params.offset,
86
96
  limit: params.limit,
87
97
  })
98
+
99
+ // @ts-ignore
100
+ result.results = result.results.map(this.postProcessResource)
101
+
102
+ return result
88
103
  }
89
104
 
90
105
  get(
@@ -92,7 +107,8 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
92
107
  id: string,
93
108
  params: GetParams = {}
94
109
  ): BaseResource | null {
95
- return this._storage.get(context.projectKey, this.getTypeId(), id, params)
110
+ const resource = this._storage.get(context.projectKey, this.getTypeId(), id, params)
111
+ return this.postProcessResource(resource)
96
112
  }
97
113
 
98
114
  getByKey(
@@ -100,12 +116,13 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
100
116
  key: string,
101
117
  params: GetParams = {}
102
118
  ): BaseResource | null {
103
- return this._storage.getByKey(
119
+ const resource = this._storage.getByKey(
104
120
  context.projectKey,
105
121
  this.getTypeId(),
106
122
  key,
107
123
  params
108
124
  )
125
+ return this.postProcessResource(resource)
109
126
  }
110
127
 
111
128
  delete(
@@ -113,12 +130,13 @@ export abstract class AbstractResourceRepository extends AbstractRepository {
113
130
  id: string,
114
131
  params: GetParams = {}
115
132
  ): BaseResource | null {
116
- return this._storage.delete(
133
+ const resource = this._storage.delete(
117
134
  context.projectKey,
118
135
  this.getTypeId(),
119
136
  id,
120
137
  params
121
138
  )
139
+ return this.postProcessResource(resource)
122
140
  }
123
141
 
124
142
  save(context: RepositoryContext, resource: BaseResource) {
@@ -10,13 +10,30 @@ import {
10
10
  } from '@commercetools/platform-sdk'
11
11
  import { Writable } from '../types'
12
12
  import { getBaseResourceProperties } from '../helpers'
13
- import { AbstractResourceRepository, RepositoryContext } from './abstract'
13
+ import { AbstractResourceRepository, GetParams, RepositoryContext } from './abstract'
14
+ import { maskSecretValue } from '../lib/masking'
14
15
 
15
16
  export class ExtensionRepository extends AbstractResourceRepository {
16
17
  getTypeId(): ReferenceTypeId {
17
18
  return 'extension'
18
19
  }
19
20
 
21
+ postProcessResource(resource: Extension) {
22
+ if (resource) {
23
+ if (resource.destination.type === "HTTP" &&
24
+ resource.destination.authentication?.type === "AuthorizationHeader"
25
+ ) {
26
+ return maskSecretValue(
27
+ resource, 'destination.authentication.headerValue')
28
+ }
29
+ else if (resource.destination.type == "AWSLambda") {
30
+ return maskSecretValue(
31
+ resource, 'destination.accessSecret')
32
+ }
33
+ }
34
+ return resource
35
+ }
36
+
20
37
  create(context: RepositoryContext, draft: ExtensionDraft): Extension {
21
38
  const resource: Extension = {
22
39
  ...getBaseResourceProperties(),
@@ -75,10 +75,44 @@ export const createPrice = (draft: PriceDraft): Price => {
75
75
  }
76
76
 
77
77
  export const createTypedMoney = (value: Money): TypedMoney => {
78
+
79
+ // Taken from https://docs.adyen.com/development-resources/currency-codes
80
+ let fractionDigits = 2
81
+ switch (value.currencyCode.toUpperCase()) {
82
+ case 'BHD':
83
+ case 'IQD':
84
+ case 'JOD':
85
+ case 'KWD':
86
+ case 'LYD':
87
+ case 'OMR':
88
+ case 'TND':
89
+ fractionDigits = 3
90
+ break
91
+ case 'CVE':
92
+ case 'DJF':
93
+ case 'GNF':
94
+ case 'IDR':
95
+ case 'JPY':
96
+ case 'KMF':
97
+ case 'KRW':
98
+ case 'PYG':
99
+ case 'RWF':
100
+ case 'UGX':
101
+ case 'VND':
102
+ case 'VUV':
103
+ case 'XAF':
104
+ case 'XOF':
105
+ case 'XPF':
106
+ fractionDigits = 0
107
+ break
108
+ default:
109
+ fractionDigits = 2
110
+ }
111
+
78
112
  return {
79
113
  type: 'centPrecision',
80
- fractionDigits: 2,
81
114
  ...value,
115
+ fractionDigits: fractionDigits,
82
116
  }
83
117
  }
84
118
 
@@ -135,10 +169,10 @@ export const getReferenceFromResourceIdentifier = <T extends Reference>(
135
169
  )
136
170
  }
137
171
 
138
- return ({
172
+ return {
139
173
  typeId: resourceIdentifier.typeId,
140
174
  id: resource?.id,
141
- } as unknown) as T
175
+ } as unknown as T
142
176
  }
143
177
 
144
178
  export const getRepositoryContext = (request: Request): RepositoryContext => {
@@ -39,6 +39,7 @@ export class ProductProjectionRepository extends AbstractResourceRepository {
39
39
  const results = this._searchService.search(context.projectKey, {
40
40
  filter: QueryParamsAsArray(query.filter),
41
41
  'filter.query': QueryParamsAsArray(query['filter.query']),
42
+ facet: QueryParamsAsArray(query.facet),
42
43
  offset: query.offset ? Number(query.offset) : undefined,
43
44
  limit: query.limit ? Number(query.limit) : undefined,
44
45
  expand: QueryParamsAsArray(query.expand),
@@ -23,11 +23,16 @@ import { maskSecretValue } from '../lib/masking'
23
23
  export class ProjectRepository extends AbstractRepository {
24
24
  get(context: RepositoryContext): Project | null {
25
25
  const resource = this._storage.getProject(context.projectKey)
26
- const masked = maskSecretValue<Project>(
27
- resource,
28
- 'externalOAuth.authorizationHeader'
29
- )
30
- return masked
26
+ return this.postProcessResource(resource)
27
+ }
28
+
29
+ postProcessResource(resource: any): any {
30
+ if (resource) {
31
+ return maskSecretValue(
32
+ resource, 'externalOAuth.authorizationHeader')
33
+ }
34
+ return resource
35
+
31
36
  }
32
37
 
33
38
  save(context: RepositoryContext, resource: Project) {
@@ -2,12 +2,14 @@ import { getBaseResourceProperties } from '../helpers'
2
2
  import { getReferenceFromResourceIdentifier } from './helpers'
3
3
  import {
4
4
  ReferenceTypeId,
5
+ StateReference,
5
6
  State,
6
7
  StateChangeKeyAction,
7
8
  StateDraft,
8
9
  StateSetDescriptionAction,
9
10
  StateSetNameAction,
10
11
  StateSetRolesAction,
12
+ StateSetTransitionsAction,
11
13
  StateUpdateAction,
12
14
  } from '@commercetools/platform-sdk'
13
15
  import { AbstractResourceRepository, RepositoryContext } from './abstract'
@@ -71,5 +73,17 @@ export class StateRepository extends AbstractResourceRepository {
71
73
  ) => {
72
74
  resource.roles = roles
73
75
  },
76
+ setTransitions: (
77
+ context: RepositoryContext,
78
+ resource: Writable<State>,
79
+ { transitions }: StateSetTransitionsAction
80
+ ) => {
81
+ resource.transitions = transitions?.map((resourceId): StateReference => {
82
+ return {
83
+ id: resourceId.id || "",
84
+ typeId: "state",
85
+ }
86
+ })
87
+ }
74
88
  }
75
89
  }
@@ -50,10 +50,29 @@ beforeEach(async () => {
50
50
  attributes: [
51
51
  {
52
52
  name: 'number',
53
- value: '1' as any,
53
+ value: 4 as any,
54
54
  },
55
55
  ],
56
56
  },
57
+ variants: [
58
+ {
59
+ sku: 'my-other-sku',
60
+ prices: [
61
+ {
62
+ value: {
63
+ currencyCode: 'EUR',
64
+ centAmount: 91789,
65
+ },
66
+ },
67
+ ],
68
+ attributes: [
69
+ {
70
+ name: 'number',
71
+ value: 50 as any,
72
+ },
73
+ ],
74
+ },
75
+ ],
57
76
  name: {
58
77
  'nl-NL': 'test product',
59
78
  },
@@ -96,7 +115,26 @@ beforeEach(async () => {
96
115
  images: [],
97
116
  attributes: productDraft.masterVariant?.attributes,
98
117
  },
99
- variants: [],
118
+ variants: [
119
+ {
120
+ id: 2,
121
+ sku: 'my-other-sku',
122
+ prices: [
123
+ {
124
+ id: product.masterData.current.variants[0].prices[0].id,
125
+ value: {
126
+ type: 'centPrecision',
127
+ currencyCode: 'EUR',
128
+ centAmount: 91789,
129
+ fractionDigits: 2,
130
+ },
131
+ },
132
+ ],
133
+ assets: [],
134
+ images: [],
135
+ attributes: productDraft.variants![0].attributes,
136
+ },
137
+ ],
100
138
  name: productDraft.name,
101
139
  slug: productDraft.slug,
102
140
  categories: [],
@@ -210,7 +248,7 @@ describe('Product Projection Search - Filters', () => {
210
248
  const response = await supertest(ctMock.app)
211
249
  .get('/dummy/product-projections/search')
212
250
  .query({
213
- filter: ['variants.attributes.number:range(2 TO 10)'],
251
+ filter: ['variants.attributes.number:range(5 TO 10)'],
214
252
  })
215
253
 
216
254
  const result: ProductProjectionPagedSearchResponse = response.body
@@ -220,3 +258,132 @@ describe('Product Projection Search - Filters', () => {
220
258
  })
221
259
  })
222
260
  })
261
+
262
+ describe('Product Projection Search - Facets', () => {
263
+ test('termExpr - variants.attributes.number', async () => {
264
+ const response = await supertest(ctMock.app)
265
+ .get('/dummy/product-projections/search')
266
+ .query({
267
+ facet: ['variants.attributes.number'],
268
+ })
269
+
270
+ const result: ProductProjectionPagedSearchResponse = response.body
271
+ expect(result).toMatchObject({
272
+ count: 1,
273
+ facets: {
274
+ 'variants.attributes.number': {
275
+ type: 'terms',
276
+ dataType: 'text',
277
+ missing: 0,
278
+ total: 2,
279
+ terms: [
280
+ {
281
+ term: '4.0',
282
+ count: 1,
283
+ },
284
+ {
285
+ term: '50.0',
286
+ count: 1,
287
+ },
288
+ ],
289
+ },
290
+ },
291
+ results: [
292
+ {
293
+ masterVariant: { sku: 'my-sku' },
294
+ },
295
+ ],
296
+ })
297
+ })
298
+
299
+ test('filterExpr - variants.attributes.number', async () => {
300
+ const response = await supertest(ctMock.app)
301
+ .get('/dummy/product-projections/search')
302
+ .query({
303
+ facet: ['variants.attributes.number:3,4'],
304
+ })
305
+
306
+ const result: ProductProjectionPagedSearchResponse = response.body
307
+ expect(result).toMatchObject({
308
+ count: 1,
309
+ facets: {
310
+ 'variants.attributes.number': {
311
+ type: 'filter',
312
+ count: 1,
313
+ },
314
+ },
315
+ results: [
316
+ {
317
+ masterVariant: { sku: 'my-sku' },
318
+ },
319
+ ],
320
+ })
321
+ })
322
+
323
+ test('rangeExpr - variants.attributes.number', async () => {
324
+ const response = await supertest(ctMock.app)
325
+ .get('/dummy/product-projections/search')
326
+ .query({
327
+ facet: [
328
+ 'variants.attributes.number:range(* TO 5), (5 TO 25), (25 TO 100)',
329
+ ],
330
+ })
331
+
332
+ const result: ProductProjectionPagedSearchResponse = response.body
333
+ expect(result).toMatchObject({
334
+ count: 1,
335
+ facets: {
336
+ 'variants.attributes.number': {
337
+ type: 'range',
338
+ dataType: 'number',
339
+ ranges: [
340
+ {
341
+ type: 'double',
342
+ from: 0.0,
343
+ fromStr: '',
344
+ to: 5.0,
345
+ toStr: '5.0',
346
+ count: 1,
347
+ // totalCount: 1,
348
+ total: 4.0,
349
+ min: 4.0,
350
+ max: 4.0,
351
+ mean: 4.0,
352
+ },
353
+ {
354
+ type: 'double',
355
+ from: 5.0,
356
+ fromStr: '5.0',
357
+ to: 25.0,
358
+ toStr: '25.0',
359
+ count: 0,
360
+ // totalCount: 0,
361
+ total: 0.0,
362
+ min: 0.0,
363
+ max: 0.0,
364
+ mean: 0.0,
365
+ },
366
+ {
367
+ type: 'double',
368
+ from: 25.0,
369
+ fromStr: '25.0',
370
+ to: 100.0,
371
+ toStr: '100.0',
372
+ count: 1,
373
+ // totalCount: 1,
374
+ total: 50,
375
+ min: 50.0,
376
+ max: 50.0,
377
+ mean: 50.0,
378
+ },
379
+ ],
380
+ },
381
+ },
382
+ results: [
383
+ {
384
+ masterVariant: { sku: 'my-sku' },
385
+ },
386
+ ],
387
+ })
388
+ })
389
+ })