@labdigital/commercetools-mock 1.5.0 → 1.6.1

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 (129) hide show
  1. package/README.md +5 -4
  2. package/dist/index.cjs +117 -17
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +30 -7
  5. package/dist/index.d.ts +30 -7
  6. package/dist/index.js +117 -17
  7. package/dist/index.js.map +1 -1
  8. package/package.json +4 -3
  9. package/src/constants.ts +2 -2
  10. package/src/ctMock.ts +176 -176
  11. package/src/exceptions.ts +10 -10
  12. package/src/helpers.ts +26 -26
  13. package/src/index.test.ts +173 -173
  14. package/src/index.ts +3 -3
  15. package/src/lib/expandParser.ts +19 -19
  16. package/src/lib/haversine.test.ts +13 -13
  17. package/src/lib/haversine.ts +14 -14
  18. package/src/lib/masking.ts +15 -15
  19. package/src/lib/parser.ts +2 -2
  20. package/src/lib/predicateParser.test.ts +204 -204
  21. package/src/lib/predicateParser.ts +398 -398
  22. package/src/lib/projectionSearchFilter.test.ts +168 -168
  23. package/src/lib/projectionSearchFilter.ts +272 -269
  24. package/src/lib/proxy.ts +8 -8
  25. package/src/oauth/errors.ts +4 -4
  26. package/src/oauth/helpers.ts +6 -6
  27. package/src/oauth/server.ts +103 -101
  28. package/src/oauth/store.ts +27 -27
  29. package/src/priceSelector.test.ts +68 -68
  30. package/src/priceSelector.ts +70 -70
  31. package/src/product-projection-search.ts +296 -296
  32. package/src/projectAPI.test.ts +3 -3
  33. package/src/projectAPI.ts +46 -46
  34. package/src/repositories/abstract.ts +190 -190
  35. package/src/repositories/associate-role.ts +10 -7
  36. package/src/repositories/attribute-group.ts +63 -8
  37. package/src/repositories/business-unit.ts +10 -7
  38. package/src/repositories/cart-discount.ts +134 -134
  39. package/src/repositories/cart.ts +517 -514
  40. package/src/repositories/category.ts +170 -167
  41. package/src/repositories/channel.ts +114 -111
  42. package/src/repositories/custom-object.ts +66 -63
  43. package/src/repositories/customer-group.ts +72 -69
  44. package/src/repositories/customer.ts +90 -90
  45. package/src/repositories/discount-code.ts +171 -168
  46. package/src/repositories/errors.ts +15 -15
  47. package/src/repositories/extension.ts +79 -76
  48. package/src/repositories/helpers.ts +180 -180
  49. package/src/repositories/index.ts +39 -39
  50. package/src/repositories/inventory-entry.ts +98 -95
  51. package/src/repositories/my-order.ts +11 -11
  52. package/src/repositories/order-edit.ts +29 -29
  53. package/src/repositories/order.test.ts +191 -191
  54. package/src/repositories/order.ts +393 -393
  55. package/src/repositories/payment.ts +155 -155
  56. package/src/repositories/product-discount.ts +149 -149
  57. package/src/repositories/product-projection.ts +135 -50
  58. package/src/repositories/product-selection.ts +31 -31
  59. package/src/repositories/product-type.ts +156 -156
  60. package/src/repositories/product.ts +600 -597
  61. package/src/repositories/project.ts +136 -135
  62. package/src/repositories/quote-request.ts +19 -19
  63. package/src/repositories/quote.ts +19 -19
  64. package/src/repositories/review.ts +24 -24
  65. package/src/repositories/shipping-method.ts +217 -217
  66. package/src/repositories/shopping-list.ts +49 -49
  67. package/src/repositories/staged-quote.ts +20 -20
  68. package/src/repositories/standalone-price.ts +72 -61
  69. package/src/repositories/state.ts +84 -84
  70. package/src/repositories/store.ts +114 -114
  71. package/src/repositories/subscription.ts +40 -40
  72. package/src/repositories/tax-category.ts +98 -98
  73. package/src/repositories/type.ts +157 -157
  74. package/src/repositories/zone.ts +71 -71
  75. package/src/server.ts +2 -2
  76. package/src/services/abstract.ts +173 -173
  77. package/src/services/attribute-group.ts +16 -0
  78. package/src/services/cart-discount.ts +8 -8
  79. package/src/services/cart.test.ts +409 -409
  80. package/src/services/cart.ts +50 -50
  81. package/src/services/category.test.ts +25 -25
  82. package/src/services/category.ts +8 -8
  83. package/src/services/channel.ts +8 -8
  84. package/src/services/custom-object.test.ts +184 -184
  85. package/src/services/custom-object.ts +48 -48
  86. package/src/services/customer-group.ts +8 -8
  87. package/src/services/customer.test.ts +151 -151
  88. package/src/services/customer.ts +27 -27
  89. package/src/services/discount-code.ts +8 -8
  90. package/src/services/extension.ts +8 -8
  91. package/src/services/index.ts +52 -44
  92. package/src/services/inventory-entry.test.ts +162 -162
  93. package/src/services/inventory-entry.ts +8 -8
  94. package/src/services/my-cart.test.ts +78 -78
  95. package/src/services/my-cart.ts +28 -28
  96. package/src/services/my-customer.test.ts +44 -44
  97. package/src/services/my-customer.ts +53 -53
  98. package/src/services/my-order.ts +20 -20
  99. package/src/services/my-payment.test.ts +65 -65
  100. package/src/services/my-payment.ts +8 -8
  101. package/src/services/order.test.ts +527 -527
  102. package/src/services/order.ts +31 -31
  103. package/src/services/payment.test.ts +65 -65
  104. package/src/services/payment.ts +8 -8
  105. package/src/services/product-discount.ts +8 -8
  106. package/src/services/product-projection.test.ts +502 -428
  107. package/src/services/product-projection.ts +32 -18
  108. package/src/services/product-type.test.ts +56 -56
  109. package/src/services/product-type.ts +8 -8
  110. package/src/services/product.test.ts +510 -510
  111. package/src/services/product.ts +8 -8
  112. package/src/services/project.ts +34 -34
  113. package/src/services/shipping-method.test.ts +81 -81
  114. package/src/services/shipping-method.ts +12 -12
  115. package/src/services/shopping-list.ts +8 -8
  116. package/src/services/standalone-price.test.ts +256 -256
  117. package/src/services/standalone-price.ts +8 -8
  118. package/src/services/state.test.ts +42 -42
  119. package/src/services/state.ts +8 -8
  120. package/src/services/store.test.ts +57 -57
  121. package/src/services/store.ts +8 -8
  122. package/src/services/subscription.ts +8 -8
  123. package/src/services/tax-category.test.ts +61 -61
  124. package/src/services/tax-category.ts +8 -8
  125. package/src/services/type.ts +8 -8
  126. package/src/services/zone.ts +8 -8
  127. package/src/storage/abstract.ts +58 -58
  128. package/src/storage/in-memory.ts +419 -419
  129. package/src/types.ts +82 -82
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@labdigital/commercetools-mock",
3
3
  "author": "Michael van Tellingen",
