@labdigital/commercetools-mock 2.12.2 → 2.14.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.12.2",
4
+ "version": "2.14.0",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
@@ -35,45 +35,45 @@
35
35
  "dependencies": {
36
36
  "basic-auth": "^2.0.1",
37
37
  "body-parser": "^1.20.2",
38
- "deep-equal": "^2.2.2",
38
+ "deep-equal": "^2.2.3",
39
39
  "express": "^4.18.2",
40
40
  "light-my-request": "^5.11.0",
41
41
  "lodash.isequal": "^4.5.0",
42
42
  "morgan": "^1.10.0",
43
- "msw": "^2.0.0",
44
- "uuid": "^9.0.0"
43
+ "msw": "^2.1.2",
44
+ "uuid": "^9.0.1"
45
45
  },
46
46
  "devDependencies": {
47
- "@changesets/changelog-github": "^0.4.8",
48
- "@changesets/cli": "^2.26.2",
49
- "@commercetools/platform-sdk": "6.0.0",
50
- "@types/basic-auth": "^1.1.3",
51
- "@types/body-parser": "^1.19.2",
52
- "@types/deep-equal": "^1.0.1",
53
- "@types/express": "^4.17.17",
54
- "@types/express-serve-static-core": "^4.17.35",
55
- "@types/lodash.isequal": "^4.5.6",
56
- "@types/morgan": "^1.9.4",
57
- "@types/node": "*",
58
- "@types/qs": "^6.9.7",
59
- "@types/supertest": "^2.0.12",
60
- "@types/uuid": "^9.0.2",
61
- "@typescript-eslint/eslint-plugin": "^6.2.0",
62
- "@typescript-eslint/parser": "^6.2.0",
63
- "@vitest/coverage-v8": "^0.33.0",
64
- "esbuild": "^0.18.17",
65
- "eslint": "^8.46.0",
47
+ "@changesets/changelog-github": "^0.5.0",
48
+ "@changesets/cli": "^2.27.1",
49
+ "@commercetools/platform-sdk": "7.2.0-alpha.2",
50
+ "@types/basic-auth": "^1.1.7",
51
+ "@types/body-parser": "^1.19.5",
52
+ "@types/deep-equal": "^1.0.4",
53
+ "@types/express": "^4.17.21",
54
+ "@types/express-serve-static-core": "^4.17.41",
55
+ "@types/lodash.isequal": "^4.5.8",
56
+ "@types/morgan": "^1.9.9",
57
+ "@types/node": "^20.11.5",
58
+ "@types/qs": "^6.9.11",
59
+ "@types/supertest": "^6.0.2",
60
+ "@types/uuid": "^9.0.7",
61
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
62
+ "@typescript-eslint/parser": "^6.19.0",
63
+ "@vitest/coverage-v8": "^1.2.1",
64
+ "esbuild": "^0.19.11",
65
+ "eslint": "^8.56.0",
66
66
  "eslint-plugin-unused-imports": "^3.0.0",
67
- "got": "^11.8.3",
67
+ "got": "^14.0.0",
68
68
  "husky": "^8.0.3",
69
- "prettier": "^3.0.0",
70
- "supertest": "^6.3.3",
69
+ "prettier": "^3.2.4",
70
+ "supertest": "^6.3.4",
71
71
  "timekeeper": "^2.3.1",
72
- "ts-node": "^10.9.1",
73
- "tslib": "^2.6.1",
74
- "tsup": "^7.1.0",
75
- "typescript": "^5.1.6",
76
- "vitest": "^0.33.0"
72
+ "ts-node": "^10.9.2",
73
+ "tslib": "^2.6.2",
74
+ "tsup": "^8.0.1",
75
+ "typescript": "^5.3.3",
76
+ "vitest": "^1.2.1"
77
77
  },
