@labdigital/commercetools-mock 2.66.0 → 3.0.0-beta.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.
Files changed (281) hide show
  1. package/README.md +31 -8
  2. package/dist/abstract-BKFcva6S.mjs +1044 -0
  3. package/dist/abstract-BKFcva6S.mjs.map +1 -0
  4. package/dist/config-BcNSzPZz.d.mts +1718 -0
  5. package/dist/index.d.mts +50 -1633
  6. package/dist/index.mjs +3769 -2653
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/storage/sqlite.d.mts +59 -0
  9. package/dist/storage/sqlite.mjs +234 -0
  10. package/dist/storage/sqlite.mjs.map +1 -0
  11. package/package.json +26 -29
  12. package/src/ctMock.ts +125 -136
  13. package/src/helpers.ts +14 -6
  14. package/src/index.ts +5 -0
  15. package/src/lib/masking.ts +4 -5
  16. package/src/lib/product-review-statistics.test.ts +257 -294
  17. package/src/lib/review-statistics.ts +17 -4
  18. package/src/oauth/helpers.ts +7 -4
  19. package/src/oauth/server.test.ts +102 -62
  20. package/src/oauth/server.ts +215 -213
  21. package/src/oauth/store.ts +20 -6
  22. package/src/orderSearch.ts +3 -3
  23. package/src/product-projection-search.ts +38 -20
  24. package/src/product-search-availability.test.ts +31 -52
  25. package/src/product-search.ts +19 -10
  26. package/src/projectAPI.ts +6 -22
  27. package/src/repositories/abstract.ts +182 -48
  28. package/src/repositories/as-associate.test.ts +19 -19
  29. package/src/repositories/associate-role.ts +12 -23
  30. package/src/repositories/attribute-group.test.ts +23 -23
  31. package/src/repositories/attribute-group.ts +6 -4
  32. package/src/repositories/business-unit.test.ts +63 -57
  33. package/src/repositories/business-unit.ts +107 -55
  34. package/src/repositories/cart/actions.ts +96 -65
  35. package/src/repositories/cart/helpers.ts +15 -11
  36. package/src/repositories/cart/index.test.ts +136 -30
  37. package/src/repositories/cart/index.ts +76 -59
  38. package/src/repositories/cart-discount/actions.ts +12 -44
  39. package/src/repositories/cart-discount/index.ts +20 -8
  40. package/src/repositories/category/actions.ts +27 -27
  41. package/src/repositories/category/index.test.ts +13 -9
  42. package/src/repositories/category/index.ts +40 -23
  43. package/src/repositories/channel.test.ts +53 -51
  44. package/src/repositories/channel.ts +12 -22
  45. package/src/repositories/custom-object.ts +34 -25
  46. package/src/repositories/customer/actions.ts +47 -25
  47. package/src/repositories/customer/index.test.ts +11 -11
  48. package/src/repositories/customer/index.ts +65 -35
  49. package/src/repositories/customer-group.test.ts +44 -42
  50. package/src/repositories/customer-group.ts +12 -22
  51. package/src/repositories/discount-code/actions.ts +3 -19
  52. package/src/repositories/discount-code/index.ts +9 -4
  53. package/src/repositories/discount-group/index.ts +8 -3
  54. package/src/repositories/extension.test.ts +27 -27
  55. package/src/repositories/extension.ts +10 -5
  56. package/src/repositories/helpers.ts +126 -47
  57. package/src/repositories/inventory-entry/actions.ts +3 -24
  58. package/src/repositories/inventory-entry/index.ts +19 -11
  59. package/src/repositories/my-customer.ts +13 -12
  60. package/src/repositories/my-order.ts +5 -2
  61. package/src/repositories/order/actions.ts +84 -56
  62. package/src/repositories/order/index.test.ts +36 -31
  63. package/src/repositories/order/index.ts +83 -49
  64. package/src/repositories/order-edit.ts +8 -3
  65. package/src/repositories/payment/actions.ts +64 -44
  66. package/src/repositories/payment/helpers.ts +3 -3
  67. package/src/repositories/payment/index.ts +28 -12
  68. package/src/repositories/product/actions.ts +133 -98
  69. package/src/repositories/product/helpers.ts +29 -16
  70. package/src/repositories/product/index.ts +42 -25
  71. package/src/repositories/product-discount.ts +6 -4
  72. package/src/repositories/product-projection.ts +41 -21
  73. package/src/repositories/product-selection.ts +8 -15
  74. package/src/repositories/product-tailoring.ts +22 -3
  75. package/src/repositories/product-type.ts +45 -4
  76. package/src/repositories/project.ts +57 -13
  77. package/src/repositories/quote/actions.ts +5 -28
  78. package/src/repositories/quote/index.ts +29 -6
  79. package/src/repositories/quote-request/actions.ts +5 -28
  80. package/src/repositories/quote-request/index.test.ts +3 -3
  81. package/src/repositories/quote-request/index.ts +31 -11
  82. package/src/repositories/quote-staged/actions.ts +5 -28
  83. package/src/repositories/quote-staged/index.ts +22 -8
  84. package/src/repositories/recurrence-policy/index.ts +6 -4
  85. package/src/repositories/recurring-order/actions.ts +7 -32
  86. package/src/repositories/recurring-order/index.ts +8 -6
  87. package/src/repositories/review.test.ts +147 -142
  88. package/src/repositories/review.ts +31 -37
  89. package/src/repositories/shipping-method/actions.ts +11 -28
  90. package/src/repositories/shipping-method/index.ts +26 -15
  91. package/src/repositories/shopping-list/actions.ts +21 -31
  92. package/src/repositories/shopping-list/index.ts +44 -22
  93. package/src/repositories/standalone-price.ts +6 -4
  94. package/src/repositories/state.ts +15 -9
  95. package/src/repositories/store.ts +21 -32
  96. package/src/repositories/subscription.test.ts +22 -22
  97. package/src/repositories/subscription.ts +8 -3
  98. package/src/repositories/tax-category/index.ts +8 -3
  99. package/src/repositories/type/actions.ts +21 -3
  100. package/src/repositories/type/index.ts +5 -3
  101. package/src/repositories/zone.test.ts +112 -77
  102. package/src/repositories/zone.ts +5 -3
  103. package/src/schemas/generated/associate-role.ts +13 -0
  104. package/src/schemas/generated/attribute-group.ts +12 -0
  105. package/src/schemas/generated/business-unit.ts +38 -0
  106. package/src/schemas/generated/cart-discount.ts +33 -0
  107. package/src/schemas/generated/cart.ts +61 -0
  108. package/src/schemas/generated/category.ts +25 -0
  109. package/src/schemas/generated/channel.ts +21 -0
  110. package/src/schemas/generated/common.ts +1372 -0
  111. package/src/schemas/generated/custom-object.ts +11 -0
  112. package/src/schemas/generated/customer-group.ts +11 -0
  113. package/src/schemas/generated/customer.ts +47 -0
  114. package/src/schemas/generated/discount-code.ts +25 -0
  115. package/src/schemas/generated/discount-group.ts +13 -0
  116. package/src/schemas/generated/extension.ts +15 -0
  117. package/src/schemas/generated/index.ts +42 -0
  118. package/src/schemas/generated/inventory-entry.ts +20 -0
  119. package/src/schemas/generated/my-quote-request.ts +10 -0
  120. package/src/schemas/generated/order-edit.ts +18 -0
  121. package/src/schemas/generated/order-from-cart.ts +25 -0
  122. package/src/schemas/generated/payment.ts +30 -0
  123. package/src/schemas/generated/product-discount.ts +20 -0
  124. package/src/schemas/generated/product-selection.ts +18 -0
  125. package/src/schemas/generated/product-tailoring.ts +26 -0
  126. package/src/schemas/generated/product-type.ts +12 -0
  127. package/src/schemas/generated/product.ts +37 -0
  128. package/src/schemas/generated/quote-request.ts +19 -0
  129. package/src/schemas/generated/quote.ts +18 -0
  130. package/src/schemas/generated/recurrence-policy.ts +15 -0
  131. package/src/schemas/generated/recurring-order.ts +19 -0
  132. package/src/schemas/generated/review.ts +24 -0
  133. package/src/schemas/generated/shipping-method.ts +24 -0
  134. package/src/schemas/generated/shopping-list.ts +28 -0
  135. package/src/schemas/generated/staged-quote.ts +18 -0
  136. package/src/schemas/generated/standalone-price.ts +32 -0
  137. package/src/schemas/generated/state.ts +20 -0
  138. package/src/schemas/generated/store.ts +23 -0
  139. package/src/schemas/generated/subscription.ts +20 -0
  140. package/src/schemas/generated/tax-category.ts +12 -0
  141. package/src/schemas/generated/type.ts +17 -0
  142. package/src/schemas/generated/zone.ts +12 -0
  143. package/src/schemas/update-request.ts +3 -5
  144. package/src/server.ts +32 -4
  145. package/src/services/abstract.ts +207 -101
  146. package/src/services/as-associate-cart.test.ts +28 -36
  147. package/src/services/as-associate-cart.ts +15 -12
  148. package/src/services/as-associate-order.test.ts +33 -40
  149. package/src/services/as-associate-order.ts +15 -12
  150. package/src/services/as-associate-quote-request.ts +15 -12
  151. package/src/services/as-associate-shopping-list.test.ts +25 -35
  152. package/src/services/as-associate-shopping-list.ts +15 -12
  153. package/src/services/as-associate.test.ts +21 -15
  154. package/src/services/as-associate.ts +23 -22
  155. package/src/services/associate-roles.test.ts +16 -22
  156. package/src/services/associate-roles.ts +2 -2
  157. package/src/services/attribute-group.test.ts +40 -44
  158. package/src/services/attribute-group.ts +2 -2
  159. package/src/services/business-units.test.ts +227 -163
  160. package/src/services/business-units.ts +2 -2
  161. package/src/services/cart-discount.test.ts +253 -187
  162. package/src/services/cart-discount.ts +2 -2
  163. package/src/services/cart.test.ts +833 -832
  164. package/src/services/cart.ts +31 -12
  165. package/src/services/category.test.ts +208 -130
  166. package/src/services/category.ts +2 -2
  167. package/src/services/channel.test.ts +39 -44
  168. package/src/services/channel.ts +2 -2
  169. package/src/services/custom-object.test.ts +103 -79
  170. package/src/services/custom-object.ts +106 -38
  171. package/src/services/customer-group.test.ts +39 -44
  172. package/src/services/customer-group.ts +2 -2
  173. package/src/services/customer.test.ts +357 -292
  174. package/src/services/customer.ts +70 -23
  175. package/src/services/discount-code.test.ts +57 -68
  176. package/src/services/discount-code.ts +2 -2
  177. package/src/services/discount-group.test.ts +111 -134
  178. package/src/services/discount-group.ts +2 -2
  179. package/src/services/draft-validation.test.ts +255 -0
  180. package/src/services/extension.test.ts +39 -44
  181. package/src/services/extension.ts +2 -2
  182. package/src/services/inventory-entry.test.ts +106 -87
  183. package/src/services/inventory-entry.ts +2 -2
  184. package/src/services/my-business-unit.test.ts +82 -112
  185. package/src/services/my-business-unit.ts +25 -19
  186. package/src/services/my-cart.test.ts +46 -41
  187. package/src/services/my-cart.ts +32 -28
  188. package/src/services/my-customer.test.ts +153 -88
  189. package/src/services/my-customer.ts +130 -61
  190. package/src/services/my-order.ts +15 -12
  191. package/src/services/my-payment.test.ts +30 -24
  192. package/src/services/my-payment.ts +2 -2
  193. package/src/services/my-shopping-list.ts +2 -2
  194. package/src/services/order.test.ts +332 -276
  195. package/src/services/order.ts +45 -27
  196. package/src/services/payment.test.ts +31 -29
  197. package/src/services/payment.ts +2 -2
  198. package/src/services/product-discount.test.ts +39 -46
  199. package/src/services/product-discount.ts +2 -2
  200. package/src/services/product-projection.test.ts +176 -166
  201. package/src/services/product-projection.ts +31 -15
  202. package/src/services/product-selection.test.ts +17 -9
  203. package/src/services/product-selection.ts +2 -2
  204. package/src/services/product-type.test.ts +80 -21
  205. package/src/services/product-type.ts +2 -2
  206. package/src/services/product.test.ts +569 -534
  207. package/src/services/product.ts +14 -7
  208. package/src/services/project.test.ts +22 -12
  209. package/src/services/project.ts +28 -13
  210. package/src/services/quote-request.test.ts +36 -39
  211. package/src/services/quote-request.ts +2 -2
  212. package/src/services/quote-staged.ts +2 -2
  213. package/src/services/quote.ts +2 -2
  214. package/src/services/recurrence-policy.test.ts +114 -139
  215. package/src/services/recurrence-policy.ts +2 -2
  216. package/src/services/recurring-order.test.ts +149 -194
  217. package/src/services/recurring-order.ts +2 -2
  218. package/src/services/reviews.test.ts +127 -106
  219. package/src/services/reviews.ts +2 -2
  220. package/src/services/shipping-method.test.ts +96 -125
  221. package/src/services/shipping-method.ts +24 -12
  222. package/src/services/shopping-list.test.ts +183 -141
  223. package/src/services/shopping-list.ts +2 -2
  224. package/src/services/standalone-price.test.ts +60 -46
  225. package/src/services/standalone-price.ts +2 -2
  226. package/src/services/state.test.ts +20 -25
  227. package/src/services/state.ts +2 -2
  228. package/src/services/store.test.ts +26 -45
  229. package/src/services/store.ts +2 -2
  230. package/src/services/subscription.test.ts +39 -44
  231. package/src/services/subscription.ts +2 -2
  232. package/src/services/tax-category.test.ts +33 -36
  233. package/src/services/tax-category.ts +2 -2
  234. package/src/services/type.test.ts +45 -44
  235. package/src/services/type.ts +2 -2
  236. package/src/services/zone.test.ts +40 -44
  237. package/src/services/zone.ts +2 -2
  238. package/src/shipping.ts +41 -11
  239. package/src/storage/abstract.ts +248 -17
  240. package/src/storage/in-memory.ts +147 -290
  241. package/src/storage/sqlite.ts +429 -0
  242. package/src/storage/storage-map.ts +75 -0
  243. package/src/storage/storage.test-helpers.ts +97 -0
  244. package/src/storage/storage.test.ts +802 -0
  245. package/src/testing/associate-role.ts +28 -0
  246. package/src/testing/attribute-group.ts +27 -0
  247. package/src/testing/business-unit.ts +9 -8
  248. package/src/testing/cart-discount.ts +34 -0
  249. package/src/testing/cart.ts +20 -0
  250. package/src/testing/category.ts +25 -0
  251. package/src/testing/channel.ts +23 -0
  252. package/src/testing/custom-object.ts +27 -0
  253. package/src/testing/customer-group.ts +26 -0
  254. package/src/testing/customer.ts +36 -33
  255. package/src/testing/discount-code.ts +29 -0
  256. package/src/testing/discount-group.ts +27 -0
  257. package/src/testing/extension.ts +32 -0
  258. package/src/testing/index.ts +33 -0
  259. package/src/testing/inventory-entry.ts +26 -0
  260. package/src/testing/order.ts +27 -0
  261. package/src/testing/payment.ts +23 -0
  262. package/src/testing/product-discount.ts +33 -0
  263. package/src/testing/product-selection.ts +28 -0
  264. package/src/testing/product-type.ts +27 -0
  265. package/src/testing/product.ts +38 -0
  266. package/src/testing/quote-request.ts +29 -0
  267. package/src/testing/recurrence-policy.ts +33 -0
  268. package/src/testing/recurring-order.ts +32 -0
  269. package/src/testing/review.ts +24 -0
  270. package/src/testing/shipping-method.ts +31 -0
  271. package/src/testing/shopping-list.ts +25 -0
  272. package/src/testing/standalone-price.ts +31 -0
  273. package/src/testing/state.ts +21 -0
  274. package/src/testing/store.ts +26 -0
  275. package/src/testing/subscription.ts +38 -0
  276. package/src/testing/tax-category.ts +27 -0
  277. package/src/testing/type.ts +9 -6
  278. package/src/testing/zone.ts +22 -0
  279. package/src/validate.test.ts +122 -0
  280. package/src/validate.ts +78 -7
  281. package/src/.env +0 -0