4
- "version": "1.5.0",
4
+ "version": "1.6.1",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
@@ -79,9 +79,10 @@
79
79
  "build": "tsup",
80
80
  "build:server": "esbuild src/server.ts --bundle --outfile=dist/server.js --platform=node",
81
81
  "publish:ci": "pnpm build && pnpm changeset publish",
82
- "check": "eslint src && tsc",
83
82
  "test": "vitest run",
84
83
  "test:ci": "vitest run --coverage",
85
- "lint": "eslint src"
84
+ "check": "pnpm lint && tsc",
85
+ "format": "eslint src --fix ; prettier --write .",
86
+ "lint": "eslint src && prettier --check ."
86
87
  }
87
88
  }
package/src/constants.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export const DEFAULT_API_HOSTNAME =
2
- /^https:\/\/api\..*?\.commercetools.com:443$/
2
+ /^https:\/\/api\..*?\.commercetools.com:443$/
3
3
  export const DEFAULT_AUTH_HOSTNAME =
4
- /^https:\/\/auth\..*?\.commercetools.com:443$/
4
+ /^https:\/\/auth\..*?\.commercetools.com:443$/
package/src/ctMock.ts CHANGED
@@ -17,188 +17,188 @@ import { createServices } from './services/index.js'
17
17
  import { ProjectRepository } from './repositories/project.js'