78
78
  "scripts": {
79
79
  "start": "tsup src/server.ts --watch --onSuccess 'node dist/server.js'",
@@ -411,7 +411,7 @@ export class CartRepository extends AbstractResourceRepository<'cart'> {
411
411
  ? this._storage.getByResourceIdentifier<'tax-category'>(
412
412
  context.projectKey,
413
413
  taxCategory
414
- )
414
+ )
415
415
  : undefined
416
416
 
417
417
  resource.shippingInfo = {
@@ -425,7 +425,7 @@ export class CartRepository extends AbstractResourceRepository<'cart'> {
425
425
  ? {
426
426
  typeId: 'tax-category',
427
427
  id: tax?.id,
428
- }
428
+ }
429
429
  : undefined,
430
430
  shippingMethodState: 'MatchesCart',
431
431
  }
@@ -73,6 +73,22 @@ export class CustomerRepository extends AbstractResourceRepository<'customer'> {
73
73
  return
74
74
  }
75
75
 
76
+ deleteMe(context: RepositoryContext): Customer | undefined {
77
+ // grab the first customer you can find for now. In the future we should
78
+ // use the customer id from the scope of the token
79
+ const results = this._storage.query(
80
+ context.projectKey,
81
+ this.getTypeId(),
82
+ {}
83
+ )
84
+
85
+ if (results.count > 0) {
86
+ return this.delete(context, results.results[0].id) as Customer
87
+ }
88
+
89
+ return
90
+ }
91
+
76
92
  actions = {
77
93
  changeEmail: (
78
94
  _context: RepositoryContext,
@@ -15,6 +15,7 @@ import type {
15
15
  OrderChangePaymentStateAction,
16
16
  OrderFromCartDraft,
17
17
  OrderImportDraft,
18
+ OrderUpdateSyncInfoAction,
18
19
  OrderSetBillingAddressAction,
19
20
  OrderSetCustomerEmailAction,
20
21
  OrderSetCustomFieldAction,
@@ -30,6 +31,7 @@ import type {
30
31
  ReturnInfo,
31
32
  State,
32
33
  Store,
34
+ SyncInfo,
33
35
  } from '@commercetools/platform-sdk'
34
36
  import assert from 'assert'
35
37
  import { CommercetoolsError } from '../exceptions.js'
@@ -96,7 +98,7 @@ export class OrderRepository extends AbstractResourceRepository<'order'> {
96
98
  ? {
97
99
  key: context.storeKey,
98
100
  typeId: 'store',
99
- }
101
+ }
100
102
  : undefined,
101
103
  lastMessageSequenceNumber: 0,
102
104
  }
@@ -301,6 +303,7 @@ export class OrderRepository extends AbstractResourceRepository<'order'> {
301
303
  id: payment.id!,
302
304
  })
303
305
  },
306
+
304
307
  addReturnInfo: (
305
308
  context: RepositoryContext,
306
309
  resource: Writable<Order>,
@@ -472,5 +475,40 @@ export class OrderRepository extends AbstractResourceRepository<'order'> {
472
475
  key: storeReference.key,
473
476
  }
474
477
  },
478
+ updateSyncInfo: (
479
+ context: RepositoryContext,
480
+ resource: Writable<Order>,
481
+ { channel, externalId, syncedAt }: OrderUpdateSyncInfoAction
482
+ ) => {
483
+ if (!channel) return
484
+ const resolvedType = this._storage.getByResourceIdentifier(
485
+ context.projectKey,
486
+ channel
487
+ )
488
+ if (!resolvedType) {
489
+ throw new Error(`Channel ${channel} not found`)
490
+ }
491
+
492
+ const syncData: SyncInfo = {
493
+ channel: {
494
+ typeId: 'channel',
495
+ id: resolvedType.id,
496
+ },
497
+ externalId,
498
+ syncedAt: syncedAt ?? new Date().toISOString(),
499
+ }
500
+
501
+ if (!resource.syncInfo?.length) {
502
+ resource.syncInfo = [syncData]
503
+ } else {
504
+ const lastSyncInfo = resource.syncInfo[resource.syncInfo.length - 1]
505
+ if (
506
+ lastSyncInfo.channel.id !== syncData.channel.id ||
507
+ lastSyncInfo.externalId !== syncData.externalId
508
+ ) {
509
+ resource.syncInfo.push(syncData)
510
+ }
511
+ }
512
+ },
475
513
  }
476
514
  }
