carepath-api / scribe /frontend /src /LeadForm.test.tsx
tranth3truong's picture
Deploy CP-UX-12/13 landing: hero draft proof, privacy and Vietnamese-capability evidence
da09932
Raw
History Blame Contribute Delete
7.98 kB
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import LeadForm from "./LeadForm";
import { scenarios } from "./demo/scenarios";
function fillRequiredFields() {
fireEvent.change(screen.getByRole("textbox", { name: "Họ và tên" }), {
target: { value: "Nguyễn Minh Anh" },
});
fireEvent.change(screen.getByRole("textbox", { name: "Vai trò" }), {
target: { value: "Giám đốc phòng khám" },
});
fireEvent.change(screen.getByRole("textbox", { name: "Email hoặc Zalo" }), {
target: { value: "minhanh@example.com" },
});
}
describe("LeadForm", () => {
it("posts the configured payload to the lead endpoint", async () => {
const fetcher = vi.fn(async () => new Response(null, { status: 204 })) as unknown as typeof fetch;
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
endpoint="https://leads.example.test/pilot"
fetcher={fetcher}
language="vi"
scenario={scenarios[0]}
specialty="Nội tổng quát"
transcript="VI: Uống nửa viên.\nEN: Take half a tablet."
/>,
);
fillRequiredFields();
fireEvent.click(
screen.getByRole("button", { name: "Gửi yêu cầu thí điểm" }),
);
await waitFor(() =>
expect(screen.getByText("Đã gửi yêu cầu thí điểm.")).toBeInTheDocument(),
);
expect(fetcher).toHaveBeenCalledOnce();
const [, request] = (fetcher as ReturnType<typeof vi.fn>).mock.calls[0];
const payload = JSON.parse(String(request.body));
expect(payload.interest).toBe("both");
expect(payload.scenarioId).toBe("");
expect(payload.transcript).toBe("");
});
it("opens a prefilled mail draft when no endpoint is configured", async () => {
const onMailto = vi.fn();
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
endpoint=""
leadEmail="pilot@example.com"
language="vi"
onMailto={onMailto}
scenario={scenarios[1]}
specialty="Dị ứng"
transcript="VI: Không dị ứng.\nEN: Not allergic."
/>,
);
fillRequiredFields();
fireEvent.click(
screen.getByRole("button", { name: "Mở email đã điền sẵn" }),
);
await waitFor(() => expect(onMailto).toHaveBeenCalledOnce());
const mailto = decodeURIComponent(onMailto.mock.calls[0][0]);
expect(mailto).toContain("mailto:pilot@example.com");
expect(mailto).not.toContain("Kiểm tra dị ứng — xác nhận phủ định");
expect(mailto).not.toContain("Not allergic");
expect(
screen.getByText(
"Đã mở bản nháp email. Hãy kiểm tra và gửi thư để hoàn tất.",
),
).toBeInTheDocument();
});
it("reports an error instead of a dead mail draft when no channel is configured", async () => {
const onMailto = vi.fn();
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
endpoint=""
leadEmail=""
language="vi"
onMailto={onMailto}
scenario={scenarios[0]}
specialty="Nội tổng quát"
transcript=""
/>,
);
fillRequiredFields();
fireEvent.click(
screen.getByRole("button", { name: "Mở email đã điền sẵn" }),
);
await waitFor(() =>
expect(
screen.getByText(
"Không thể gửi yêu cầu. Vui lòng kiểm tra kết nối và thử lại.",
),
).toBeInTheDocument(),
);
expect(onMailto).not.toHaveBeenCalled();
});
it("shows inline errors without attempting submission", () => {
const fetcher = vi.fn();
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
endpoint="https://leads.example.test/pilot"
fetcher={fetcher as unknown as typeof fetch}
language="vi"
scenario={scenarios[0]}
specialty="Nội tổng quát"
transcript=""
/>,
);
fireEvent.click(
screen.getByRole("button", { name: "Gửi yêu cầu thí điểm" }),
);
expect(screen.getAllByText("Vui lòng điền trường này.")).toHaveLength(3);
expect(fetcher).not.toHaveBeenCalled();
});
it("submits a selectable Scribe interest without interpreter context", async () => {
const fetcher = vi.fn(async () => new Response(null, { status: 204 })) as unknown as typeof fetch;
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
endpoint="https://leads.example.test/pilot"
fetcher={fetcher}
language="vi"
scenario={scenarios[0]}
specialty="Nội tổng quát"
transcript="VI: Uống nửa viên.\nEN: Take half a tablet."
/>,
);
fireEvent.change(screen.getByRole("combobox", { name: "Chức năng quan tâm" }), {
target: { value: "scribe" },
});
fillRequiredFields();
fireEvent.click(
screen.getByRole("button", { name: "Gửi yêu cầu thí điểm" }),
);
await waitFor(() => expect(fetcher).toHaveBeenCalledOnce());
const [, request] = (fetcher as ReturnType<typeof vi.fn>).mock.calls[0];
expect(JSON.parse(String(request.body))).toMatchObject({
interest: "scribe",
scenarioId: "",
scenarioTitle: "",
transcript: "",
});
});
it("reports controlled product-interest changes", () => {
const onInterestChange = vi.fn();
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
interest="interpreter"
language="vi"
onInterestChange={onInterestChange}
scenario={scenarios[0]}
specialty="Nội tổng quát"
transcript=""
/>,
);
const selector = screen.getByRole("combobox", { name: "Chức năng quan tâm" });
expect(selector).toHaveValue("interpreter");
fireEvent.change(selector, { target: { value: "both" } });
expect(onInterestChange).toHaveBeenCalledWith("both");
});
it("submits a fixed Scribe interest when the landing selector is hidden", async () => {
const fetcher = vi.fn(async () => new Response(null, { status: 204 })) as unknown as typeof fetch;
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
endpoint="https://leads.example.test/pilot"
fetcher={fetcher}
hideInterestField
interest="scribe"
language="vi"
scenario={scenarios[0]}
specialty="Nội tổng quát"
transcript=""
/>,
);
expect(screen.queryByRole("combobox", { name: "Chức năng quan tâm" })).not.toBeInTheDocument();
fillRequiredFields();
fireEvent.click(screen.getByRole("button", { name: "Gửi yêu cầu thí điểm" }));
await waitFor(() => expect(fetcher).toHaveBeenCalledOnce());
const [, request] = (fetcher as ReturnType<typeof vi.fn>).mock.calls[0];
expect(JSON.parse(String(request.body)).interest).toBe("scribe");
});
it("includes the simulation context only after explicit opt-in", async () => {
const fetcher = vi.fn(async () => new Response(null, { status: 204 })) as unknown as typeof fetch;
render(
<LeadForm
clinic="Phòng khám Minh Tâm"
endpoint="https://leads.example.test/pilot"
fetcher={fetcher}
language="vi"
scenario={scenarios[0]}
specialty="Nội tổng quát"
transcript="VI: Uống nửa viên.\nEN: Take half a tablet."
/>,
);
fireEvent.click(screen.getByLabelText("Gửi kèm kịch bản mô phỏng và bản chép song ngữ"));
fillRequiredFields();
fireEvent.click(screen.getByRole("button", { name: "Gửi yêu cầu thí điểm" }));
await waitFor(() => expect(fetcher).toHaveBeenCalledOnce());
const [, request] = (fetcher as ReturnType<typeof vi.fn>).mock.calls[0];
expect(JSON.parse(String(request.body))).toMatchObject({
scenarioId: "prescription",
transcript: expect.stringContaining("Take half a tablet"),
});
});
});