@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/dist/index.cjs +75 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/ctMock.ts +31 -0
- package/src/repositories/category.ts +26 -0
- package/src/repositories/product.ts +60 -0
- package/src/services/category.test.ts +99 -0
- package/src/services/custom-object.test.ts +17 -1
- package/src/services/customer.test.ts +20 -0
- package/src/services/product.test.ts +100 -0
package/package.json
CHANGED
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('
|
|
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
|
|