@@ -5,6 +5,13 @@ import type {
5
5
  PaymentDraft,
6
6
  PaymentSetCustomFieldAction,
7
7
  PaymentSetCustomTypeAction,
8
+ PaymentSetInterfaceIdAction,
9
+ PaymentSetKeyAction,
10
+ PaymentSetMethodInfoInterfaceAction,
11
+ PaymentSetMethodInfoMethodAction,
12
+ PaymentSetMethodInfoNameAction,
13
+ PaymentSetStatusInterfaceCodeAction,
14
+ PaymentSetStatusInterfaceTextAction,
8
15
  PaymentTransitionStateAction,
9
16
  State,
10
17
  StateReference,
@@ -39,9 +46,9 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
39
46
  draft.paymentStatus.state,
40
47
  context.projectKey,
41
48
  this._storage
42
- )
49
+ )
43
50
  : undefined,
44
- }
51
+ }
45
52
  : {},
46
53
  transactions: (draft.transactions || []).map((t) =>
47
54
  this.transactionFromTransactionDraft(t, context)
@@ -73,6 +80,50 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
73
80
  })
74
81
 
75
82
  actions = {
83
+ addTransaction: (
84
+ context: RepositoryContext,
85
+ resource: Writable<Payment>,
86
+ { transaction }: PaymentAddTransactionAction
87
+ ) => {
88
+ resource.transactions = [
89
+ ...resource.transactions,
90
+ this.transactionFromTransactionDraft(transaction, context),
91
+ ]
92
+ },
93
+ changeTransactionState: (
94
+ _context: RepositoryContext,
95
+ resource: Writable<Payment>,
96
+ { transactionId, state }: PaymentChangeTransactionStateAction
97
+ ) => {
98
+ const index = resource.transactions.findIndex(
99
+ (e: Transaction) => e.id === transactionId
100
+ )
101
+ const updatedTransaction: Transaction = {
102
+ ...resource.transactions[index],
103
+ state,
104
+ }
105
+ resource.transactions[index] = updatedTransaction
106
+ },
107
+ transitionState: (
108
+ context: RepositoryContext,
109
+ resource: Writable<Payment>,
110
+ { state }: PaymentTransitionStateAction
111
+ ) => {
112
+ const stateObj = this._storage.getByResourceIdentifier(
113
+ context.projectKey,
114
+ state
115
+ ) as State | null
116
+
117
+ if (!stateObj) {
118
+ throw new Error(`State ${state} not found`)
119
+ }
120
+
121
+ resource.paymentStatus.state = {
122
+ typeId: 'state',
123
+ id: stateObj.id,
124
+ obj: stateObj,
125
+ }
126
+ },
76
127
  setCustomField: (
77
128
  context: RepositoryContext,
78
129
  resource: Payment,
@@ -109,66 +160,60 @@ export class PaymentRepository extends AbstractResourceRepository<'payment'> {
109
160
  }
110
161
  }
111
162
  },