18
18
 
19
19
  export type CommercetoolsMockOptions = {
20
- validateCredentials: boolean
21
- enableAuthentication: boolean
22
- defaultProjectKey: string | undefined
23
- apiHost: RegExp | string
24
- authHost: RegExp | string
25
- silent: boolean
20
+ validateCredentials: boolean
21
+ enableAuthentication: boolean
22
+ defaultProjectKey: string | undefined
23
+ apiHost: RegExp | string
24
+ authHost: RegExp | string
25
+ silent: boolean
26
26
  }
27
27
 
28
28
  type AppOptions = { silent?: boolean }
29
29
 
30
30
  const DEFAULT_OPTIONS: CommercetoolsMockOptions = {
31
- enableAuthentication: false,
32
- validateCredentials: false,
33
- defaultProjectKey: undefined,
34
- apiHost: DEFAULT_API_HOSTNAME,
35
- authHost: DEFAULT_AUTH_HOSTNAME,
36
- silent: false,
31
+ enableAuthentication: false,
32
+ validateCredentials: false,
33
+ defaultProjectKey: undefined,
34
+ apiHost: DEFAULT_API_HOSTNAME,
35
+ authHost: DEFAULT_AUTH_HOSTNAME,
36
+ silent: false,
37
37
  }
38
38
 
