@open-loyalty/mcp-server 1.0.0 → 1.0.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 +134 -12
- package/dist/auth/provider.d.ts +33 -0
- package/dist/auth/provider.js +395 -0
- package/dist/auth/storage.d.ts +16 -0
- package/dist/auth/storage.js +98 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +22 -0
- package/dist/http.d.ts +2 -0
- package/dist/http.js +214 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -0
- package/package.json +11 -10
- package/dist/tools/member.test.d.ts +0 -1
- package/dist/tools/member.test.js +0 -213
- package/dist/tools/points.test.d.ts +0 -1
- package/dist/tools/points.test.js +0 -292
- package/dist/tools/reward.test.d.ts +0 -1
- package/dist/tools/reward.test.js +0 -240
- package/dist/tools/transaction.test.d.ts +0 -1
- package/dist/tools/transaction.test.js +0 -235
- package/dist/utils/cursor.d.ts +0 -84
- package/dist/utils/cursor.js +0 -117
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
// src/tools/points.test.ts
|
|
2
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
3
|
-
import { setupMockAxios, teardownMockAxios, getMockAxios } from '../../tests/mocks/http.mock.js';
|
|
4
|
-
import { pointsFixtures } from '../../tests/fixtures/points.fixtures.js';
|
|
5
|
-
import { pointsAdd, pointsSpend, pointsTransfer, pointsGetBalance, pointsGetHistory, pointsGetHistogram, } from './points.js';
|
|
6
|
-
describe('Points Operations', () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
setupMockAxios();
|
|
9
|
-
});
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
teardownMockAxios();
|
|
12
|
-
});
|
|
13
|
-
describe('pointsAdd', () => {
|
|
14
|
-
it('should add points with transfer wrapper', async () => {
|
|
15
|
-
const mockAxios = getMockAxios();
|
|
16
|
-
mockAxios.onPost('/default/points/add').reply(200, pointsFixtures.addResponse);
|
|
17
|
-
const result = await pointsAdd({
|
|
18
|
-
memberId: 'member-uuid',
|
|
19
|
-
points: 100,
|
|
20
|
-
});
|
|
21
|
-
expect(result.transferId).toBe('123e4567-e89b-12d3-a456-426614174000');
|
|
22
|
-
// Verify request body format with transfer wrapper
|
|
23
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
24
|
-
expect(requestData).toEqual({
|
|
25
|
-
transfer: {
|
|
26
|
-
customer: 'member-uuid',
|
|
27
|
-
points: 100,
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
it('should include optional fields in transfer wrapper', async () => {
|
|
32
|
-
const mockAxios = getMockAxios();
|
|
33
|
-
mockAxios.onPost('/default/points/add').reply(200, pointsFixtures.addResponse);
|
|
34
|
-
await pointsAdd({
|
|
35
|
-
memberId: 'member-uuid',
|
|
36
|
-
points: 500,
|
|
37
|
-
walletCode: 'bonus',
|
|
38
|
-
comment: 'Welcome bonus',
|
|
39
|
-
expiresInDays: 90,
|
|
40
|
-
lockedUntilDays: 7,
|
|
41
|
-
});
|
|
42
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
43
|
-
expect(requestData.transfer.customer).toBe('member-uuid');
|
|
44
|
-
expect(requestData.transfer.points).toBe(500);
|
|
45
|
-
expect(requestData.transfer.walletCode).toBe('bonus');
|
|
46
|
-
expect(requestData.transfer.comment).toBe('Welcome bonus');
|
|
47
|
-
expect(requestData.transfer.expiresInDays).toBe(90);
|
|
48
|
-
expect(requestData.transfer.lockedUntilDays).toBe(7);
|
|
49
|
-
});
|
|
50
|
-
it('should use custom storeCode when provided', async () => {
|
|
51
|
-
const mockAxios = getMockAxios();
|
|
52
|
-
mockAxios.onPost('/custom-store/points/add').reply(200, pointsFixtures.addResponse);
|
|
53
|
-
await pointsAdd({
|
|
54
|
-
storeCode: 'custom-store',
|
|
55
|
-
memberId: 'member-uuid',
|
|
56
|
-
points: 100,
|
|
57
|
-
});
|
|
58
|
-
expect(mockAxios.history.post[0].url).toBe('/custom-store/points/add');
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
describe('pointsSpend', () => {
|
|
62
|
-
it('should spend points with transfer wrapper', async () => {
|
|
63
|
-
const mockAxios = getMockAxios();
|
|
64
|
-
mockAxios.onPost('/default/points/spend').reply(200, pointsFixtures.spendResponse);
|
|
65
|
-
const result = await pointsSpend({
|
|
66
|
-
memberId: 'member-uuid',
|
|
67
|
-
points: 50,
|
|
68
|
-
});
|
|
69
|
-
expect(result.transferId).toBe('223e4567-e89b-12d3-a456-426614174001');
|
|
70
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
71
|
-
expect(requestData).toEqual({
|
|
72
|
-
transfer: {
|
|
73
|
-
customer: 'member-uuid',
|
|
74
|
-
points: 50,
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
it('should include optional fields', async () => {
|
|
79
|
-
const mockAxios = getMockAxios();
|
|
80
|
-
mockAxios.onPost('/default/points/spend').reply(200, pointsFixtures.spendResponse);
|
|
81
|
-
await pointsSpend({
|
|
82
|
-
memberId: 'member-uuid',
|
|
83
|
-
points: 100,
|
|
84
|
-
walletCode: 'default',
|
|
85
|
-
comment: 'Reward redemption',
|
|
86
|
-
});
|
|
87
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
88
|
-
expect(requestData.transfer.walletCode).toBe('default');
|
|
89
|
-
expect(requestData.transfer.comment).toBe('Reward redemption');
|
|
90
|
-
});
|
|
91
|
-
it('should throw error for insufficient points', async () => {
|
|
92
|
-
const mockAxios = getMockAxios();
|
|
93
|
-
mockAxios.onPost('/default/points/spend').reply(400, {
|
|
94
|
-
message: 'NotEnoughPoints',
|
|
95
|
-
code: 400,
|
|
96
|
-
});
|
|
97
|
-
// API returns 400 error which gets thrown
|
|
98
|
-
await expect(pointsSpend({
|
|
99
|
-
memberId: 'member-uuid',
|
|
100
|
-
points: 10000,
|
|
101
|
-
})).rejects.toThrow();
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
describe('pointsTransfer', () => {
|
|
105
|
-
it('should transfer points between members', async () => {
|
|
106
|
-
const mockAxios = getMockAxios();
|
|
107
|
-
mockAxios.onPost('/default/points/transfer').reply(200, pointsFixtures.transferResponse);
|
|
108
|
-
const result = await pointsTransfer({
|
|
109
|
-
senderId: 'sender-uuid',
|
|
110
|
-
receiverId: 'receiver-uuid',
|
|
111
|
-
points: 100,
|
|
112
|
-
});
|
|
113
|
-
expect(result.transferId).toBe('323e4567-e89b-12d3-a456-426614174002');
|
|
114
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
115
|
-
expect(requestData).toEqual({
|
|
116
|
-
transfer: {
|
|
117
|
-
sender: 'sender-uuid',
|
|
118
|
-
receiver: 'receiver-uuid',
|
|
119
|
-
points: 100,
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
it('should throw error when sender equals receiver', async () => {
|
|
124
|
-
await expect(pointsTransfer({
|
|
125
|
-
senderId: 'same-uuid',
|
|
126
|
-
receiverId: 'same-uuid',
|
|
127
|
-
points: 100,
|
|
128
|
-
})).rejects.toThrow('Cannot transfer points to yourself');
|
|
129
|
-
});
|
|
130
|
-
it('should throw error for insufficient balance on transfer', async () => {
|
|
131
|
-
const mockAxios = getMockAxios();
|
|
132
|
-
mockAxios.onPost('/default/points/transfer').reply(400, {
|
|
133
|
-
message: 'NotEnoughPoints',
|
|
134
|
-
});
|
|
135
|
-
// API returns 400 error which gets thrown
|
|
136
|
-
await expect(pointsTransfer({
|
|
137
|
-
senderId: 'sender-uuid',
|
|
138
|
-
receiverId: 'receiver-uuid',
|
|
139
|
-
points: 10000,
|
|
140
|
-
})).rejects.toThrow();
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
describe('pointsGetBalance', () => {
|
|
144
|
-
it('should get balance from wallet list response', async () => {
|
|
145
|
-
const mockAxios = getMockAxios();
|
|
146
|
-
mockAxios.onGet('/default/member/member-uuid/wallet').reply(200, pointsFixtures.walletResponse);
|
|
147
|
-
const result = await pointsGetBalance({ memberId: 'member-uuid' });
|
|
148
|
-
expect(result.activeUnits).toBe(750);
|
|
149
|
-
expect(result.earnedUnits).toBe(1000);
|
|
150
|
-
expect(result.spentUnits).toBe(200);
|
|
151
|
-
expect(result.lockedUnits).toBe(50);
|
|
152
|
-
expect(result.expiredUnits).toBe(0);
|
|
153
|
-
});
|
|
154
|
-
it('should filter by wallet code', async () => {
|
|
155
|
-
const mockAxios = getMockAxios();
|
|
156
|
-
mockAxios.onGet(/\/default\/member\/member-uuid\/wallet/).reply(200, pointsFixtures.walletResponse);
|
|
157
|
-
await pointsGetBalance({
|
|
158
|
-
memberId: 'member-uuid',
|
|
159
|
-
walletCode: 'bonus',
|
|
160
|
-
});
|
|
161
|
-
const url = mockAxios.history.get[0].url;
|
|
162
|
-
expect(url).toContain('walletType%3Acode=bonus');
|
|
163
|
-
});
|
|
164
|
-
it('should aggregate multiple wallets from nested account objects', async () => {
|
|
165
|
-
const mockAxios = getMockAxios();
|
|
166
|
-
mockAxios.onGet('/default/member/member-uuid/wallet').reply(200, {
|
|
167
|
-
items: [
|
|
168
|
-
{ account: { activeUnits: 100, earnedUnits: 200, spentUnits: 50, lockedUnits: 25, expiredUnits: 10 } },
|
|
169
|
-
{ account: { activeUnits: 200, earnedUnits: 300, spentUnits: 100, lockedUnits: 0, expiredUnits: 0 } },
|
|
170
|
-
],
|
|
171
|
-
total: { all: 2, filtered: 2 },
|
|
172
|
-
});
|
|
173
|
-
const result = await pointsGetBalance({ memberId: 'member-uuid' });
|
|
174
|
-
expect(result.activeUnits).toBe(300);
|
|
175
|
-
expect(result.earnedUnits).toBe(500);
|
|
176
|
-
expect(result.spentUnits).toBe(150);
|
|
177
|
-
expect(result.lockedUnits).toBe(25);
|
|
178
|
-
expect(result.expiredUnits).toBe(10);
|
|
179
|
-
});
|
|
180
|
-
it('should handle single wallet response format', async () => {
|
|
181
|
-
const mockAxios = getMockAxios();
|
|
182
|
-
mockAxios.onGet('/default/member/member-uuid/wallet').reply(200, {
|
|
183
|
-
account: {
|
|
184
|
-
activeUnits: 500,
|
|
185
|
-
earnedUnits: 800,
|
|
186
|
-
spentUnits: 300,
|
|
187
|
-
lockedUnits: 0,
|
|
188
|
-
expiredUnits: 0,
|
|
189
|
-
},
|
|
190
|
-
});
|
|
191
|
-
const result = await pointsGetBalance({ memberId: 'member-uuid' });
|
|
192
|
-
expect(result.activeUnits).toBe(500);
|
|
193
|
-
expect(result.earnedUnits).toBe(800);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
describe('pointsGetHistory', () => {
|
|
197
|
-
it('should get history and map items correctly', async () => {
|
|
198
|
-
const mockAxios = getMockAxios();
|
|
199
|
-
mockAxios.onGet(/\/default\/points/).reply(200, pointsFixtures.historyResponse);
|
|
200
|
-
const result = await pointsGetHistory({ memberId: 'member-uuid' });
|
|
201
|
-
expect(result.transfers).toHaveLength(2);
|
|
202
|
-
expect(result.transfers[0].transferId).toBe('transfer-uuid-1');
|
|
203
|
-
expect(result.transfers[0].type).toBe('adding');
|
|
204
|
-
expect(result.transfers[0].points).toBe(100);
|
|
205
|
-
expect(result.transfers[0].comment).toBe('Welcome bonus');
|
|
206
|
-
});
|
|
207
|
-
it('should include member:id in query params', async () => {
|
|
208
|
-
const mockAxios = getMockAxios();
|
|
209
|
-
mockAxios.onGet(/\/default\/points/).reply(200, pointsFixtures.historyResponse);
|
|
210
|
-
await pointsGetHistory({ memberId: 'member-uuid' });
|
|
211
|
-
const url = mockAxios.history.get[0].url;
|
|
212
|
-
expect(url).toContain('member%3Aid=member-uuid');
|
|
213
|
-
});
|
|
214
|
-
it('should include pagination params', async () => {
|
|
215
|
-
const mockAxios = getMockAxios();
|
|
216
|
-
mockAxios.onGet(/\/default\/points/).reply(200, pointsFixtures.historyResponse);
|
|
217
|
-
await pointsGetHistory({
|
|
218
|
-
memberId: 'member-uuid',
|
|
219
|
-
page: 2,
|
|
220
|
-
perPage: 25,
|
|
221
|
-
});
|
|
222
|
-
const url = mockAxios.history.get[0].url;
|
|
223
|
-
expect(url).toContain('_page=2');
|
|
224
|
-
expect(url).toContain('_itemsOnPage=25');
|
|
225
|
-
});
|
|
226
|
-
it('should filter by transfer type', async () => {
|
|
227
|
-
const mockAxios = getMockAxios();
|
|
228
|
-
mockAxios.onGet(/\/default\/points/).reply(200, pointsFixtures.historyResponse);
|
|
229
|
-
await pointsGetHistory({
|
|
230
|
-
memberId: 'member-uuid',
|
|
231
|
-
type: 'spending',
|
|
232
|
-
});
|
|
233
|
-
const url = mockAxios.history.get[0].url;
|
|
234
|
-
expect(url).toContain('type=spending');
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
describe('pointsGetHistogram', () => {
|
|
238
|
-
it('should get histogram data', async () => {
|
|
239
|
-
const mockAxios = getMockAxios();
|
|
240
|
-
mockAxios.onGet(/\/default\/points\/history/).reply(200, [
|
|
241
|
-
{ date: '2026-01-01', earned: 100, spent: 50, balance: 50 },
|
|
242
|
-
{ date: '2026-01-02', earned: 200, spent: 75, balance: 175 },
|
|
243
|
-
]);
|
|
244
|
-
const result = await pointsGetHistogram({ memberId: 'member-uuid' });
|
|
245
|
-
expect(result).toHaveLength(2);
|
|
246
|
-
expect(result[0].date).toBe('2026-01-01');
|
|
247
|
-
expect(result[0].earned).toBe(100);
|
|
248
|
-
expect(result[0].spent).toBe(50);
|
|
249
|
-
expect(result[0].balance).toBe(50);
|
|
250
|
-
});
|
|
251
|
-
it('should include member:id in query params', async () => {
|
|
252
|
-
const mockAxios = getMockAxios();
|
|
253
|
-
mockAxios.onGet(/\/default\/points\/history/).reply(200, []);
|
|
254
|
-
await pointsGetHistogram({ memberId: 'member-uuid' });
|
|
255
|
-
const url = mockAxios.history.get[0].url;
|
|
256
|
-
expect(url).toContain('member%3Aid=member-uuid');
|
|
257
|
-
});
|
|
258
|
-
it('should set interval parameter', async () => {
|
|
259
|
-
const mockAxios = getMockAxios();
|
|
260
|
-
mockAxios.onGet(/\/default\/points\/history/).reply(200, []);
|
|
261
|
-
await pointsGetHistogram({
|
|
262
|
-
memberId: 'member-uuid',
|
|
263
|
-
interval: 'week',
|
|
264
|
-
});
|
|
265
|
-
const url = mockAxios.history.get[0].url;
|
|
266
|
-
expect(url).toContain('interval=week');
|
|
267
|
-
});
|
|
268
|
-
it('should handle object response format with items', async () => {
|
|
269
|
-
const mockAxios = getMockAxios();
|
|
270
|
-
mockAxios.onGet(/\/default\/points\/history/).reply(200, {
|
|
271
|
-
items: [
|
|
272
|
-
{ date: '2026-01-01', earned: 100, spent: 50, balance: 50 },
|
|
273
|
-
],
|
|
274
|
-
});
|
|
275
|
-
const result = await pointsGetHistogram({ memberId: 'member-uuid' });
|
|
276
|
-
expect(result).toHaveLength(1);
|
|
277
|
-
expect(result[0].date).toBe('2026-01-01');
|
|
278
|
-
});
|
|
279
|
-
it('should calculate lastDays from dateFrom', async () => {
|
|
280
|
-
const mockAxios = getMockAxios();
|
|
281
|
-
mockAxios.onGet(/\/default\/points\/history/).reply(200, []);
|
|
282
|
-
// Set a fixed dateFrom to test calculation
|
|
283
|
-
await pointsGetHistogram({
|
|
284
|
-
memberId: 'member-uuid',
|
|
285
|
-
dateFrom: '2026-01-01',
|
|
286
|
-
});
|
|
287
|
-
const url = mockAxios.history.get[0].url;
|
|
288
|
-
expect(url).toContain('lastDays=');
|
|
289
|
-
expect(url).toContain('futureDays=0');
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
// src/tools/reward.test.ts
|
|
2
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
3
|
-
import { setupMockAxios, teardownMockAxios, getMockAxios } from '../../tests/mocks/http.mock.js';
|
|
4
|
-
import { rewardFixtures } from '../../tests/fixtures/reward.fixtures.js';
|
|
5
|
-
import { rewardList, rewardCreate, rewardGet, rewardUpdate, rewardActivate, rewardDeactivate, rewardBuy, rewardRedeem, rewardCategoryList, } from './reward.js';
|
|
6
|
-
describe('Reward Operations', () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
setupMockAxios();
|
|
9
|
-
});
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
teardownMockAxios();
|
|
12
|
-
});
|
|
13
|
-
describe('rewardList', () => {
|
|
14
|
-
it('should list rewards and map items correctly', async () => {
|
|
15
|
-
const mockAxios = getMockAxios();
|
|
16
|
-
mockAxios.onGet('/default/reward').reply(200, rewardFixtures.listResponse);
|
|
17
|
-
const result = await rewardList({});
|
|
18
|
-
expect(result.rewards).toHaveLength(2);
|
|
19
|
-
expect(result.rewards[0].rewardId).toBe('reward-uuid-1');
|
|
20
|
-
expect(result.rewards[0].name).toBe('Discount Coupon');
|
|
21
|
-
expect(result.rewards[0].type).toBe('static_coupon');
|
|
22
|
-
expect(result.rewards[0].costInPoints).toBe(100);
|
|
23
|
-
expect(result.total.all).toBe(10);
|
|
24
|
-
expect(result.total.filtered).toBe(2);
|
|
25
|
-
});
|
|
26
|
-
it('should include pagination params', async () => {
|
|
27
|
-
const mockAxios = getMockAxios();
|
|
28
|
-
mockAxios.onGet(/\/default\/reward/).reply(200, rewardFixtures.listResponse);
|
|
29
|
-
await rewardList({ page: 2, perPage: 25 });
|
|
30
|
-
const url = mockAxios.history.get[0].url;
|
|
31
|
-
expect(url).toContain('_page=2');
|
|
32
|
-
expect(url).toContain('_itemsOnPage=25');
|
|
33
|
-
});
|
|
34
|
-
it('should include filter params', async () => {
|
|
35
|
-
const mockAxios = getMockAxios();
|
|
36
|
-
mockAxios.onGet(/\/default\/reward/).reply(200, rewardFixtures.listResponse);
|
|
37
|
-
await rewardList({
|
|
38
|
-
active: true,
|
|
39
|
-
type: 'static_coupon',
|
|
40
|
-
categoryId: 'cat-uuid',
|
|
41
|
-
});
|
|
42
|
-
const url = mockAxios.history.get[0].url;
|
|
43
|
-
expect(url).toContain('active=true');
|
|
44
|
-
expect(url).toContain('reward=static_coupon');
|
|
45
|
-
expect(url).toContain('categoryId=cat-uuid');
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('rewardCreate', () => {
|
|
49
|
-
it('should create reward with reward wrapper', async () => {
|
|
50
|
-
const mockAxios = getMockAxios();
|
|
51
|
-
mockAxios.onPost('/default/reward').reply(200, rewardFixtures.createResponse);
|
|
52
|
-
const result = await rewardCreate({
|
|
53
|
-
name: 'Test Reward',
|
|
54
|
-
type: 'static_coupon',
|
|
55
|
-
costInPoints: 100,
|
|
56
|
-
});
|
|
57
|
-
expect(result.rewardId).toBe('reward-uuid-123');
|
|
58
|
-
expect(result.name).toBe('Test Reward');
|
|
59
|
-
expect(result.costInPoints).toBe(100);
|
|
60
|
-
// Verify request body format with reward wrapper
|
|
61
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
62
|
-
expect(requestData.reward).toBeDefined();
|
|
63
|
-
expect(requestData.reward.name).toBe('Test Reward');
|
|
64
|
-
expect(requestData.reward.type).toBe('static_coupon');
|
|
65
|
-
expect(requestData.reward.costInPoints).toBe(100);
|
|
66
|
-
});
|
|
67
|
-
it('should include optional fields', async () => {
|
|
68
|
-
const mockAxios = getMockAxios();
|
|
69
|
-
mockAxios.onPost('/default/reward').reply(200, rewardFixtures.createResponse);
|
|
70
|
-
await rewardCreate({
|
|
71
|
-
name: 'Full Reward',
|
|
72
|
-
type: 'static_coupon',
|
|
73
|
-
costInPoints: 200,
|
|
74
|
-
description: 'A test reward',
|
|
75
|
-
couponValue: 10,
|
|
76
|
-
couponValueType: 'Money',
|
|
77
|
-
daysValid: 30,
|
|
78
|
-
active: true,
|
|
79
|
-
categories: ['cat-1', 'cat-2'],
|
|
80
|
-
levels: ['level-1'],
|
|
81
|
-
target: 'level',
|
|
82
|
-
});
|
|
83
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
84
|
-
expect(requestData.reward.description).toBe('A test reward');
|
|
85
|
-
expect(requestData.reward.couponValue).toBe(10);
|
|
86
|
-
expect(requestData.reward.couponValueType).toBe('Money');
|
|
87
|
-
expect(requestData.reward.daysValid).toBe(30);
|
|
88
|
-
expect(requestData.reward.categories).toEqual(['cat-1', 'cat-2']);
|
|
89
|
-
expect(requestData.reward.target).toBe('level');
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
describe('rewardGet', () => {
|
|
93
|
-
it('should get reward details', async () => {
|
|
94
|
-
const mockAxios = getMockAxios();
|
|
95
|
-
mockAxios.onGet('/default/reward/reward-uuid').reply(200, rewardFixtures.getResponse);
|
|
96
|
-
const result = await rewardGet({ rewardId: 'reward-uuid' });
|
|
97
|
-
expect(result.rewardId).toBe('reward-uuid-123');
|
|
98
|
-
expect(result.name).toBe('Test Reward');
|
|
99
|
-
expect(result.type).toBe('static_coupon');
|
|
100
|
-
expect(result.costInPoints).toBe(100);
|
|
101
|
-
expect(result.active).toBe(true);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
describe('rewardUpdate', () => {
|
|
105
|
-
it('should update reward with reward wrapper', async () => {
|
|
106
|
-
const mockAxios = getMockAxios();
|
|
107
|
-
mockAxios.onPut('/default/reward/reward-uuid').reply(200);
|
|
108
|
-
await rewardUpdate({
|
|
109
|
-
rewardId: 'reward-uuid',
|
|
110
|
-
name: 'Updated Reward',
|
|
111
|
-
costInPoints: 150,
|
|
112
|
-
});
|
|
113
|
-
const requestData = JSON.parse(mockAxios.history.put[0].data);
|
|
114
|
-
expect(requestData.reward).toBeDefined();
|
|
115
|
-
expect(requestData.reward.name).toBe('Updated Reward');
|
|
116
|
-
expect(requestData.reward.costInPoints).toBe(150);
|
|
117
|
-
});
|
|
118
|
-
it('should include optional arrays', async () => {
|
|
119
|
-
const mockAxios = getMockAxios();
|
|
120
|
-
mockAxios.onPut('/default/reward/reward-uuid').reply(200);
|
|
121
|
-
await rewardUpdate({
|
|
122
|
-
rewardId: 'reward-uuid',
|
|
123
|
-
categories: ['cat-1'],
|
|
124
|
-
levels: ['level-1', 'level-2'],
|
|
125
|
-
segments: ['segment-1'],
|
|
126
|
-
});
|
|
127
|
-
const requestData = JSON.parse(mockAxios.history.put[0].data);
|
|
128
|
-
expect(requestData.reward.categories).toEqual(['cat-1']);
|
|
129
|
-
expect(requestData.reward.levels).toEqual(['level-1', 'level-2']);
|
|
130
|
-
expect(requestData.reward.segments).toEqual(['segment-1']);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
describe('rewardActivate', () => {
|
|
134
|
-
it('should call activate endpoint', async () => {
|
|
135
|
-
const mockAxios = getMockAxios();
|
|
136
|
-
mockAxios.onPost('/default/reward/reward-uuid/activate').reply(200);
|
|
137
|
-
await rewardActivate({ rewardId: 'reward-uuid' });
|
|
138
|
-
expect(mockAxios.history.post[0].url).toBe('/default/reward/reward-uuid/activate');
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
describe('rewardDeactivate', () => {
|
|
142
|
-
it('should call deactivate endpoint', async () => {
|
|
143
|
-
const mockAxios = getMockAxios();
|
|
144
|
-
mockAxios.onPost('/default/reward/reward-uuid/deactivate').reply(200);
|
|
145
|
-
await rewardDeactivate({ rewardId: 'reward-uuid' });
|
|
146
|
-
expect(mockAxios.history.post[0].url).toBe('/default/reward/reward-uuid/deactivate');
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
describe('rewardBuy', () => {
|
|
150
|
-
it('should buy reward and return first issued', async () => {
|
|
151
|
-
const mockAxios = getMockAxios();
|
|
152
|
-
mockAxios.onPost('/default/reward/reward-uuid/buy').reply(200, rewardFixtures.buyResponse);
|
|
153
|
-
const result = await rewardBuy({
|
|
154
|
-
rewardId: 'reward-uuid',
|
|
155
|
-
memberId: 'member-uuid',
|
|
156
|
-
});
|
|
157
|
-
expect(result.issuedRewardId).toBe('issued-uuid-123');
|
|
158
|
-
expect(result.couponCode).toBe('COUPON-ABC123');
|
|
159
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
160
|
-
expect(requestData.customerId).toBe('member-uuid');
|
|
161
|
-
});
|
|
162
|
-
it('should include optional parameters', async () => {
|
|
163
|
-
const mockAxios = getMockAxios();
|
|
164
|
-
mockAxios.onPost('/default/reward/reward-uuid/buy').reply(200, rewardFixtures.buyResponse);
|
|
165
|
-
await rewardBuy({
|
|
166
|
-
rewardId: 'reward-uuid',
|
|
167
|
-
memberId: 'member-uuid',
|
|
168
|
-
quantity: 3,
|
|
169
|
-
couponValue: 50,
|
|
170
|
-
withoutPoints: true,
|
|
171
|
-
});
|
|
172
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
173
|
-
expect(requestData.quantity).toBe(3);
|
|
174
|
-
expect(requestData.couponValue).toBe(50);
|
|
175
|
-
expect(requestData.withoutPoints).toBe(true);
|
|
176
|
-
});
|
|
177
|
-
it('should throw error for insufficient points', async () => {
|
|
178
|
-
const mockAxios = getMockAxios();
|
|
179
|
-
mockAxios.onPost('/default/reward/reward-uuid/buy').reply(400, {
|
|
180
|
-
message: 'NotEnoughPoints',
|
|
181
|
-
});
|
|
182
|
-
// API returns 400 error which gets thrown
|
|
183
|
-
await expect(rewardBuy({
|
|
184
|
-
rewardId: 'reward-uuid',
|
|
185
|
-
memberId: 'member-uuid',
|
|
186
|
-
})).rejects.toThrow();
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
describe('rewardRedeem', () => {
|
|
190
|
-
it('should redeem coupon', async () => {
|
|
191
|
-
const mockAxios = getMockAxios();
|
|
192
|
-
mockAxios.onPost('/default/member/member-uuid/reward/redeem').reply(200, rewardFixtures.redeemResponse);
|
|
193
|
-
const result = await rewardRedeem({
|
|
194
|
-
memberId: 'member-uuid',
|
|
195
|
-
couponCode: 'COUPON-ABC123',
|
|
196
|
-
});
|
|
197
|
-
expect(result.code).toBe('COUPON-ABC123');
|
|
198
|
-
expect(result.used).toBe(true);
|
|
199
|
-
const requestData = JSON.parse(mockAxios.history.post[0].data);
|
|
200
|
-
expect(requestData.couponCode).toBe('COUPON-ABC123');
|
|
201
|
-
});
|
|
202
|
-
it('should throw error for non-existent coupon', async () => {
|
|
203
|
-
const mockAxios = getMockAxios();
|
|
204
|
-
mockAxios.onPost('/default/member/member-uuid/reward/redeem').reply(400, {
|
|
205
|
-
message: 'CouponDoesNotExist',
|
|
206
|
-
});
|
|
207
|
-
// API returns 400 error which gets thrown
|
|
208
|
-
await expect(rewardRedeem({
|
|
209
|
-
memberId: 'member-uuid',
|
|
210
|
-
couponCode: 'INVALID-CODE',
|
|
211
|
-
})).rejects.toThrow();
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
describe('rewardCategoryList', () => {
|
|
215
|
-
it('should list categories and map rewardCategoryId to categoryId', async () => {
|
|
216
|
-
const mockAxios = getMockAxios();
|
|
217
|
-
mockAxios.onGet('/default/rewardCategory').reply(200, rewardFixtures.categoryListResponse);
|
|
218
|
-
const result = await rewardCategoryList({});
|
|
219
|
-
expect(result.categories).toHaveLength(2);
|
|
220
|
-
expect(result.categories[0].categoryId).toBe('cat-uuid-1');
|
|
221
|
-
expect(result.categories[0].name).toBe('Discounts');
|
|
222
|
-
expect(result.categories[0].active).toBe(true);
|
|
223
|
-
});
|
|
224
|
-
it('should include pagination params', async () => {
|
|
225
|
-
const mockAxios = getMockAxios();
|
|
226
|
-
mockAxios.onGet(/\/default\/rewardCategory/).reply(200, rewardFixtures.categoryListResponse);
|
|
227
|
-
await rewardCategoryList({ page: 2, perPage: 10 });
|
|
228
|
-
const url = mockAxios.history.get[0].url;
|
|
229
|
-
expect(url).toContain('_page=2');
|
|
230
|
-
expect(url).toContain('_itemsOnPage=10');
|
|
231
|
-
});
|
|
232
|
-
it('should filter by active status', async () => {
|
|
233
|
-
const mockAxios = getMockAxios();
|
|
234
|
-
mockAxios.onGet(/\/default\/rewardCategory/).reply(200, rewardFixtures.categoryListResponse);
|
|
235
|
-
await rewardCategoryList({ active: true });
|
|
236
|
-
const url = mockAxios.history.get[0].url;
|
|
237
|
-
expect(url).toContain('active=true');
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|