112
- addTransaction: (
113
- context: RepositoryContext,
163
+ setKey: (
164
+ _context: RepositoryContext,
114
165
  resource: Writable<Payment>,
115
- { transaction }: PaymentAddTransactionAction
166
+ { key }: PaymentSetKeyAction
116
167
  ) => {
117
- resource.transactions = [
118
- ...resource.transactions,
119
- this.transactionFromTransactionDraft(transaction, context),
120
- ]
168
+ resource.key = key
121
169
  },
122
- changeTransactionState: (
170
+ setStatusInterfaceCode: (
123
171
  _context: RepositoryContext,
124
172
  resource: Writable<Payment>,
125
- { transactionId, state }: PaymentChangeTransactionStateAction
173
+ { interfaceCode }: PaymentSetStatusInterfaceCodeAction
126
174
  ) => {
127
- const index = resource.transactions.findIndex(
128
- (e: Transaction) => e.id === transactionId
129
- )
130
- const updatedTransaction: Transaction = {
131
- ...resource.transactions[index],
132
- state,
133
- }
134
- resource.transactions[index] = updatedTransaction
175
+ resource.paymentStatus.interfaceCode = interfaceCode
135
176
  },
136
- transitionState: (
137
- context: RepositoryContext,
177
+ setStatusInterfaceText: (
178
+ _context: RepositoryContext,
138
179
  resource: Writable<Payment>,
139
- { state }: PaymentTransitionStateAction
180
+ { interfaceText }: PaymentSetStatusInterfaceTextAction
140
181
  ) => {
141
- const stateObj = this._storage.getByResourceIdentifier(
142
- context.projectKey,
143
- state
144
- ) as State | null
145
-
146
- if (!stateObj) {
147
- throw new Error(`State ${state} not found`)
148
- }
149
-
150
- resource.paymentStatus.state = {
151
- typeId: 'state',
152
- id: stateObj.id,
153
- obj: stateObj,
154
- }
182
+ resource.paymentStatus.interfaceText = interfaceText
183
+ },
184
+ setMethodInfoName: (
185
+ _context: RepositoryContext,
186
+ resource: Writable<Payment>,
187
+ { name }: PaymentSetMethodInfoNameAction
188
+ ) => {
189
+ resource.paymentMethodInfo.name = name
190
+ },
191
+ setMethodInfoMethod: (
192
+ _context: RepositoryContext,
193
+ resource: Writable<Payment>,
194
+ { method }: PaymentSetMethodInfoMethodAction
195
+ ) => {
196
+ resource.paymentMethodInfo.method = method
197
+ },
198
+ setMethodInfoInterface: (
199
+ _context: RepositoryContext,
200
+ resource: Writable<Payment>,
201
+ args: PaymentSetMethodInfoInterfaceAction
202
+ ) => {
203
+ resource.paymentMethodInfo.paymentInterface = args.interface
204
+ },
205
+ setInterfaceId: (
206
+ _context: RepositoryContext,
207
+ resource: Writable<Payment>,
208
+ { interfaceId }: PaymentSetInterfaceIdAction
209
+ ) => {
210
+ resource.interfaceId = interfaceId
155
211
  },
156
212
  // addInterfaceInteraction: () => {},
157
213
  // changeAmountPlanned: () => {},
158
214
  // changeTransactionInteractionId: () => {},
159
215
  // changeTransactionTimestamp: () => {},
160
- // setAmountPaid: () => {},
161
- // setAmountRefunded: () => {},
162
216
  // setAnonymousId: () => {},
163
- // setAuthorization: () => {},
164
217
  // setCustomer: () => {},
165
- // setExternalId: () => {},
166
- // setInterfaceId: () => {},
167
- // setKey: () => {},
168
- // setMethodInfoInterface: () => {},
169
- // setMethodInfoMethod: () => {},
170
- // setMethodInfoName: () => {},
171
- // setStatusInterfaceCode: () => {},
172
- // setStatusInterfaceText: () => {},
173
218
  }
174
219
  }
@@ -184,7 +184,7 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
184
184
  draft.channel,
185
185
  context.projectKey,
186
186
  this._storage
187
- )
187
+ )
188
188
  : undefined,
189
189
  }
190
190
  }