39
39
  export class CommercetoolsMock {
40
- public app: express.Express
41
- public options: CommercetoolsMockOptions
42
-
43
- private _storage: AbstractStorage
44
- private _oauth2: OAuth2Server
45
- private _nockScopes: {
46
- auth: nock.Scope | undefined
47
- api: nock.Scope | undefined
48
- } = { auth: undefined, api: undefined }
49
- private _services: Services | null
50
- private _repositories: RepositoryMap | null
51
- private _projectService?: ProjectService
52
-
53
- constructor(options: Partial<CommercetoolsMockOptions> = {}) {
54
- this.options = { ...DEFAULT_OPTIONS, ...options }
55
- this._services = null
56
- this._repositories = null
57
- this._projectService = undefined
58
-
59
- this._storage = new InMemoryStorage()
60
- this._oauth2 = new OAuth2Server({
61
- enabled: this.options.enableAuthentication,
62
- validate: this.options.validateCredentials,
63
- })
64
-
65
- this.app = this.createApp({ silent: this.options.silent })
66
- }
67
-
68
- start() {
69
- // Order is important here when the hostnames match
70
- this.mockAuthHost()
71
- this.mockApiHost()
72
- }
73
-
74
- stop() {
75
- this._nockScopes.auth?.persist(false)
76
- this._nockScopes.auth = undefined
77
-
78
- this._nockScopes.api?.persist(false)
79
- this._nockScopes.api = undefined
80
- }
81
-
82
- clear() {
83
- this._storage.clear()
84
- }
85
-
86
- project(projectKey?: string) {
87
- if (!projectKey && !this.options.defaultProjectKey) {
88
- throw new Error('No projectKey passed and no default set')
89
- }
90
-
91
- if (this._repositories === null) {
92
- throw new Error('repositories not initialized yet')
93
- }
94
-
95
- return new ProjectAPI(
96
- projectKey || this.options.defaultProjectKey!,
97
- this._repositories,
98
- this._storage
99
- )
100
- }
101
-
102
- runServer(port = 3000, options?: AppOptions) {
103
- const server = this.app.listen(port, () => {
104
- console.info(`Mock server listening at http://localhost:${port}`)
105
- })
106
- server.keepAliveTimeout = 60 * 1000
107
- }
108
-
109
- private createApp(options?: AppOptions): express.Express {
110
- this._repositories = createRepositories(this._storage)
111
-
112
- const app = express()
113
-
114
- const projectRouter = express.Router({ mergeParams: true })
115
- projectRouter.use(express.json())
116
-
117
- if (!options?.silent) {
118
- app.use(morgan('tiny'))
119
- }
120
- app.use('/oauth', this._oauth2.createRouter())
121
-
122
- // Only enable auth middleware if we have enabled this
123
- if (this.options.enableAuthentication) {
124
- app.use('/:projectKey', this._oauth2.createMiddleware(), projectRouter)
125
- app.use(
126
- '/:projectKey/in-store/key=:storeKey',
127
- this._oauth2.createMiddleware(),
128
- projectRouter
129
- )
130
- } else {
131
- app.use('/:projectKey', projectRouter)
132
- app.use('/:projectKey/in-store/key=:storeKey', projectRouter)
133
- }
134
-
135
- // Register the rest api services in the router
136
- this._services = createServices(projectRouter, this._repositories)
137
- this._projectService = new ProjectService(
138
- projectRouter,
139
- this._repositories.project as ProjectRepository
140
- )
141
-
142
- app.use((err: Error, req: Request, resp: Response, next: NextFunction) => {
143
- if (err instanceof CommercetoolsError) {
144
- return resp.status(err.statusCode).send({
145
- statusCode: err.statusCode,
146
- message: err.message,
147
- errors: [err.info],
148
- })
149
- } else {
150
- console.error(err)
151
- return resp.status(500).send({
152
- error: err.message,
153
- })
154
- }
155
- })
156
-
157
- return app
158
- }
159
-
160
- private mockApiHost() {
161
- const app = this.app
162
-
163
- this._nockScopes.api = nock(this.options.apiHost)
164
- .persist()
165
- .get(/.*/)
166
- .reply(async function (uri) {
167
- const response = await supertest(app)
168
- .get(uri)
169
- .set(copyHeaders(this.req.headers))
170
- return [response.status, response.body]
171
- })
172
- .post(/.*/)
173
- .reply(async function (uri, body) {
174
- const response = await supertest(app)
175
- .post(uri)
176
- .set(copyHeaders(this.req.headers))
177
- .send(body)
178
- return [response.status, response.body]
179
- })
180
- .delete(/.*/)
181
- .reply(async function (uri, body) {
182
- const response = await supertest(app)
183
- .delete(uri)
184
- .set(copyHeaders(this.req.headers))
185
- .send(body)
186
- return [response.status, response.body]
187
- })
188
- }
189
-
190
- private mockAuthHost() {
191
- const app = this.app
192
-
193
- this._nockScopes.auth = nock(this.options.authHost)
194
- .persist()
195
- .post(/^\/oauth\/.*/)
196
- .reply(async function (uri, body) {
197
- const response = await supertest(app)
198
- .post(uri + '?' + body)
199
- .set(copyHeaders(this.req.headers))
200
- .send()
201
- return [response.status, response.body]
202
- })
203
- }
40
+ public app: express.Express
41
+ public options: CommercetoolsMockOptions
42
+
43
+ private _storage: AbstractStorage
44
+ private _oauth2: OAuth2Server
45
+ private _nockScopes: {
46
+ auth: nock.Scope | undefined
47
+ api: nock.Scope | undefined
48
+ } = { auth: undefined, api: undefined }
49
+ private _services: Services | null
50
+ private _repositories: RepositoryMap | null
51
+ private _projectService?: ProjectService
52
+
53
+ constructor(options: Partial<CommercetoolsMockOptions> = {}) {
54
+ this.options = { ...DEFAULT_OPTIONS, ...options }
55
+ this._services = null
56
+ this._repositories = null
57
+ this._projectService = undefined
58
+
59
+ this._storage = new InMemoryStorage()
60
+ this._oauth2 = new OAuth2Server({
61
+ enabled: this.options.enableAuthentication,
62
+ validate: this.options.validateCredentials,
63
+ })
64
+
65
+ this.app = this.createApp({ silent: this.options.silent })
66
+ }
67
+
68
+ start() {
69
+ // Order is important here when the hostnames match
70
+ this.mockAuthHost()
71
+ this.mockApiHost()
72
+ }
73
+
74
+ stop() {
75
+ this._nockScopes.auth?.persist(false)
76
+ this._nockScopes.auth = undefined
77
+
78
+ this._nockScopes.api?.persist(false)
79
+ this._nockScopes.api = undefined
80
+ }
81
+
82
+ clear() {
83
+ this._storage.clear()
84
+ }
85
+
86
+ project(projectKey?: string) {
87
+ if (!projectKey && !this.options.defaultProjectKey) {
88
+ throw new Error('No projectKey passed and no default set')
89
+ }
90
+
91
+ if (this._repositories === null) {
92
+ throw new Error('repositories not initialized yet')
93
+ }
94
+
95
+ return new ProjectAPI(
96
+ projectKey || this.options.defaultProjectKey!,
97
+ this._repositories,
98
+ this._storage
99
+ )
100
+ }
101
+
102
+ runServer(port = 3000, options?: AppOptions) {
103
+ const server = this.app.listen(port, () => {
104
+ console.info(`Mock server listening at http://localhost:${port}`)
105
+ })
106
+ server.keepAliveTimeout = 60 * 1000
107
+ }
108
+
109
+ private createApp(options?: AppOptions): express.Express {
110
+ this._repositories = createRepositories(this._storage)
111
+
112
+ const app = express()
113
+
114
+ const projectRouter = express.Router({ mergeParams: true })
115
+ projectRouter.use(express.json())
116
+
117
+ if (!options?.silent) {
118
+ app.use(morgan('tiny'))
119
+ }
120
+ app.use('/oauth', this._oauth2.createRouter())
121
+
122
+ // Only enable auth middleware if we have enabled this
123
+ if (this.options.enableAuthentication) {
124
+ app.use('/:projectKey', this._oauth2.createMiddleware(), projectRouter)
125
+ app.use(
126
+ '/:projectKey/in-store/key=:storeKey',
127
+ this._oauth2.createMiddleware(),
128
+ projectRouter
129
+ )
130
+ } else {
131
+ app.use('/:projectKey', projectRouter)
132
+ app.use('/:projectKey/in-store/key=:storeKey', projectRouter)
133
+ }
134
+
135
+ // Register the rest api services in the router
136
+ this._services = createServices(projectRouter, this._repositories)
137
+ this._projectService = new ProjectService(
138
+ projectRouter,
139
+ this._repositories.project as ProjectRepository
140
+ )
141
+
142
+ app.use((err: Error, req: Request, resp: Response, next: NextFunction) => {
143
+ if (err instanceof CommercetoolsError) {
144
+ return resp.status(err.statusCode).send({
145
+ statusCode: err.statusCode,
146
+ message: err.message,
147
+ errors: [err.info],
148
+ })
149
+ } else {
150
+ console.error(err)
151
+ return resp.status(500).send({
152
+ error: err.message,
153
+ })
154
+ }
155
+ })
156
+
157
+ return app
158
+ }
159
+
160
+ private mockApiHost() {
161
+ const app = this.app
162
+
163
+ this._nockScopes.api = nock(this.options.apiHost)
164
+ .persist()
165
+ .get(/.*/)
166
+ .reply(async function (uri) {
167
+ const response = await supertest(app)
168
+ .get(uri)
169
+ .set(copyHeaders(this.req.headers))
170
+ return [response.status, response.body]
171
+ })
172
+ .post(/.*/)
173
+ .reply(async function (uri, body) {
174
+ const response = await supertest(app)
175
+ .post(uri)
176
+ .set(copyHeaders(this.req.headers))
177
+ .send(body)
178
+ return [response.status, response.body]
179
+ })
180
+ .delete(/.*/)
181
+ .reply(async function (uri, body) {
182
+ const response = await supertest(app)
183
+ .delete(uri)
184
+ .set(copyHeaders(this.req.headers))
185
+ .send(body)
186
+ return [response.status, response.body]
187
+ })
188
+ }
189
+
190
+ private mockAuthHost() {
191
+ const app = this.app
192
+
193
+ this._nockScopes.auth = nock(this.options.authHost)
194
+ .persist()
195
+ .post(/^\/oauth\/.*/)
196
+ .reply(async function (uri, body) {
197
+ const response = await supertest(app)
198
+ .post(uri + '?' + body)
199
+ .set(copyHeaders(this.req.headers))
200
+ .send()
201
+ return [response.status, response.body]
202
+ })
203
+ }
204
204
  }