package/src/ctMock.ts CHANGED
@@ -1,10 +1,7 @@
1
- import type { NextFunction, Request, Response } from "express";
2
- import express from "express";
3
- import inject from "light-my-request";
4
- import morgan from "morgan";
1
+ import Fastify, { type FastifyBaseLogger, type FastifyInstance } from "fastify";
5
2
  import { HttpResponse, http } from "msw";
6
3
  import type { SetupServer, SetupServerApi } from "msw/node";
7
- import { setupServer } from "msw/node";
4
+ import qs from "qs";
8
5
  import type { Config } from "./config.ts";
9
6
  import { DEFAULT_API_HOSTNAME, DEFAULT_AUTH_HOSTNAME } from "./constants.ts";
10
7
  import { CommercetoolsError } from "./exceptions.ts";
@@ -28,10 +25,10 @@ export type CommercetoolsMockOptions = {
28
25
  authHost: RegExp | string;
29
26
  silent: boolean;
30
27
  strict: boolean;
28
+ storage: AbstractStorage | undefined;
29
+ logger: FastifyBaseLogger | undefined;
31
30
  };
32
31
 
33
- type AppOptions = { silent?: boolean };
34
-
35
32
  const DEFAULT_OPTIONS: CommercetoolsMockOptions = {
36
33
  enableAuthentication: false,
37
34
  validateCredentials: false,
@@ -40,12 +37,14 @@ const DEFAULT_OPTIONS: CommercetoolsMockOptions = {
40
37
  authHost: DEFAULT_AUTH_HOSTNAME,
41
38
  silent: true,
42
39
  strict: false,
40
+ storage: undefined,
41
+ logger: undefined,
43
42
  };
44
43
 
45
44
  const _globalListeners: SetupServer[] = [];
46
45
 
47
46
  export class CommercetoolsMock {
48
- public app: express.Express;
47
+ public app: FastifyInstance;
49
48
 
50
49
  public options: CommercetoolsMockOptions;
51
50
 
@@ -65,37 +64,21 @@ export class CommercetoolsMock {
65
64
  this._repositories = null;
66
65
  this._projectService = undefined;
67
66
 
68
- this._storage = new InMemoryStorage();
67
+ this._storage = this.options.storage ?? new InMemoryStorage();
69
68
  this._oauth2 = new OAuth2Server({
70
69
  enabled: this.options.enableAuthentication,
71
70
  validate: this.options.validateCredentials,
72
71
  });
73
72
 
74
- this.app = this.createApp({ silent: this.options.silent });
75
- }
76
-
77
- start() {
78
- process.emitWarning(
79
- "The start() method is deprecated, use .registerHandlers() to bind to an msw server instead",
80
- "DeprecationWarning",
81
- );
82
-
83
- // Order is important here when the hostnames match
84
- this.clear();
85
- this.startServer();
73
+ this.app = this.createApp();
86
74
  }
87
75
 
88
- stop() {
89
- process.emitWarning(
90
- "The stop() method is deprecated, use .registerHandlers() to bind to an msw server instead",
91
- "DeprecationWarning",
92
- );
93
- this._mswServer?.close();
94
- this._mswServer = undefined;
76
+ get server() {
77
+ return this.app.server;
95
78
  }
96
79
 
97
- clear() {
98
- this._storage.clear();
80
+ async clear() {
81
+ await this._storage.clear();
99
82
  }
100
83
 
101
84
  project(projectKey?: string) {
@@ -123,12 +106,11 @@ export class CommercetoolsMock {
123
106
  return this._oauth2.store;
124
107
  }
125
108
 
126
- runServer(port = 3000, options?: AppOptions) {
127
- const server = this.app.listen(port, () => {});
128
- server.keepAliveTimeout = 60 * 1000;
109
+ async runServer(port = 3000) {
110
+ await this.app.listen({ port, host: "0.0.0.0" });
129
111
  }
130
112
 
131
- private createApp(options?: AppOptions): express.Express {
113
+ private createApp(): FastifyInstance {
132
114
  const config: Config = {
133
115
  strict: this.options.strict,
134
116
  storage: this._storage,
@@ -136,59 +118,92 @@ export class CommercetoolsMock {
136
118
  this._repositories = createRepositories(config);
137
119
  this._oauth2.setCustomerRepository(this._repositories.customer);
138
120
 
139
- const app = express();
140
- // Set limit to 16mb, this is the maximum size allowed by the commercetools API: https://docs.commercetools.com/api/limits
141
- app.use(express.json({ limit: "16mb" }));
121
+ const loggerConfig = this.options.logger
122
+ ? { loggerInstance: this.options.logger }
123
+ : { logger: !this.options.silent ? { level: "info" as const } : false };
142
124
 
143
- const projectRouter = express.Router({ mergeParams: true });
144
-
145
- if (!options?.silent) {
146
- app.use(morgan("tiny"));
147
- }
148
- app.use("/oauth", this._oauth2.createRouter());
149
-
150
- // Only enable auth middleware if we have enabled this
151
- if (this.options.enableAuthentication) {
152
- app.use("/:projectKey", this._oauth2.createMiddleware(), projectRouter);
153
- app.use(
154
- "/:projectKey/in-store/key=:storeKey",
155
- this._oauth2.createMiddleware(),
156
- projectRouter,
157
- );
158
- } else {
159
- app.use("/:projectKey", projectRouter);
160
- app.use("/:projectKey/in-store/key=:storeKey", projectRouter);
161
- }
162
-
163
- // Register the rest api services in the router
164
- createServices(projectRouter, this._repositories);
165
- this._projectService = new ProjectService(
166
- projectRouter,
167
- this._repositories.project as ProjectRepository,
168
- );
125
+ const app = Fastify({
126
+ // Set limit to 16mb, this is the maximum size allowed by the commercetools API: https://docs.commercetools.com/api/limits
127
+ bodyLimit: 16 * 1024 * 1024,
128
+ ...loggerConfig,
129
+ routerOptions: {
130
+ querystringParser: (str) => qs.parse(str),
131
+ },
132
+ });
169
133
 
170
- app.use((err: Error, req: Request, resp: Response, next: NextFunction) => {
171
- if (err instanceof CommercetoolsError) {
172
- if (err.errors?.length > 0) {
173
- resp.status(err.statusCode).send({
174
- statusCode: err.statusCode,
175
- message: err.message,
176
- errors: err.errors,
177
- });
134
+ // Override the default JSON parser to accept empty bodies. This is
135
+ // needed because some HTTP clients (e.g. commercetools SDKs) send
136
+ // DELETE requests with a Content-Type: application/json header but
137
+ // without a body. Fastify 5 rejects these by default.
138
+ app.addContentTypeParser(
139
+ "application/json",
140
+ { parseAs: "string" },
141
+ (_req, body, done) => {
142
+ if (!body || (typeof body === "string" && body.trim() === "")) {
143
+ done(null, undefined);
178
144
  return;
179
145
  }
146
+ try {
147
+ done(null, JSON.parse(body as string));
148
+ } catch (err) {
149
+ done(err as Error, undefined);
150
+ }
151
+ },
152
+ );
180
153
 
181
- resp.status(err.statusCode).send({
182
- statusCode: err.statusCode,
183
- message: err.message,
184
- errors: [err.info],
185
- });
186
- return;
154
+ // Register OAuth routes
155
+ app.register(this._oauth2.createPlugin(), { prefix: "/oauth" });
156
+
157
+ // Register project routes
158
+ const repositories = this._repositories;
159
+ const oauth2 = this._oauth2;
160
+ const enableAuth = this.options.enableAuthentication;
161
+
162
+ const projectPlugin = async (instance: FastifyInstance) => {
163
+ if (enableAuth) {
164
+ instance.addHook("preHandler", oauth2.createMiddleware());
187
165
  }
188
- resp.status(500).send({
189
- error: err.message,
166
+ createServices(instance, repositories);
167
+ new ProjectService(instance, repositories.project as ProjectRepository);
168
+ };
169
+
170
+ app.register(projectPlugin, { prefix: "/:projectKey" });
171
+ app.register(projectPlugin, {
172
+ prefix: "/:projectKey/in-store/key=:storeKey",
173
+ });
174
+
175
+ // Error handler
176
+ app.setErrorHandler((error, request, reply) => {
177
+ if (error instanceof CommercetoolsError) {
178
+ const responseBody =
179
+ error.errors?.length > 0
180
+ ? {
181
+ statusCode: error.statusCode,
182
+ message: error.message,
183
+ errors: error.errors,
184
+ }
185
+ : {
186
+ statusCode: error.statusCode,
187
+ message: error.message,
188
+ errors: [error.info],
189
+ };
190
+
191
+ request.log.error(
192
+ { statusCode: error.statusCode, err: error },
193
+ `${request.method} ${request.url} - ${error.statusCode}: ${error.message}`,
194
+ );
195
+
196
+ return reply.status(error.statusCode).send(responseBody);
197
+ }
198
+
199
+ request.log.error(
200
+ { statusCode: 500, err: error },
201
+ `${request.method} ${request.url} - 500: ${error instanceof Error ? error.message : String(error)}`,
202
+ );
203
+
204
+ return reply.status(500).send({
205
+ error: error instanceof Error ? error.message : String(error),
190
206
  });
191
- return;
192
207
  });
193
208
 
194
209
  return app;
@@ -210,11 +225,12 @@ export class CommercetoolsMock {
210
225
  const url = new URL(request.url);
211
226
  const headers = copyHeaders(request.headers);
212
227
 
213
- const res = await inject(app)
214
- .post(`${url.pathname}?${url.searchParams.toString()}`)
215
- .body(body)
216
- .headers(headers)
217
- .end();
228
+ const res = await app.inject({
229
+ method: "POST",
230
+ url: `${url.pathname}?${url.searchParams.toString()}`,
231
+ body,
232
+ headers,
233
+ });
218
234
  return new HttpResponse(res.body, {
219
235
  status: res.statusCode,
220
236
  headers: mapHeaderType(res.headers),
@@ -225,16 +241,15 @@ export class CommercetoolsMock {
225
241
  const url = new URL(request.url);
226
242
  const headers = copyHeaders(request.headers);
227
243
 
228
- const res = await inject(app)
229
- .get(`${url.pathname}?${url.searchParams.toString()}`)
230
- .body(body)
231
- .headers(headers)
232
- .end();
244
+ const res = await app.inject({
245
+ method: "GET",
246
+ url: `${url.pathname}?${url.searchParams.toString()}`,
247
+ body,
248
+ headers,
249
+ });
233
250
 
234
251
  if (res.statusCode === 200) {
235
252
  const parsedBody = JSON.parse(res.body);
236
- // Check if we have a count property (e.g. for query-lookups)
237
- // or if we have a result object (e.g. for single lookups)
238
253
  const resultCount =
239
254
  "count" in parsedBody
240
255
  ? parsedBody.count
@@ -256,11 +271,12 @@ export class CommercetoolsMock {
256
271
  const url = new URL(request.url);
257
272
  const headers = copyHeaders(request.headers);
258
273
 
259
- const res = await inject(app)
260
- .get(`${url.pathname}?${url.searchParams.toString()}`)
261
- .body(body)
262
- .headers(headers)
263
- .end();
274
+ const res = await app.inject({
275
+ method: "GET",
276
+ url: `${url.pathname}?${url.searchParams.toString()}`,
277
+ body,
278
+ headers,
279
+ });
264
280
  return new HttpResponse(res.body, {
265
281
  status: res.statusCode,
266
282
  headers: mapHeaderType(res.headers),
@@ -271,11 +287,12 @@ export class CommercetoolsMock {
271
287
  const url = new URL(request.url);
272
288
  const headers = copyHeaders(request.headers);
273
289
 
274
- const res = await inject(app)
275
- .post(`${url.pathname}?${url.searchParams.toString()}`)
276
- .body(body)
277
- .headers(headers)
278
- .end();
290
+ const res = await app.inject({
291
+ method: "POST",
292
+ url: `${url.pathname}?${url.searchParams.toString()}`,
293
+ body,
294
+ headers,
295
+ });
279
296
  return new HttpResponse(res.body, {
280
297
  status: res.statusCode,
281
298
  headers: mapHeaderType(res.headers),
@@ -286,11 +303,12 @@ export class CommercetoolsMock {
286
303
  const url = new URL(request.url);
287
304
  const headers = copyHeaders(request.headers);
288
305
 
289
- const res = await inject(app)
290
- .delete(`${url.pathname}?${url.searchParams.toString()}`)
291
- .body(body)
292
- .headers(headers)
293
- .end();
306
+ const res = await app.inject({
307
+ method: "DELETE",
308
+ url: `${url.pathname}?${url.searchParams.toString()}`,
309
+ body,
310
+ headers,
311
+ });
294
312
  return new HttpResponse(res.body, {
295
313
  status: res.statusCode,
296
314
  headers: mapHeaderType(res.headers),
@@ -302,33 +320,4 @@ export class CommercetoolsMock {
302
320
  public mswServer() {
303
321
  return this._mswServer;
304
322
  }
305
-
306
- private startServer() {
307
- // Check if there are any other servers running
308
- if (_globalListeners.length > 0) {
309
- if (this._mswServer !== undefined) {
310
- throw new Error("Server already started");
311
- }
312
- process.emitWarning("Server wasn't stopped properly, clearing");
313
- for (const listener of _globalListeners) {
314
- listener.close();
315
- }
316
- _globalListeners.length = 0;
317
- }
318
-
319
- const server = setupServer();
320
- this.registerHandlers(server);
321
- server.listen({
322
- // We need to allow requests done by supertest
323
- onUnhandledRequest: (request, print) => {
324
- const url = new URL(request.url);
325
- if (url.hostname === "127.0.0.1") {
326
- return;
327
- }
328
- print.error();
329
- },
330
- });
331
- _globalListeners.push(server);
332
- this._mswServer = server;
333
- }
334
323
  }
package/src/helpers.ts CHANGED
@@ -2,12 +2,20 @@ import type { OutgoingHttpHeaders } from "node:http";
2
2
  import type { ParsedQs } from "qs";
3
3
  import { v4 as uuidv4 } from "uuid";
4
4
 
5
- export const getBaseResourceProperties = () => ({
6
- id: uuidv4(),
7
- createdAt: new Date().toISOString(),
8
- lastModifiedAt: new Date().toISOString(),
9
- version: 0,
10
- });
5
+ export const getBaseResourceProperties = (clientId?: string) => {
6
+ const clientInfo = {
7
+ clientId: clientId ?? "",
8
+ isPlatformClient: false,
9
+ };
10
+ return {
11
+ id: uuidv4(),
12
+ createdAt: new Date().toISOString(),
13
+ lastModifiedAt: new Date().toISOString(),
14
+ version: 0,
15
+ createdBy: clientInfo,
16
+ lastModifiedBy: clientInfo,
17
+ };
18
+ };
11
19
 
12
20
  /**
13
21
  * Do a nested lookup by using a path. For example `foo.bar.value` will
package/src/index.ts CHANGED
@@ -1,9 +1,14 @@
1
1
  import type { CommercetoolsMockOptions } from "./ctMock.ts";
2
2
  import { CommercetoolsMock } from "./ctMock.ts";
3
3
  import { getBaseResourceProperties } from "./helpers.ts";
4
+ import { AbstractStorage, InMemoryStorage } from "./storage/index.ts";
5
+
6
+ export type { FastifyBaseLogger } from "fastify";
4
7
 
5
8
  export {
9
+ AbstractStorage,
6
10
  CommercetoolsMock,
11
+ InMemoryStorage,
7
12
  getBaseResourceProperties,
8
13
  type CommercetoolsMockOptions,
9
14
  };
@@ -1,9 +1,8 @@
1
- import { cloneObject } from "../helpers.ts";
2
-
3
1
  export const maskSecretValue = <T>(resource: T, path: string): T => {
4
2
  const parts = path.split(".");
5
- const clone = cloneObject(resource) as any;
6
- let val = clone;
3
+ // Callers are expected to pass objects that are safe to mutate
4
+ // (e.g. clones from storage retrieval).
5
+ let val = resource as any;
7
6
 
8
7
  const target = parts.pop();
9
8
  for (let i = 0; i < parts.length; i++) {
@@ -18,5 +17,5 @@ export const maskSecretValue = <T>(resource: T, path: string): T => {
18
17
  if (val && target && val[target]) {
19
18
  val[target] = "****";
20
19
  }
21
- return clone;
20
+ return resource;
22
21
  };