@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
@@ -0,0 +1,20 @@
1
+ // This file is auto-generated by scripts/generate-schemas.ts
2
+ // Do not edit manually.
3
+
4
+ import { z } from "zod";
5
+ import {
6
+ ChangeSubscriptionSchema,
7
+ DeliveryFormatSchema,
8
+ DestinationSchema,
9
+ EventSubscriptionSchema,
10
+ MessageSubscriptionSchema,
11
+ } from "./common.ts";
12
+
13
+ export const SubscriptionDraftSchema = z.object({
14
+ destination: DestinationSchema,
15
+ key: z.string().optional(),
16
+ messages: z.array(MessageSubscriptionSchema).optional(),
17
+ changes: z.array(ChangeSubscriptionSchema).optional(),
18
+ events: z.array(EventSubscriptionSchema).optional(),
19
+ format: DeliveryFormatSchema.optional(),
20
+ });
@@ -0,0 +1,12 @@
1
+ // This file is auto-generated by scripts/generate-schemas.ts
2
+ // Do not edit manually.
3
+
4
+ import { z } from "zod";
5
+ import { TaxRateDraftSchema } from "./common.ts";
6
+
7
+ export const TaxCategoryDraftSchema = z.object({
8
+ name: z.string(),
9
+ description: z.string().optional(),
10
+ rates: z.array(TaxRateDraftSchema).optional(),
11
+ key: z.string().optional(),
12
+ });
@@ -0,0 +1,17 @@
1
+ // This file is auto-generated by scripts/generate-schemas.ts
2
+ // Do not edit manually.
3
+
4
+ import { z } from "zod";
5
+ import {
6
+ FieldDefinitionSchema,
7
+ LocalizedStringSchema,
8
+ ResourceTypeIdSchema,
9
+ } from "./common.ts";
10
+
11
+ export const TypeDraftSchema = z.object({
12
+ key: z.string(),
13
+ name: LocalizedStringSchema,
14
+ description: LocalizedStringSchema.optional(),
15
+ resourceTypeIds: z.array(ResourceTypeIdSchema),
16
+ fieldDefinitions: z.array(FieldDefinitionSchema).optional(),
17
+ });
@@ -0,0 +1,12 @@
1
+ // This file is auto-generated by scripts/generate-schemas.ts
2
+ // Do not edit manually.
3
+
4
+ import { z } from "zod";
5
+ import { LocationSchema } from "./common.ts";
6
+
7
+ export const ZoneDraftSchema = z.object({
8
+ key: z.string().optional(),
9
+ name: z.string(),
10
+ description: z.string().optional(),
11
+ locations: z.array(LocationSchema).optional(),
12
+ });
@@ -1,10 +1,8 @@
1
1
  import { z } from "zod";
2
2
 
3
- const UpdateActionSchema = z
4
- .object({
5
- action: z.string(),
6
- })
7
- .passthrough();
3
+ const UpdateActionSchema = z.looseObject({
4
+ action: z.string(),
5
+ });
8
6
 