package/src/exceptions.ts CHANGED
@@ -1,19 +1,19 @@
1
1
  export abstract class BaseError {
2
- abstract message: string
2
+ abstract message: string
3
3
  }
4
4
 
5
5
  export class CommercetoolsError<T extends BaseError> extends Error {
6
- info: T
7
- statusCode: number
6
+ info: T
7
+ statusCode: number
8
8
 
9
- constructor(info: T, statusCode = 400) {
10
- super(info.message)
11
- this.info = info
12
- this.statusCode = statusCode || 500
13
- }
9
+ constructor(info: T, statusCode = 400) {
10
+ super(info.message)
11
+ this.info = info
12
+ this.statusCode = statusCode || 500
13
+ }
14
14
  }
15
15
 
16
16
  export interface InvalidRequestError {
17
- readonly code: 'invalid_request'
18
- readonly message: string
17
+ readonly code: 'invalid_request'
18
+ readonly message: string
19
19
  }
package/src/helpers.ts CHANGED
@@ -2,10 +2,10 @@ import { ParsedQs } from 'qs'
2
2
  import { v4 as uuidv4 } from 'uuid'
3
3
 
4
4
  export const getBaseResourceProperties = () => ({
5
- id: uuidv4(),
6
- createdAt: new Date().toISOString(),
7
- lastModifiedAt: new Date().toISOString(),
8
- version: 0,
5
+ id: uuidv4(),
6
+ createdAt: new Date().toISOString(),
7
+ lastModifiedAt: new Date().toISOString(),
8
+ version: 0,
9
9
  })
