@alexkroman1/aai-cli 5.13.2 → 5.14.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/scaffold/package.json +3 -3
- package/dist/scaffold/pnpm-workspace.yaml +24 -0
- package/dist/templates/dispatch-center/agent.test.ts +10 -17
- package/dist/templates/dispatch-center/agent.ts +2 -2
- package/dist/templates/dispatch-center/client.tsx +9 -13
- package/dist/templates/dispatch-center/shared.ts +36 -63
- package/dist/templates/dispatch-center/tools/incident_add_note.ts +4 -4
- package/dist/templates/dispatch-center/tools/incident_create.ts +2 -2
- package/dist/templates/dispatch-center/tools/incident_escalate.ts +4 -4
- package/dist/templates/dispatch-center/tools/incident_get.ts +9 -4
- package/dist/templates/dispatch-center/tools/incident_triage.ts +4 -4
- package/dist/templates/dispatch-center/tools/incident_update_status.ts +4 -4
- package/dist/templates/dispatch-center/tools/ops_dashboard.ts +2 -2
- package/dist/templates/dispatch-center/tools/ops_run_scenario.ts +2 -2
- package/dist/templates/dispatch-center/tools/resources_dispatch.ts +4 -4
- package/dist/templates/dispatch-center/tools/resources_get_available.ts +2 -2
- package/dist/templates/dispatch-center/tools/resources_update_status.ts +2 -2
- package/dist/templates/infocom-adventure/agent.ts +10 -10
- package/dist/templates/infocom-adventure/client.tsx +5 -17
- package/dist/templates/infocom-adventure/shared.ts +17 -14
- package/dist/templates/pizza-ordering/agent.test.ts +27 -31
- package/dist/templates/pizza-ordering/agent.ts +8 -8
- package/dist/templates/pizza-ordering/client.tsx +4 -4
- package/dist/templates/pizza-ordering/shared.ts +14 -20
- package/dist/templates/retail/agent.test.ts +137 -138
- package/dist/templates/retail/agent.ts +7 -10
- package/dist/templates/retail/authenticate.ts +2 -2
- package/dist/templates/retail/client.tsx +13 -14
- package/dist/templates/retail/registry.test.ts +9 -9
- package/dist/templates/retail/resolve.test.ts +17 -16
- package/dist/templates/retail/resolve.ts +5 -4
- package/dist/templates/retail/shared.test.ts +17 -16
- package/dist/templates/retail/shared.ts +39 -18
- package/dist/templates/retail/store.test.ts +40 -47
- package/dist/templates/retail/store.ts +39 -65
- package/dist/templates/retail/swap.test.ts +20 -17
- package/dist/templates/retail/swap.ts +7 -14
- package/dist/templates/retail/tools/cancel_pending_order.ts +5 -4
- package/dist/templates/retail/tools/exchange_delivered_order_items.ts +6 -5
- package/dist/templates/retail/tools/find_user_id_by_email.ts +2 -2
- package/dist/templates/retail/tools/find_user_id_by_name_zip.ts +2 -2
- package/dist/templates/retail/tools/get_item_details.ts +4 -3
- package/dist/templates/retail/tools/get_order_details.ts +4 -3
- package/dist/templates/retail/tools/get_product_details.ts +4 -3
- package/dist/templates/retail/tools/get_user_details.ts +4 -3
- package/dist/templates/retail/tools/list_all_product_types.ts +2 -2
- package/dist/templates/retail/tools/modify_pending_order_address.ts +4 -3
- package/dist/templates/retail/tools/modify_pending_order_items.ts +6 -6
- package/dist/templates/retail/tools/modify_pending_order_payment.ts +6 -6
- package/dist/templates/retail/tools/modify_user_address.ts +4 -3
- package/dist/templates/retail/tools/return_delivered_order_items.ts +6 -6
- package/dist/templates/solo-rpg/agent.test.ts +26 -34
- package/dist/templates/solo-rpg/agent.ts +2 -2
- package/dist/templates/solo-rpg/client.tsx +1 -1
- package/dist/templates/solo-rpg/shared.ts +6 -14
- package/dist/templates/solo-rpg/tools/action_roll.ts +2 -2
- package/dist/templates/solo-rpg/tools/burn_momentum.ts +2 -2
- package/dist/templates/solo-rpg/tools/check_state.ts +2 -2
- package/dist/templates/solo-rpg/tools/load_game.ts +2 -2
- package/dist/templates/solo-rpg/tools/oracle.ts +3 -3
- package/dist/templates/solo-rpg/tools/save_game.ts +2 -2
- package/dist/templates/solo-rpg/tools/setup_character.ts +2 -2
- package/dist/templates/solo-rpg/tools/update_state.ts +12 -11
- package/package.json +3 -3
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { ToolContext } from "@alexkroman1/aai";
|
|
1
|
+
import type { ToolContext, ToolFailure } from "@alexkroman1/aai";
|
|
2
|
+
import { isToolFailure } from "@alexkroman1/aai";
|
|
3
|
+
import { createToolContext } from "@alexkroman1/aai/testing";
|
|
2
4
|
import { describe, expect, test } from "vitest";
|
|
3
5
|
import type { AuthResult } from "./authenticate.ts";
|
|
4
6
|
import type { Address } from "./shared.ts";
|
|
5
|
-
import type
|
|
6
|
-
import { getState, isError } from "./store.ts";
|
|
7
|
+
import { retailSlot, type StateSlot } from "./store.ts";
|
|
7
8
|
import { cancelPendingOrder } from "./tools/cancel_pending_order.ts";
|
|
8
9
|
import { exchangeDeliveredOrderItems } from "./tools/exchange_delivered_order_items.ts";
|
|
9
10
|
import { findUserIdByEmail } from "./tools/find_user_id_by_email.ts";
|
|
@@ -20,28 +21,22 @@ import { modifyUserAddress } from "./tools/modify_user_address.ts";
|
|
|
20
21
|
import { returnDeliveredOrderItems } from "./tools/return_delivered_order_items.ts";
|
|
21
22
|
import { transferToHumanAgents } from "./tools/transfer_to_human_agents.ts";
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
function makeCtx(): ToolContext {
|
|
26
|
-
return
|
|
27
|
-
sessionId: `retail-test-${++sessionCounter}`,
|
|
28
|
-
send: () => {},
|
|
29
|
-
env: {},
|
|
30
|
-
state: {},
|
|
31
|
-
messages: [],
|
|
32
|
-
} as unknown as ToolContext;
|
|
24
|
+
/** Each call is its own session, so two contexts are two independent stores —
|
|
25
|
+
* which is what the isolation tests below rest on. */
|
|
26
|
+
function makeCtx(): ToolContext<StateSlot> {
|
|
27
|
+
return createToolContext<StateSlot>();
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
/** A context already authenticated as `userId`, via the real tool. */
|
|
36
|
-
async function authedCtx(email: string): Promise<ToolContext
|
|
31
|
+
async function authedCtx(email: string): Promise<ToolContext<StateSlot>> {
|
|
37
32
|
const ctx = makeCtx();
|
|
38
33
|
// `ToolDef["execute"]`'s public signature always returns `unknown` (the
|
|
39
34
|
// wire type is fixed so any tool is assignable to `ToolDef`, regardless of
|
|
40
35
|
// what its own `execute` body actually returns), so a cast is needed
|
|
41
36
|
// anywhere a test reads a success field back off the result — matching the
|
|
42
37
|
// `as {...}` convention other templates already use for the same reason.
|
|
43
|
-
const result = (await findUserIdByEmail.execute({ email }, ctx)) as AuthResult |
|
|
44
|
-
if (
|
|
38
|
+
const result = (await findUserIdByEmail.execute({ email }, ctx)) as AuthResult | ToolFailure;
|
|
39
|
+
if (isToolFailure(result)) throw new Error(`fixture failed to authenticate: ${result.error}`);
|
|
45
40
|
return ctx;
|
|
46
41
|
}
|
|
47
42
|
|
|
@@ -51,16 +46,16 @@ describe("authentication", () => {
|
|
|
51
46
|
const result = (await findUserIdByEmail.execute(
|
|
52
47
|
{ email: "OLIVIA.ITO5204@EXAMPLE.COM" },
|
|
53
48
|
ctx,
|
|
54
|
-
)) as AuthResult |
|
|
55
|
-
expect(
|
|
56
|
-
expect(
|
|
49
|
+
)) as AuthResult | ToolFailure;
|
|
50
|
+
expect(isToolFailure(result) ? null : result.user_id).toBe("olivia_ito_3591");
|
|
51
|
+
expect(retailSlot.get(ctx).authenticatedUserId).toBe("olivia_ito_3591");
|
|
57
52
|
});
|
|
58
53
|
|
|
59
54
|
test("an unknown email is refused and leaves the session unauthenticated", async () => {
|
|
60
55
|
const ctx = makeCtx();
|
|
61
56
|
const result = await findUserIdByEmail.execute({ email: "nobody@example.com" }, ctx);
|
|
62
|
-
expect(
|
|
63
|
-
expect(
|
|
57
|
+
expect(isToolFailure(result)).toBe(true);
|
|
58
|
+
expect(retailSlot.get(ctx).authenticatedUserId).toBeNull();
|
|
64
59
|
});
|
|
65
60
|
|
|
66
61
|
test("find_user_id_by_name_zip is case-insensitive on names and exact on zip", async () => {
|
|
@@ -68,34 +63,34 @@ describe("authentication", () => {
|
|
|
68
63
|
const ok = (await findUserIdByNameZip.execute(
|
|
69
64
|
{ first_name: "aarav", last_name: "ANDERSON", zip: "19031" },
|
|
70
65
|
ctx,
|
|
71
|
-
)) as AuthResult |
|
|
72
|
-
expect(
|
|
66
|
+
)) as AuthResult | ToolFailure;
|
|
67
|
+
expect(isToolFailure(ok) ? null : ok.user_id).toBe("aarav_anderson_8794");
|
|
73
68
|
|
|
74
69
|
const wrongZip = await findUserIdByNameZip.execute(
|
|
75
70
|
{ first_name: "Aarav", last_name: "Anderson", zip: "78268" },
|
|
76
71
|
makeCtx(),
|
|
77
72
|
);
|
|
78
|
-
expect(
|
|
73
|
+
expect(isToolFailure(wrongZip)).toBe(true);
|
|
79
74
|
});
|
|
80
75
|
|
|
81
76
|
test("two customers share a first name — the zip is what separates them", async () => {
|
|
82
77
|
const a = (await findUserIdByNameZip.execute(
|
|
83
78
|
{ first_name: "Aarav", last_name: "Anderson", zip: "19031" },
|
|
84
79
|
makeCtx(),
|
|
85
|
-
)) as AuthResult |
|
|
80
|
+
)) as AuthResult | ToolFailure;
|
|
86
81
|
const b = (await findUserIdByNameZip.execute(
|
|
87
82
|
{ first_name: "Aarav", last_name: "Gonzalez", zip: "78268" },
|
|
88
83
|
makeCtx(),
|
|
89
|
-
)) as AuthResult |
|
|
90
|
-
expect(
|
|
91
|
-
expect(
|
|
84
|
+
)) as AuthResult | ToolFailure;
|
|
85
|
+
expect(isToolFailure(a) ? null : a.user_id).toBe("aarav_anderson_8794");
|
|
86
|
+
expect(isToolFailure(b) ? null : b.user_id).toBe("aarav_gonzalez_5113");
|
|
92
87
|
});
|
|
93
88
|
|
|
94
89
|
test("re-authenticating as the same customer is a no-op success", async () => {
|
|
95
90
|
const ctx = await authedCtx("olivia.ito5204@example.com");
|
|
96
91
|
const again = await findUserIdByEmail.execute({ email: "olivia.ito5204@example.com" }, ctx);
|
|
97
|
-
expect(
|
|
98
|
-
expect(
|
|
92
|
+
expect(isToolFailure(again)).toBe(false);
|
|
93
|
+
expect(retailSlot.get(ctx).authenticatedUserId).toBe("olivia_ito_3591");
|
|
99
94
|
});
|
|
100
95
|
|
|
101
96
|
test("switching to a DIFFERENT customer mid-conversation is refused", async () => {
|
|
@@ -104,8 +99,8 @@ describe("authentication", () => {
|
|
|
104
99
|
{ email: "aarav.anderson9752@example.com" },
|
|
105
100
|
ctx,
|
|
106
101
|
);
|
|
107
|
-
expect(
|
|
108
|
-
expect(
|
|
102
|
+
expect(isToolFailure(switched) && switched.error.toLowerCase()).toContain("one customer");
|
|
103
|
+
expect(retailSlot.get(ctx).authenticatedUserId).toBe("olivia_ito_3591");
|
|
109
104
|
});
|
|
110
105
|
|
|
111
106
|
test("switching via name + zip is refused too — both doors, one lock", async () => {
|
|
@@ -114,8 +109,8 @@ describe("authentication", () => {
|
|
|
114
109
|
{ first_name: "Aarav", last_name: "Anderson", zip: "19031" },
|
|
115
110
|
ctx,
|
|
116
111
|
);
|
|
117
|
-
expect(
|
|
118
|
-
expect(
|
|
112
|
+
expect(isToolFailure(switched)).toBe(true);
|
|
113
|
+
expect(retailSlot.get(ctx).authenticatedUserId).toBe("olivia_ito_3591");
|
|
119
114
|
});
|
|
120
115
|
});
|
|
121
116
|
|
|
@@ -149,8 +144,8 @@ describe("read tools", () => {
|
|
|
149
144
|
const ctx = await authedCtx("olivia.ito5204@example.com");
|
|
150
145
|
const result = (await getUserDetails.execute({ user_id: "olivia_ito_3591" }, ctx)) as
|
|
151
146
|
| UserDetailsResult
|
|
152
|
-
|
|
|
153
|
-
if (
|
|
147
|
+
| ToolFailure;
|
|
148
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
154
149
|
expect(result.email).toBe("olivia.ito5204@example.com");
|
|
155
150
|
expect(result.orders).toHaveLength(5);
|
|
156
151
|
const card = result.payment_methods.find((m) => m.payment_method_id === "gift_card_7794233");
|
|
@@ -160,30 +155,30 @@ describe("read tools", () => {
|
|
|
160
155
|
test("get_user_details refuses a different user id", async () => {
|
|
161
156
|
const ctx = await authedCtx("olivia.ito5204@example.com");
|
|
162
157
|
const result = await getUserDetails.execute({ user_id: "aarav_anderson_8794" }, ctx);
|
|
163
|
-
expect(
|
|
158
|
+
expect(isToolFailure(result)).toBe(true);
|
|
164
159
|
});
|
|
165
160
|
|
|
166
161
|
test("get_order_details resolves shorthand and sets focus", async () => {
|
|
167
162
|
const ctx = await authedCtx("olivia.ito5204@example.com");
|
|
168
163
|
const result = (await getOrderDetails.execute({ order_id: "the delivered one" }, ctx)) as
|
|
169
164
|
| OrderDetailsResult
|
|
170
|
-
|
|
|
171
|
-
if (
|
|
165
|
+
| ToolFailure;
|
|
166
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
172
167
|
expect(result.order_id).toBe("#W5866402");
|
|
173
|
-
expect(
|
|
168
|
+
expect(retailSlot.get(ctx).focus.orderId).toBe("#W5866402");
|
|
174
169
|
});
|
|
175
170
|
|
|
176
171
|
test("get_order_details refuses another customer's order", async () => {
|
|
177
172
|
const ctx = await authedCtx("olivia.ito5204@example.com");
|
|
178
173
|
const result = await getOrderDetails.execute({ order_id: "#W4316152" }, ctx);
|
|
179
|
-
expect(
|
|
174
|
+
expect(isToolFailure(result)).toBe(true);
|
|
180
175
|
});
|
|
181
176
|
|
|
182
177
|
test("get_product_details lists variants and needs no authentication", async () => {
|
|
183
178
|
const result = (await getProductDetails.execute({ product_id: "9832717871" }, makeCtx())) as
|
|
184
179
|
| ProductDetailsResult
|
|
185
|
-
|
|
|
186
|
-
if (
|
|
180
|
+
| ToolFailure;
|
|
181
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
187
182
|
expect(result.name).toBe("Tea Kettle");
|
|
188
183
|
expect(result.variants.length).toBeGreaterThan(1);
|
|
189
184
|
expect(result.variants[0]).toHaveProperty("item_id");
|
|
@@ -191,14 +186,14 @@ describe("read tools", () => {
|
|
|
191
186
|
|
|
192
187
|
test("get_product_details rejects an item id passed as a product id, and says so", async () => {
|
|
193
188
|
const result = await getProductDetails.execute({ product_id: "3909406921" }, makeCtx());
|
|
194
|
-
expect(
|
|
189
|
+
expect(isToolFailure(result) && result.error).toContain("item id");
|
|
195
190
|
});
|
|
196
191
|
|
|
197
192
|
test("get_item_details resolves an item without knowing its product", async () => {
|
|
198
193
|
const result = (await getItemDetails.execute({ item_id: "3909406921" }, makeCtx())) as
|
|
199
194
|
| ItemDetailsResult
|
|
200
|
-
|
|
|
201
|
-
if (
|
|
195
|
+
| ToolFailure;
|
|
196
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
202
197
|
expect(result.price).toBe(98.25);
|
|
203
198
|
expect(result.product_name).toBe("Tea Kettle");
|
|
204
199
|
});
|
|
@@ -206,8 +201,8 @@ describe("read tools", () => {
|
|
|
206
201
|
test("list_all_product_types returns all 50, sorted by name", async () => {
|
|
207
202
|
const result = (await listAllProductTypes.execute({}, makeCtx())) as
|
|
208
203
|
| ProductTypesResult
|
|
209
|
-
|
|
|
210
|
-
if (
|
|
204
|
+
| ToolFailure;
|
|
205
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
211
206
|
expect(Object.keys(result.products)).toHaveLength(50);
|
|
212
207
|
const names = Object.keys(result.products);
|
|
213
208
|
// localeCompare, not the default lexicographic sort — the tool sorts for a
|
|
@@ -232,12 +227,12 @@ describe("cancel_pending_order", () => {
|
|
|
232
227
|
const result = (await cancelPendingOrder.execute(
|
|
233
228
|
{ order_id: "#W9300146", reason: "ordered by mistake" },
|
|
234
229
|
ctx,
|
|
235
|
-
)) as CancelOrderResult |
|
|
236
|
-
if (
|
|
230
|
+
)) as CancelOrderResult | ToolFailure;
|
|
231
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
237
232
|
expect(result.status).toBe("cancelled");
|
|
238
233
|
expect(result.refund_immediate).toBe(true);
|
|
239
234
|
|
|
240
|
-
const state =
|
|
235
|
+
const state = retailSlot.get(ctx);
|
|
241
236
|
expect(state.store.orders["#W9300146"]?.status).toBe("cancelled");
|
|
242
237
|
expect(state.store.orders["#W9300146"]?.cancel_reason).toBe("ordered by mistake");
|
|
243
238
|
// $17.00 card + the $153.23 order total.
|
|
@@ -248,7 +243,7 @@ describe("cancel_pending_order", () => {
|
|
|
248
243
|
test("appends a matching refund to the payment history", async () => {
|
|
249
244
|
const ctx = await authedCtx("aarav.anderson9752@example.com");
|
|
250
245
|
await cancelPendingOrder.execute({ order_id: "#W9300146", reason: "no longer needed" }, ctx);
|
|
251
|
-
const history =
|
|
246
|
+
const history = retailSlot.get(ctx).store.orders["#W9300146"]?.payment_history ?? [];
|
|
252
247
|
expect(history).toHaveLength(2);
|
|
253
248
|
expect(history[1]).toMatchObject({
|
|
254
249
|
transaction_type: "refund",
|
|
@@ -262,11 +257,11 @@ describe("cancel_pending_order", () => {
|
|
|
262
257
|
const result = (await cancelPendingOrder.execute(
|
|
263
258
|
{ order_id: "#W5442520", reason: "no longer needed" },
|
|
264
259
|
ctx,
|
|
265
|
-
)) as CancelOrderResult |
|
|
266
|
-
if (
|
|
260
|
+
)) as CancelOrderResult | ToolFailure;
|
|
261
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
267
262
|
expect(result.refund_immediate).toBe(false);
|
|
268
263
|
expect(result.message).toContain("5 to 7");
|
|
269
|
-
const card =
|
|
264
|
+
const card = retailSlot.get(ctx).store.users.olivia_ito_3591?.payment_methods.gift_card_7794233;
|
|
270
265
|
expect(card?.source === "gift_card" && card.balance).toBe(56);
|
|
271
266
|
});
|
|
272
267
|
|
|
@@ -276,8 +271,8 @@ describe("cancel_pending_order", () => {
|
|
|
276
271
|
{ order_id: "#W5353646", reason: "no longer needed" },
|
|
277
272
|
ctx,
|
|
278
273
|
);
|
|
279
|
-
expect(
|
|
280
|
-
expect(
|
|
274
|
+
expect(isToolFailure(result) && result.error).toContain("processed");
|
|
275
|
+
expect(retailSlot.get(ctx).store.orders["#W5353646"]?.status).toBe("processed");
|
|
281
276
|
});
|
|
282
277
|
|
|
283
278
|
test("refuses a delivered order", async () => {
|
|
@@ -286,7 +281,7 @@ describe("cancel_pending_order", () => {
|
|
|
286
281
|
{ order_id: "#W5866402", reason: "no longer needed" },
|
|
287
282
|
ctx,
|
|
288
283
|
);
|
|
289
|
-
expect(
|
|
284
|
+
expect(isToolFailure(result)).toBe(true);
|
|
290
285
|
});
|
|
291
286
|
|
|
292
287
|
test("refuses a reason outside tau2's two accepted values", async () => {
|
|
@@ -298,8 +293,8 @@ describe("cancel_pending_order", () => {
|
|
|
298
293
|
{ order_id: "#W9300146", reason: "changed my mind" as unknown as "no longer needed" },
|
|
299
294
|
ctx,
|
|
300
295
|
);
|
|
301
|
-
expect(
|
|
302
|
-
expect(
|
|
296
|
+
expect(isToolFailure(result) && result.error).toContain("no longer needed");
|
|
297
|
+
expect(retailSlot.get(ctx).store.orders["#W9300146"]?.status).toBe("pending");
|
|
303
298
|
});
|
|
304
299
|
|
|
305
300
|
test("refuses cancelling twice", async () => {
|
|
@@ -309,8 +304,9 @@ describe("cancel_pending_order", () => {
|
|
|
309
304
|
{ order_id: "#W9300146", reason: "no longer needed" },
|
|
310
305
|
ctx,
|
|
311
306
|
);
|
|
312
|
-
expect(
|
|
313
|
-
const card =
|
|
307
|
+
expect(isToolFailure(second)).toBe(true);
|
|
308
|
+
const card =
|
|
309
|
+
retailSlot.get(ctx).store.users.aarav_anderson_8794?.payment_methods.gift_card_7245904;
|
|
314
310
|
expect(card?.source === "gift_card" && card.balance).toBe(170.23);
|
|
315
311
|
});
|
|
316
312
|
|
|
@@ -319,8 +315,8 @@ describe("cancel_pending_order", () => {
|
|
|
319
315
|
const result = (await cancelPendingOrder.execute(
|
|
320
316
|
{ order_id: "my pending order", reason: "ordered by mistake" },
|
|
321
317
|
ctx,
|
|
322
|
-
)) as CancelOrderResult |
|
|
323
|
-
expect(
|
|
318
|
+
)) as CancelOrderResult | ToolFailure;
|
|
319
|
+
expect(isToolFailure(result) ? null : result.order_id).toBe("#W9300146");
|
|
324
320
|
});
|
|
325
321
|
|
|
326
322
|
test("refuses ambiguous shorthand rather than cancelling the wrong order", async () => {
|
|
@@ -329,9 +325,9 @@ describe("cancel_pending_order", () => {
|
|
|
329
325
|
{ order_id: "my pending order", reason: "no longer needed" },
|
|
330
326
|
ctx,
|
|
331
327
|
);
|
|
332
|
-
expect(
|
|
328
|
+
expect(isToolFailure(result)).toBe(true);
|
|
333
329
|
const statuses = ["#W5442520", "#W7941031", "#W3657213"].map(
|
|
334
|
-
(id) =>
|
|
330
|
+
(id) => retailSlot.get(ctx).store.orders[id]?.status,
|
|
335
331
|
);
|
|
336
332
|
expect(statuses).toEqual(["pending", "pending", "pending"]);
|
|
337
333
|
});
|
|
@@ -357,28 +353,28 @@ describe("modify_pending_order_address", () => {
|
|
|
357
353
|
const result = (await modifyPendingOrderAddress.execute(
|
|
358
354
|
{ order_id: "#W9300146", ...NEW_ADDRESS },
|
|
359
355
|
ctx,
|
|
360
|
-
)) as AddressToolResult |
|
|
361
|
-
if (
|
|
356
|
+
)) as AddressToolResult | ToolFailure;
|
|
357
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
362
358
|
expect(result.address).toEqual(NEW_ADDRESS);
|
|
363
|
-
expect(
|
|
359
|
+
expect(retailSlot.get(ctx).store.orders["#W9300146"]?.address).toEqual(NEW_ADDRESS);
|
|
364
360
|
});
|
|
365
361
|
|
|
366
362
|
test("leaves the customer's default address untouched", async () => {
|
|
367
363
|
const ctx = await authedCtx("aarav.anderson9752@example.com");
|
|
368
364
|
await modifyPendingOrderAddress.execute({ order_id: "#W9300146", ...NEW_ADDRESS }, ctx);
|
|
369
|
-
expect(
|
|
365
|
+
expect(retailSlot.get(ctx).store.users.aarav_anderson_8794?.address.zip).toBe("19031");
|
|
370
366
|
});
|
|
371
367
|
|
|
372
368
|
test("accepts a 'pending (item modified)' order — unlike cancel", async () => {
|
|
373
369
|
const ctx = await authedCtx("aarav.anderson9752@example.com");
|
|
374
|
-
const order =
|
|
370
|
+
const order = retailSlot.get(ctx).store.orders["#W9300146"];
|
|
375
371
|
if (!order) throw new Error("fixture missing");
|
|
376
372
|
order.status = "pending (item modified)";
|
|
377
373
|
const result = await modifyPendingOrderAddress.execute(
|
|
378
374
|
{ order_id: "#W9300146", ...NEW_ADDRESS },
|
|
379
375
|
ctx,
|
|
380
376
|
);
|
|
381
|
-
expect(
|
|
377
|
+
expect(isToolFailure(result)).toBe(false);
|
|
382
378
|
});
|
|
383
379
|
|
|
384
380
|
test("refuses a delivered order", async () => {
|
|
@@ -387,7 +383,7 @@ describe("modify_pending_order_address", () => {
|
|
|
387
383
|
{ order_id: "#W5866402", ...NEW_ADDRESS },
|
|
388
384
|
ctx,
|
|
389
385
|
);
|
|
390
|
-
expect(
|
|
386
|
+
expect(isToolFailure(result)).toBe(true);
|
|
391
387
|
});
|
|
392
388
|
|
|
393
389
|
test("refuses another customer's order", async () => {
|
|
@@ -396,7 +392,7 @@ describe("modify_pending_order_address", () => {
|
|
|
396
392
|
{ order_id: "#W9300146", ...NEW_ADDRESS },
|
|
397
393
|
ctx,
|
|
398
394
|
);
|
|
399
|
-
expect(
|
|
395
|
+
expect(isToolFailure(result)).toBe(true);
|
|
400
396
|
});
|
|
401
397
|
});
|
|
402
398
|
|
|
@@ -407,15 +403,15 @@ describe("modify_user_address", () => {
|
|
|
407
403
|
{ user_id: "emma_smith_8564", ...NEW_ADDRESS },
|
|
408
404
|
ctx,
|
|
409
405
|
);
|
|
410
|
-
if (
|
|
411
|
-
expect(
|
|
406
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
407
|
+
expect(retailSlot.get(ctx).store.users.emma_smith_8564?.address).toEqual(NEW_ADDRESS);
|
|
412
408
|
});
|
|
413
409
|
|
|
414
410
|
test("leaves existing orders' addresses untouched", async () => {
|
|
415
411
|
const ctx = await authedCtx("emma.smith3991@example.com");
|
|
416
|
-
const before = structuredClone(
|
|
412
|
+
const before = structuredClone(retailSlot.get(ctx).store.orders["#W2417020"]?.address);
|
|
417
413
|
await modifyUserAddress.execute({ user_id: "emma_smith_8564", ...NEW_ADDRESS }, ctx);
|
|
418
|
-
expect(
|
|
414
|
+
expect(retailSlot.get(ctx).store.orders["#W2417020"]?.address).toEqual(before);
|
|
419
415
|
});
|
|
420
416
|
|
|
421
417
|
test("refuses a different user id", async () => {
|
|
@@ -424,8 +420,8 @@ describe("modify_user_address", () => {
|
|
|
424
420
|
{ user_id: "olivia_ito_3591", ...NEW_ADDRESS },
|
|
425
421
|
ctx,
|
|
426
422
|
);
|
|
427
|
-
expect(
|
|
428
|
-
expect(
|
|
423
|
+
expect(isToolFailure(result)).toBe(true);
|
|
424
|
+
expect(retailSlot.get(ctx).store.users.olivia_ito_3591?.address.zip).toBe("80218");
|
|
429
425
|
});
|
|
430
426
|
|
|
431
427
|
test("requires authentication", async () => {
|
|
@@ -433,7 +429,7 @@ describe("modify_user_address", () => {
|
|
|
433
429
|
{ user_id: "emma_smith_8564", ...NEW_ADDRESS },
|
|
434
430
|
makeCtx(),
|
|
435
431
|
);
|
|
436
|
-
expect(
|
|
432
|
+
expect(isToolFailure(result) && result.error).toContain("find_user_id_by_email");
|
|
437
433
|
});
|
|
438
434
|
});
|
|
439
435
|
|
|
@@ -456,12 +452,12 @@ describe("modify_pending_order_items", () => {
|
|
|
456
452
|
payment_method_id: "gift_card_8541487",
|
|
457
453
|
},
|
|
458
454
|
ctx,
|
|
459
|
-
)) as ModifyItemsResult |
|
|
460
|
-
if (
|
|
455
|
+
)) as ModifyItemsResult | ToolFailure;
|
|
456
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
461
457
|
expect(result.price_difference).toBe(-382.03);
|
|
462
458
|
expect(result.status).toBe("pending (item modified)");
|
|
463
459
|
|
|
464
|
-
const state =
|
|
460
|
+
const state = retailSlot.get(ctx);
|
|
465
461
|
const order = state.store.orders["#W2417020"];
|
|
466
462
|
expect(order?.items[0]?.item_id).toBe("6017636844");
|
|
467
463
|
expect(order?.items[0]?.price).toBe(2292.37);
|
|
@@ -481,7 +477,7 @@ describe("modify_pending_order_items", () => {
|
|
|
481
477
|
},
|
|
482
478
|
ctx,
|
|
483
479
|
);
|
|
484
|
-
const history =
|
|
480
|
+
const history = retailSlot.get(ctx).store.orders["#W2417020"]?.payment_history ?? [];
|
|
485
481
|
expect(history[1]).toMatchObject({
|
|
486
482
|
transaction_type: "refund",
|
|
487
483
|
amount: 382.03,
|
|
@@ -509,7 +505,7 @@ describe("modify_pending_order_items", () => {
|
|
|
509
505
|
},
|
|
510
506
|
ctx,
|
|
511
507
|
);
|
|
512
|
-
expect(
|
|
508
|
+
expect(isToolFailure(second) && second.error).toContain("pending (item modified)");
|
|
513
509
|
});
|
|
514
510
|
|
|
515
511
|
test("a modified order can no longer be cancelled", async () => {
|
|
@@ -527,7 +523,7 @@ describe("modify_pending_order_items", () => {
|
|
|
527
523
|
{ order_id: "#W2417020", reason: "no longer needed" },
|
|
528
524
|
ctx,
|
|
529
525
|
);
|
|
530
|
-
expect(
|
|
526
|
+
expect(isToolFailure(cancelled)).toBe(true);
|
|
531
527
|
});
|
|
532
528
|
|
|
533
529
|
test("refuses when the gift card cannot cover the difference, changing nothing", async () => {
|
|
@@ -545,9 +541,9 @@ describe("modify_pending_order_items", () => {
|
|
|
545
541
|
},
|
|
546
542
|
ctx,
|
|
547
543
|
);
|
|
548
|
-
expect(
|
|
544
|
+
expect(isToolFailure(result) && result.error.toLowerCase()).toContain("balance");
|
|
549
545
|
|
|
550
|
-
const state =
|
|
546
|
+
const state = retailSlot.get(ctx);
|
|
551
547
|
const order = state.store.orders["#W6436609"];
|
|
552
548
|
expect(order?.status).toBe("pending");
|
|
553
549
|
expect(order?.items.map((i) => i.item_id)).toContain("6017636844");
|
|
@@ -566,10 +562,10 @@ describe("modify_pending_order_items", () => {
|
|
|
566
562
|
payment_method_id: "credit_card_8955149",
|
|
567
563
|
},
|
|
568
564
|
ctx,
|
|
569
|
-
)) as ModifyItemsResult |
|
|
570
|
-
if (
|
|
565
|
+
)) as ModifyItemsResult | ToolFailure;
|
|
566
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
571
567
|
expect(result.price_difference).toBe(167.37);
|
|
572
|
-
const history =
|
|
568
|
+
const history = retailSlot.get(ctx).store.orders["#W6436609"]?.payment_history ?? [];
|
|
573
569
|
expect(history[1]).toMatchObject({
|
|
574
570
|
transaction_type: "payment",
|
|
575
571
|
amount: 167.37,
|
|
@@ -588,7 +584,7 @@ describe("modify_pending_order_items", () => {
|
|
|
588
584
|
},
|
|
589
585
|
ctx,
|
|
590
586
|
);
|
|
591
|
-
expect(
|
|
587
|
+
expect(isToolFailure(result)).toBe(true);
|
|
592
588
|
});
|
|
593
589
|
|
|
594
590
|
test("refuses a payment method belonging to another customer", async () => {
|
|
@@ -602,8 +598,8 @@ describe("modify_pending_order_items", () => {
|
|
|
602
598
|
},
|
|
603
599
|
ctx,
|
|
604
600
|
);
|
|
605
|
-
expect(
|
|
606
|
-
expect(
|
|
601
|
+
expect(isToolFailure(result)).toBe(true);
|
|
602
|
+
expect(retailSlot.get(ctx).store.orders["#W2417020"]?.status).toBe("pending");
|
|
607
603
|
});
|
|
608
604
|
});
|
|
609
605
|
|
|
@@ -623,11 +619,11 @@ describe("modify_pending_order_payment", () => {
|
|
|
623
619
|
const result = (await modifyPendingOrderPayment.execute(
|
|
624
620
|
{ order_id: "#W5442520", payment_method_id: "paypal_8049766" },
|
|
625
621
|
ctx,
|
|
626
|
-
)) as ModifyPaymentResult |
|
|
627
|
-
if (
|
|
622
|
+
)) as ModifyPaymentResult | ToolFailure;
|
|
623
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
628
624
|
expect(result.status).toBe("pending");
|
|
629
625
|
|
|
630
|
-
const history =
|
|
626
|
+
const history = retailSlot.get(ctx).store.orders["#W5442520"]?.payment_history ?? [];
|
|
631
627
|
expect(history).toHaveLength(3);
|
|
632
628
|
expect(history[1]).toMatchObject({
|
|
633
629
|
transaction_type: "payment",
|
|
@@ -648,8 +644,9 @@ describe("modify_pending_order_payment", () => {
|
|
|
648
644
|
{ order_id: "#W9160732", payment_method_id: "paypal_6121064" },
|
|
649
645
|
ctx,
|
|
650
646
|
);
|
|
651
|
-
expect(
|
|
652
|
-
const card =
|
|
647
|
+
expect(isToolFailure(result)).toBe(false);
|
|
648
|
+
const card =
|
|
649
|
+
retailSlot.get(ctx).store.users.aarav_gonzalez_5113?.payment_methods.gift_card_5979071;
|
|
653
650
|
expect(card?.source === "gift_card" && card.balance).toBe(1107.54);
|
|
654
651
|
});
|
|
655
652
|
|
|
@@ -660,10 +657,11 @@ describe("modify_pending_order_payment", () => {
|
|
|
660
657
|
{ order_id: "#W6979932", payment_method_id: "gift_card_5979071" },
|
|
661
658
|
ctx,
|
|
662
659
|
);
|
|
663
|
-
expect(
|
|
664
|
-
const card =
|
|
660
|
+
expect(isToolFailure(result) && result.error.toLowerCase()).toContain("balance");
|
|
661
|
+
const card =
|
|
662
|
+
retailSlot.get(ctx).store.users.aarav_gonzalez_5113?.payment_methods.gift_card_5979071;
|
|
665
663
|
expect(card?.source === "gift_card" && card.balance).toBe(96);
|
|
666
|
-
expect(
|
|
664
|
+
expect(retailSlot.get(ctx).store.orders["#W6979932"]?.payment_history).toHaveLength(1);
|
|
667
665
|
});
|
|
668
666
|
|
|
669
667
|
test("refuses the method the order already uses", async () => {
|
|
@@ -672,12 +670,12 @@ describe("modify_pending_order_payment", () => {
|
|
|
672
670
|
{ order_id: "#W5442520", payment_method_id: "credit_card_9753331" },
|
|
673
671
|
ctx,
|
|
674
672
|
);
|
|
675
|
-
expect(
|
|
673
|
+
expect(isToolFailure(result) && result.error.toLowerCase()).toContain("different");
|
|
676
674
|
});
|
|
677
675
|
|
|
678
676
|
test("refuses an order whose payment history is not a single payment", async () => {
|
|
679
677
|
const ctx = await authedCtx("olivia.ito5204@example.com");
|
|
680
|
-
const order =
|
|
678
|
+
const order = retailSlot.get(ctx).store.orders["#W5442520"];
|
|
681
679
|
if (!order) throw new Error("fixture missing");
|
|
682
680
|
// No seeded pending order has a second history entry, so construct one —
|
|
683
681
|
// tau2 guards this case and the guard should still be covered.
|
|
@@ -690,7 +688,7 @@ describe("modify_pending_order_payment", () => {
|
|
|
690
688
|
{ order_id: "#W5442520", payment_method_id: "paypal_8049766" },
|
|
691
689
|
ctx,
|
|
692
690
|
);
|
|
693
|
-
expect(
|
|
691
|
+
expect(isToolFailure(result) && result.error.toLowerCase()).toContain("exactly one payment");
|
|
694
692
|
});
|
|
695
693
|
|
|
696
694
|
test("refuses a delivered order", async () => {
|
|
@@ -699,7 +697,7 @@ describe("modify_pending_order_payment", () => {
|
|
|
699
697
|
{ order_id: "#W5866402", payment_method_id: "gift_card_7794233" },
|
|
700
698
|
ctx,
|
|
701
699
|
);
|
|
702
|
-
expect(
|
|
700
|
+
expect(isToolFailure(result)).toBe(true);
|
|
703
701
|
});
|
|
704
702
|
|
|
705
703
|
test("refuses a method not on the customer's profile", async () => {
|
|
@@ -708,7 +706,7 @@ describe("modify_pending_order_payment", () => {
|
|
|
708
706
|
{ order_id: "#W5442520", payment_method_id: "gift_card_7245904" },
|
|
709
707
|
ctx,
|
|
710
708
|
);
|
|
711
|
-
expect(
|
|
709
|
+
expect(isToolFailure(result)).toBe(true);
|
|
712
710
|
});
|
|
713
711
|
});
|
|
714
712
|
|
|
@@ -739,10 +737,10 @@ describe("return_delivered_order_items", () => {
|
|
|
739
737
|
payment_method_id: "paypal_2306935",
|
|
740
738
|
},
|
|
741
739
|
ctx,
|
|
742
|
-
)) as ReturnResult |
|
|
743
|
-
if (
|
|
740
|
+
)) as ReturnResult | ToolFailure;
|
|
741
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
744
742
|
expect(result.status).toBe("return requested");
|
|
745
|
-
const order =
|
|
743
|
+
const order = retailSlot.get(ctx).store.orders["#W1840144"];
|
|
746
744
|
expect(order?.return_items).toEqual(["8590708195"]);
|
|
747
745
|
expect(order?.return_payment_method_id).toBe("paypal_2306935");
|
|
748
746
|
});
|
|
@@ -758,7 +756,7 @@ describe("return_delivered_order_items", () => {
|
|
|
758
756
|
},
|
|
759
757
|
ctx,
|
|
760
758
|
);
|
|
761
|
-
expect(
|
|
759
|
+
expect(isToolFailure(result)).toBe(false);
|
|
762
760
|
});
|
|
763
761
|
|
|
764
762
|
test("refuses a non-original, non-gift-card method", async () => {
|
|
@@ -772,8 +770,8 @@ describe("return_delivered_order_items", () => {
|
|
|
772
770
|
},
|
|
773
771
|
ctx,
|
|
774
772
|
);
|
|
775
|
-
expect(
|
|
776
|
-
expect(
|
|
773
|
+
expect(isToolFailure(result) && result.error.toLowerCase()).toContain("original");
|
|
774
|
+
expect(retailSlot.get(ctx).store.orders["#W1840144"]?.status).toBe("delivered");
|
|
777
775
|
});
|
|
778
776
|
|
|
779
777
|
test("returns both copies of a duplicate item and sorts the recorded list", async () => {
|
|
@@ -786,8 +784,8 @@ describe("return_delivered_order_items", () => {
|
|
|
786
784
|
},
|
|
787
785
|
ctx,
|
|
788
786
|
);
|
|
789
|
-
expect(
|
|
790
|
-
expect(
|
|
787
|
+
expect(isToolFailure(result)).toBe(false);
|
|
788
|
+
expect(retailSlot.get(ctx).store.orders["#W1840144"]?.return_items).toEqual([
|
|
791
789
|
"6534134392",
|
|
792
790
|
"8590708195",
|
|
793
791
|
"8590708195",
|
|
@@ -804,7 +802,7 @@ describe("return_delivered_order_items", () => {
|
|
|
804
802
|
},
|
|
805
803
|
ctx,
|
|
806
804
|
);
|
|
807
|
-
expect(
|
|
805
|
+
expect(isToolFailure(result)).toBe(true);
|
|
808
806
|
});
|
|
809
807
|
|
|
810
808
|
test("refuses a pending order and refuses a second return", async () => {
|
|
@@ -817,7 +815,7 @@ describe("return_delivered_order_items", () => {
|
|
|
817
815
|
},
|
|
818
816
|
ctx,
|
|
819
817
|
);
|
|
820
|
-
expect(
|
|
818
|
+
expect(isToolFailure(pending)).toBe(true);
|
|
821
819
|
|
|
822
820
|
await returnDeliveredOrderItems.execute(
|
|
823
821
|
{ order_id: "#W1840144", item_ids: ["8590708195"], payment_method_id: "paypal_2306935" },
|
|
@@ -827,7 +825,7 @@ describe("return_delivered_order_items", () => {
|
|
|
827
825
|
{ order_id: "#W1840144", item_ids: ["6534134392"], payment_method_id: "paypal_2306935" },
|
|
828
826
|
ctx,
|
|
829
827
|
);
|
|
830
|
-
expect(
|
|
828
|
+
expect(isToolFailure(again) && again.error).toContain("return requested");
|
|
831
829
|
});
|
|
832
830
|
});
|
|
833
831
|
|
|
@@ -842,10 +840,10 @@ describe("exchange_delivered_order_items", () => {
|
|
|
842
840
|
payment_method_id: "gift_card_7245904",
|
|
843
841
|
},
|
|
844
842
|
ctx,
|
|
845
|
-
)) as ExchangeResult |
|
|
846
|
-
if (
|
|
843
|
+
)) as ExchangeResult | ToolFailure;
|
|
844
|
+
if (isToolFailure(result)) throw new Error(result.error);
|
|
847
845
|
expect(result.price_difference).toBe(3.45);
|
|
848
|
-
const order =
|
|
846
|
+
const order = retailSlot.get(ctx).store.orders["#W4316152"];
|
|
849
847
|
expect(order?.status).toBe("exchange requested");
|
|
850
848
|
expect(order?.exchange_items).toEqual(["7292993796"]);
|
|
851
849
|
expect(order?.exchange_new_items).toEqual(["3909406921"]);
|
|
@@ -863,7 +861,8 @@ describe("exchange_delivered_order_items", () => {
|
|
|
863
861
|
},
|
|
864
862
|
ctx,
|
|
865
863
|
);
|
|
866
|
-
const card =
|
|
864
|
+
const card =
|
|
865
|
+
retailSlot.get(ctx).store.users.aarav_anderson_8794?.payment_methods.gift_card_7245904;
|
|
867
866
|
expect(card?.source === "gift_card" && card.balance).toBe(17);
|
|
868
867
|
});
|
|
869
868
|
|
|
@@ -878,7 +877,7 @@ describe("exchange_delivered_order_items", () => {
|
|
|
878
877
|
},
|
|
879
878
|
ctx,
|
|
880
879
|
);
|
|
881
|
-
expect(
|
|
880
|
+
expect(retailSlot.get(ctx).store.orders["#W4316152"]?.items.map((i) => i.item_id)).toEqual([
|
|
882
881
|
"7292993796",
|
|
883
882
|
"7292993796",
|
|
884
883
|
]);
|
|
@@ -894,8 +893,8 @@ describe("exchange_delivered_order_items", () => {
|
|
|
894
893
|
payment_method_id: "gift_card_7245904",
|
|
895
894
|
},
|
|
896
895
|
ctx,
|
|
897
|
-
)) as ExchangeResult |
|
|
898
|
-
expect(
|
|
896
|
+
)) as ExchangeResult | ToolFailure;
|
|
897
|
+
expect(isToolFailure(result) ? null : result.price_difference).toBe(6.9);
|
|
899
898
|
});
|
|
900
899
|
|
|
901
900
|
test("records a negative difference as a refund direction", async () => {
|
|
@@ -908,8 +907,8 @@ describe("exchange_delivered_order_items", () => {
|
|
|
908
907
|
payment_method_id: "gift_card_7794233",
|
|
909
908
|
},
|
|
910
909
|
ctx,
|
|
911
|
-
)) as ExchangeResult |
|
|
912
|
-
expect(
|
|
910
|
+
)) as ExchangeResult | ToolFailure;
|
|
911
|
+
expect(isToolFailure(result) ? null : result.price_difference).toBe(-40.86);
|
|
913
912
|
});
|
|
914
913
|
|
|
915
914
|
test("refuses a gift card that cannot cover the difference", async () => {
|
|
@@ -923,8 +922,8 @@ describe("exchange_delivered_order_items", () => {
|
|
|
923
922
|
},
|
|
924
923
|
ctx,
|
|
925
924
|
);
|
|
926
|
-
expect(
|
|
927
|
-
expect(
|
|
925
|
+
expect(isToolFailure(result) && result.error.toLowerCase()).toContain("balance");
|
|
926
|
+
expect(retailSlot.get(ctx).store.orders["#W9311069"]?.status).toBe("delivered");
|
|
928
927
|
});
|
|
929
928
|
|
|
930
929
|
test("refuses a cross-product swap", async () => {
|
|
@@ -938,7 +937,7 @@ describe("exchange_delivered_order_items", () => {
|
|
|
938
937
|
},
|
|
939
938
|
ctx,
|
|
940
939
|
);
|
|
941
|
-
expect(
|
|
940
|
+
expect(isToolFailure(result)).toBe(true);
|
|
942
941
|
});
|
|
943
942
|
|
|
944
943
|
test("refuses an unavailable target", async () => {
|
|
@@ -952,7 +951,7 @@ describe("exchange_delivered_order_items", () => {
|
|
|
952
951
|
},
|
|
953
952
|
ctx,
|
|
954
953
|
);
|
|
955
|
-
expect(
|
|
954
|
+
expect(isToolFailure(result) && result.error.toLowerCase()).toContain("not available");
|
|
956
955
|
});
|
|
957
956
|
|
|
958
957
|
test("refuses a pending order and refuses a second exchange", async () => {
|
|
@@ -966,7 +965,7 @@ describe("exchange_delivered_order_items", () => {
|
|
|
966
965
|
},
|
|
967
966
|
ctx,
|
|
968
967
|
);
|
|
969
|
-
expect(
|
|
968
|
+
expect(isToolFailure(pending)).toBe(true);
|
|
970
969
|
|
|
971
970
|
await exchangeDeliveredOrderItems.execute(
|
|
972
971
|
{
|
|
@@ -986,7 +985,7 @@ describe("exchange_delivered_order_items", () => {
|
|
|
986
985
|
},
|
|
987
986
|
ctx,
|
|
988
987
|
);
|
|
989
|
-
expect(
|
|
988
|
+
expect(isToolFailure(again)).toBe(true);
|
|
990
989
|
});
|
|
991
990
|
|
|
992
991
|
test("a returned order can no longer be exchanged", async () => {
|
|
@@ -1008,7 +1007,7 @@ describe("exchange_delivered_order_items", () => {
|
|
|
1008
1007
|
},
|
|
1009
1008
|
ctx,
|
|
1010
1009
|
);
|
|
1011
|
-
expect(
|
|
1010
|
+
expect(isToolFailure(result)).toBe(true);
|
|
1012
1011
|
});
|
|
1013
1012
|
});
|
|
1014
1013
|
|
|
@@ -1023,8 +1022,8 @@ describe("transfer_to_human_agents", () => {
|
|
|
1023
1022
|
const result = (await transferToHumanAgents.execute(
|
|
1024
1023
|
{ summary: "Caller wants to dispute a charge from 2019." },
|
|
1025
1024
|
makeCtx(),
|
|
1026
|
-
)) as TransferResult |
|
|
1027
|
-
expect(
|
|
1028
|
-
expect(
|
|
1025
|
+
)) as TransferResult | ToolFailure;
|
|
1026
|
+
expect(isToolFailure(result)).toBe(false);
|
|
1027
|
+
expect(isToolFailure(result) ? null : result.transferred).toBe(true);
|
|
1029
1028
|
});
|
|
1030
1029
|
});
|