@reactionary/source 0.3.17 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -11
- package/core/src/schemas/models/cart.model.ts +7 -2
- package/core/src/schemas/models/identifiers.model.ts +12 -8
- package/core/src/schemas/models/price.model.ts +9 -0
- package/examples/node/package.json +7 -7
- package/examples/node/src/capabilities/cart.spec.ts +97 -15
- package/examples/node/src/capabilities/category.spec.ts +27 -32
- package/examples/node/src/capabilities/checkout.spec.ts +5 -5
- package/examples/node/src/capabilities/identity.spec.ts +5 -1
- package/examples/node/src/capabilities/inventory.spec.ts +1 -1
- package/package.json +3 -3
- package/providers/algolia/src/providers/product-search.provider.ts +19 -14
- package/providers/commercetools/src/providers/cart.provider.ts +76 -11
- package/providers/fake/src/providers/cart.provider.ts +1 -0
- package/providers/medusa/src/providers/cart.provider.ts +159 -70
- package/providers/medusa/src/providers/category.provider.ts +35 -23
- package/providers/medusa/src/providers/checkout.provider.ts +78 -41
- package/providers/medusa/src/providers/order-search.provider.ts +21 -10
- package/providers/medusa/src/providers/product-recommendations.provider.ts +10 -6
- package/providers/medusa/src/providers/product-search.provider.ts +19 -10
- package/providers/medusa/src/providers/product.provider.ts +20 -12
- package/providers/medusa/src/providers/profile.provider.ts +38 -13
- package/providers/meilisearch/src/providers/order-search.provider.ts +17 -12
- package/providers/meilisearch/src/providers/product-recommendations.provider.ts +10 -11
- package/providers/meilisearch/src/providers/product-search.provider.ts +23 -18
package/README.md
CHANGED
|
@@ -146,34 +146,45 @@ Vendors: Commercetools
|
|
|
146
146
|
|
|
147
147
|
### Roadmap to V0.7
|
|
148
148
|
Usecase: As a B2B user i want to shop using my own prices
|
|
149
|
-
Vendors: Commercetools
|
|
149
|
+
Vendors: Commercetools, Medusa
|
|
150
150
|
|
|
151
151
|
- PDP / PLP
|
|
152
|
-
- External Pricing
|
|
153
|
-
-
|
|
154
|
-
-
|
|
152
|
+
- [ ] External Pricing
|
|
153
|
+
- [ ] Customer specific pricing
|
|
154
|
+
- [ ] Organizational/Entitlement Context. Choose to shop private or for company?
|
|
155
|
+
- [ ] Multi currency/Multi lingual
|
|
155
156
|
|
|
156
157
|
|
|
157
158
|
### Roadmap to V0.8
|
|
158
159
|
Usecase: As a B2B user i want to see my organization data
|
|
159
|
-
Vendors: Commercetools
|
|
160
|
+
Vendors: Commercetools, Medusa
|
|
160
161
|
|
|
161
|
-
- Account
|
|
162
|
-
-
|
|
162
|
+
- Account
|
|
163
|
+
- [ ] My Organization(s)
|
|
164
|
+
- [ ] Edit organization data (if admin)
|
|
165
|
+
- [ ] Edit organization address book (if admin)
|
|
166
|
+
- Account
|
|
167
|
+
- [ ] Self management of users and roles
|
|
163
168
|
|
|
164
169
|
|
|
165
170
|
### Roadmap to V0.9
|
|
166
171
|
Usecase: As a B2B user i want have multiple carts and requisition lists
|
|
167
172
|
Vendors: Commercetools
|
|
168
173
|
|
|
169
|
-
-
|
|
174
|
+
- Header
|
|
175
|
+
- [ ] Pick active cart
|
|
176
|
+
- Account
|
|
177
|
+
- [ ] My Open Carts
|
|
178
|
+
- [ ] My Requisition Lists (private)
|
|
179
|
+
- [ ] My Orgs Requisition Lists (everyones public lists)
|
|
170
180
|
|
|
171
181
|
### Roadmap to V1.0
|
|
172
182
|
Usecase: As a B2B user i want to see other peoples carts and orders
|
|
173
183
|
Vendors: Commercetools
|
|
174
184
|
|
|
175
|
-
- Account
|
|
176
|
-
|
|
185
|
+
- Account
|
|
186
|
+
- [ ] Organizational Order History
|
|
187
|
+
- [ ] Pick someone elses cart (from someone else)
|
|
177
188
|
|
|
178
189
|
|
|
179
190
|
|
|
@@ -182,7 +193,7 @@ Vendors: Commercetools
|
|
|
182
193
|
|
|
183
194
|
|
|
184
195
|
|
|
185
|
-
### Roadmap
|
|
196
|
+
### Roadmap V1.x
|
|
186
197
|
- Additional vendors
|
|
187
198
|
- AthosCommerce (Klevu)
|
|
188
199
|
- ShopifyPlus
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
+
import type { InferType } from '../../zod-utils.js';
|
|
2
3
|
import { CartIdentifierSchema, CartItemIdentifierSchema, IdentityIdentifierSchema, ProductIdentifierSchema, ProductVariantIdentifierSchema } from '../models/identifiers.model.js';
|
|
3
|
-
import { CostBreakDownSchema, ItemCostBreakdownSchema } from './cost.model.js';
|
|
4
4
|
import { BaseModelSchema } from './base.model.js';
|
|
5
|
-
import
|
|
5
|
+
import { CostBreakDownSchema, ItemCostBreakdownSchema } from './cost.model.js';
|
|
6
|
+
import { PromotionSchema } from './price.model.js';
|
|
7
|
+
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
export const CartItemSchema = z.looseObject({
|
|
8
11
|
identifier: CartItemIdentifierSchema.default(() => CartItemIdentifierSchema.parse({})),
|
|
@@ -12,11 +15,13 @@ export const CartItemSchema = z.looseObject({
|
|
|
12
15
|
price: ItemCostBreakdownSchema.default(() => ItemCostBreakdownSchema.parse({})),
|
|
13
16
|
});
|
|
14
17
|
|
|
18
|
+
|
|
15
19
|
export const CartSchema = BaseModelSchema.extend({
|
|
16
20
|
identifier: CartIdentifierSchema.default(() => CartIdentifierSchema.parse({})),
|
|
17
21
|
userId: IdentityIdentifierSchema.default(() => IdentityIdentifierSchema.parse({})),
|
|
18
22
|
items: z.array(CartItemSchema).default(() => []),
|
|
19
23
|
price: CostBreakDownSchema.default(() => CostBreakDownSchema.parse({})),
|
|
24
|
+
appliedPromotions: z.array(PromotionSchema).default(() => []),
|
|
20
25
|
name: z.string().default(''),
|
|
21
26
|
description: z.string().default(''),
|
|
22
27
|
});
|
|
@@ -140,8 +140,8 @@ export const ProductSearchIdentifierSchema = z.looseObject({
|
|
|
140
140
|
term: z.string().meta({ description: 'The search term used to find products.' }),
|
|
141
141
|
facets: z.array(FacetValueIdentifierSchema).meta({ description: 'The facets applied to filter the search results.' }),
|
|
142
142
|
filters: z.array(z.string()).meta({ description: 'Additional filters applied to the search results.' }),
|
|
143
|
-
paginationOptions: PaginationOptionsSchema.
|
|
144
|
-
categoryFilter: FacetValueIdentifierSchema.optional().
|
|
143
|
+
paginationOptions: PaginationOptionsSchema.meta({ description: 'Pagination options for the search results.' }),
|
|
144
|
+
categoryFilter: FacetValueIdentifierSchema.optional().meta({ description: 'An optional category filter applied to the search results.' }),
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
/**
|
|
@@ -151,17 +151,17 @@ export const OrderSearchIdentifierSchema = z.looseObject({
|
|
|
151
151
|
term: z.string().meta({ description: 'The search term used to find orders. Not all providers may support term-based search for orders.' }),
|
|
152
152
|
partNumber: z.array(z.string()).optional().meta({ description: 'An optional list part number to filter orders by specific products. Will be ANDed together.' }),
|
|
153
153
|
orderStatus: z.array(OrderStatusSchema).optional().meta({ description: 'An optional list of order statuses to filter the search results.' }),
|
|
154
|
-
user: IdentityIdentifierSchema.optional().
|
|
154
|
+
user: IdentityIdentifierSchema.optional().meta({ description: 'An optional user ID to filter orders by specific users. Mostly for b2b usecases with hierachial order access.' }),
|
|
155
155
|
startDate: z.string().optional().meta({ description: 'An optional start date to filter orders from a specific date onwards. ISO8601' }),
|
|
156
156
|
endDate: z.string().optional().meta({ description: 'An optional end date to filter orders up to a specific date. ISO8601' }),
|
|
157
157
|
filters: z.array(z.string()).meta({ description: 'Additional filters applied to the search results.' }),
|
|
158
|
-
paginationOptions: PaginationOptionsSchema.
|
|
158
|
+
paginationOptions: PaginationOptionsSchema.meta({ description: 'Pagination options for the search results.' }),
|
|
159
159
|
});
|
|
160
160
|
|
|
161
161
|
|
|
162
162
|
export const ProductListSearchIdentifierSchema = z.looseObject({
|
|
163
163
|
listType: ProductListTypeSchema.meta({ description: 'The type of product list, e.g., "wishlist" or "favorites".' }),
|
|
164
|
-
paginationOptions: PaginationOptionsSchema.
|
|
164
|
+
paginationOptions: PaginationOptionsSchema.meta({ description: 'Pagination options for the search results.' }),
|
|
165
165
|
});
|
|
166
166
|
|
|
167
167
|
|
|
@@ -171,8 +171,8 @@ export const ProductListIdentifierSchema = z.looseObject({
|
|
|
171
171
|
});
|
|
172
172
|
|
|
173
173
|
export const ProductListItemSearchIdentifierSchema = z.looseObject({
|
|
174
|
-
list: ProductListIdentifierSchema.
|
|
175
|
-
paginationOptions: PaginationOptionsSchema.
|
|
174
|
+
list: ProductListIdentifierSchema.meta({ description: 'The identifier for the product list to query. The provider should return the items in the list that match this identifier. For example, if the identifier is a customer ID, the provider should return the items in the customer\'s wishlist. If the identifier is a session ID, the provider should return the items in the customer\'s current shopping cart. If the identifier is a product ID, the provider should return the items in the product\'s related products list.' }),
|
|
175
|
+
paginationOptions: PaginationOptionsSchema.meta({ description: 'Pagination options for the search results.' }),
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
export const ProductListItemIdentifierSchema = z.looseObject({
|
|
@@ -180,7 +180,9 @@ export const ProductListItemIdentifierSchema = z.looseObject({
|
|
|
180
180
|
list: ProductListIdentifierSchema,
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
-
|
|
183
|
+
export const PromotionIdentifierSchema = z.looseObject({
|
|
184
|
+
key: z.string().meta({ description: 'The unique identifier for the promotion.' }),
|
|
185
|
+
});
|
|
184
186
|
|
|
185
187
|
|
|
186
188
|
|
|
@@ -232,6 +234,7 @@ export type ProductListItemIdentifier = InferType<typeof ProductListItemIdentifi
|
|
|
232
234
|
export type ProductListSearchIdentifier = InferType<typeof ProductListSearchIdentifierSchema>;
|
|
233
235
|
export type ProductListItemSearchIdentifier = InferType<typeof ProductListItemSearchIdentifierSchema>;
|
|
234
236
|
export type ProductListType = InferType<typeof ProductListTypeSchema>;
|
|
237
|
+
export type PromotionIdentifier = InferType<typeof PromotionIdentifierSchema>;
|
|
235
238
|
|
|
236
239
|
export type IdentifierType =
|
|
237
240
|
| ProductIdentifier
|
|
@@ -268,5 +271,6 @@ export type IdentifierType =
|
|
|
268
271
|
| ProductListIdentifier
|
|
269
272
|
| ProductListItemIdentifier
|
|
270
273
|
| ProductListSearchIdentifier
|
|
274
|
+
| PromotionIdentifier
|
|
271
275
|
|
|
272
276
|
;
|
|
@@ -21,8 +21,17 @@ export const PriceSchema = BaseModelSchema.extend({
|
|
|
21
21
|
tieredPrices: z.array(TieredPriceSchema)
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
export const PromotionSchema = z.looseObject({
|
|
25
|
+
code: z.string().default('').meta({ description: 'The code for the promotion, if applicable. This can be used to indicate the coupon code used for a promotion, for example.' }),
|
|
26
|
+
isCouponCode: z.boolean().default(false).meta({ description: 'Indicates whether the promotion is a coupon code that the user added himself.' }),
|
|
27
|
+
name: z.string().default('').meta({ description: 'The name of the promotion.' }),
|
|
28
|
+
description: z.string().default('').meta({ description: 'A description of the promotion.' }),
|
|
29
|
+
amount: MonetaryAmountSchema.optional().meta({ description: 'The amount of the promotion, if applicable/available from the source system. This can be used to indicate the discount amount for a promotion, for example.' }) ,
|
|
30
|
+
});
|
|
31
|
+
|
|
24
32
|
|
|
25
33
|
|
|
26
34
|
export type MonetaryAmount = InferType<typeof MonetaryAmountSchema>;
|
|
27
35
|
export type Price = InferType<typeof PriceSchema>;
|
|
36
|
+
export type Promotion = InferType<typeof PromotionSchema>;
|
|
28
37
|
export type TieredPrice = InferType<typeof TieredPriceSchema>;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/examples-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"types": "src/index.d.ts",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@reactionary/core": "0.
|
|
8
|
-
"@reactionary/provider-commercetools": "0.
|
|
9
|
-
"@reactionary/provider-algolia": "0.
|
|
10
|
-
"@reactionary/provider-medusa": "0.
|
|
11
|
-
"@reactionary/provider-meilisearch": "0.
|
|
12
|
-
"@reactionary/provider-fake": "0.
|
|
7
|
+
"@reactionary/core": "0.6.1",
|
|
8
|
+
"@reactionary/provider-commercetools": "0.6.1",
|
|
9
|
+
"@reactionary/provider-algolia": "0.6.1",
|
|
10
|
+
"@reactionary/provider-medusa": "0.6.1",
|
|
11
|
+
"@reactionary/provider-meilisearch": "0.6.1",
|
|
12
|
+
"@reactionary/provider-fake": "0.6.1"
|
|
13
13
|
},
|
|
14
14
|
"type": "module"
|
|
15
15
|
}
|
|
@@ -8,7 +8,7 @@ const testData = {
|
|
|
8
8
|
skuWithTiers: '0766623360203',
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider) => {
|
|
11
|
+
describe.each([ PrimaryProvider.COMMERCETOOLS, PrimaryProvider.MEDUSA])('Cart Capability - %s', (provider) => {
|
|
12
12
|
let client: ReturnType<typeof createClient>;
|
|
13
13
|
|
|
14
14
|
beforeEach(() => {
|
|
@@ -37,7 +37,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
if (!cart.success) {
|
|
40
|
-
assert.fail();
|
|
40
|
+
assert.fail(JSON.stringify(cart.error));
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
expect(cart.value.identifier.key).toBeDefined();
|
|
@@ -61,9 +61,8 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
61
61
|
},
|
|
62
62
|
quantity: 1,
|
|
63
63
|
});
|
|
64
|
-
|
|
65
64
|
if (!cart.success) {
|
|
66
|
-
assert.fail();
|
|
65
|
+
assert.fail(JSON.stringify(cart.error));
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
const updatedCart = await client.cart.add({
|
|
@@ -75,7 +74,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
75
74
|
});
|
|
76
75
|
|
|
77
76
|
if (!updatedCart.success) {
|
|
78
|
-
assert.fail();
|
|
77
|
+
assert.fail(JSON.stringify(updatedCart.error) );
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
expect(updatedCart.value.items.length).toBe(2);
|
|
@@ -94,7 +93,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
94
93
|
});
|
|
95
94
|
|
|
96
95
|
if (!cart.success) {
|
|
97
|
-
assert.fail();
|
|
96
|
+
assert.fail (JSON.stringify(cart.error) );
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
const updatedCart = await client.cart.changeQuantity({
|
|
@@ -104,7 +103,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
104
103
|
});
|
|
105
104
|
|
|
106
105
|
if (!updatedCart.success) {
|
|
107
|
-
assert.fail();
|
|
106
|
+
assert.fail(JSON.stringify(updatedCart.error));
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
expect(updatedCart.value.items.length).toBe(1);
|
|
@@ -127,7 +126,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
127
126
|
});
|
|
128
127
|
|
|
129
128
|
if (!cart.success) {
|
|
130
|
-
assert.fail();
|
|
129
|
+
assert.fail(JSON.stringify(cart.error));
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
const updatedCart = await client.cart.remove({
|
|
@@ -136,13 +135,15 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
136
135
|
});
|
|
137
136
|
|
|
138
137
|
if (!updatedCart.success) {
|
|
139
|
-
assert.fail();
|
|
138
|
+
assert.fail(JSON.stringify(updatedCart.error));
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
expect(updatedCart.value.items.length).toBe(0);
|
|
143
142
|
});
|
|
144
143
|
|
|
145
144
|
it('should be able to delete a cart', async () => {
|
|
145
|
+
|
|
146
|
+
|
|
146
147
|
const cart = await client.cart.add({
|
|
147
148
|
variant: {
|
|
148
149
|
sku: testData.skuWithoutTiers,
|
|
@@ -151,22 +152,38 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
151
152
|
});
|
|
152
153
|
|
|
153
154
|
if (!cart.success) {
|
|
154
|
-
assert.fail();
|
|
155
|
+
assert.fail(JSON.stringify(cart.error) );
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
expect(cart.value.items.length).toBe(1);
|
|
158
159
|
expect(cart.value.identifier.key).toBeTruthy();
|
|
159
160
|
|
|
160
|
-
await client.cart.deleteCart({
|
|
161
|
+
const deleteCartResponse = await client.cart.deleteCart({
|
|
161
162
|
cart: cart.value.identifier,
|
|
162
163
|
});
|
|
163
164
|
|
|
165
|
+
if (!deleteCartResponse.success) {
|
|
166
|
+
assert.fail(JSON.stringify(deleteCartResponse.error));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
164
170
|
const originalCart = await client.cart.getById({
|
|
165
171
|
cart: cart.value.identifier,
|
|
166
172
|
});
|
|
167
173
|
|
|
174
|
+
|
|
175
|
+
if (provider === PrimaryProvider.MEDUSA) {
|
|
176
|
+
// medusa can't delete a cart, so we just empty it.
|
|
177
|
+
if (!originalCart.success) {
|
|
178
|
+
assert.fail(JSON.stringify(originalCart.error));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
expect(originalCart.value.items.length).toBe(0);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
168
185
|
if (originalCart.success) {
|
|
169
|
-
assert.fail();
|
|
186
|
+
assert.fail(JSON.stringify(originalCart.value));
|
|
170
187
|
}
|
|
171
188
|
expect(originalCart.error.type).toBe('NotFound');
|
|
172
189
|
});
|
|
@@ -180,7 +197,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
180
197
|
});
|
|
181
198
|
|
|
182
199
|
if (!cart.success) {
|
|
183
|
-
assert.fail();
|
|
200
|
+
assert.fail(JSON.stringify(cart.error));
|
|
184
201
|
}
|
|
185
202
|
|
|
186
203
|
expect(cart.value.items[0].variant).toBeDefined();
|
|
@@ -190,7 +207,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
190
207
|
});
|
|
191
208
|
|
|
192
209
|
if (!product.success) {
|
|
193
|
-
assert.fail();
|
|
210
|
+
assert.fail(JSON.stringify(product.error));
|
|
194
211
|
}
|
|
195
212
|
|
|
196
213
|
expect(product).toBeTruthy();
|
|
@@ -201,6 +218,71 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
201
218
|
}
|
|
202
219
|
});
|
|
203
220
|
|
|
221
|
+
it('can apply a coupon code to a cart', async () => {
|
|
222
|
+
const cart = await client.cart.add({
|
|
223
|
+
variant: {
|
|
224
|
+
sku: testData.skuWithoutTiers,
|
|
225
|
+
},
|
|
226
|
+
quantity: 1,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
if (!cart.success) {
|
|
230
|
+
assert.fail(JSON.stringify(cart.error));
|
|
231
|
+
}
|
|
232
|
+
expect(cart.value.price.totalDiscount.value).toBe(0);
|
|
233
|
+
|
|
234
|
+
const updatedCart = await client.cart.applyCouponCode({
|
|
235
|
+
cart: cart.value.identifier,
|
|
236
|
+
couponCode: 'TESTCODE1',
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
if (!updatedCart.success) {
|
|
240
|
+
assert.fail(JSON.stringify(updatedCart.error));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
expect(updatedCart.value.price.grandTotal.value).toBeLessThan(cart.value.price.grandTotal.value);
|
|
244
|
+
expect(updatedCart.value.price.totalDiscount.value).toBeGreaterThan(0);
|
|
245
|
+
|
|
246
|
+
expect(updatedCart.value.appliedPromotions.find(promo => promo.code === 'TESTCODE1' && promo.isCouponCode === true)).toBeTruthy();
|
|
247
|
+
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('can remove a coupon code from a cart', async () => {
|
|
251
|
+
const cart = await client.cart.add({
|
|
252
|
+
variant: {
|
|
253
|
+
sku: testData.skuWithoutTiers,
|
|
254
|
+
},
|
|
255
|
+
quantity: 1,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
if (!cart.success) {
|
|
259
|
+
assert.fail(JSON.stringify(cart.error));
|
|
260
|
+
}
|
|
261
|
+
const updatedCart = await client.cart.applyCouponCode({
|
|
262
|
+
cart: cart.value.identifier,
|
|
263
|
+
couponCode: 'TESTCODE1',
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
if (!updatedCart.success) {
|
|
267
|
+
assert.fail(JSON.stringify(updatedCart.error));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
expect(updatedCart.value.price.grandTotal.value).toBeLessThan(cart.value.price.grandTotal.value);
|
|
271
|
+
|
|
272
|
+
const removedCouponCart = await client.cart.removeCouponCode({
|
|
273
|
+
cart: cart.value.identifier,
|
|
274
|
+
couponCode: 'TESTCODE1',
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
if (!removedCouponCart.success) {
|
|
278
|
+
assert.fail(JSON.stringify(removedCouponCart.error));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
expect(removedCouponCart.value.price.grandTotal.value).toBeGreaterThan(updatedCart.value.price.grandTotal.value);
|
|
282
|
+
expect(removedCouponCart.value.price.grandTotal.value).toBe(cart.value.price.grandTotal.value);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
|
|
204
286
|
it('should be able to add an 50 items to a cart in less than 30 seconds', async () => {
|
|
205
287
|
const searchResult = await client.productSearch.queryByTerm(
|
|
206
288
|
ProductSearchQueryByTermSchema.parse({
|
|
@@ -217,7 +299,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Cart Capability - %s', (provider
|
|
|
217
299
|
);
|
|
218
300
|
|
|
219
301
|
if (!searchResult.success) {
|
|
220
|
-
assert.fail();
|
|
302
|
+
assert.fail(JSON.stringify(searchResult.error) );
|
|
221
303
|
}
|
|
222
304
|
|
|
223
305
|
let cartIdentifier = undefined;
|
|
@@ -24,7 +24,7 @@ const testData = {
|
|
|
24
24
|
breadCrumb: ['2833', '225'],
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (provider) => {
|
|
27
|
+
describe.each([PrimaryProvider.COMMERCETOOLS, PrimaryProvider.MEDUSA])('Category Capability - %s', (provider) => {
|
|
28
28
|
let client: ReturnType<typeof createClient>;
|
|
29
29
|
|
|
30
30
|
beforeEach(() => {
|
|
@@ -37,7 +37,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (prov
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
if (!result.success) {
|
|
40
|
-
assert.fail();
|
|
40
|
+
assert.fail(JSON.stringify(result.error));
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
expect(result.value.items.length).toBeGreaterThan(0);
|
|
@@ -55,23 +55,26 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (prov
|
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
if (!result.success) {
|
|
58
|
-
assert.fail();
|
|
58
|
+
assert.fail(JSON.stringify(result.error));
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
expect(result.value.items.length).toBeGreaterThan(0);
|
|
62
|
-
expect(result.value.items
|
|
63
|
-
testData.childCategoriesOfFirstTopcategory[0].key
|
|
64
|
-
);
|
|
65
|
-
expect(result.value.items[0].name).toBe(
|
|
66
|
-
testData.childCategoriesOfFirstTopcategory[0].name
|
|
67
|
-
);
|
|
62
|
+
expect(result.value.items).toEqual(
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
64
|
+
expect.arrayContaining([
|
|
65
|
+
expect.objectContaining({
|
|
66
|
+
identifier: { key: testData.childCategoriesOfFirstTopcategory[0].key },
|
|
67
|
+
name: testData.childCategoriesOfFirstTopcategory[0].name,
|
|
68
|
+
}),
|
|
69
|
+
|
|
70
|
+
expect.objectContaining({
|
|
71
|
+
identifier: { key: testData.childCategoriesOfFirstTopcategory[1].key },
|
|
72
|
+
name: testData.childCategoriesOfFirstTopcategory[1].name,
|
|
73
|
+
}),
|
|
74
|
+
|
|
75
|
+
])
|
|
74
76
|
);
|
|
77
|
+
|
|
75
78
|
});
|
|
76
79
|
|
|
77
80
|
it('should be able to get child categories for a category, paged', async () => {
|
|
@@ -79,43 +82,35 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (prov
|
|
|
79
82
|
parentId: { key: testData.topCategories[0].key },
|
|
80
83
|
paginationOptions: { pageSize: 1, pageNumber: 1 },
|
|
81
84
|
});
|
|
82
|
-
|
|
85
|
+
|
|
83
86
|
if (!result.success) {
|
|
84
|
-
assert.fail();
|
|
87
|
+
assert.fail(JSON.stringify(result.error));
|
|
85
88
|
}
|
|
86
89
|
|
|
87
90
|
expect(result.value.items.length).toBeGreaterThan(0);
|
|
88
|
-
expect(result.value.items[0].identifier.key).toBe(
|
|
89
|
-
testData.childCategoriesOfFirstTopcategory[0].key
|
|
90
|
-
);
|
|
91
|
-
expect(result.value.items[0].name).toBe(
|
|
92
|
-
testData.childCategoriesOfFirstTopcategory[0].name
|
|
93
|
-
);
|
|
94
91
|
expect(result.value.totalCount).toBe(3);
|
|
95
92
|
expect(result.value.totalPages).toBe(3);
|
|
96
93
|
expect(result.value.pageSize).toBe(1);
|
|
97
94
|
expect(result.value.pageNumber).toBe(1);
|
|
98
95
|
|
|
96
|
+
const idFrom1 = result.value.items[0].identifier.key;
|
|
97
|
+
|
|
99
98
|
result = await client.category.findChildCategories({
|
|
100
99
|
parentId: { key: testData.topCategories[0].key },
|
|
101
100
|
paginationOptions: { pageSize: 1, pageNumber: 2 },
|
|
102
101
|
});
|
|
103
102
|
|
|
104
103
|
if (!result.success) {
|
|
105
|
-
assert.fail();
|
|
104
|
+
assert.fail(JSON.stringify(result.error) );
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
expect(result.value.items.length).toBeGreaterThan(0);
|
|
109
|
-
expect(result.value.items[0].identifier.key).toBe(
|
|
110
|
-
testData.childCategoriesOfFirstTopcategory[1].key
|
|
111
|
-
);
|
|
112
|
-
expect(result.value.items[0].name).toBe(
|
|
113
|
-
testData.childCategoriesOfFirstTopcategory[1].name
|
|
114
|
-
);
|
|
115
108
|
expect(result.value.totalCount).toBe(3);
|
|
116
109
|
expect(result.value.totalPages).toBe(3);
|
|
117
110
|
expect(result.value.pageSize).toBe(1);
|
|
118
111
|
expect(result.value.pageNumber).toBe(2);
|
|
112
|
+
|
|
113
|
+
expect(result.value.items[0].identifier.key).not.toBe(idFrom1);
|
|
119
114
|
});
|
|
120
115
|
|
|
121
116
|
it('can load all breadcrumbs for a category', async () => {
|
|
@@ -138,7 +133,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (prov
|
|
|
138
133
|
const result = await client.category.getBySlug({
|
|
139
134
|
slug: testData.topCategories[0].slug!,
|
|
140
135
|
});
|
|
141
|
-
|
|
136
|
+
|
|
142
137
|
if (!result.success) {
|
|
143
138
|
assert.fail();
|
|
144
139
|
}
|
|
@@ -154,7 +149,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (prov
|
|
|
154
149
|
|
|
155
150
|
it('returns NotFound if looking for slug that does not exist', async () => {
|
|
156
151
|
const result = await client.category.getBySlug({ slug: 'non-existent-slug' });
|
|
157
|
-
|
|
152
|
+
|
|
158
153
|
if (result.success) {
|
|
159
154
|
assert.fail();
|
|
160
155
|
}
|
|
@@ -183,7 +178,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (prov
|
|
|
183
178
|
const result = await client.category.getById({
|
|
184
179
|
id: { key: 'non-existent-category' },
|
|
185
180
|
});
|
|
186
|
-
|
|
181
|
+
|
|
187
182
|
if (result.success) {
|
|
188
183
|
assert.fail();
|
|
189
184
|
}
|
|
@@ -12,7 +12,7 @@ const testData = {
|
|
|
12
12
|
skuWithTiers: '0766623360203',
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
describe.each([PrimaryProvider.COMMERCETOOLS])(
|
|
15
|
+
describe.each([PrimaryProvider.COMMERCETOOLS, PrimaryProvider.MEDUSA])(
|
|
16
16
|
'Checkout Capability - %s',
|
|
17
17
|
(provider) => {
|
|
18
18
|
let client: ReturnType<typeof createClient>;
|
|
@@ -46,7 +46,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])(
|
|
|
46
46
|
const checkout = await client.checkout.initiateCheckoutForCart({
|
|
47
47
|
cart: cart,
|
|
48
48
|
billingAddress: {
|
|
49
|
-
countryCode: '
|
|
49
|
+
countryCode: 'DK',
|
|
50
50
|
firstName: 'John',
|
|
51
51
|
lastName: 'Doe',
|
|
52
52
|
streetAddress: '123 Main St',
|
|
@@ -80,7 +80,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])(
|
|
|
80
80
|
const cc = await client.checkout.initiateCheckoutForCart({
|
|
81
81
|
cart: cart,
|
|
82
82
|
billingAddress: {
|
|
83
|
-
countryCode: '
|
|
83
|
+
countryCode: 'DK',
|
|
84
84
|
firstName: 'John',
|
|
85
85
|
lastName: 'Doe',
|
|
86
86
|
streetAddress: '123 Main St',
|
|
@@ -114,7 +114,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])(
|
|
|
114
114
|
|
|
115
115
|
expect(paymentMethods.value.length).toBeGreaterThan(0);
|
|
116
116
|
expect(
|
|
117
|
-
paymentMethods.value.find((x) => x.identifier.method === 'stripe')
|
|
117
|
+
paymentMethods.value.find((x) => x.identifier.method === 'stripe' || x.identifier.method.includes('stripe'))
|
|
118
118
|
).toBeDefined();
|
|
119
119
|
});
|
|
120
120
|
|
|
@@ -306,7 +306,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS])(
|
|
|
306
306
|
const r = await client.checkout.getAvailablePaymentMethods({
|
|
307
307
|
checkout: checkout.identifier,
|
|
308
308
|
});
|
|
309
|
-
|
|
309
|
+
|
|
310
310
|
if (!r.success) {
|
|
311
311
|
assert.fail();
|
|
312
312
|
}
|
|
@@ -2,6 +2,10 @@ import 'dotenv/config';
|
|
|
2
2
|
import { describe, expect, it, beforeEach, assert } from 'vitest';
|
|
3
3
|
import { createClient, PrimaryProvider } from '../utils.js';
|
|
4
4
|
|
|
5
|
+
const testData = {
|
|
6
|
+
sku: '0766623301831'
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
describe.each([PrimaryProvider.COMMERCETOOLS, PrimaryProvider.MEDUSA])('Identity Capability - %s', (provider) => {
|
|
6
10
|
let client: ReturnType<typeof createClient>;
|
|
7
11
|
|
|
@@ -24,7 +28,7 @@ describe.each([PrimaryProvider.COMMERCETOOLS, PrimaryProvider.MEDUSA])('Identity
|
|
|
24
28
|
{
|
|
25
29
|
quantity: 1,
|
|
26
30
|
variant: {
|
|
27
|
-
sku:
|
|
31
|
+
sku: testData.sku
|
|
28
32
|
},
|
|
29
33
|
}
|
|
30
34
|
);
|
|
@@ -2,7 +2,7 @@ import 'dotenv/config';
|
|
|
2
2
|
import { describe, expect, it, beforeEach, assert } from 'vitest';
|
|
3
3
|
import { createClient, PrimaryProvider } from '../utils.js';
|
|
4
4
|
|
|
5
|
-
describe.each([PrimaryProvider.COMMERCETOOLS])('Inventory Capability', (provider) => {
|
|
5
|
+
describe.each([PrimaryProvider.COMMERCETOOLS, PrimaryProvider.MEDUSA])('Inventory Capability', (provider) => {
|
|
6
6
|
let client: ReturnType<typeof createClient>;
|
|
7
7
|
|
|
8
8
|
beforeEach(() => {
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/source",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@commercetools/platform-sdk": "^8.
|
|
8
|
-
"@commercetools/ts-client": "^4.
|
|
7
|
+
"@commercetools/platform-sdk": "^8.25.0",
|
|
8
|
+
"@commercetools/ts-client": "^4.9.1",
|
|
9
9
|
"@commercetools/ts-sdk-apm": "^4.0.0",
|
|
10
10
|
"@docusaurus/core": "^3.9.2",
|
|
11
11
|
"@docusaurus/preset-classic": "^3.9.2",
|