1import type { Api } from "../../helpers/api";
2import { expect, test } from "../../helpers/fixtures";
3import { FormScripts } from "../../helpers/form-script";
4import { snapshotSettings } from "../../helpers/settings";
5import { openTicket } from "../../helpers/ticket";
6
7test.describe("field permission notice", () => {
8 const NOTICE = "show_ticket_field_permission_notice";
9 let restoreSettings: () => Promise<unknown>;
10
11 test.beforeEach(async ({ api }) => {
12 restoreSettings = await snapshotSettings(api, [
13 NOTICE,
14 "show_customer_portal_permission_notice",
15 ]);
16 // the customer portal notice has its own Learn more button
17 await api.update("OD Settings", "OD Settings", {
18 [NOTICE]: 1,
19 show_customer_portal_permission_notice: 0,
20 });
21 });
22
23 test.afterEach(async () => {
24 await restoreSettings();
25 });
26
27 test("a manager sees it until they dismiss it in any tab", async ({ api, pageAs }) => {
28 const text = "Some fields are now hidden from customers";
29 const otherTab = await pageAs("manager");
30 await otherTab.goto("/opendesk/tickets");
31 await expect(otherTab.getByText(text)).toBeVisible();
32 const page = await pageAs("manager");
33 await page.goto("/opendesk/tickets");
34 const banner = page.getByText(text);
35 await expect(banner).toBeVisible();
36
37 await page.getByRole("button", { name: "Learn more" }).click();
38 const dialog = page.getByRole("dialog", { name: "Ticket fields have changed" });
39 await expect(dialog.getByRole("link", { name: "See how" })).toHaveAttribute(
40 "href",
41 /perm-levels-in-opendesk/
42 );
43 await dialog.getByRole("button", { name: "Got it" }).click();
44 await expect(dialog).toHaveCount(0);
45 await expect(banner).toHaveCount(0);
46 expect((await api.get("OD Settings", "OD Settings"))[NOTICE]).toBe(0);
47 await expect(otherTab.getByText(text)).toHaveCount(0);
48
49 await page.reload();
50 await page.waitForLoadState("networkidle");
51 await expect(banner).toHaveCount(0);
52 });
53
54 test("agents and customers never see it", async ({ pageAs }) => {
55 for (const [persona, url] of [
56 ["agent", "/opendesk/tickets"],
57 ["customer", "/help/my-tickets"],
58 ] as const) {
59 const page = await pageAs(persona);
60 await page.goto(url);
61 await page.waitForLoadState("networkidle");
62 await expect(page.getByText("Ticket fields update")).toHaveCount(0);
63 }
64 });
65});
66
67test.describe("Default template rows", () => {
68 let restoreTemplate: () => Promise<unknown>;
69
70 test.afterEach(async () => {
71 await restoreTemplate?.();
72 });
73
74 test("a row visible to Agents shows on the agent pages only", async ({
75 api,
76 pageAs,
77 ticket,
78 }) => {
79 restoreTemplate = await setTemplateRows(api, [
80 { fieldname: "priority", visible_to: "Everyone" },
81 { fieldname: "ticket_type", visible_to: "Agents" },
82 ]);
83 await api.update("OD Ticket", ticket.name, { priority: "High", ticket_type: "Bug" });
84
85 const customer = await pageAs("customer");
86 await customer.goto("/help/my-tickets/new");
87 await expect(customer.getByText("Priority", { exact: true })).toBeVisible();
88 await expect(customer.getByText("Ticket Type", { exact: true })).toHaveCount(0);
89
90 await customer.goto(`/help/my-tickets/${ticket.name}`);
91 await expect(customer.getByText("High", { exact: true })).toBeVisible();
92 await expect(customer.getByText("Bug", { exact: true })).toHaveCount(0);
93
94 const agent = await pageAs("agent");
95 await openTicket(agent, ticket.name);
96 await expect(agent.getByRole("combobox", { name: "Set Ticket Type..." })).toHaveValue("Bug");
97 await agent.goto("/opendesk/tickets/new");
98 await expect(agent.getByText("Ticket Type", { exact: true })).toBeVisible();
99 });
100
101 test("a portal script changes only the fields editable after creation", async ({
102 api,
103 pageAs,
104 ticket,
105 }) => {
106 restoreTemplate = await setTemplateRows(api, [
107 { fieldname: "priority", visible_to: "Everyone", editable_after_creation: 1 },
108 { fieldname: "ticket_type", visible_to: "Everyone", editable_after_creation: 0 },
109 ]);
110 await api.update("OD Ticket", ticket.name, { priority: "High", ticket_type: "Question" });
111 const scripts = new FormScripts(api);
112 await scripts.create(
113 `return { actions: [
114 { label: "E2E Set Priority", onClick: () => ctx.updateField("priority", "Low") },
115 { label: "E2E Set Type", onClick: () => ctx.updateField("ticket_type", "Bug") },
116 ] };`,
117 { portal: true }
118 );
119 try {
120 const page = await pageAs("customer");
121 await page.goto(`/help/my-tickets/${ticket.name}`);
122 await page.getByRole("button", { name: "E2E Set Priority" }).click();
123 await expect.poll(async () => (await api.get("OD Ticket", ticket.name)).priority).toBe("Low");
124
125 // Only the type's save: the priority save's response may still be in flight.
126 const refused = page.waitForResponse(
127 (r) =>
128 r.url().endsWith("/api/method/frappe.client.set_value") &&
129 (r.request().postData() || "").includes("ticket_type")
130 );
131 await page.getByRole("button", { name: "E2E Set Type" }).click();
132 expect((await refused).status()).toBe(403);
133 expect((await api.get("OD Ticket", ticket.name)).ticket_type).toBe("Question");
134 } finally {
135 await scripts.removeAll();
136 }
137 });
138});
139
140/** Replace the Default template's rows; returns a function that puts them back. */
141async function setTemplateRows(api: Api, rows: Record<string, unknown>[]) {
142 const { fields } = await api.get("OD Ticket Template", "Default");
143 await api.update("OD Ticket Template", "Default", { fields: rows });
144 return () => api.update("OD Ticket Template", "Default", { fields });
145}
146