@labdigital/commercetools-mock 2.51.0 → 2.53.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/dist/index.d.ts +34 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +140 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/product-review-statistics.test.ts +349 -0
- package/src/lib/productSearchFilter.test.ts +77 -0
- package/src/lib/review-statistics.ts +58 -0
- package/src/product-projection-search.ts +17 -2
- package/src/product-search-availability.test.ts +242 -0
- package/src/product-search.ts +22 -4
- package/src/repositories/as-associate.test.ts +126 -0
- package/src/repositories/attribute-group.test.ts +221 -0
- package/src/repositories/business-unit.test.ts +425 -0
- package/src/repositories/business-unit.ts +57 -1
- package/src/repositories/channel.test.ts +374 -0
- package/src/repositories/customer-group.test.ts +262 -0
- package/src/repositories/extension.test.ts +306 -0
- package/src/repositories/index.test.ts +17 -0
- package/src/repositories/product/index.ts +22 -1
- package/src/repositories/product-projection.ts +8 -2
- package/src/repositories/review.test.ts +636 -0
- package/src/repositories/review.ts +145 -4
- package/src/repositories/subscription.test.ts +207 -0
- package/src/repositories/zone.test.ts +278 -0
- package/src/services/as-associate-cart.test.ts +58 -0
- package/src/services/as-associate.test.ts +34 -0
- package/src/services/attribute-group.test.ts +114 -0
- package/src/services/channel.test.ts +90 -0
- package/src/services/customer-group.test.ts +85 -0
- package/src/services/discount-code.test.ts +120 -0
- package/src/services/extension.test.ts +130 -0
- package/src/services/my-business-unit.test.ts +113 -0
- package/src/services/my-business-unit.ts +6 -0
- package/src/services/my-customer.test.ts +24 -0
- package/src/services/order.test.ts +18 -0
- package/src/services/product-discount.test.ts +146 -0
- package/src/services/project.test.ts +17 -0
- package/src/services/reviews.test.ts +230 -0
- package/src/services/subscription.test.ts +151 -0
- package/src/services/type.test.ts +127 -0
- package/src/services/zone.test.ts +117 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
InventoryEntryDraft,
|
|
3
|
+
ProductDraft,
|
|
4
|
+
ProductPagedSearchResponse,
|
|
5
|
+
ProductSearchRequest,
|
|
6
|
+
} from "@commercetools/platform-sdk";
|
|
7
|
+
import supertest from "supertest";
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
9
|
+
import { CommercetoolsMock } from "./index";
|
|
10
|
+
|
|
11
|
+
describe("Product Search - Availability Filtering", () => {
|
|
12
|
+
const ctMock = new CommercetoolsMock();
|
|
13
|
+
let productId: string;
|
|
14
|
+
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
// Create a product type first
|
|
17
|
+
const productTypeDraft = {
|
|
18
|
+
name: "Test Product Type",
|
|
19
|
+
key: "test-type",
|
|
20
|
+
description: "Test Product Type",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
await supertest(ctMock.app)
|
|
24
|
+
.post("/dummy/product-types")
|
|
25
|
+
.send(productTypeDraft);
|
|
26
|
+
|
|
27
|
+
// Create a test product
|
|
28
|
+
const productDraft: ProductDraft = {
|
|
29
|
+
name: { "en-US": "Test Product" },
|
|
30
|
+
productType: {
|
|
31
|
+
typeId: "product-type",
|
|
32
|
+
key: "test-type",
|
|
33
|
+
},
|
|
34
|
+
slug: { "en-US": "test-product" },
|
|
35
|
+
masterVariant: {
|
|
36
|
+
sku: "TEST-SKU-001",
|
|
37
|
+
},
|
|
38
|
+
variants: [
|
|
39
|
+
{
|
|
40
|
+
sku: "TEST-SKU-002",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const productResponse = await supertest(ctMock.app)
|
|
46
|
+
.post("/dummy/products")
|
|
47
|
+
.send(productDraft);
|
|
48
|
+
|
|
49
|
+
productId = productResponse.body.id;
|
|
50
|
+
|
|
51
|
+
// Publish the product
|
|
52
|
+
await supertest(ctMock.app)
|
|
53
|
+
.post(`/dummy/products/${productId}`)
|
|
54
|
+
.send({
|
|
55
|
+
version: productResponse.body.version,
|
|
56
|
+
actions: [{ action: "publish" }],
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
ctMock.clear();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
async function createInventoryEntry(
|
|
65
|
+
sku: string,
|
|
66
|
+
quantityOnStock: number,
|
|
67
|
+
channelId?: string,
|
|
68
|
+
) {
|
|
69
|
+
const inventoryEntry: InventoryEntryDraft = {
|
|
70
|
+
sku,
|
|
71
|
+
quantityOnStock,
|
|
72
|
+
...(channelId && {
|
|
73
|
+
supplyChannel: {
|
|
74
|
+
typeId: "channel",
|
|
75
|
+
id: channelId,
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
await supertest(ctMock.app).post("/dummy/inventory").send(inventoryEntry);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function searchProducts(
|
|
84
|
+
query?: any,
|
|
85
|
+
): Promise<ProductPagedSearchResponse> {
|
|
86
|
+
const searchRequest: ProductSearchRequest = {
|
|
87
|
+
...(query && { query }),
|
|
88
|
+
productProjectionParameters: {
|
|
89
|
+
staged: false,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const response = await supertest(ctMock.app)
|
|
94
|
+
.post("/dummy/products/search")
|
|
95
|
+
.send(searchRequest);
|
|
96
|
+
|
|
97
|
+
return response.body;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
test("should filter products by variants.availability.isOnStock = true", async () => {
|
|
101
|
+
// Create inventory with stock for one variant
|
|
102
|
+
await createInventoryEntry("TEST-SKU-001", 10);
|
|
103
|
+
|
|
104
|
+
const result = await searchProducts({
|
|
105
|
+
exact: {
|
|
106
|
+
field: "variants.availability.isOnStock",
|
|
107
|
+
value: true,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
expect(result.results).toHaveLength(1);
|
|
112
|
+
expect(
|
|
113
|
+
result.results[0].productProjection?.masterVariant?.availability
|
|
114
|
+
?.isOnStock,
|
|
115
|
+
).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("should filter products by variants.availability.isOnStock = false", async () => {
|
|
119
|
+
// Create inventory with zero stock
|
|
120
|
+
await createInventoryEntry("TEST-SKU-001", 0);
|
|
121
|
+
|
|
122
|
+
const result = await searchProducts({
|
|
123
|
+
exact: {
|
|
124
|
+
field: "variants.availability.isOnStock",
|
|
125
|
+
value: false,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Should find the product because it's not on stock
|
|
130
|
+
expect(result.results).toHaveLength(1);
|
|
131
|
+
expect(
|
|
132
|
+
result.results[0].productProjection?.masterVariant?.availability
|
|
133
|
+
?.isOnStock,
|
|
134
|
+
).toBe(false);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("should filter products by variants.availability.isOnStockForChannel", async () => {
|
|
138
|
+
const channelId = "test-channel-1";
|
|
139
|
+
|
|
140
|
+
// Create inventory for specific channel
|
|
141
|
+
await createInventoryEntry("TEST-SKU-001", 5, channelId);
|
|
142
|
+
|
|
143
|
+
const result = await searchProducts({
|
|
144
|
+
exact: {
|
|
145
|
+
field: "variants.availability.isOnStockForChannel",
|
|
146
|
+
value: channelId,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(result.results).toHaveLength(1);
|
|
151
|
+
expect(
|
|
152
|
+
(result.results[0].productProjection?.masterVariant?.availability as any)
|
|
153
|
+
?.isOnStockForChannel,
|
|
154
|
+
).toBe(channelId);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("should not find products when filtering by non-matching channel", async () => {
|
|
158
|
+
const channelId = "test-channel-1";
|
|
159
|
+
const otherChannelId = "test-channel-2";
|
|
160
|
+
|
|
161
|
+
// Create inventory for specific channel
|
|
162
|
+
await createInventoryEntry("TEST-SKU-001", 5, channelId);
|
|
163
|
+
|
|
164
|
+
const result = await searchProducts({
|
|
165
|
+
exact: {
|
|
166
|
+
field: "variants.availability.isOnStockForChannel",
|
|
167
|
+
value: otherChannelId,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(result.results).toHaveLength(0);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("should handle products without inventory entries", async () => {
|
|
175
|
+
// Don't create any inventory entries
|
|
176
|
+
|
|
177
|
+
const result = await searchProducts({
|
|
178
|
+
exact: {
|
|
179
|
+
field: "variants.availability.isOnStock",
|
|
180
|
+
value: false,
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Should find the product because it has no stock
|
|
185
|
+
expect(result.results).toHaveLength(1);
|
|
186
|
+
expect(
|
|
187
|
+
result.results[0].productProjection?.masterVariant?.availability
|
|
188
|
+
?.isOnStock,
|
|
189
|
+
).toBe(false);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("should work with OR queries for availability", async () => {
|
|
193
|
+
// Create inventory with stock
|
|
194
|
+
await createInventoryEntry("TEST-SKU-001", 10);
|
|
195
|
+
|
|
196
|
+
const result = await searchProducts({
|
|
197
|
+
or: [
|
|
198
|
+
{
|
|
199
|
+
exact: {
|
|
200
|
+
field: "variants.availability.isOnStock",
|
|
201
|
+
value: true,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
exact: {
|
|
206
|
+
field: "variants.availability.isOnStock",
|
|
207
|
+
value: false,
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
],
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Should find the product regardless of stock status
|
|
214
|
+
expect(result.results).toHaveLength(1);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test("should work with AND queries combining availability and other fields", async () => {
|
|
218
|
+
await createInventoryEntry("TEST-SKU-001", 10);
|
|
219
|
+
|
|
220
|
+
const result = await searchProducts({
|
|
221
|
+
and: [
|
|
222
|
+
{
|
|
223
|
+
exact: {
|
|
224
|
+
field: "variants.availability.isOnStock",
|
|
225
|
+
value: true,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
exact: {
|
|
230
|
+
field: "variants.sku",
|
|
231
|
+
value: "TEST-SKU-001",
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
expect(result.results).toHaveLength(1);
|
|
238
|
+
expect(result.results[0].productProjection?.masterVariant?.sku).toBe(
|
|
239
|
+
"TEST-SKU-001",
|
|
240
|
+
);
|
|
241
|
+
});
|
|
242
|
+
});
|
package/src/product-search.ts
CHANGED
|
@@ -148,6 +148,23 @@ export class ProductSearch {
|
|
|
148
148
|
? product.masterData.current
|
|
149
149
|
: product.masterData.staged;
|
|
150
150
|
|
|
151
|
+
const getVariantAvailability = (sku?: string) => {
|
|
152
|
+
if (!sku) {
|
|
153
|
+
return {
|
|
154
|
+
isOnStock: false,
|
|
155
|
+
availableQuantity: 0,
|
|
156
|
+
isOnStockForChannel: undefined,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return (
|
|
160
|
+
availabilityBySku.get(sku) || {
|
|
161
|
+
isOnStock: false,
|
|
162
|
+
availableQuantity: 0,
|
|
163
|
+
isOnStockForChannel: undefined,
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
151
168
|
return {
|
|
152
169
|
id: product.id,
|
|
153
170
|
createdAt: product.createdAt,
|
|
@@ -159,12 +176,13 @@ export class ProductSearch {
|
|
|
159
176
|
metaDescription: obj.metaDescription,
|
|
160
177
|
slug: obj.slug,
|
|
161
178
|
categories: obj.categories,
|
|
162
|
-
masterVariant:
|
|
179
|
+
masterVariant: {
|
|
180
|
+
...obj.masterVariant,
|
|
181
|
+
availability: getVariantAvailability(obj.masterVariant.sku),
|
|
182
|
+
},
|
|
163
183
|
variants: obj.variants.map((variant) => ({
|
|
164
184
|
...variant,
|
|
165
|
-
availability: variant.sku
|
|
166
|
-
? availabilityBySku.get(variant.sku)
|
|
167
|
-
: { isOnStock: false, availableQuantity: 0, isOnStockForChannel: [] },
|
|
185
|
+
availability: getVariantAvailability(variant.sku),
|
|
168
186
|
})),
|
|
169
187
|
productType: product.productType,
|
|
170
188
|
hasStagedChanges: product.masterData.hasStagedChanges,
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import type { Config } from "~src/config";
|
|
3
|
+
import { InMemoryStorage } from "~src/storage";
|
|
4
|
+
import {
|
|
5
|
+
AsAssociateCartRepository,
|
|
6
|
+
AsAssociateOrderRepository,
|
|
7
|
+
AsAssociateQuoteRequestRepository,
|
|
8
|
+
} from "./as-associate";
|
|
9
|
+
import { CustomerRepository } from "./customer";
|
|
10
|
+
|
|
11
|
+
describe("As Associate Repositories", () => {
|
|
12
|
+
const storage = new InMemoryStorage();
|
|
13
|
+
const config: Config = { storage, strict: false };
|
|
14
|
+
|
|
15
|
+
test("AsAssociateCartRepository can create and retrieve carts", () => {
|
|
16
|
+
const repository = new AsAssociateCartRepository(config);
|
|
17
|
+
const ctx = { projectKey: "test-project" };
|
|
18
|
+
|
|
19
|
+
const cartDraft = {
|
|
20
|
+
currency: "EUR",
|
|
21
|
+
inventoryMode: "None" as const,
|
|
22
|
+
taxMode: "Platform" as const,
|
|
23
|
+
taxRoundingMode: "HalfEven" as const,
|
|
24
|
+
taxCalculationMode: "UnitPriceLevel" as const,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const cart = repository.create(ctx, cartDraft);
|
|
28
|
+
expect(cart.id).toBeDefined();
|
|
29
|
+
expect(cart.version).toBe(1);
|
|
30
|
+
expect(cart.totalPrice.currencyCode).toBe("EUR");
|
|
31
|
+
|
|
32
|
+
// Test query
|
|
33
|
+
const result = repository.query(ctx);
|
|
34
|
+
expect(result.count).toBe(1);
|
|
35
|
+
expect(result.results[0].id).toBe(cart.id);
|
|
36
|
+
|
|
37
|
+
// Test get
|
|
38
|
+
const retrieved = repository.get(ctx, cart.id);
|
|
39
|
+
expect(retrieved).toBeDefined();
|
|
40
|
+
expect(retrieved?.id).toBe(cart.id);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("AsAssociateOrderRepository can create and retrieve orders", () => {
|
|
44
|
+
const repository = new AsAssociateOrderRepository(config);
|
|
45
|
+
const ctx = { projectKey: "test-project" };
|
|
46
|
+
|
|
47
|
+
// First create a cart to create an order from
|
|
48
|
+
const cartRepository = new AsAssociateCartRepository(config);
|
|
49
|
+
const cartDraft = {
|
|
50
|
+
currency: "EUR",
|
|
51
|
+
inventoryMode: "None" as const,
|
|
52
|
+
taxMode: "Platform" as const,
|
|
53
|
+
taxRoundingMode: "HalfEven" as const,
|
|
54
|
+
taxCalculationMode: "UnitPriceLevel" as const,
|
|
55
|
+
};
|
|
56
|
+
const cart = cartRepository.create(ctx, cartDraft);
|
|
57
|
+
|
|
58
|
+
const orderDraft = {
|
|
59
|
+
cart: {
|
|
60
|
+
id: cart.id,
|
|
61
|
+
typeId: "cart" as const,
|
|
62
|
+
},
|
|
63
|
+
version: cart.version,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const order = repository.create(ctx, orderDraft);
|
|
67
|
+
expect(order.id).toBeDefined();
|
|
68
|
+
expect(order.version).toBe(1);
|
|
69
|
+
expect(order.cart?.id).toBe(cart.id);
|
|
70
|
+
|
|
71
|
+
// Test query
|
|
72
|
+
const result = repository.query(ctx);
|
|
73
|
+
expect(result.count).toBe(1);
|
|
74
|
+
expect(result.results[0].id).toBe(order.id);
|
|
75
|
+
|
|
76
|
+
// Test get
|
|
77
|
+
const retrieved = repository.get(ctx, order.id);
|
|
78
|
+
expect(retrieved).toBeDefined();
|
|
79
|
+
expect(retrieved?.id).toBe(order.id);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("AsAssociateQuoteRequestRepository can create and retrieve quote requests", () => {
|
|
83
|
+
const repository = new AsAssociateQuoteRequestRepository(config);
|
|
84
|
+
const ctx = { projectKey: "test-project" };
|
|
85
|
+
|
|
86
|
+
// Create a customer using the customer repository
|
|
87
|
+
const customerRepository = new CustomerRepository(config);
|
|
88
|
+
const customer = customerRepository.create(ctx, {
|
|
89
|
+
email: "test@example.com",
|
|
90
|
+
password: "password123",
|
|
91
|
+
firstName: "John",
|
|
92
|
+
lastName: "Doe",
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// First create a cart to create a quote request from
|
|
96
|
+
const cartRepository = new AsAssociateCartRepository(config);
|
|
97
|
+
const cartDraft = {
|
|
98
|
+
currency: "EUR",
|
|
99
|
+
customerId: customer.id,
|
|
100
|
+
};
|
|
101
|
+
const cart = cartRepository.create(ctx, cartDraft);
|
|
102
|
+
|
|
103
|
+
const quoteRequestDraft = {
|
|
104
|
+
cart: {
|
|
105
|
+
id: cart.id,
|
|
106
|
+
typeId: "cart" as const,
|
|
107
|
+
},
|
|
108
|
+
cartVersion: cart.version,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const quoteRequest = repository.create(ctx, quoteRequestDraft);
|
|
112
|
+
expect(quoteRequest.id).toBeDefined();
|
|
113
|
+
expect(quoteRequest.version).toBe(1);
|
|
114
|
+
expect(quoteRequest.cart?.id).toBe(cart.id);
|
|
115
|
+
|
|
116
|
+
// Test query
|
|
117
|
+
const result = repository.query(ctx);
|
|
118
|
+
expect(result.count).toBe(1);
|
|
119
|
+
expect(result.results[0].id).toBe(quoteRequest.id);
|
|
120
|
+
|
|
121
|
+
// Test get
|
|
122
|
+
const retrieved = repository.get(ctx, quoteRequest.id);
|
|
123
|
+
expect(retrieved).toBeDefined();
|
|
124
|
+
expect(retrieved?.id).toBe(quoteRequest.id);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AttributeGroupChangeNameAction,
|
|
3
|
+
AttributeGroupDraft,
|
|
4
|
+
AttributeGroupSetAttributesAction,
|
|
5
|
+
AttributeGroupSetDescriptionAction,
|
|
6
|
+
AttributeGroupSetKeyAction,
|
|
7
|
+
} from "@commercetools/platform-sdk";
|
|
8
|
+
import { describe, expect, test } from "vitest";
|
|
9
|
+
import type { Config } from "~src/config";
|
|
10
|
+
import { InMemoryStorage } from "~src/storage";
|
|
11
|
+
import { AttributeGroupRepository } from "./attribute-group";
|
|
12
|
+
|
|
13
|
+
describe("AttributeGroup Repository", () => {
|
|
14
|
+
const storage = new InMemoryStorage();
|
|
15
|
+
const config: Config = { storage, strict: false };
|
|
16
|
+
const repository = new AttributeGroupRepository(config);
|
|
17
|
+
|
|
18
|
+
test("create attribute group", () => {
|
|
19
|
+
const draft: AttributeGroupDraft = {
|
|
20
|
+
name: { "en-US": "Size Attributes", "de-DE": "Größenattribute" },
|
|
21
|
+
description: { "en-US": "Attributes related to product size" },
|
|
22
|
+
key: "size-attributes",
|
|
23
|
+
attributes: [
|
|
24
|
+
{
|
|
25
|
+
key: "size",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "weight",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const ctx = { projectKey: "dummy" };
|
|
34
|
+
const result = repository.create(ctx, draft);
|
|
35
|
+
|
|
36
|
+
expect(result.id).toBeDefined();
|
|
37
|
+
expect(result.version).toBe(1);
|
|
38
|
+
expect(result.name).toEqual(draft.name);
|
|
39
|
+
expect(result.description).toEqual(draft.description);
|
|
40
|
+
expect(result.key).toBe(draft.key);
|
|
41
|
+
expect(result.attributes).toEqual(draft.attributes);
|
|
42
|
+
|
|
43
|
+
// Test that the attribute group is stored
|
|
44
|
+
const items = repository.query(ctx);
|
|
45
|
+
expect(items.count).toBe(1);
|
|
46
|
+
expect(items.results[0].id).toBe(result.id);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("create attribute group with minimal data", () => {
|
|
50
|
+
const draft: AttributeGroupDraft = {
|
|
51
|
+
name: { "en-US": "Minimal Attributes" },
|
|
52
|
+
attributes: [],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const ctx = { projectKey: "dummy" };
|
|
56
|
+
const result = repository.create(ctx, draft);
|
|
57
|
+
|
|
58
|
+
expect(result.id).toBeDefined();
|
|
59
|
+
expect(result.name).toEqual(draft.name);
|
|
60
|
+
expect(result.description).toBeUndefined();
|
|
61
|
+
expect(result.key).toBeUndefined();
|
|
62
|
+
expect(result.attributes).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("update attribute group - changeName", () => {
|
|
66
|
+
const draft: AttributeGroupDraft = {
|
|
67
|
+
name: { "en-US": "Original Name" },
|
|
68
|
+
key: "test-attributes",
|
|
69
|
+
attributes: [],
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const ctx = { projectKey: "dummy" };
|
|
73
|
+
const attributeGroup = repository.create(ctx, draft);
|
|
74
|
+
|
|
75
|
+
const result = repository.processUpdateActions(
|
|
76
|
+
ctx,
|
|
77
|
+
attributeGroup,
|
|
78
|
+
attributeGroup.version,
|
|
79
|
+
[
|
|
80
|
+
{
|
|
81
|
+
action: "changeName",
|
|
82
|
+
name: { "en-US": "Updated Name", "de-DE": "Aktualisierter Name" },
|
|
83
|
+
} as AttributeGroupChangeNameAction,
|
|
84
|
+
],
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(result.name).toEqual({
|
|
88
|
+
"en-US": "Updated Name",
|
|
89
|
+
"de-DE": "Aktualisierter Name",
|
|
90
|
+
});
|
|
91
|
+
expect(result.version).toBe(attributeGroup.version + 1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("update attribute group - setDescription", () => {
|
|
95
|
+
const draft: AttributeGroupDraft = {
|
|
96
|
+
name: { "en-US": "Test Attributes" },
|
|
97
|
+
key: "test-attributes-2",
|
|
98
|
+
attributes: [],
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const ctx = { projectKey: "dummy" };
|
|
102
|
+
const attributeGroup = repository.create(ctx, draft);
|
|
103
|
+
|
|
104
|
+
const result = repository.processUpdateActions(
|
|
105
|
+
ctx,
|
|
106
|
+
attributeGroup,
|
|
107
|
+
attributeGroup.version,
|
|
108
|
+
[
|
|
109
|
+
{
|
|
110
|
+
action: "setDescription",
|
|
111
|
+
description: {
|
|
112
|
+
"en-US": "New description",
|
|
113
|
+
"de-DE": "Neue Beschreibung",
|
|
114
|
+
},
|
|
115
|
+
} as AttributeGroupSetDescriptionAction,
|
|
116
|
+
],
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
expect(result.description).toEqual({
|
|
120
|
+
"en-US": "New description",
|
|
121
|
+
"de-DE": "Neue Beschreibung",
|
|
122
|
+
});
|
|
123
|
+
expect(result.version).toBe(attributeGroup.version + 1);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("update attribute group - setKey", () => {
|
|
127
|
+
const draft: AttributeGroupDraft = {
|
|
128
|
+
name: { "en-US": "Key Test Attributes" },
|
|
129
|
+
key: "original-key",
|
|
130
|
+
attributes: [],
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const ctx = { projectKey: "dummy" };
|
|
134
|
+
const attributeGroup = repository.create(ctx, draft);
|
|
135
|
+
|
|
136
|
+
const result = repository.processUpdateActions(
|
|
137
|
+
ctx,
|
|
138
|
+
attributeGroup,
|
|
139
|
+
attributeGroup.version,
|
|
140
|
+
[
|
|
141
|
+
{
|
|
142
|
+
action: "setKey",
|
|
143
|
+
key: "updated-key",
|
|
144
|
+
} as AttributeGroupSetKeyAction,
|
|
145
|
+
],
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
expect(result.key).toBe("updated-key");
|
|
149
|
+
expect(result.version).toBe(attributeGroup.version + 1);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("update attribute group - setAttributes", () => {
|
|
153
|
+
const draft: AttributeGroupDraft = {
|
|
154
|
+
name: { "en-US": "Attributes Test" },
|
|
155
|
+
key: "attributes-test",
|
|
156
|
+
attributes: [
|
|
157
|
+
{
|
|
158
|
+
key: "original-attribute",
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const ctx = { projectKey: "dummy" };
|
|
164
|
+
const attributeGroup = repository.create(ctx, draft);
|
|
165
|
+
|
|
166
|
+
const result = repository.processUpdateActions(
|
|
167
|
+
ctx,
|
|
168
|
+
attributeGroup,
|
|
169
|
+
attributeGroup.version,
|
|
170
|
+
[
|
|
171
|
+
{
|
|
172
|
+
action: "setAttributes",
|
|
173
|
+
attributes: [
|
|
174
|
+
{
|
|
175
|
+
key: "new-attribute-1",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
key: "new-attribute-2",
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
} as AttributeGroupSetAttributesAction,
|
|
182
|
+
],
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
expect(result.attributes).toEqual([
|
|
186
|
+
{ key: "new-attribute-1" },
|
|
187
|
+
{ key: "new-attribute-2" },
|
|
188
|
+
]);
|
|
189
|
+
expect(result.version).toBe(attributeGroup.version + 1);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
test("get and delete attribute group", () => {
|
|
193
|
+
const draft: AttributeGroupDraft = {
|
|
194
|
+
name: { "en-US": "Delete Test Attributes" },
|
|
195
|
+
key: "delete-test",
|
|
196
|
+
attributes: [],
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const ctx = { projectKey: "dummy" };
|
|
200
|
+
const attributeGroup = repository.create(ctx, draft);
|
|
201
|
+
|
|
202
|
+
// Test get
|
|
203
|
+
const retrieved = repository.get(ctx, attributeGroup.id);
|
|
204
|
+
expect(retrieved).toBeDefined();
|
|
205
|
+
expect(retrieved?.id).toBe(attributeGroup.id);
|
|
206
|
+
|
|
207
|
+
// Test getByKey
|
|
208
|
+
const retrievedByKey = repository.getByKey(ctx, attributeGroup.key!);
|
|
209
|
+
expect(retrievedByKey).toBeDefined();
|
|
210
|
+
expect(retrievedByKey?.key).toBe(attributeGroup.key);
|
|
211
|
+
|
|
212
|
+
// Test delete
|
|
213
|
+
const deleted = repository.delete(ctx, attributeGroup.id);
|
|
214
|
+
expect(deleted).toBeDefined();
|
|
215
|
+
expect(deleted?.id).toBe(attributeGroup.id);
|
|
216
|
+
|
|
217
|
+
// Verify it's deleted
|
|
218
|
+
const notFound = repository.get(ctx, attributeGroup.id);
|
|
219
|
+
expect(notFound).toBeNull();
|
|
220
|
+
});
|
|
221
|
+
});
|