feat(tip): support dynamic gift products
This commit is contained in:
@@ -65,8 +65,8 @@ describe("payment order flow", () => {
|
||||
expect(actor.getSnapshot().context).toMatchObject({
|
||||
currentOrderId: "pay_test_001",
|
||||
orderStatus: "paid",
|
||||
tipCount: null,
|
||||
thankYouMessage: null,
|
||||
tipMessage: null,
|
||||
tipMessageError: null,
|
||||
orderPollingStartedAt: null,
|
||||
launchNonce: 1,
|
||||
});
|
||||
@@ -81,33 +81,46 @@ describe("payment order flow", () => {
|
||||
actor.stop();
|
||||
});
|
||||
|
||||
it("stores a stable Tip success result and clears it on reset", async () => {
|
||||
it("loads a stable Tip message after payment and clears it on reset", async () => {
|
||||
const loadTipMessage = vi.fn();
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({
|
||||
orderType: "tip",
|
||||
orderPlanId: "tip_coffee_usd_9_99",
|
||||
tipCount: 2,
|
||||
thankYouMessage: "You made my day.",
|
||||
onLoadTipMessage: loadTipMessage,
|
||||
tipMessage: {
|
||||
orderId: "pay_test_001",
|
||||
characterId: "elio",
|
||||
planId: "tip_coffee_usd_9_99",
|
||||
productName: "Golden Reserve",
|
||||
tipCount: 2,
|
||||
poolIndex: 18,
|
||||
message: "You made my day.",
|
||||
},
|
||||
}),
|
||||
).start();
|
||||
await initialize(actor);
|
||||
await initializeTip(actor);
|
||||
actor.send({
|
||||
type: "PaymentCreateOrderSubmitted",
|
||||
recipientCharacterId: "maya-tan",
|
||||
recipientCharacterId: "elio",
|
||||
});
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("paid"));
|
||||
|
||||
expect(loadTipMessage).toHaveBeenCalledWith("pay_test_001");
|
||||
expect(actor.getSnapshot().context).toMatchObject({
|
||||
orderStatus: "paid",
|
||||
tipCount: 2,
|
||||
thankYouMessage: "You made my day.",
|
||||
tipMessage: expect.objectContaining({
|
||||
tipCount: 2,
|
||||
message: "You made my day.",
|
||||
}),
|
||||
tipMessageError: null,
|
||||
});
|
||||
|
||||
actor.send({ type: "PaymentReset" });
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("ready"));
|
||||
expect(actor.getSnapshot().context).toMatchObject({
|
||||
tipCount: null,
|
||||
thankYouMessage: null,
|
||||
tipMessage: null,
|
||||
tipMessageError: null,
|
||||
});
|
||||
actor.stop();
|
||||
});
|
||||
@@ -116,19 +129,18 @@ describe("payment order flow", () => {
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({
|
||||
orderType: "tip",
|
||||
tipCount: 3,
|
||||
thankYouMessage: "Another warm coffee.",
|
||||
orderPlanId: "tip_coffee_usd_4_99",
|
||||
}),
|
||||
).start();
|
||||
await initialize(actor);
|
||||
await initializeTip(actor);
|
||||
actor.send({ type: "PaymentCreateOrderSubmitted" });
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("paid"));
|
||||
|
||||
actor.send({ type: "PaymentCreateOrderSubmitted" });
|
||||
expect(actor.getSnapshot().matches("creatingOrder")).toBe(true);
|
||||
expect(actor.getSnapshot().context).toMatchObject({
|
||||
tipCount: null,
|
||||
thankYouMessage: null,
|
||||
tipMessage: null,
|
||||
tipMessageError: null,
|
||||
});
|
||||
actor.stop();
|
||||
});
|
||||
@@ -137,11 +149,10 @@ describe("payment order flow", () => {
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({
|
||||
orderType: "tip",
|
||||
tipCount: 4,
|
||||
thankYouMessage: "That was so thoughtful.",
|
||||
orderPlanId: "tip_coffee_usd_4_99",
|
||||
}),
|
||||
).start();
|
||||
await initialize(actor);
|
||||
await initializeTip(actor);
|
||||
actor.send({ type: "PaymentCreateOrderSubmitted" });
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("paid"));
|
||||
|
||||
@@ -149,8 +160,8 @@ describe("payment order flow", () => {
|
||||
expect(actor.getSnapshot().matches("ready")).toBe(true);
|
||||
expect(actor.getSnapshot().context).toMatchObject({
|
||||
payChannel: "ezpay",
|
||||
tipCount: null,
|
||||
thankYouMessage: null,
|
||||
tipMessage: null,
|
||||
tipMessageError: null,
|
||||
});
|
||||
actor.stop();
|
||||
});
|
||||
@@ -211,8 +222,8 @@ describe("payment order flow", () => {
|
||||
currentOrderId: null,
|
||||
payParams: null,
|
||||
orderStatus: null,
|
||||
tipCount: null,
|
||||
thankYouMessage: null,
|
||||
tipMessage: null,
|
||||
tipMessageError: null,
|
||||
orderPollingStartedAt: null,
|
||||
errorMessage: null,
|
||||
});
|
||||
@@ -235,6 +246,48 @@ describe("payment order flow", () => {
|
||||
actor.stop();
|
||||
});
|
||||
|
||||
it("moves expired orders to a dedicated terminal state", async () => {
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({ orderStatus: "expired" }),
|
||||
).start();
|
||||
await initialize(actor);
|
||||
actor.send({ type: "PaymentCreateOrderSubmitted" });
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("expired"));
|
||||
|
||||
expect(actor.getSnapshot().context).toMatchObject({
|
||||
orderStatus: "expired",
|
||||
payParams: null,
|
||||
errorMessage:
|
||||
"This payment order has expired. Please create a new order.",
|
||||
});
|
||||
actor.stop();
|
||||
});
|
||||
|
||||
it("keeps paid state when the Tip message fails and retries only the message", async () => {
|
||||
const loadTipMessage = vi.fn();
|
||||
const actor = createActor(
|
||||
createTestPaymentMachine({
|
||||
orderType: "tip",
|
||||
orderPlanId: "tip_coffee_usd_4_99",
|
||||
tipMessageError: new Error("message unavailable"),
|
||||
onLoadTipMessage: loadTipMessage,
|
||||
}),
|
||||
).start();
|
||||
await initializeTip(actor);
|
||||
actor.send({ type: "PaymentCreateOrderSubmitted" });
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("tipMessageFailed"));
|
||||
|
||||
expect(actor.getSnapshot().context).toMatchObject({
|
||||
orderStatus: "paid",
|
||||
tipMessage: null,
|
||||
tipMessageError: "message unavailable",
|
||||
});
|
||||
actor.send({ type: "PaymentTipMessageRetryRequested" });
|
||||
await waitFor(actor, () => loadTipMessage.mock.calls.length === 2);
|
||||
expect(actor.getSnapshot().context.orderStatus).toBe("paid");
|
||||
actor.stop();
|
||||
});
|
||||
|
||||
it("times out an old pending order", async () => {
|
||||
const statusPollTimeout = vi
|
||||
.spyOn(behaviorAnalytics, "statusPollTimeout")
|
||||
@@ -336,3 +389,10 @@ async function initialize(
|
||||
actor.send({ type: "PaymentInit" });
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("ready"));
|
||||
}
|
||||
|
||||
async function initializeTip(
|
||||
actor: ReturnType<typeof createActor<ReturnType<typeof createTestPaymentMachine>>>,
|
||||
): Promise<void> {
|
||||
actor.send({ type: "PaymentInit", catalog: "tip", characterId: "elio" });
|
||||
await waitFor(actor, (snapshot) => snapshot.matches("ready"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user