dreame-shopify-app/test/activity-flow.test.ts

261 lines
8.2 KiB
TypeScript
Raw Permalink Normal View History

2026-06-19 00:53:13 +08:00
import { describe, expect, test } from "vitest";
import { runActivityCheck } from "../app/services/activity.server";
import type { ActivityDeps, PushPayload } from "../app/services/activity.server";
function baseDeps(overrides: Partial<ActivityDeps> = {}): ActivityDeps {
return {
nowMs: () => 1776901800000,
uuid: () => "00000000-0000-4000-8000-000000000000",
getOrder: async () => ({
id: "gid://shopify/Order/123",
legacyId: "123",
orderNumber: "#1001",
email: "customer@example.com",
customerId: "99999",
currency: "USD",
shopDomain: "demo.myshopify.com",
}),
getConfig: async () => ({
activityId: 12,
apiAppId: "app-id",
apiSecret: "secret",
statusApiUrl: "https://third.example/status",
pushApiUrl: "https://third.example/push",
redirectUrl: "https://activity.example.com",
buttonText: { en: "Claim Your Reward", "zh-CN": "领取奖励" },
shop: "configured-shop",
}),
findSuccess: async () => null,
recordSuccess: async () => undefined,
log: async () => undefined,
callStatus: async () => ({
httpOk: true,
status: 200,
body: { code: 0, data: { status: true, trigger: ["card_add"] } },
requestBody: '{"activity_id":12}',
responseBody: '{"code":0,"data":{"status":true}}',
}),
callPush: async () => ({
httpOk: true,
status: 200,
body: { code: 0 },
requestBody: "{}",
responseBody: '{"code":0}',
}),
...overrides,
};
}
describe("activity flow", () => {
test("returns false when status api says activity is inactive", async () => {
let pushCalls = 0;
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "123", orderNumber: "#1001", locale: "en" },
baseDeps({
callStatus: async () => ({
httpOk: true,
status: 200,
body: { code: 0, data: { status: false, trigger: ["order_end"] } },
requestBody: '{"activity_id":12}',
responseBody: '{"code":0,"data":{"status":false}}',
}),
callPush: async () => {
pushCalls += 1;
return { httpOk: true, status: 200, body: { code: 0 }, requestBody: "{}", responseBody: "{}" };
},
}),
);
expect(result).toEqual({ success: false });
expect(pushCalls).toBe(0);
});
test("returns false when status api code is not zero", async () => {
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "123", orderNumber: "#1001", locale: "en" },
baseDeps({
callStatus: async () => ({
httpOk: true,
status: 200,
body: { code: 401, data: {}, msg: "auth required" },
requestBody: '{"activity_id":12}',
responseBody: '{"code":401}',
}),
}),
);
expect(result).toEqual({ success: false });
});
test("pushes order_end with configured shop and no line items", async () => {
const capturedPayloads: PushPayload[] = [];
2026-06-19 00:53:13 +08:00
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "gid://shopify/Order/123", orderNumber: "#1001", locale: "zh-CN" },
baseDeps({
callPush: async (_config, payload) => {
capturedPayloads.push(payload);
2026-06-19 00:53:13 +08:00
return {
httpOk: true,
status: 200,
body: { code: 0 },
requestBody: JSON.stringify(payload),
responseBody: '{"code":0}',
};
},
}),
);
expect(result).toEqual({
success: true,
redirectUrl: "https://activity.example.com",
buttonText: "领取奖励",
});
expect(capturedPayloads).toHaveLength(1);
const captured = capturedPayloads[0];
2026-06-19 00:53:13 +08:00
expect(captured).toMatchObject({
activity_id: 12,
event_type: "order_end",
created_at: 1776901800000,
user_id: "99999",
email: "customer@example.com",
event_id: "00000000-0000-4000-8000-000000000000",
properties: {
shop: "configured-shop",
currency: "USD",
order_id: "123",
order_number: "#1001",
},
});
expect(captured.properties).not.toHaveProperty("lineItems");
expect(captured.event_id).toMatch(/^[0-9a-f-]{36}$/);
2026-06-19 00:53:13 +08:00
});
test("returns false when push api fails", async () => {
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "123", orderNumber: "#1001", locale: "en" },
baseDeps({
callPush: async () => ({
httpOk: true,
status: 200,
body: { code: 500 },
requestBody: "{}",
responseBody: '{"code":500}',
}),
}),
);
expect(result).toEqual({ success: false });
});
test("uses configured push success code", async () => {
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "123", orderNumber: "#1001", locale: "en" },
baseDeps({
getConfig: async () => ({
activityId: 12,
apiAppId: "app-id",
apiSecret: "secret",
statusApiUrl: "https://third.example/status",
pushApiUrl: "https://third.example/push",
redirectUrl: "https://activity.example.com",
buttonText: { en: "Claim Your Reward", "zh-CN": "领取奖励" },
pushSuccessCode: 2001,
}),
callPush: async () => ({
httpOk: true,
status: 200,
body: { code: 2001 },
requestBody: "{}",
responseBody: '{"code":2001}',
}),
}),
);
expect(result).toEqual({
success: true,
redirectUrl: "https://activity.example.com",
buttonText: "Claim Your Reward",
});
});
test("uses configured status success code and active flag policy", async () => {
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "123", orderNumber: "#1001", locale: "en" },
baseDeps({
getConfig: async () => ({
activityId: 12,
apiAppId: "app-id",
apiSecret: "secret",
statusApiUrl: "https://third.example/status",
pushApiUrl: "https://third.example/push",
redirectUrl: "https://activity.example.com",
buttonText: { en: "Claim Your Reward", "zh-CN": "领取奖励" },
statusSuccessCode: 2001,
statusActiveRequired: false,
}),
callStatus: async () => ({
httpOk: true,
status: 200,
body: { code: 2001 },
requestBody: '{"activity_id":12}',
responseBody: '{"code":2001}',
}),
}),
);
expect(result).toEqual({
success: true,
redirectUrl: "https://activity.example.com",
buttonText: "Claim Your Reward",
});
});
2026-06-19 00:53:13 +08:00
test("does not push when email is missing", async () => {
let pushCalls = 0;
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "123", orderNumber: "#1001", locale: "en" },
baseDeps({
getOrder: async () => ({
id: "gid://shopify/Order/123",
legacyId: "123",
orderNumber: "#1001",
customerId: "99999",
currency: "USD",
shopDomain: "demo.myshopify.com",
}),
callPush: async () => {
pushCalls += 1;
return { httpOk: true, status: 200, body: { code: 0 }, requestBody: "{}", responseBody: "{}" };
},
}),
);
expect(result).toEqual({ success: false });
expect(pushCalls).toBe(0);
});
test("does not push when customer id is missing", async () => {
let pushCalls = 0;
const result = await runActivityCheck(
{ shop: "demo.myshopify.com", orderId: "123", orderNumber: "#1001", locale: "en" },
baseDeps({
getOrder: async () => ({
id: "gid://shopify/Order/123",
legacyId: "123",
orderNumber: "#1001",
email: "customer@example.com",
currency: "USD",
shopDomain: "demo.myshopify.com",
}),
callPush: async () => {
pushCalls += 1;
return { httpOk: true, status: 200, body: { code: 0 }, requestBody: "{}", responseBody: "{}" };
},
}),
);
expect(result).toEqual({ success: false });
expect(pushCalls).toBe(0);
});
});