@labdigital/commercetools-mock 2.41.0 → 2.42.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@labdigital/commercetools-mock",
3
- "version": "2.41.0",
3
+ "version": "2.42.0",
4
4
  "license": "MIT",
5
5
  "author": "Michael van Tellingen",
6
6
  "type": "module",
package/src/ctMock.ts CHANGED
@@ -12,7 +12,6 @@ import { OAuth2Server } from "./oauth/server";
12
12
  import { ProjectAPI } from "./projectAPI";
13
13
  import type { AbstractStorage } from "./storage";
14
14
  import { InMemoryStorage } from "./storage";
15
- import type { Services } from "./types";
16
15
 
17
16
  // Services
18
17
  import { warnDeprecation } from "./deprecation";
@@ -56,15 +55,12 @@ export class CommercetoolsMock {
56
55
 
57
56
  private _mswServer: SetupServer | undefined = undefined;
58
57
 
59
- private _services: Services | null;
60
-
61
58
  private _repositories: RepositoryMap | null;
62
59
 
63
60
  private _projectService?: ProjectService;
64
61
 
65
62
  constructor(options: Partial<CommercetoolsMockOptions> = {}) {
66
63
  this.options = { ...DEFAULT_OPTIONS, ...options };
67
- this._services = null;
68
64
  this._repositories = null;
69
65
  this._projectService = undefined;
70
66
 
@@ -154,7 +150,7 @@ export class CommercetoolsMock {
154
150
  }
155
151
 
156
152
  // Register the rest api services in the router
157
- this._services = createServices(projectRouter, this._repositories);
153
+ createServices(projectRouter, this._repositories);
158
154
  this._projectService = new ProjectService(
159
155
  projectRouter,
160
156
  this._repositories.project as ProjectRepository,
@@ -0,0 +1,5 @@
1
+ import { CartRepository } from "./cart";
2
+ import { OrderRepository } from "./order";
3
+
4
+ export class AsAssociateOrderRepository extends OrderRepository {}
5
+ export class AsAssociateCartRepository extends CartRepository {}
@@ -91,9 +91,10 @@ export class BusinessUnitRepository extends AbstractResourceRepository<"business
91
91
  associateMode: draft.associateMode,
92
92
  approvalRuleMode: draft.approvalRuleMode,
93
93
 
94
- associates: draft.associates?.map((a) =>
95
- createAssociate(a, context.projectKey, this._storage),
96
- ),
94
+ associates:
95
+ draft.associates?.map((a) =>
96
+ createAssociate(a, context.projectKey, this._storage),
97
+ ) ?? [],
97
98
  };
98
99
 
99
100
  if (this._isDivisionDraft(draft)) {
@@ -46,7 +46,7 @@ describe("Customer repository", () => {
46
46
  );
47
47
  });
48
48
 
49
- test("adding stores to customer", async () => {
49
+ test("adding multiple stores to customer", async () => {
50
50
  const store1: Store = {
51
51
  id: "d0016081-e9af-48a7-8133-1f04f340a335",
52
52
  key: "store-1",
@@ -112,6 +112,46 @@ describe("Customer repository", () => {
112
112
  ]);
113
113
  });
114
114
 
115
+ test("adding single store to customer", async () => {
116
+ const store1: Store = {
117
+ id: "58082253-fe4e-4714-941f-86ab596d42ed",
118
+ key: "store-1",
119
+ name: {
120
+ en: "Store 1",
121
+ },
122
+ version: 1,
123
+ createdAt: "2021-09-02T12:23:30.036Z",
124
+ lastModifiedAt: "2021-09-02T12:23:30.546Z",
125
+ languages: [],
126
+ distributionChannels: [],
127
+ countries: [],
128
+ supplyChannels: [],
129
+ productSelections: [],
130
+ };
131
+
132
+ storage.add("dummy", "store", store1);
133
+
134
+ const result = repository.create(
135
+ { projectKey: "dummy" },
136
+ {
137
+ email: "my-customer2@email.com",
138
+ stores: [
139
+ {
140
+ typeId: "store",
141
+ key: store1.key,
142
+ },
143
+ ],
144
+ },
145
+ );
146
+
147
+ expect(result?.stores).toEqual([
148
+ {
149
+ typeId: "store",
150
+ key: store1.key,
151
+ },
152
+ ]);
153
+ });
154
+
115
155
  test("adding customer without linked stores", async () => {
116
156
  const result = repository.create(
117
157
  { projectKey: "dummy" },
@@ -9,7 +9,9 @@ import type {
9
9
  InvalidInputError,
10
10
  MyCustomerResetPassword,
11
11
  ResourceNotFoundError,
12
+ Store,
12
13
  StoreKeyReference,
14
+ StoreResourceIdentifier,
13
15
  } from "@commercetools/platform-sdk";
14
16
  import { CommercetoolsError } from "~src/exceptions";
15
17
  import { generateRandomString, getBaseResourceProperties } from "~src/helpers";
@@ -106,28 +108,10 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
106
108
  let storesForCustomer: StoreKeyReference[] = [];
107
109
 
108
110
  if (draft.stores && draft.stores.length > 0) {
109
- const storeIds = draft.stores
110
- .map((storeReference) => storeReference.id)
111
- .filter(Boolean);
112
-
113
- const stores = this._storage.query(context.projectKey, "store", {
114
- where: storeIds.map((id) => `id="${id}"`),
115
- }).results;
116
-
117
- if (storeIds.length !== stores.length) {
118
- throw new CommercetoolsError<ResourceNotFoundError>({
119
- code: "ResourceNotFound",
120
- message: `Store with ID '${storeIds.find((id) => !stores.some((store) => store.id === id))}' was not found.`,
121
- });
122
- }
123
-
124
- storesForCustomer = draft.stores.map((storeReference) => ({
125
- typeId: "store",
126
- key:
127
- storeReference.key ??
128
- (stores.find((store) => store.id === storeReference.id)
129
- ?.key as string),
130
- }));
111
+ storesForCustomer = this.storeReferenceToStoreKeyReference(
112
+ draft.stores,
113
+ context.projectKey,
114
+ );
131
115
  }
132
116
 
133
117
  const resource: Customer = {
@@ -267,4 +251,35 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
267
251
  value: token,
268
252
  };
269
253
  }
254
+
255
+ private storeReferenceToStoreKeyReference(
256
+ draftStores: StoreResourceIdentifier[],
257
+ projectKey: string,
258
+ ): StoreKeyReference[] {
259
+ const storeIds = draftStores
260
+ .map((storeReference) => storeReference.id)
261
+ .filter(Boolean);
262
+
263
+ let stores: Store[] = [];
264
+
265
+ if (storeIds.length > 0) {
266
+ stores = this._storage.query(projectKey, "store", {
267
+ where: storeIds.map((id) => `id="${id}"`),
268
+ }).results;
269
+
270
+ if (storeIds.length !== stores.length) {
271
+ throw new CommercetoolsError<ResourceNotFoundError>({
272
+ code: "ResourceNotFound",
273
+ message: `Store with ID '${storeIds.find((id) => !stores.some((store) => store.id === id))}' was not found.`,
274
+ });
275
+ }
276
+ }
277
+
278
+ return draftStores.map((storeReference) => ({
279
+ typeId: "store",
280
+ key:
281
+ storeReference.key ??
282
+ (stores.find((store) => store.id === storeReference.id)?.key as string),
283
+ }));
284
+ }
270
285
  }
@@ -1,5 +1,9 @@
1
1
  import { ProductTailoringRepository } from "~src/repositories/product-tailoring";
2
2
  import type { AbstractStorage } from "../storage";
3
+ import {
4
+ AsAssociateCartRepository,
5
+ AsAssociateOrderRepository,
6
+ } from "./as-associate";
3
7
  import { AssociateRoleRepository } from "./associate-role";
4
8
  import { AttributeGroupRepository } from "./attribute-group";
5
9
  import { BusinessUnitRepository } from "./business-unit";
@@ -41,6 +45,10 @@ import { ZoneRepository } from "./zone";
41
45
  export type RepositoryMap = ReturnType<typeof createRepositories>;
42
46
 
43
47
  export const createRepositories = (storage: AbstractStorage) => ({
48
+ "as-associate": {
49
+ cart: new AsAssociateCartRepository(storage),
50
+ order: new AsAssociateOrderRepository(storage),
51
+ },
44
52
  "associate-role": new AssociateRoleRepository(storage),
45
53
  "attribute-group": new AttributeGroupRepository(storage),
46
54
  "business-unit": new BusinessUnitRepository(storage),
@@ -0,0 +1,33 @@
1
+ import { Router } from "express";
2
+ import type { CartRepository } from "../repositories/cart";
3
+ import AbstractService from "./abstract";
4
+
5
+ export class AsAssociateCartService extends AbstractService {
6
+ public repository: CartRepository;
7
+
8
+ constructor(parent: Router, repository: CartRepository) {
9
+ super(parent);
10
+ this.repository = repository;
11
+ }
12
+
13
+ getBasePath() {
14
+ return "carts";
15
+ }
16
+
17
+ registerRoutes(parent: Router) {
18
+ const basePath = this.getBasePath();
19
+ const router = Router({ mergeParams: true });
20
+
21
+ this.extraRoutes(router);
22
+
23
+ router.get("/", this.get.bind(this));
24
+ router.get("/:id", this.getWithId.bind(this));
25
+
26
+ router.delete("/:id", this.deleteWithId.bind(this));
27
+
28
+ router.post("/", this.post.bind(this));
29
+ router.post("/:id", this.postWithId.bind(this));
30
+
31
+ parent.use(`/${basePath}`, router);
32
+ }
33
+ }
@@ -0,0 +1,64 @@
1
+ import type { Order } from "@commercetools/platform-sdk";
2
+ import assert from "assert";
3
+ import supertest from "supertest";
4
+ import { afterEach, beforeEach, describe, expect, test } from "vitest";
5
+ import { CommercetoolsMock } from "../index";
6
+
7
+ describe("Order Query", () => {
8
+ const ctMock = new CommercetoolsMock();
9
+ let order: Order | undefined;
10
+ const projectKey = "dummy";
11
+ const customerId = "5fac8fca-2484-4b14-a1d1-cfdce2f8d3c4";
12
+ const businessUnitKey = "business-unit";
13
+
14
+ beforeEach(async () => {
15
+ let response = await supertest(ctMock.app)
16
+ .post(
17
+ `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/carts`,
18
+ )
19
+ .send({
20
+ currency: "EUR",
21
+ custom: {
22
+ type: {
23
+ key: "my-cart",
24
+ },
25
+ fields: {
26
+ description: "example description",
27
+ },
28
+ },
29
+ });
30
+ expect(response.status).toBe(201);
31
+ const cart = response.body;
32
+
33
+ response = await supertest(ctMock.app)
34
+ .post(
35
+ `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/orders`,
36
+ )
37
+ .send({
38
+ cart: {
39
+ typeId: "cart",
40
+ id: cart.id,
41
+ },
42
+ orderNumber: "foobar",
43
+ });
44
+ expect(response.status).toBe(201);
45
+ order = response.body;
46
+ });
47
+
48
+ afterEach(() => {
49
+ ctMock.clear();
50
+ });
51
+
52
+ test("no filter", async () => {
53
+ assert(order, "order not created");
54
+
55
+ const response = await supertest(ctMock.app).get(
56
+ `/${projectKey}/as-associate/${customerId}/in-business-unit/key=${businessUnitKey}/orders`,
57
+ );
58
+ expect(response.status).toBe(200);
59
+ expect(response.body.count).toBe(1);
60
+ expect(response.body.total).toBe(1);
61
+ expect(response.body.offset).toBe(0);
62
+ expect(response.body.limit).toBe(20);
63
+ });
64
+ });
@@ -0,0 +1,33 @@
1
+ import { Router } from "express";
2
+ import type { MyOrderRepository } from "../repositories/my-order";
3
+ import AbstractService from "./abstract";
4
+
5
+ export class AsAssociateOrderService extends AbstractService {
6
+ public repository: MyOrderRepository;
7
+
8
+ constructor(parent: Router, repository: MyOrderRepository) {
9
+ super(parent);
10
+ this.repository = repository;
11
+ }
12
+
13
+ getBasePath() {
14
+ return "orders";
15
+ }
16
+
17
+ registerRoutes(parent: Router) {
18
+ const basePath = this.getBasePath();
19
+ const router = Router({ mergeParams: true });
20
+
21
+ this.extraRoutes(router);
22
+
23
+ router.get("/", this.get.bind(this));
24
+ router.get("/:id", this.getWithId.bind(this));
25
+
26
+ router.delete("/:id", this.deleteWithId.bind(this));
27
+
28
+ router.post("/", this.post.bind(this));
29
+ router.post("/:id", this.postWithId.bind(this));
30
+
31
+ parent.use(`/${basePath}`, router);
32
+ }
33
+ }
@@ -0,0 +1,34 @@
1
+ import { Router } from "express";
2
+ import type {
3
+ AsAssociateCartRepository,
4
+ AsAssociateOrderRepository,
5
+ } from "~src/repositories/as-associate";
6
+ import { AsAssociateCartService } from "./as-associate-cart";
7
+ import { AsAssociateOrderService } from "./as-associate-order";
8
+
9
+ type Repositories = {
10
+ cart: AsAssociateCartRepository;
11
+ order: AsAssociateOrderRepository;
12
+ };
13
+
14
+ export class AsAssociateService {
15
+ router: Router;
16
+
17
+ subServices: {
18
+ cart: AsAssociateCartService;
19
+ order: AsAssociateOrderService;
20
+ };
21
+
22
+ constructor(parent: Router, repositories: Repositories) {
23
+ this.router = Router({ mergeParams: true });
24
+
25
+ this.subServices = {
26
+ order: new AsAssociateOrderService(this.router, repositories.order),
27
+ cart: new AsAssociateCartService(this.router, repositories.cart),
28
+ };
29
+ parent.use(
30
+ "/as-associate/:associateId/in-business-unit/key=:businessUnitId",
31
+ this.router,
32
+ );
33
+ }
34
+ }
@@ -1,4 +1,5 @@
1
1
  import type { createRepositories } from "../repositories";
2
+ import { AsAssociateService } from "./as-associate";
2
3
  import { AssociateRoleServices } from "./associate-roles";
3
4
  import { AttributeGroupService } from "./attribute-group";
4
5
  import { BusinessUnitServices } from "./business-units";
@@ -41,6 +42,7 @@ export const createServices = (
41
42
  repos: ReturnType<typeof createRepositories>,
42
43
  ) => ({
43
44
  "associate-role": new AssociateRoleServices(router, repos["associate-role"]),
45
+ "as-associate": new AsAssociateService(router, repos["as-associate"]),
44
46
  "business-unit": new BusinessUnitServices(router, repos["business-unit"]),
45
47
  "category": new CategoryServices(router, repos["category"]),
46
48
  "cart": new CartService(router, repos["cart"], repos["order"]),
package/src/types.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import type * as ctp from "@commercetools/platform-sdk";
2
2
  import type { RepositoryMap } from "./repositories";
3
- import type AbstractService from "./services/abstract";
4
3
 
5
4
  export const isType = <T>(x: T) => x;
6
5
 
@@ -17,10 +16,6 @@ export type ServiceTypes =
17
16
  | "my-customer"
18
17
  | "my-business-unit";
19
18
 
20
- export type Services = Partial<{
21
- [index in ServiceTypes]: AbstractService;
22
- }>;
23
-
24
19
  export type ResourceType = keyof ResourceMap & keyof RepositoryMap;
25
20
 
26
21
  export type ResourceMap = {