9
7
  export const updateRequestSchema = z.object({
10
8
  version: z.number(),
package/src/server.ts CHANGED
@@ -1,16 +1,44 @@
1
+ import pino from "pino";
1
2
  import { CommercetoolsMock } from "./index.ts";
3
+ import { SQLiteStorage } from "./storage/sqlite.ts";
4
+
5
+ const storage = new SQLiteStorage();
2
6
 
3
7
  process.on("SIGINT", () => {
8
+ storage.close();
4
9
  process.exit();
5
10
  });
6
11
 
7
- const instance = new CommercetoolsMock();
12
+ const enableLogging = process.env.ENABLE_LOGGING === "true";
13
+
14
+ const logger = enableLogging
15
+ ? pino({ transport: { target: "pino-pretty" } })
16
+ : undefined;
17
+
18
+ const instance = new CommercetoolsMock({
19
+ strict: true,
20
+ silent: !enableLogging,
21
+ logger,
22
+ storage,
23
+ // enableAuthentication: true,
24
+ // validateCredentials: true,
25
+ });
8
26
 
9
27
  let port = 3000;
10
28
 
11
29
  if (process.env.HTTP_SERVER_PORT)
12
30
  port = Number.parseInt(process.env.HTTP_SERVER_PORT, 10);
13
31
 
14
- // biome-ignore lint: lint/correctness/noConsoleLog
15
- console.info("Starting commercetools-mock on http://localhost:" + port);
16
- instance.runServer(port);
32
+ instance.app.log.info(
33
+ `Starting commercetools-mock on http://localhost:${port}`,
34
+ );
35
+
36
+ async function main() {
37
+ await instance.runServer(port);
38
+ }
39
+
40
+ main().catch((error) => {
41
+ // biome-ignore lint/suspicious/noConsole: Fatal startup error must always be visible regardless of logger config
42
+ console.error("Failed to start commercetools-mock server:", error);
43
+ process.exitCode = 1;
44
+ });
@@ -1,8 +1,12 @@
1
- import type { Update } from "@commercetools/platform-sdk";
2
- import { type Request, type Response, Router } from "express";
1
+ import type {
2
+ ResourceNotFoundError,
3
+ Update,
4
+ } from "@commercetools/platform-sdk";
5
+ import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
3
6
  import type { ParsedQs } from "qs";
7
+ import { CommercetoolsError } from "#src/exceptions.ts";
4
8
  import { updateRequestSchema } from "#src/schemas/update-request.ts";
5
- import { validateData } from "#src/validate.ts";
9
+ import { validateData, validateDraft } from "#src/validate.ts";
6
10
  import { queryParamsArray } from "../helpers.ts";
7
11
  import type {
8
12
  AbstractResourceRepository,
@@ -15,207 +19,309 @@ export default abstract class AbstractService {
15
19
 
16
20
  createStatusCode = 201;
17
21
 
18
- constructor(parent: Router) {
22
+ constructor(parent: FastifyInstance) {
19
23
  this.registerRoutes(parent);
20
24
  }
21
25
 
22
26
  protected abstract getBasePath(): string;
23
27
 
24
- extraRoutes(router: Router) {}
28
+ extraRoutes(instance: FastifyInstance) {}
25
29
 
26
- registerRoutes(parent: Router) {
30
+ registerRoutes(parent: FastifyInstance) {
27
31
  const basePath = this.getBasePath();
28
- const router = Router({ mergeParams: true });
29
-
30
- // Bind this first since the `/:id` routes are currently a bit to greedy
31
- this.extraRoutes(router);
32
+ parent.register(
33
+ (instance, opts, done) => {
34
+ this.extraRoutes(instance);
32
35
 
33
- router.get("/", this.get.bind(this));
34
- router.get("/key=:key", this.getWithKey.bind(this)); // same thing goes for the key routes
35
- router.get("/:id", this.getWithId.bind(this));
36
+ instance.get("/", this.get.bind(this));
37
+ instance.get("/key=:key", this.getWithKey.bind(this));
38
+ instance.get("/:id", this.getWithId.bind(this));
36
39
 
37
- router.delete("/key=:key", this.deleteWithKey.bind(this));
38
- router.delete("/:id", this.deleteWithId.bind(this));
40
+ instance.delete("/key=:key", this.deleteWithKey.bind(this));
41
+ instance.delete("/:id", this.deleteWithId.bind(this));
39
42
 
40
- router.post("/", this.post.bind(this));
41
- router.post("/key=:key", this.postWithKey.bind(this));
42
- router.post("/:id", this.postWithId.bind(this));
43
+ instance.post("/", this.post.bind(this));
44
+ instance.post("/key=:key", this.postWithKey.bind(this));
45
+ instance.post("/:id", this.postWithId.bind(this));
43
46
 
44
- parent.use(`/${basePath}`, router);
47
+ done();
48
+ },
49
+ { prefix: `/${basePath}` },
50
+ );
45
51
  }
46
52
 
47
- get(request: Request, response: Response) {
48
- const limit = this._parseParam(request.query.limit);
49
- const offset = this._parseParam(request.query.offset);
53
+ async get(
54
+ request: FastifyRequest<{
55
+ Params: Record<string, string>;
56
+ Querystring: Record<string, any>;
57
+ }>,
58
+ reply: FastifyReply,
59
+ ) {
60
+ const query = request.query;
61
+ const limit = this._parseParam(query.limit);
62
+ const offset = this._parseParam(query.offset);
50
63
  const params: QueryParams = {
51
- expand: this._parseParam(request.query.expand),
52
- where: this._parseParam(request.query.where),
64
+ expand: this._parseParam(query.expand),
65
+ where: this._parseParam(query.where),
53
66
  limit: limit !== undefined ? Number(limit) : undefined,
54
67
  offset: offset !== undefined ? Number(offset) : undefined,
55
68
  };
56
69
 
57
- for (const key in request.query) {
70
+ for (const key in query) {
58
71
  if (key.startsWith("var.")) {
59
- const items = this._parseParam(request.query[key]);
72
+ const items = this._parseParam(query[key]);
60
73
  if (items) {
61
74
  params[key] = items.length === 1 ? items[0] : items;
62
75
  }
63
76
  }
64
77
  }
65
78
 
66
- const result = this.repository.query(getRepositoryContext(request), params);
67
- response.status(200).send(result);
68
- return;
79
+ const result = await this.repository.query(
80
+ getRepositoryContext(request),
81
+ params,
82
+ );
83
+ return reply.status(200).send(result);
69
84
  }
70
85
 
71
- getWithId(request: Request, response: Response) {
72
- const result = this._expandWithId(request, request.params.id);
86
+ async getWithId(
87
+ request: FastifyRequest<{
88
+ Params: Record<string, string>;
89
+ Querystring: Record<string, any>;
90
+ }>,
91
+ reply: FastifyReply,
92
+ ) {
93
+ const params = request.params;
94
+ const result = await this._expandWithId(request, params.id);
73
95
  if (!result) {
74
- response.status(404).send({
75
- statusCode: 404,
76
- message: `The Resource with ID '${request.params.id} was not found.`,
77
- errors: [
78
- {
79
- code: "ResourceNotFound",
80
- message: `The Resource with ID '${request.params.id} was not found.`,
81
- },
82
- ],
83
- });
84
- return;
96
+ throw new CommercetoolsError<ResourceNotFoundError>(
97
+ {
98
+ code: "ResourceNotFound",
99
+ message: `The Resource with ID '${params.id}' was not found.`,
100
+ },
101
+ 404,
102
+ );
85
103
  }
86
- response.status(200).send(result);
104
+ return reply.status(200).send(result);
87
105
  }
88
106
 
89
- getWithKey(request: Request, response: Response) {
90
- const result = this.repository.getByKey(
107
+ async getWithKey(
108
+ request: FastifyRequest<{
109
+ Params: Record<string, string>;
110
+ Querystring: Record<string, any>;
111
+ }>,
112
+ reply: FastifyReply,
113
+ ) {
114
+ const params = request.params;
115
+ const query = request.query;
116
+ const result = await this.repository.getByKey(
91
117
  getRepositoryContext(request),
92
- request.params.key,
118
+ params.key,
93
119
  {
94
- expand: this._parseParam(request.query.expand),
120
+ expand: this._parseParam(query.expand),
95
121
  },
96
122
  );
97
123
  if (!result) {
98
- response.status(404).send({
99
- statusCode: 404,
100
- message: `The Resource with key '${request.params.id} was not found.`,
101
- errors: [
102
- {
103
- code: "ResourceNotFound",
104
- message: `The Resource with key '${request.params.id} was not found.`,
105
- },
106
- ],
107
- });
108
- return;
124
+ throw new CommercetoolsError<ResourceNotFoundError>(
125
+ {
126
+ code: "ResourceNotFound",
127
+ message: `The Resource with key '${params.key}' was not found.`,
128
+ },
129
+ 404,
130
+ );
109
131
  }
110
- response.status(200).send(result);
132
+ return reply.status(200).send(result);
111
133
  }
112
134
 
113
- deleteWithId(request: Request, response: Response) {
114
- const result = this.repository.delete(
135
+ async deleteWithId(
136
+ request: FastifyRequest<{
137
+ Params: Record<string, string>;
138
+ Querystring: Record<string, any>;
139
+ }>,
140
+ reply: FastifyReply,
141
+ ) {
142
+ const params = request.params;
143
+ const query = request.query;
144
+ const result = await this.repository.delete(
115
145
  getRepositoryContext(request),
116
- request.params.id,
146
+ params.id,
117
147
  {
118
- expand: this._parseParam(request.query.expand),
148
+ expand: this._parseParam(query.expand),
119
149
  },
120
150
  );
121
151
  if (!result) {
122
- response.status(404).send({ statusCode: 404 });
123
- return;
152
+ throw new CommercetoolsError<ResourceNotFoundError>(
153
+ {
154
+ code: "ResourceNotFound",
155
+ message: `The Resource with ID '${params.id}' was not found.`,
156
+ },
157
+ 404,
158
+ );
124
159
  }
125
- response.status(200).send(result);
160
+ return reply.status(200).send(result);
126
161
  }
127
162
 
128
- deleteWithKey(request: Request, response: Response) {
129
- const resource = this.repository.getByKey(
163
+ async deleteWithKey(
164
+ request: FastifyRequest<{
165
+ Params: Record<string, string>;
166
+ Querystring: Record<string, any>;
167
+ }>,
168
+ reply: FastifyReply,
169
+ ) {
170
+ const params = request.params;
171
+ const query = request.query;
172
+ const resource = await this.repository.getByKey(
130
173
  getRepositoryContext(request),
131
- request.params.key,
174
+ params.key,
132
175
  );
133
176
  if (!resource) {
134
- response.status(404).send({ statusCode: 404 });
135
- return;
177
+ throw new CommercetoolsError<ResourceNotFoundError>(
178
+ {
179
+ code: "ResourceNotFound",
180
+ message: `The Resource with key '${params.key}' was not found.`,
181
+ },
182
+ 404,
183
+ );
136
184
  }
137
185
 
138
- const result = this.repository.delete(
186
+ const result = await this.repository.delete(
139
187
  getRepositoryContext(request),
140
188
  resource.id,
141
189
  {
142
- expand: this._parseParam(request.query.expand),
190
+ expand: this._parseParam(query.expand),
143
191
  },
144
192
  );
145
193
  if (!result) {
146
- response.status(404).send({ statusCode: 404 });
147
- return;
194
+ throw new CommercetoolsError<ResourceNotFoundError>(
195
+ {
196
+ code: "ResourceNotFound",
197
+ message: `The Resource with ID '${resource.id}' was not found.`,
198
+ },
199
+ 404,
200
+ );
148
201
  }
149
- response.status(200).send(result);
202
+ return reply.status(200).send(result);
150
203
  }
151
204
 
152
- post(request: Request, response: Response) {
153
- const draft = request.body;
154
- const resource = this.repository.create(
205
+ async post(
206
+ request: FastifyRequest<{
207
+ Params: Record<string, string>;
208
+ Querystring: Record<string, any>;
209
+ }>,
210
+ reply: FastifyReply,
211
+ ) {
212
+ // Validate the draft against the schema when strict mode is enabled
213
+ if (this.repository.strict && this.repository.draftSchema) {
214
+ validateDraft(request.body, this.repository.draftSchema);
215
+ }
216
+
217
+ const resource = await this.repository.create(
155
218
  getRepositoryContext(request),
156
- draft,
219
+ request.body,
220
+ );
221
+
222
+ const query = request.query;
223
+ const expand = this._parseParam(query.expand);
224
+
225
+ // Apply expand on the already-created resource and post-process it
226
+ // instead of re-fetching from storage via _expandWithId.
227
+ const context = getRepositoryContext(request);
228
+ const expanded = await this.repository.expand(context, resource, expand);
229
+ const result = await this.repository.postProcessResource(
230
+ context,
231
+ expanded,
232
+ { expand },
157
233
  );
158
- const result = this._expandWithId(request, resource.id);
159
- response.status(this.createStatusCode).send(result);
234
+ return reply.status(this.createStatusCode).send(result);
160
235
  }
161
236
 
162
- postWithId(request: Request, response: Response) {
237
+ async postWithId(
238
+ request: FastifyRequest<{
239
+ Params: Record<string, string>;
240
+ Querystring: Record<string, any>;
241
+ }>,
242
+ reply: FastifyReply,
243
+ ) {
244
+ const params = request.params;
163
245
  const updateRequest = validateData<Update>(
164
246
  request.body,
165
247
  updateRequestSchema,
166
248
  );
167
- const resource = this.repository.get(
249
+ const resource = await this.repository.get(
168
250
  getRepositoryContext(request),
169
- request.params.id,
251
+ params.id,
170
252
  );
171
253
  if (!resource) {
172
- response.status(404).send({ statusCode: 404 });
173
- return;
254
+ throw new CommercetoolsError<ResourceNotFoundError>(
255
+ {
256
+ code: "ResourceNotFound",
257
+ message: `The Resource with ID '${params.id}' was not found.`,
258
+ },
259
+ 404,
260
+ );
174
261
  }
175
262
 
176
- const updatedResource = this.repository.processUpdateActions(
263
+ const updatedResource = await this.repository.processUpdateActions(
177
264
  getRepositoryContext(request),
178
265
  resource,
179
266
  updateRequest.version,
180
267
  updateRequest.actions,
181
268
  );
182
269
 
183
- const result = this._expandWithId(request, updatedResource.id);
184
- response.status(200).send(result);
270
+ const result = await this._expandWithId(request, updatedResource.id);
271
+ return reply.status(200).send(result);
185
272
  }
186
273
 
187
- postWithKey(request: Request, response: Response) {
274
+ async postWithKey(
275
+ request: FastifyRequest<{
276
+ Params: Record<string, string>;
277
+ Querystring: Record<string, any>;
278
+ }>,
279
+ reply: FastifyReply,
280
+ ) {
281
+ const params = request.params;
188
282
  const updateRequest = validateData<Update>(
189
283
  request.body,
190
284
  updateRequestSchema,
191
285
  );
192
286
 
193
- const resource = this.repository.getByKey(
287
+ const resource = await this.repository.getByKey(
194
288
  getRepositoryContext(request),
195
- request.params.key,
289
+ params.key,
196
290
  );
197
291
  if (!resource) {
198
- response.status(404).send({ statusCode: 404 });
199
- return;
292
+ throw new CommercetoolsError<ResourceNotFoundError>(
293
+ {
294
+ code: "ResourceNotFound",
295
+ message: `The Resource with key '${params.key}' was not found.`,
296
+ },
297
+ 404,
298
+ );
200
299
  }
201
300
 
202
- const updatedResource = this.repository.processUpdateActions(
301
+ const updatedResource = await this.repository.processUpdateActions(
203
302
  getRepositoryContext(request),
204
303
  resource,
205
304
  updateRequest.version,
206
305
  updateRequest.actions,
207
306
  );
208
307
 
209
- const result = this._expandWithId(request, updatedResource.id);
210
- response.status(200).send(result);
308
+ const result = await this._expandWithId(request, updatedResource.id);
309
+ return reply.status(200).send(result);
211
310
  }
212
311
 
213
- protected _expandWithId(request: Request, resourceId: string) {
214
- const result = this.repository.get(
312
+ protected async _expandWithId(
313
+ request: FastifyRequest<{
314
+ Params: Record<string, string>;
315
+ Querystring: Record<string, any>;
316
+ }>,
317
+ resourceId: string,
318
+ ) {
319
+ const query = request.query;
320
+ const result = await this.repository.get(
215
321
  getRepositoryContext(request),
216
322
  resourceId,
217
323
  {
218
- expand: this._parseParam(request.query.expand),
324
+ expand: this._parseParam(query.expand),
219
325
  },
220
326
  );
221
327
  return result;
@@ -1,5 +1,5 @@
1
- import supertest from "supertest";
2
1
  import { describe, expect, test } from "vitest";
2
+ import { cartDraftFactory } from "#src/testing/index.ts";
3
3
  import { CommercetoolsMock } from "../index.ts";
4
4
 
5
5
  const ctMock = new CommercetoolsMock();
@@ -8,51 +8,43 @@ const customerId = "5fac8fca-2484-4b14-a1d1-cfdce2f8d3c4";
8
8
  const businessUnitKey = "test-business-unit";
9
9
 
10
10
  describe("AsAssociateCart", () => {
11
+ const factory = cartDraftFactory(ctMock);
12
+
11
13
  test("Create cart", async () => {
12
- const draft = {
13
- currency: "EUR",
14
- };
15
- const response = await supertest(ctMock.app)
16
- .post(
17
- `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
18
- )
19
- .send(draft);
20
-
21
- expect(response.status).toBe(201);
22
- expect(response.body.id).toBeDefined();
14
+ const draft = factory.build({ currency: "EUR" });
15
+
16
+ const response = await ctMock.app.inject({
17
+ method: "POST",
18
+ url: `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
19
+ payload: draft,
20
+ });
21
+
22
+ expect(response.statusCode).toBe(201);
23
+ const cart = response.json();
24
+ expect(cart.id).toBeDefined();
23
25
  });
24
26
 
25
27
  test("Get cart", async () => {
26
- const createResponse = await supertest(ctMock.app)
27
- .post(
28
- `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
29
- )
30
- .send({ currency: "USD" });
28
+ const cart = await factory.create({ currency: "USD" });
31
29
 
32
- expect(createResponse.status).toBe(201);
30
+ const response = await ctMock.app.inject({
31
+ method: "GET",
32
+ url: `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts/${cart.id}`,
33
+ });
33
34
 
34
- const response = await supertest(ctMock.app).get(
35
- `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts/${createResponse.body.id}`,
36
- );
37
-
38
- expect(response.status).toBe(200);
39
- expect(response.body).toEqual(createResponse.body);
35
+ expect(response.statusCode).toBe(200);
36
+ expect(response.json()).toEqual(cart);
40
37
  });
41
38
 
42
39
  test("Query carts", async () => {
43
- const createResponse = await supertest(ctMock.app)
44
- .post(
45
- `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
46
- )
47
- .send({ currency: "GBP" });
48
-
49
- expect(createResponse.status).toBe(201);
40
+ await factory.create({ currency: "GBP" });
50
41
 
51
- const response = await supertest(ctMock.app).get(
52
- `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
53
- );
42
+ const response = await ctMock.app.inject({
43
+ method: "GET",
44
+ url: `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
45
+ });
54
46
 
55
- expect(response.status).toBe(200);
56
- expect(response.body.count).toBeGreaterThan(0);
47
+ expect(response.statusCode).toBe(200);
48
+ expect(response.json().count).toBeGreaterThan(0);
57
49
  });
58
50
  });