@labdigital/commercetools-mock 2.3.0 → 2.5.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@labdigital/commercetools-mock",
3
3
  "author": "Michael van Tellingen",
4
- "version": "2.3.0",
4
+ "version": "2.5.0",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
package/src/ctMock.ts CHANGED
@@ -193,6 +193,37 @@ export class CommercetoolsMock {
193
193
  headers: mapHeaderType(res.headers),
194
194
  })
195
195
  }),
196
+ http.head(`${this.options.apiHost}/*`, async ({ request }) => {
197
+ const body = await request.text()
198
+ const url = new URL(request.url)
199
+ const headers = copyHeaders(request.headers)
200
+
201
+ const res = await inject(server)
202
+ .get(url.pathname + '?' + url.searchParams.toString())
203
+ .body(body)
204
+ .headers(headers)
205
+ .end()
206
+
207
+ if (res.statusCode === 200) {
208
+ const parsedBody = JSON.parse(res.body)
209
+ // Check if we have a count property (e.g. for query-lookups)
210
+ // or if we have a result object (e.g. for single lookups)
211
+ const resultCount =
212
+ 'count' in parsedBody
213
+ ? parsedBody.count
214
+ : Object.keys(parsedBody).length
215
+
216
+ return new HttpResponse(null, {
217
+ status: resultCount > 0 ? 200 : 404,
218
+ headers: mapHeaderType(res.headers),
219
+ })
220
+ }
221
+
222
+ return new HttpResponse(null, {
223
+ status: res.statusCode,
224
+ headers: mapHeaderType(res.headers),
225
+ })
226
+ }),
196
227
  http.get(`${this.options.apiHost}/*`, async ({ request }) => {
197
228
  const body = await request.text()
198
229
  const url = new URL(request.url)
@@ -4,6 +4,8 @@ import type {
4
4
  Category,
5
5
  CategoryAddAssetAction,
6
6
  CategoryChangeAssetNameAction,
7
+ CategoryChangeNameAction,
8
+ CategoryChangeParentAction,
7
9
  CategoryChangeSlugAction,
8
10
  CategoryDraft,
9
11
  CategoryRemoveAssetAction,
@@ -98,6 +100,30 @@ export class CategoryRepository extends AbstractResourceRepository<'category'> {
98
100
  ) => {
99
101
  resource.slug = slug
100
102
  },
103
+ changeName: (
104
+ context: RepositoryContext,
105
+ resource: Writable<Category>,
106
+ { name }: CategoryChangeNameAction
107
+ ) => {
108
+ resource.name = name
109
+ },
110
+ changeParent: (
111
+ context: RepositoryContext,
112
+ resource: Writable<Category>,
113
+ { parent }: CategoryChangeParentAction
114
+ ) => {
115
+ const category = this._storage.getByResourceIdentifier(
116
+ context.projectKey,
117
+ parent
118
+ )
119
+ if (!category) {
120
+ throw new Error('No category found for reference')
121
+ }
122
+ resource.parent = {
123
+ typeId: 'category',
124
+ id: category.id,
125
+ }
126
+ },
101
127
  setKey: (
102
128
  context: RepositoryContext,
103
129
  resource: Writable<Category>,
@@ -6,6 +6,7 @@ import type {
6
6
  ProductDraft,
7
7
  ProductPublishAction,
8
8
  ProductSetAttributeAction,
9
+ ProductSetAttributeInAllVariantsAction,
9
10
  ProductSetDescriptionAction,
10
11
  ProductAddExternalImageAction,
11
12
  ProductRemoveImageAction,
@@ -238,6 +239,65 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
238
239
 
239
240
  return resource
240
241
  },
242
+ setAttributeInAllVariants: (
243
+ context: RepositoryContext,
244
+ resource: Writable<Product>,
245
+ { name, value, staged }: ProductSetAttributeInAllVariantsAction
246
+ ) => {
247
+ const setAttrInAllVariants = (data: Writable<ProductData>) => {
248
+ if (!data.masterVariant.attributes) {
249
+ data.masterVariant.attributes = []
250
+ }
251
+
252
+ const existingAttr = data.masterVariant.attributes?.find(
253
+ (attr) => attr.name === name
254
+ )
255
+
256
+ if (existingAttr) {
257
+ existingAttr.value = value
258
+ } else {
259
+ data.masterVariant.attributes.push({
260
+ name,
261
+ value,
262
+ })
263
+ }
264
+
265
+ data.variants.forEach((variant) => {
266
+ if (!variant.attributes) {
267
+ variant.attributes = []
268
+ }
269
+
270
+ const existingAttr = variant.attributes.find(
271
+ (attr) => attr.name === name
272
+ )
273
+ if (existingAttr) {
274
+ existingAttr.value = value
275
+ } else {
276
+ variant.attributes.push({
277
+ name,
278
+ value,
279
+ })
280
+ }
281
+ })
282
+ }
283
+
284
+ // If true, only the staged Attribute is set. If false, both current and
285
+ // staged Attribute is set. Default is true
286
+ const onlyStaged = staged !== undefined ? staged : true
287
+
288
+ // Write the attribute to the staged data
289
+ setAttrInAllVariants(resource.masterData.staged)
290
+
291
+ // Also write to published data is isStaged = false
292
+ // if isStaged is false we set the attribute on both the staged and
293
+ // published data.
294
+ if (!onlyStaged) {
295
+ setAttrInAllVariants(resource.masterData.current)
296
+ }
297
+ checkForStagedChanges(resource)
298
+
299
+ return resource
300
+ },
241
301
  setDescription: (
242
302
  context: RepositoryContext,
243
303
  resource: Writable<Product>,
@@ -48,6 +48,105 @@ describe('Categories Query', () => {
48
48
  })
49
49
  })
50
50
 
51
+ describe('categories changeName', () => {
52
+ const ctMock = new CommercetoolsMock()
53
+ let category: Category | undefined
54
+
55
+ beforeEach(async () => {
56
+ const response = await supertest(ctMock.app)
57
+ .post('/dummy/categories')
58
+ .send({
59
+ name: {
60
+ en: 'Top hat',
61
+ },
62
+ slug: {
63
+ en: 'top-hat',
64
+ },
65
+ orderHint: '0.1',
66
+ })
67
+ expect(response.status).toBe(201)
68
+ category = response.body as Category
69
+ })
70
+
71
+ test('changeName', async () => {
72
+ const changeNameResponse = await supertest(ctMock.app)
73
+ .post(`/dummy/categories/${category?.id}`)
74
+ .send({
75
+ version: 1,
76
+ actions: [
77
+ {
78
+ action: 'changeName',
79
+ name: {
80
+ en: 'Top hat - new name',
81
+ },
82
+ },
83
+ ],
84
+ })
85
+
86
+ expect(changeNameResponse.status).toBe(200)
87
+ expect(changeNameResponse.body.name.en).toBe('Top hat - new name')
88
+ })
89
+ })
90
+
91
+ describe('categories changeParent', () => {
92
+ const ctMock = new CommercetoolsMock()
93
+ let category1: Category | undefined
94
+ let category2: Category | undefined
95
+
96
+ beforeEach(async () => {
97
+ const response1 = await supertest(ctMock.app)
98
+ .post('/dummy/categories')
99
+ .send({
100
+ name: {
101
+ en: 'Top hat',
102
+ },
103
+ slug: {
104
+ en: 'top-hat',
105
+ },
106
+ orderHint: '0.1',
107
+ })
108
+ expect(response1.status).toBe(201)
109
+ category1 = response1.body as Category
110
+
111
+ const response2 = await supertest(ctMock.app)
112
+ .post('/dummy/categories')
113
+ .send({
114
+ name: {
115
+ en: 'Top hat',
116
+ },
117
+ slug: {
118
+ en: 'top-hat',
119
+ },
120
+ orderHint: '0.1',
121
+ })
122
+ expect(response2.status).toBe(201)
123
+ category2 = response2.body as Category
124
+ })
125
+
126
+ test('changeParent', async () => {
127
+ const changeNameResponse = await supertest(ctMock.app)
128
+ .post(`/dummy/categories/${category2?.id}`)
129
+ .send({
130
+ version: 1,
131
+ actions: [
132
+ {
133
+ action: 'changeParent',
134
+ parent: {
135
+ typeId: 'category',
136
+ id: category1?.id,
137
+ },
138
+ },
139
+ ],
140
+ })
141
+
142
+ expect(changeNameResponse.status).toBe(200)
143
+ expect(changeNameResponse.body.parent).toEqual({
144
+ typeId: 'category',
145
+ id: category1?.id,
146
+ })
147
+ })
148
+ })
149
+
51
150
  describe('Categories add asset', () => {
52
151
  const ctMock = new CommercetoolsMock()
53
152
  let category: Category | undefined
@@ -47,7 +47,23 @@ describe('CustomObject retrieve', () => {
47
47
  ctMock.clear()
48
48
  })
49
49
 
50
- test('createget', async () => {
50
+ test('exists', async () => {
51
+ const response = await supertest(ctMock.app)
52
+ .head('/dummy/custom-objects/my-container/my-key')
53
+ .send()
54
+
55
+ expect(response.status).toBe(200)
56
+ })
57
+
58
+ test('non-existent', async () => {
59
+ const response = await supertest(ctMock.app)
60
+ .head('/dummy/custom-objects/invalid-container/invalid')
61
+ .send()
62
+
63
+ expect(response.status).toBe(404)
64
+ })
65
+
66
+ test('get', async () => {
51
67
  const response = await supertest(ctMock.app)
52
68
  .get('/dummy/custom-objects/my-container/my-key')
53
69
  .send()
@@ -26,6 +26,26 @@ describe('Customer Update Actions', () => {
26
26
  ctMock.clear()
27
27
  })
28
28
 
29
+ test('exists', async () => {
30
+ assert(customer, 'customer not created')
31
+
32
+ const response = await supertest(ctMock.app)
33
+ .head(`/dummy/customers/${customer.id}`)
34
+ .send()
35
+
36
+ expect(response.status).toBe(200)
37
+ })
38
+
39
+ test('non-existent', async () => {
40
+ assert(customer, 'customer not created')
41
+
42
+ const response = await supertest(ctMock.app)
43
+ .head(`/dummy/customers/invalid-id`)
44
+ .send()
45
+
46
+ expect(response.status).toBe(404)
47
+ })
48
+
29
49
  test('changeEmail', async () => {
30
50
  assert(customer, 'customer not created')
31
51
 
@@ -594,6 +594,106 @@ describe('Product update actions', () => {
594
594
  expect(attr).toEqual({ name: 'test', value: 'foo' })
595
595
  })
596
596
 
597
+ test('setAttributeInAllVariants overwrite', async () => {
598
+ assert(productPublished, 'product not created')
599
+ const response = await supertest(ctMock.app)
600
+ .post(`/dummy/products/${productPublished.id}`)
601
+ .send({
602
+ version: 1,
603
+ actions: [
604
+ {
605
+ action: 'setAttributeInAllVariants',
606
+ name: 'test',
607
+ value: 'foo',
608
+ },
609
+ ],
610
+ })
611
+ expect(response.status).toBe(200)
612
+ expect(response.body.version).toBe(2)
613
+ expect(
614
+ response.body.masterData.staged.masterVariant.attributes
615
+ ).toHaveLength(1)
616
+
617
+ const masterVariantAttr1 =
618
+ response.body.masterData.staged.masterVariant.attributes[0]
619
+ expect(masterVariantAttr1).toEqual({ name: 'test', value: 'foo' })
620
+
621
+ response.body.masterData.staged.variants.forEach((variant) => {
622
+ expect(variant.attributes).toHaveLength(2)
623
+ expect(variant.attributes[1]).toEqual({
624
+ name: 'test',
625
+ value: 'foo',
626
+ })
627
+ })
628
+ })
629
+
630
+ test('setAttributeInAllVariants product staged', async () => {
631
+ assert(productPublished, 'product not created')
632
+ const response = await supertest(ctMock.app)
633
+ .post(`/dummy/products/${productPublished.id}`)
634
+ .send({
635
+ version: 1,
636
+ actions: [
637
+ {
638
+ action: 'setAttributeInAllVariants',
639
+ name: 'foo',
640
+ value: 'bar',
641
+ },
642
+ ],
643
+ })
644
+ expect(response.status).toBe(200)
645
+ expect(response.body.version).toBe(2)
646
+ expect(
647
+ response.body.masterData.staged.masterVariant.attributes
648
+ ).toHaveLength(2)
649
+ const masterVariantAttr1 =
650
+ response.body.masterData.staged.masterVariant.attributes[0]
651
+ expect(masterVariantAttr1).toEqual({ name: 'test', value: 'test' })
652
+
653
+ const masterVariantAttr2 =
654
+ response.body.masterData.staged.masterVariant.attributes[1]
655
+ expect(masterVariantAttr2).toEqual({
656
+ name: 'foo',
657
+ value: 'bar',
658
+ })
659
+ response.body.masterData.staged.variants.forEach((variant) => {
660
+ expect(variant.attributes).toHaveLength(2)
661
+ expect(variant.attributes[1]).toEqual({
662
+ name: 'foo',
663
+ value: 'bar',
664
+ })
665
+ })
666
+ })
667
+
668
+ test('setAttributeInAllVariants and publish', async () => {
669
+ assert(productPublished, 'product not created')
670
+
671
+ const response = await supertest(ctMock.app)
672
+ .post(`/dummy/products/${productPublished.id}`)
673
+ .send({
674
+ version: 1,
675
+ actions: [
676
+ { action: 'setAttributeInAllVariants', name: 'foo', value: 'bar' },
677
+ { action: 'publish' },
678
+ ],
679
+ })
680
+ expect(response.status).toBe(200)
681
+ expect(response.body.version).toBe(3)
682
+ expect(
683
+ response.body.masterData.current.masterVariant.attributes
684
+ ).toHaveLength(2)
685
+ const attr = response.body.masterData.current.masterVariant.attributes[1]
686
+ expect(attr).toEqual({ name: 'foo', value: 'bar' })
687
+
688
+ response.body.masterData.current.variants.forEach((variant) => {
689
+ expect(variant.attributes).toHaveLength(2)
690
+ expect(variant.attributes[1]).toEqual({
691
+ name: 'foo',
692
+ value: 'bar',
693
+ })
694
+ })
695
+ })
696
+
597
697
  test('addExternalImage variant', async () => {
598
698
  assert(productPublished, 'product not created')
599
699