收敛报销明细与材料交互(07-27-yang-jun-reimbursement-readiness)
这个提交包含在:
@@ -10,6 +10,7 @@ const WECOM_UA =
|
||||
const reimbursementId = "11111111-1111-4111-8111-111111111111";
|
||||
const ownerId = "employee-r111";
|
||||
const pendingInvoiceId = "22222222-2222-4222-8222-222222222222";
|
||||
const unlinkedInvoiceId = "66666666-6666-4666-8666-666666666666";
|
||||
const attachmentId = "33333333-3333-4333-8333-333333333333";
|
||||
const availableInvoiceId = "44444444-4444-4444-8444-444444444444";
|
||||
const failedInvoiceId = "55555555-5555-4555-8555-555555555555";
|
||||
@@ -80,7 +81,18 @@ function buildInvoice() {
|
||||
originalName: "北京悦海堂发票.pdf",
|
||||
mimeType: "application/pdf",
|
||||
fileSize: 4096,
|
||||
linkedItemId: "item-r111",
|
||||
linkedItemId: "item-r111" as string | null,
|
||||
};
|
||||
}
|
||||
|
||||
function buildUnlinkedInvoice() {
|
||||
return {
|
||||
...buildInvoice(),
|
||||
id: unlinkedInvoiceId,
|
||||
invoiceNumber: "12345679",
|
||||
sellerName: "未关联材料供应方",
|
||||
originalName: "未关联发票.pdf",
|
||||
linkedItemId: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -432,7 +444,7 @@ async function mockApis(page: Page, state: ReturnType<typeof buildReimbursementS
|
||||
}
|
||||
|
||||
if (pathName === `/api/invoice-pool/${pendingInvoiceId}/bind`) {
|
||||
state.invoices = [buildInvoice()];
|
||||
state.invoices = [buildInvoice(), buildUnlinkedInvoice()];
|
||||
await fulfillJson(route, {
|
||||
id: pendingInvoiceId,
|
||||
status: "bound",
|
||||
@@ -596,9 +608,15 @@ test.describe("R111 国内报销发票与附件双端体验", () => {
|
||||
expect(state.statusPollCount).toBeGreaterThanOrEqual(1);
|
||||
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(page.getByText("北京悦海堂餐饮管理有限公司")).toBeVisible();
|
||||
await expect(page.getByText("北京悦海堂餐饮管理有限公司").first()).toBeVisible();
|
||||
await expect(page.getByText("明细:业务招待 · 客户招待")).toBeVisible();
|
||||
await page.getByRole("button", { name: "查看原件" }).first().click();
|
||||
await expect(page.getByTestId("reimbursement-materials")).toContainText("发票 2 · 补充附件 0");
|
||||
const itemRow = page.getByTestId("reimbursement-item-row");
|
||||
await expect(itemRow.getByRole("button", { name: /查看关联发票/ })).toHaveCount(1);
|
||||
await expect(itemRow).not.toContainText("未关联材料供应方");
|
||||
await expect(page.getByRole("button", { name: /查看发票原件/ })).toHaveCount(2);
|
||||
await expect(page.getByRole("button", { name: "查看原件", exact: true })).toHaveCount(0);
|
||||
await itemRow.getByRole("button", { name: /查看关联发票/ }).click();
|
||||
await expect.poll(() => page.evaluate(() => (window as typeof window & { __r111OpenCalls: unknown[][] }).__r111OpenCalls.length)).toBe(1);
|
||||
const invoiceOpenUrl = await page.evaluate(
|
||||
() => String((window as typeof window & { __r111OpenCalls: unknown[][] }).__r111OpenCalls[0]?.[0] ?? ""),
|
||||
@@ -612,7 +630,8 @@ test.describe("R111 国内报销发票与附件双端体验", () => {
|
||||
});
|
||||
await page.getByRole("button", { name: "上传附件" }).click();
|
||||
await expect(page.getByText("付款截图.png")).toBeVisible();
|
||||
await page.getByTestId("reimbursement-attachments").getByRole("button", { name: "查看原件" }).click();
|
||||
await expect(page.getByTestId("reimbursement-materials")).toContainText("发票 2 · 补充附件 1");
|
||||
await page.getByTestId("reimbursement-attachments").getByRole("button", { name: /查看补充附件/ }).click();
|
||||
await expect.poll(() => page.evaluate(() => (window as typeof window & { __r111OpenCalls: unknown[][] }).__r111OpenCalls.length)).toBe(2);
|
||||
|
||||
const bodyText = await page.locator("body").innerText();
|
||||
@@ -656,7 +675,7 @@ test.describe("R111 国内报销发票与附件双端体验", () => {
|
||||
await login(mobile.page);
|
||||
await mobile.page.goto(`/mobile/reimbursements/${reimbursementId}`);
|
||||
await expect(mobile.page.getByTestId("mobile-reimbursement-detail")).toBeVisible();
|
||||
await expect(mobile.page.getByRole("heading", { name: "附件材料" })).toBeVisible();
|
||||
await expect(mobile.page.getByRole("heading", { name: "报销材料" })).toBeVisible();
|
||||
|
||||
const beforeDialogMetrics = await collectVisualMetrics(mobile.page);
|
||||
expect(beforeDialogMetrics.scrollWidth).toBeLessThanOrEqual(beforeDialogMetrics.width + 2);
|
||||
@@ -712,21 +731,29 @@ test.describe("R111 国内报销发票与附件双端体验", () => {
|
||||
mobile.page.getByTestId("reimbursement-invoice-dialog").getByText("已添加 1 张发票"),
|
||||
).toBeVisible({ timeout: 15_000 });
|
||||
await mobile.page.keyboard.press("Escape");
|
||||
await expect(mobile.page.getByText("北京悦海堂餐饮管理有限公司")).toBeVisible();
|
||||
await mobile.page.getByRole("button", { name: "查看原件" }).first().click();
|
||||
await expect(mobile.page.getByText("北京悦海堂餐饮管理有限公司").first()).toBeVisible();
|
||||
await expect(mobile.page.getByTestId("mobile-reimbursement-materials")).toContainText("发票 2 · 补充附件 0");
|
||||
const mobileItem = mobile.page.locator("article.mobile-list-card").filter({ hasText: "客户招待" }).first();
|
||||
await expect(mobileItem.getByRole("button", { name: /查看关联发票/ })).toHaveCount(1);
|
||||
await expect(mobileItem).not.toContainText("未关联材料供应方");
|
||||
await expect(mobile.page.getByRole("button", { name: "查看原件", exact: true })).toHaveCount(0);
|
||||
const linkedInvoiceTarget = await mobileItem.getByRole("button", { name: /查看关联发票/ }).boundingBox();
|
||||
expect(linkedInvoiceTarget?.height ?? 0).toBeGreaterThanOrEqual(44);
|
||||
await mobile.page.getByRole("button", { name: /查看发票原件:044002600111-12345678/ }).click();
|
||||
await expect.poll(() => mobile.page.evaluate(() => (
|
||||
window as typeof window & { __r111BridgeCalls: Array<{ name: string }> }
|
||||
).__r111BridgeCalls.filter((call) => call.name === "previewFile").length)).toBe(1);
|
||||
|
||||
await mobile.page.getByTestId("mobile-reimbursement-attachments").getByRole("button", { name: "选择" }).click();
|
||||
await mobile.page.locator("[data-testid='mobile-reimbursement-attachments'] input[type='file']").setInputFiles({
|
||||
await mobile.page.getByRole("button", { name: "添加附件" }).click();
|
||||
await mobile.page.getByTestId("mobile-reimbursement-materials").locator("input[type='file']").setInputFiles({
|
||||
name: "付款截图.png",
|
||||
mimeType: "image/png",
|
||||
buffer: Buffer.from("r111 mobile attachment"),
|
||||
});
|
||||
await mobile.page.getByTestId("mobile-reimbursement-attachments").getByRole("button", { name: "上传附件" }).click();
|
||||
await mobile.page.getByTestId("mobile-reimbursement-materials").getByRole("button", { name: "上传附件" }).click();
|
||||
await expect(mobile.page.getByText("付款截图.png")).toBeVisible();
|
||||
await mobile.page.getByTestId("mobile-reimbursement-attachments").getByRole("button", { name: "查看原件" }).click();
|
||||
await expect(mobile.page.getByTestId("mobile-reimbursement-materials")).toContainText("发票 2 · 补充附件 1");
|
||||
await mobile.page.getByTestId("mobile-reimbursement-attachments").getByRole("button", { name: /查看补充附件/ }).click();
|
||||
await expect.poll(() => mobile.page.evaluate(() => (
|
||||
window as typeof window & { __r111BridgeCalls: Array<{ name: string }> }
|
||||
).__r111BridgeCalls.filter((call) => call.name === "previewFile").length)).toBe(2);
|
||||
@@ -753,6 +780,11 @@ test.describe("R111 国内报销发票与附件双端体验", () => {
|
||||
window as typeof window & { __r111OpenCalls: unknown[][] }
|
||||
).__r111OpenCalls.length)).toBe(0);
|
||||
|
||||
await mobile.page.setViewportSize({ width: 667, height: 375 });
|
||||
const landscapeMetrics = await collectVisualMetrics(mobile.page);
|
||||
expect(landscapeMetrics.scrollWidth).toBeLessThanOrEqual(landscapeMetrics.width + 2);
|
||||
await mobile.page.setViewportSize({ width: 390, height: 844 });
|
||||
|
||||
const bodyText = await mobile.page.locator("body").innerText();
|
||||
expect(bodyText).not.toContain("绑定整单");
|
||||
expect(bodyText).not.toContain("不绑定明细");
|
||||
|
||||
在新工单中引用
屏蔽一个用户