@@ -587,8 +587,8 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
587
587
  ) => {
588
588
  const changeVariantPrice = (data: Writable<ProductData>) => {
589
589
  const allVariants = [data.masterVariant, ...(data.variants ?? [])]
590
- const priceVariant = allVariants.find(
591
- (variant) => variant.prices?.some((x) => x.id === priceId)
590
+ const priceVariant = allVariants.find((variant) =>
591
+ variant.prices?.some((x) => x.id === priceId)
592
592
  )
593
593
  if (!priceVariant) {
594
594
  throw new Error(
@@ -645,8 +645,8 @@ export class ProductRepository extends AbstractResourceRepository<'product'> {
645
645
  ) => {
646
646
  const removeVariantPrice = (data: Writable<ProductData>) => {
647
647
  const allVariants = [data.masterVariant, ...(data.variants ?? [])]
648
- const priceVariant = allVariants.find(
649
- (variant) => variant.prices?.some((x) => x.id === priceId)
648
+ const priceVariant = allVariants.find((variant) =>
649
+ variant.prices?.some((x) => x.id === priceId)
650
650
  )
651
651
  if (!priceVariant) {
652
652
  throw new Error(
@@ -35,12 +35,12 @@ export class ReviewRepository extends AbstractResourceRepository<'review'> {
35
35
  draft.state,
36
36
  context.projectKey,
37
37
  this._storage
38
- )
38
+ )
39
39
  : undefined,
40
40
  target: draft.target
41
41
  ? getReferenceFromResourceIdentifier<
42
42
  ProductReference | ChannelReference
43
- >(draft.target, context.projectKey, this._storage)
43
+ >(draft.target, context.projectKey, this._storage)
44
44
  : undefined,
45
45
  includedInStatistics: false,
46
46
  custom: createCustomFields(
@@ -48,7 +48,7 @@ export class ShoppingListRepository extends AbstractResourceRepository<'shopping
48
48
  draft.customer,
49
49
  context.projectKey,
50
50
  this._storage
51
- )
51
+ )
52
52
  : undefined,
53
53
  store: draft.store
54
54
  ? getStoreKeyReference(draft.store, context.projectKey, this._storage)
@@ -25,7 +25,7 @@ export class CustomerService extends AbstractService {
25
25
  // @ts-ignore
26
26
  const ttlMinutes: number = request.params.ttlMinutes
27
27
  ? // @ts-ignore
28
- +request.params.ttlMinutes
28
+ +request.params.ttlMinutes
29
29
  : 34560
30
30
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
31
31
  const { version, ...rest } = getBaseResourceProperties()
@@ -94,6 +94,32 @@ describe('/me', () => {
94
94
  })
95
95
  })
96
96
 
97
+ test('Delete me', async () => {
98
+ const response = await supertest(ctMock.app).delete('/dummy/me')
99
+
100
+ expect(response.status).toBe(200)
101
+ expect(response.body).toEqual({
102
+ id: '123',
103
+ createdAt: '2021-03-18T14:00:00.000Z',
104
+ version: 2,
105
+ lastModifiedAt: '2021-03-18T14:00:00.000Z',
106
+ email: 'foo@example.org',
107
+ addresses: [],
108
+ isEmailVerified: true,
109
+ authenticationMode: 'password',
110
+ custom: {
111
+ fields: {},
112
+ type: {
113
+ id: '',
114
+ typeId: 'type',
115
+ },
116
+ },
117
+ })
118
+
119
+ const newResponse = await supertest(ctMock.app).get('/dummy/me')
120
+ expect(newResponse.status).toBe(404)
121
+ })
122
+
97
123
  test('setCustomField', async () => {
98
124
  const response = await supertest(ctMock.app)
99
125
  .post(`/dummy/me`)
@@ -26,6 +26,7 @@ export class MyCustomerService extends AbstractService {
26
26
 
27
27
  router.get('', this.getMe.bind(this))
28
28
  router.post('', this.updateMe.bind(this))
29
+ router.delete('', this.deleteMe.bind(this))
29
30
 
30
31
  router.post('/signup', this.signUp.bind(this))
31
32
 
@@ -59,6 +60,14 @@ export class MyCustomerService extends AbstractService {
59
60
  const result = this._expandWithId(request, updatedResource.id)
60
61
  return response.status(200).send(result)
61
62
  }
63
+ deleteMe(request: Request, response: Response) {
64
+ const resource = this.repository.deleteMe(getRepositoryContext(request))
65
+ if (!resource) {
66
+ return response.status(404).send('Not found')
67
+ }
68
+
69
+ return response.status(200).send(resource)
70
+ }
62
71
 
63
72
  signUp(request: Request, response: Response) {
64
73
  const draft = request.body
@@ -366,6 +366,40 @@ describe('Order Update Actions', () => {
366
366
  expect(response.body.orderState).toBe('Cancelled')
367
367
  expect(response.body.paymentState).toBe('Failed')
368
368
  })
369
+
370
+ test('updateSyncInfo', async () => {
371
+ assert(order, 'order not created')
372
+
373
+ const channelResponse = await supertest(ctMock.app)
374
+ .post('/dummy/channels')
375
+ .send({
376
+ key: 'order-sync',
377
+ roles: ['OrderImport', 'OrderExport'],
378
+ })
379
+ expect(channelResponse.status).toBe(201)
380
+ const channel = channelResponse.body
381
+
382
+ const response = await supertest(ctMock.app)
383
+ .post(`/dummy/orders/${order.id}`)
384
+ .send({
385
+ version: 1,
386
+ actions: [
387
+ {
388
+ action: 'updateSyncInfo',
389
+ channel: { typeId: 'channel', key: 'order-sync' },
390
+ externalId: '1234',
391
+ },
392
+ ],
393
+ })
394
+ expect(response.status).toBe(200)
395
+ expect(response.body.version).toBe(2)
396
+ expect(response.body.syncInfo).toMatchObject([
397
+ {
398
+ channel: { typeId: 'channel', id: channel.id },
399
+ externalId: '1234',
400
+ },
401
+ ])
402
+ })
369
403
  })
370
404
 
371
405
  describe('Order Import', () => {