10
10
 
11
11
  /**
@@ -13,36 +13,36 @@ export const getBaseResourceProperties = () => ({
13
13
  * return obj['foo']['bar']['value']
14
14
  */
15
15
  export const nestedLookup = (obj: any, path: string): any => {
16
- if (!path || path === '') {
17
- return obj
18
- }
16
+ if (!path || path === '') {
17
+ return obj
18
+ }
19
19
 
20
- const parts = path.split('.')
21
- let val = obj
20
+ const parts = path.split('.')
21
+ let val = obj
22
22
 
23
- for (let i = 0; i < parts.length; i++) {
24
- const part = parts[i]
25
- if (val == undefined) {
26
- return undefined
27
- }
23
+ for (let i = 0; i < parts.length; i++) {
24
+ const part = parts[i]
25
+ if (val == undefined) {
26
+ return undefined
27
+ }
28
28
 
29
- val = val[part]
30
- }
29
+ val = val[part]
30
+ }
31
31
 
32
- return val
32
+ return val
33
33
  }
34
34
 
35
35
  export const QueryParamsAsArray = (
36
- input: string | ParsedQs | string[] | ParsedQs[] | undefined
36
+ input: string | ParsedQs | string[] | ParsedQs[] | undefined
37
37
  ): string[] => {
38
- if (input == undefined) {
39
- return []
40
- }
41
-
42
- if (Array.isArray(input)) {
43
- return input as string[]
44
- }
45
- return [input] as string[]
38
+ if (input == undefined) {
39
+ return []
40
+ }
41
+
42
+ if (Array.isArray(input)) {
43
+ return input as string[]
44
+ }
45
+ return [input] as string[]
46
46
  }
47
47
 
48
48
  export const cloneObject = <T>(o: T): T => JSON.parse(JSON.stringify(o))