@reactionary/examples-node 0.1.5

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.
@@ -0,0 +1,158 @@
1
+ import 'dotenv/config';
2
+ import { describe, expect, it, beforeEach } from 'vitest';
3
+ import { createClient, PrimaryProvider } from '../utils.js';
4
+
5
+ const testData = {
6
+ topCategories: [
7
+ {
8
+ key: '2833',
9
+ name: 'Computers & Peripherals',
10
+ slug: 'computers-and-peripherals',
11
+ text: 'Computers & Peripherals',
12
+ },
13
+ {
14
+ key: '9541',
15
+ name: 'Computer Spare Parts & Accessories',
16
+ },
17
+ ],
18
+
19
+ childCategoriesOfFirstTopcategory: [
20
+ { key: '225', name: 'Printers & Scanners' },
21
+ { key: '830', name: 'Computer Cables' },
22
+ ],
23
+
24
+ breadCrumb: ['2833', '225'],
25
+ };
26
+
27
+ describe.each([PrimaryProvider.COMMERCETOOLS])('Category Capability - %s', (provider) => {
28
+ let client: ReturnType<typeof createClient>;
29
+
30
+ beforeEach(() => {
31
+ client = createClient(provider);
32
+ });
33
+
34
+ it('should be able to get top-categories', async () => {
35
+ const result = await client.category.findTopCategories({
36
+ paginationOptions: { pageSize: 10, pageNumber: 1 },
37
+ });
38
+
39
+ expect(result.items.length).toBeGreaterThan(0);
40
+ expect(result.items[0].identifier.key).toBe(testData.topCategories[0].key);
41
+ expect(result.items[0].name).toBe(testData.topCategories[0].name);
42
+
43
+ expect(result.items[1].identifier.key).toBe(testData.topCategories[1].key);
44
+ expect(result.items[1].name).toBe(testData.topCategories[1].name);
45
+ });
46
+
47
+ it('should be able to get child categories for a category', async () => {
48
+ const result = await client.category.findChildCategories({
49
+ parentId: { key: testData.topCategories[0].key },
50
+ paginationOptions: { pageSize: 10, pageNumber: 1 },
51
+ });
52
+
53
+ expect(result.items.length).toBeGreaterThan(0);
54
+ expect(result.items[0].identifier.key).toBe(
55
+ testData.childCategoriesOfFirstTopcategory[0].key
56
+ );
57
+ expect(result.items[0].name).toBe(
58
+ testData.childCategoriesOfFirstTopcategory[0].name
59
+ );
60
+
61
+ expect(result.items[1].identifier.key).toBe(
62
+ testData.childCategoriesOfFirstTopcategory[1].key
63
+ );
64
+ expect(result.items[1].name).toBe(
65
+ testData.childCategoriesOfFirstTopcategory[1].name
66
+ );
67
+ });
68
+
69
+ it('should be able to get child categories for a category, paged', async () => {
70
+ let result = await client.category.findChildCategories({
71
+ parentId: { key: testData.topCategories[0].key },
72
+ paginationOptions: { pageSize: 1, pageNumber: 1 },
73
+ });
74
+
75
+ expect(result.items.length).toBeGreaterThan(0);
76
+ expect(result.items[0].identifier.key).toBe(
77
+ testData.childCategoriesOfFirstTopcategory[0].key
78
+ );
79
+ expect(result.items[0].name).toBe(
80
+ testData.childCategoriesOfFirstTopcategory[0].name
81
+ );
82
+ expect(result.totalCount).toBe(3);
83
+ expect(result.totalPages).toBe(3);
84
+ expect(result.pageSize).toBe(1);
85
+ expect(result.pageNumber).toBe(1);
86
+
87
+ result = await client.category.findChildCategories({
88
+ parentId: { key: testData.topCategories[0].key },
89
+ paginationOptions: { pageSize: 1, pageNumber: 2 },
90
+ });
91
+
92
+ expect(result.items.length).toBeGreaterThan(0);
93
+ expect(result.items[0].identifier.key).toBe(
94
+ testData.childCategoriesOfFirstTopcategory[1].key
95
+ );
96
+ expect(result.items[0].name).toBe(
97
+ testData.childCategoriesOfFirstTopcategory[1].name
98
+ );
99
+ expect(result.totalCount).toBe(3);
100
+ expect(result.totalPages).toBe(3);
101
+ expect(result.pageSize).toBe(1);
102
+ expect(result.pageNumber).toBe(2);
103
+ });
104
+
105
+ it('can load all breadcrumbs for a category', async () => {
106
+ const leaf = testData.breadCrumb[testData.breadCrumb.length - 1];
107
+ const result = await client.category.getBreadcrumbPathToCategory({
108
+ id: { key: leaf! },
109
+ });
110
+
111
+ expect(result.length).toBe(testData.breadCrumb.length);
112
+ for (let i = 0; i < testData.breadCrumb.length; i++) {
113
+ expect(result[i].identifier.key).toBe(testData.breadCrumb[i]);
114
+ }
115
+ });
116
+
117
+ it('should be able to get a category by slug', async () => {
118
+ const result = await client.category.getBySlug({
119
+ slug: testData.topCategories[0].slug!,
120
+ });
121
+ expect(result).toBeTruthy();
122
+ if (result) {
123
+ expect(result.identifier.key).toBe(testData.topCategories[0].key);
124
+ expect(result.name).toBe(testData.topCategories[0].name);
125
+ expect(result.slug).toBe(testData.topCategories[0].slug);
126
+ expect(result.parentCategory).toBeUndefined();
127
+ expect(result.text).not.toBe('');
128
+ expect(result.meta.placeholder).toBe(false);
129
+ }
130
+ });
131
+
132
+ it('returns null if looking for slug that does not exist', async () => {
133
+ const result = await client.category.getBySlug({ slug: 'non-existent-slug' });
134
+ expect(result).toBeNull();
135
+ });
136
+
137
+ it('should be able to get a category by id', async () => {
138
+ const result = await client.category.getById({
139
+ id: { key: testData.topCategories[0].key },
140
+ });
141
+
142
+ expect(result.identifier.key).toBe(testData.topCategories[0].key);
143
+ expect(result.name).toBe(testData.topCategories[0].name);
144
+ expect(result.slug).toBe(testData.topCategories[0].slug);
145
+ expect(result.parentCategory).toBeUndefined();
146
+
147
+ expect(result.text).toBe(testData.topCategories[0].text);
148
+ expect(result.meta.placeholder).toBe(false);
149
+ });
150
+
151
+ it('returns a placeholder if you search for a category that does not exist', async () => {
152
+ const result = await client.category.getById({
153
+ id: { key: 'non-existent-category' },
154
+ });
155
+ expect(result.identifier.key).toBe('non-existent-category');
156
+ expect(result.meta.placeholder).toBe(true);
157
+ });
158
+ });
@@ -0,0 +1,272 @@
1
+ import 'dotenv/config';
2
+ import type { Cart, Checkout, PaymentInstruction } from '@reactionary/core';
3
+ import {
4
+ PaymentInstructionSchema,
5
+ ShippingInstructionSchema,
6
+ } from '@reactionary/core';
7
+ import { describe, expect, it, beforeEach } from 'vitest';
8
+ import { createClient, PrimaryProvider } from '../utils.js';
9
+
10
+ const testData = {
11
+ skuWithoutTiers: '0766623301831',
12
+ skuWithTiers: '0766623360203',
13
+ };
14
+
15
+ describe.each([PrimaryProvider.COMMERCETOOLS])('Checkout Capability - %s', (provider) => {
16
+ let client: ReturnType<typeof createClient>;
17
+
18
+ beforeEach(() => {
19
+ client = createClient(provider);
20
+ });
21
+
22
+ describe('anonymous sessions', () => {
23
+ let cart: Cart;
24
+
25
+ beforeEach(async () => {
26
+ cart = await client.cart.add(
27
+ {
28
+ cart: { key: '' },
29
+ variant: {
30
+ sku: testData.skuWithoutTiers,
31
+ },
32
+ quantity: 1,
33
+ },
34
+ );
35
+ });
36
+
37
+ it('can create a checkout session from a cart', async () => {
38
+ // we have either an anonymous user, or an authenticated user.
39
+ // if it is anonymous, we assume you will have collected some basic info by now ?
40
+
41
+ const checkout = await client.checkout.initiateCheckoutForCart(
42
+ {
43
+ cart: cart,
44
+ billingAddress: {
45
+ countryCode: 'US',
46
+ firstName: 'John',
47
+ lastName: 'Doe',
48
+ streetAddress: '123 Main St',
49
+ streetNumber: '1A',
50
+ postalCode: '12345',
51
+ city: 'Anytown',
52
+ region: '',
53
+ },
54
+ notificationEmail: 'sample@example.com',
55
+ notificationPhone: '+4512345678',
56
+ }
57
+ );
58
+
59
+ expect(checkout.identifier.key).toBeDefined();
60
+ expect(checkout.originalCartReference.key).toBe(cart.identifier.key);
61
+ expect(checkout.billingAddress?.firstName).toBe('John');
62
+ expect(checkout.items.length).toBe(1);
63
+ expect(checkout.items[0].variant.sku).toBe(testData.skuWithoutTiers);
64
+ });
65
+
66
+ describe('checkout actions', () => {
67
+ let checkout: Checkout;
68
+ beforeEach(async () => {
69
+ checkout = await client.checkout.initiateCheckoutForCart(
70
+ {
71
+ cart: cart,
72
+ billingAddress: {
73
+ countryCode: 'US',
74
+ firstName: 'John',
75
+ lastName: 'Doe',
76
+ streetAddress: '123 Main St',
77
+ streetNumber: '1A',
78
+ postalCode: '12345',
79
+ city: 'Anytown',
80
+ region: '',
81
+ },
82
+ notificationEmail: 'sample@example.com',
83
+ notificationPhone: '+4512345678',
84
+ }
85
+ );
86
+ });
87
+
88
+ it('can list payment methods', async () => {
89
+ const paymentMethods = await client.checkout.getAvailablePaymentMethods(
90
+ {
91
+ checkout: checkout.identifier,
92
+ }
93
+ );
94
+ expect(paymentMethods.length).toBeGreaterThan(0);
95
+ expect(
96
+ paymentMethods.find((x) => x.identifier.method === 'stripe')
97
+ ).toBeDefined();
98
+ });
99
+
100
+ it('can list shipping methods', async () => {
101
+ const shippingMethods = await client.checkout.getAvailableShippingMethods(
102
+ {
103
+ checkout: checkout.identifier,
104
+ }
105
+ );
106
+ expect(shippingMethods.length).toBeGreaterThan(0);
107
+ expect(
108
+ shippingMethods.find((x) => x.identifier.key === 'us-delivery')
109
+ ).toBeDefined();
110
+ });
111
+
112
+ it('can add a payment instruction', async () => {
113
+ const paymentMethods = await client.checkout.getAvailablePaymentMethods(
114
+ {
115
+ checkout: checkout.identifier,
116
+ }
117
+ );
118
+ const pm = paymentMethods.find((x) => x.identifier.method === 'stripe');
119
+ expect(pm).toBeDefined();
120
+
121
+ const checkoutWithPi = await client.checkout.addPaymentInstruction(
122
+ {
123
+ checkout: checkout.identifier,
124
+ paymentInstruction: PaymentInstructionSchema.parse({
125
+ paymentMethod: pm!.identifier,
126
+ amount: checkout.price.grandTotal,
127
+ protocolData: [{ key: 'test-key', value: 'test-value' }],
128
+ identifier: {
129
+ key: 'pm1'
130
+ },
131
+ status: 'pending'
132
+ } satisfies Omit<PaymentInstruction, 'meta'>),
133
+ }
134
+ );
135
+
136
+ expect(checkoutWithPi.paymentInstructions.length).toBe(1);
137
+ expect(checkoutWithPi.paymentInstructions[0].paymentMethod.method).toBe(
138
+ 'stripe'
139
+ );
140
+ expect(checkoutWithPi.paymentInstructions[0].protocolData.find(x => x.key === 'stripe_clientSecret')?.value).toBeDefined();
141
+
142
+ });
143
+
144
+ it.skip('can cancel an in-progress payment', async () => {
145
+ const paymentMethods = await client.checkout.getAvailablePaymentMethods(
146
+ {
147
+ checkout: checkout.identifier,
148
+ }
149
+ );
150
+ const pm = paymentMethods.find((x) => x.identifier.method === 'stripe');
151
+ expect(pm).toBeDefined();
152
+
153
+ const checkoutWithPi = await client.checkout.addPaymentInstruction(
154
+ {
155
+ checkout: checkout.identifier,
156
+ paymentInstruction: {
157
+ paymentMethod: pm!.identifier,
158
+ amount: checkout.price.grandTotal,
159
+ protocolData: [{ key: 'test-key', value: 'test-value' }],
160
+ },
161
+ }
162
+ );
163
+
164
+ expect(checkoutWithPi.paymentInstructions.length).toBe(1);
165
+
166
+ const checkoutAfterCancel = await client.checkout.removePaymentInstruction(
167
+ {
168
+ checkout: checkout.identifier,
169
+ paymentInstruction:
170
+ checkoutWithPi.paymentInstructions[0].identifier,
171
+ }
172
+ );
173
+
174
+ expect(checkoutAfterCancel.paymentInstructions.length).toBe(0);
175
+ });
176
+
177
+ it('can set shipping address', async () => {
178
+ const checkoutWithShipping = await client.checkout.setShippingAddress(
179
+ {
180
+ checkout: checkout.identifier,
181
+ shippingAddress: {
182
+ countryCode: 'US',
183
+ firstName: 'Jane',
184
+ lastName: 'Doe',
185
+ streetAddress: '456 Other St',
186
+ streetNumber: '2B',
187
+ postalCode: '54321',
188
+ city: 'Othertown',
189
+ region: '',
190
+ },
191
+ }
192
+ );
193
+
194
+ expect(checkoutWithShipping.shippingAddress).toBeDefined();
195
+ expect(checkoutWithShipping.shippingAddress?.firstName).toBe('Jane');
196
+ });
197
+
198
+ it('can set shipping instructions', async () => {
199
+ const shippingMethods = await client.checkout.getAvailableShippingMethods(
200
+ {
201
+ checkout: checkout.identifier,
202
+ }
203
+ );
204
+ const sm = shippingMethods.find((x) => x.identifier.key === 'us-delivery');
205
+ expect(sm).toBeDefined();
206
+
207
+ const shippingInstruction = ShippingInstructionSchema.parse({
208
+ shippingMethod: sm?.identifier || { key: '' },
209
+ amount: checkout.price.totalShipping,
210
+ instructions: 'Leave at front door if not home',
211
+ consentForUnattendedDelivery: true,
212
+ pickupPoint: '4190asx141', // this would be a real pickup point ID in a real scenario
213
+ });
214
+
215
+ const checkoutWithShipping = await client.checkout.setShippingInstruction(
216
+ {
217
+ checkout: checkout.identifier,
218
+ shippingInstruction,
219
+ }
220
+ );
221
+
222
+ expect(checkout.price.totalShipping.value).toBe(0);
223
+ expect(checkoutWithShipping.price.totalShipping.value).toBeGreaterThan(0);
224
+ expect(checkoutWithShipping.shippingInstruction).toBeDefined();
225
+ expect(
226
+ checkoutWithShipping.shippingInstruction?.shippingMethod.key
227
+ ).toBe('us-delivery');
228
+ expect(checkoutWithShipping.shippingInstruction?.instructions).toBe(
229
+ 'Leave at front door if not home'
230
+ );
231
+ expect(checkoutWithShipping.shippingInstruction?.pickupPoint).toBe(
232
+ '4190asx141'
233
+ );
234
+ expect(
235
+ checkoutWithShipping.shippingInstruction?.consentForUnattendedDelivery
236
+ ).toBe(true);
237
+ });
238
+
239
+ it.skip('wont report it finalizable until everything is paid/authorized', async () => {
240
+ expect(checkout.readyForFinalization).toBe(false);
241
+ const pm = (
242
+ await client.checkout.getAvailablePaymentMethods(
243
+ {
244
+ checkout: checkout.identifier,
245
+ }
246
+ )
247
+ ).find((x) => x.identifier.method === 'stripe');
248
+ expect(pm).toBeDefined();
249
+
250
+ const checkoutWithPi = await client.checkout.addPaymentInstruction(
251
+ {
252
+ checkout: checkout.identifier,
253
+ paymentInstruction: {
254
+ paymentMethod: pm!.identifier,
255
+ amount: checkout.price.grandTotal,
256
+ protocolData: [{ key: 'test-key', value: 'test-value' }],
257
+ },
258
+ }
259
+ );
260
+
261
+ // do something to simulate payment authorization ?
262
+ const checkoutReady = await client.checkout.getById(
263
+ { identifier: checkoutWithPi.identifier },
264
+ );
265
+ if (!checkoutReady) {
266
+ expect.fail('checkout not found');
267
+ }
268
+ expect(checkoutReady.readyForFinalization).toBe(true);
269
+ });
270
+ });
271
+ });
272
+ });
@@ -0,0 +1,67 @@
1
+ import 'dotenv/config';
2
+ import { describe, expect, it, beforeEach } from 'vitest';
3
+ import { createClient, PrimaryProvider } from '../utils.js';
4
+
5
+ describe.each([PrimaryProvider.COMMERCETOOLS])('Identity Capability - %s', (provider) => {
6
+ let client: ReturnType<typeof createClient>;
7
+
8
+ beforeEach(() => {
9
+ client = createClient(provider);
10
+ });
11
+
12
+ it('should default to an anonymous identity if no operations have been performed', async () => {
13
+ const identity = await client.identity.getSelf({});
14
+
15
+ expect(identity.type).toBe('Anonymous');
16
+ });
17
+
18
+ it('should automatically upgrade to guest the moment an operation is performed', async () => {
19
+ const cart = await client.cart.getActiveCartId();
20
+ const updatedCart = await client.cart.add(
21
+ {
22
+ cart,
23
+ quantity: 1,
24
+ variant: {
25
+ sku: '0766623301831'
26
+ },
27
+ }
28
+ );
29
+
30
+ const identity = await client.identity.getSelf({});
31
+
32
+ expect(identity.type).toBe('Guest');
33
+ });
34
+
35
+ it('should be able to register a new customer', async () => {
36
+ const time = new Date().getTime();
37
+ const identity = await client.identity.register(
38
+ {
39
+ username: `test-user+${time}@example.com`,
40
+ password: 'love2test',
41
+ }
42
+ );
43
+
44
+ expect(identity.type).toBe('Registered');
45
+
46
+ const refreshedIdentity = await client.identity.getSelf({});
47
+ expect(refreshedIdentity.type).toBe('Registered');
48
+ });
49
+
50
+ it('should be able to log out from a Registered identity', async () => {
51
+ const time = new Date().getTime();
52
+ const identity = await client.identity.register(
53
+ {
54
+ username: `test-user+${time}@example.com`,
55
+ password: 'love2test',
56
+ }
57
+ );
58
+
59
+ expect(identity.type).toBe('Registered');
60
+
61
+ const loggedOutIdentity = await client.identity.logout({});
62
+ expect(loggedOutIdentity.type).toBe('Anonymous');
63
+
64
+ const refreshedIdentity = await client.identity.getSelf({});
65
+ expect(refreshedIdentity.type).toBe('Anonymous');
66
+ });
67
+ });
@@ -0,0 +1,66 @@
1
+ import 'dotenv/config';
2
+ import { describe, expect, it, beforeEach } from 'vitest';
3
+ import { createClient, PrimaryProvider } from '../utils.js';
4
+
5
+ describe.each([PrimaryProvider.COMMERCETOOLS])('Inventory Capability', (provider) => {
6
+ let client: ReturnType<typeof createClient>;
7
+
8
+ beforeEach(() => {
9
+ client = createClient(provider);
10
+ });
11
+
12
+ it('should return unavailable for unknown SKU', async () => {
13
+ const inventory = await client.inventory.getBySKU({
14
+ variant: {
15
+ sku: 'GMCT-01x',
16
+ },
17
+ fulfilmentCenter: {
18
+ key: 'solteqPhysicalStore',
19
+ },
20
+ });
21
+
22
+ expect(inventory.identifier.variant.sku).toBe('GMCT-01x');
23
+ expect(inventory.identifier.fulfillmentCenter.key).toBe(
24
+ 'solteqPhysicalStore'
25
+ );
26
+ expect(inventory.status).toBe('outOfStock');
27
+ expect(inventory.quantity).toBe(0);
28
+ expect(inventory.meta.placeholder).toBe(true);
29
+ });
30
+
31
+ it('should return unavailable for unknown ffmcenter', async () => {
32
+ const inventory = await client.inventory.getBySKU({
33
+ variant: {
34
+ sku: 'GMCT-01',
35
+ },
36
+ fulfilmentCenter: {
37
+ key: 'unknown-ffmcenter',
38
+ },
39
+ });
40
+
41
+ expect(inventory.identifier.variant.sku).toBe('GMCT-01');
42
+ expect(inventory.identifier.fulfillmentCenter.key).toBe(
43
+ 'unknown-ffmcenter'
44
+ );
45
+ expect(inventory.status).toBe('outOfStock');
46
+ expect(inventory.quantity).toBe(0);
47
+ expect(inventory.meta.placeholder).toBe(true);
48
+
49
+ });
50
+ it('should be able to fetch inventory for a given SKU and Fulfillment Center', async () => {
51
+ const inventory = await client.inventory.getBySKU({
52
+ variant: {
53
+ sku: 'GMCT-01',
54
+ },
55
+ fulfilmentCenter: {
56
+ key: 'solteqPhysicalStore',
57
+ },
58
+ });
59
+
60
+ expect(inventory.identifier.variant.sku).toBe('GMCT-01');
61
+ expect(inventory.identifier.fulfillmentCenter.key).toBe(
62
+ 'solteqPhysicalStore'
63
+ );
64
+ expect(inventory.quantity).toBe(42);
65
+ });
66
+ });
@@ -0,0 +1,41 @@
1
+ import 'dotenv/config';
2
+ import { describe, expect, it, beforeEach } from 'vitest';
3
+ import { createClient, PrimaryProvider } from '../utils.js';
4
+
5
+ const testData = {
6
+ skuWithoutTiers: '4049699458101'
7
+ }
8
+
9
+
10
+ // FIXME: Currently broken in terms of actually looking up anything...
11
+ describe.each([PrimaryProvider.COMMERCETOOLS])('Price Capability - %s', (provider) => {
12
+ let client: ReturnType<typeof createClient>;
13
+
14
+ beforeEach(() => {
15
+ client = createClient(provider);
16
+ });
17
+
18
+ it('should be able to get an offer price for a sku', async () => {
19
+ const result = await client.price.getCustomerPrice({ variant: { sku: testData.skuWithoutTiers } });
20
+
21
+ expect(result).toBeTruthy();
22
+ if (result) {
23
+ expect(result.identifier.variant.sku).toBe(testData.skuWithoutTiers);
24
+ expect(result.unitPrice.value).toBe(155.1);
25
+ expect(result.unitPrice.currency).toBe('USD');
26
+ expect(result.tieredPrices.length).toBe(0);
27
+ }
28
+ });
29
+
30
+ it('should be able to get a list price for a sku', async () => {
31
+ const result = await client.price.getListPrice({ variant: { sku: testData.skuWithoutTiers } });
32
+
33
+ expect(result).toBeTruthy();
34
+ if (result) {
35
+ expect(result.identifier.variant.sku).toBe(testData.skuWithoutTiers);
36
+ expect(result.unitPrice.value).toBeGreaterThan(200);
37
+ expect(result.unitPrice.currency).toBe('USD');
38
+ expect(result.tieredPrices.length).toBe(0);
39
+ }
40
+ });
41
+ });