From 56c87787ed23cccb4cd965d8944adecfdfa9f908 Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Mon, 13 Nov 2023 23:10:57 +0100 Subject: [PATCH] Add e2e tests for editing patches, issues, comments, labels and assignees --- src/views/projects/Cob/AssigneeInput.svelte | 7 +- src/views/projects/Cob/LabelInput.svelte | 4 +- src/views/projects/Patch.svelte | 2 +- tests/e2e/project/assignees.spec.ts | 78 ++++++ tests/e2e/project/issue.spec.ts | 161 +++++++++++ tests/e2e/project/issues.spec.ts | 150 +---------- tests/e2e/project/labels.spec.ts | 46 ++++ tests/e2e/project/patch.spec.ts | 246 +++++++++++++++++ tests/e2e/project/patches.spec.ts | 280 -------------------- tests/e2e/project/threads.spec.ts | 69 +++++ tests/support/project.ts | 142 ++++++++++ 11 files changed, 759 insertions(+), 426 deletions(-) create mode 100644 tests/e2e/project/assignees.spec.ts create mode 100644 tests/e2e/project/issue.spec.ts create mode 100644 tests/e2e/project/labels.spec.ts create mode 100644 tests/e2e/project/patch.spec.ts create mode 100644 tests/e2e/project/threads.spec.ts diff --git a/src/views/projects/Cob/AssigneeInput.svelte b/src/views/projects/Cob/AssigneeInput.svelte index 2728f1d88..fcf78b35e 100644 --- a/src/views/projects/Cob/AssigneeInput.svelte +++ b/src/views/projects/Cob/AssigneeInput.svelte @@ -98,6 +98,7 @@
{#if mode === "readEdit"} { dispatch("save", updatedAssignees); @@ -106,6 +107,7 @@ { updatedAssignees = assignees; @@ -116,6 +118,7 @@ {:else if mode !== "readCreate"} (mode = "readEdit")}> @@ -131,11 +134,11 @@
{formatNodeId(assignee)} - + removeAssignee(assignee)} /> - +
{:else} diff --git a/src/views/projects/Cob/LabelInput.svelte b/src/views/projects/Cob/LabelInput.svelte index 82dae019f..a6277c366 100644 --- a/src/views/projects/Cob/LabelInput.svelte +++ b/src/views/projects/Cob/LabelInput.svelte @@ -120,9 +120,9 @@ {#each updatedLabels as label}
{label}
- + removeLabel(label)} /> - +
{:else}
No labels
diff --git a/src/views/projects/Patch.svelte b/src/views/projects/Patch.svelte index aba3186eb..98988a9b0 100644 --- a/src/views/projects/Patch.svelte +++ b/src/views/projects/Patch.svelte @@ -675,7 +675,7 @@ body={newDescription} submitCaption="Save" submitInProgress={descriptionState === "submit"} - placeholder="Leave your description" + placeholder="Leave a description" on:close={() => (descriptionState = "read")} on:submit={async ({ detail: { comment } }) => { descriptionState = "submit"; diff --git a/tests/e2e/project/assignees.spec.ts b/tests/e2e/project/assignees.spec.ts new file mode 100644 index 000000000..1c95f4fd5 --- /dev/null +++ b/tests/e2e/project/assignees.spec.ts @@ -0,0 +1,78 @@ +import { test, expect } from "@tests/support/fixtures.js"; +import { createProject } from "@tests/support/project"; + +test("add and remove assignees", async ({ page, authenticatedPeer }) => { + await page.goto(authenticatedPeer.uiUrl()); + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "handle-assignees", + ); + await authenticatedPeer.rad( + [ + "issue", + "open", + "--title", + "This is an issue to test assignee handling", + "--description", + "We'll add and remove assignees to them", + ], + { cwd: projectFolder }, + ); + await page.goto( + `${authenticatedPeer.uiUrl()}/${rid}/issues/4fe061828a067ae52bda43537ca61b7aeeb44563`, + ); + + await expect(page.getByText("No assignees")).toBeVisible(); + + await page.getByRole("button", { name: "edit assignees" }).click(); + await page + .getByPlaceholder("Add assignee") + .fill("z6MktULudTtAsAhRegYPiZ6631RV3viv12qd4GQF8z1xB22S"); + await page.getByRole("button", { name: "dismiss changes" }).click(); + await expect(page.getByText("No assignees")).toBeVisible(); + await page.getByRole("button", { name: "edit assignees" }).click(); + await expect(page.getByPlaceholder("Add assignee")).toHaveValue(""); + + await page + .getByPlaceholder("Add assignee") + .fill("z6MktULudTtAsAhRegYPiZ6631RV3viv12qd4GQF8z1xB22S"); + await page.keyboard.press("Enter"); + await page + .getByPlaceholder("Add assignee") + .fill("z6MktULudTtAsAhRegYPiZ6631RV3viv12qd4GQF8z1xB22S"); + await expect(page.getByText("This assignee is already added")).toBeVisible(); + await page.getByPlaceholder("Add assignee").clear(); + await expect(page.getByText("This assignee is already added")).toBeHidden(); + + await page + .getByPlaceholder("Add assignee") + .fill("z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5"); + await page.keyboard.press("Enter"); + await page.getByRole("button", { name: "save assignees" }).click(); + await expect( + page.getByRole("button", { name: "save assignees" }), + ).toBeHidden(); + await page.reload(); + await expect( + page.getByRole("button", { name: "avatar did:key:z6MktU…1xB22S" }), + ).toBeVisible(); + await expect( + page.getByRole("button", { name: "avatar did:key:z6Mkkf…XVsVz5" }), + ).toBeVisible(); + + await page.getByRole("button", { name: "edit assignees" }).click(); + await page + .getByRole("button", { + name: "avatar did:key:z6MktU…1xB22S remove assignee", + }) + .getByTitle("remove assignee") + .click(); + await page.getByRole("button", { name: "save assignees" }).click(); + await expect( + page.getByRole("button", { name: "save assignees" }), + ).toBeHidden(); + await page.reload(); + await expect( + page.getByRole("button", { name: "avatar did:key:z6Mkkf…XVsVz5" }), + ).toBeVisible(); +}); diff --git a/tests/e2e/project/issue.spec.ts b/tests/e2e/project/issue.spec.ts new file mode 100644 index 000000000..69a486eb7 --- /dev/null +++ b/tests/e2e/project/issue.spec.ts @@ -0,0 +1,161 @@ +import { test, cobUrl, expect } from "@tests/support/fixtures.js"; +import { createProject, expectReactionsToWork } from "@tests/support/project"; + +test("navigate single issue", async ({ page }) => { + await page.goto(`${cobUrl}/issues`); + await page.getByText("This title has markdown").click(); + + await expect(page).toHaveURL( + `${cobUrl}/issues/d72196335761c1d5fa7883f6620e7334b34e38f9`, + ); +}); + +test("test issue editing failing", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "issue-editing", + ); + await authenticatedPeer.rad( + [ + "issue", + "open", + "--title", + "This issue is going to fail", + "--description", + "Let's see", + ], + { cwd: projectFolder }, + ); + + await page.route( + `**/v1/projects/${rid}/issues/ecd5f103110b08b93bede17163d35de1e1068148`, + route => { + if (route.request().method() !== "PATCH") { + void route.fallback(); + return; + } + void route.fulfill({ status: 500 }); + }, + ); + + await page.goto( + `${authenticatedPeer.uiUrl()}/${rid}/issues/ecd5f103110b08b93bede17163d35de1e1068148`, + ); + + await page.getByRole("button", { name: "Leave your comment" }).click(); + await page.getByPlaceholder("Leave your comment").fill("This is a comment"); + await page.getByRole("button", { name: "Comment" }).first().click(); + await expect(page.getByText("Comment creation failed")).toBeVisible(); +}); + +test("edit title", async ({ page, authenticatedPeer }) => { + await page.goto(authenticatedPeer.uiUrl()); + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "edit-title", + ); + await authenticatedPeer.rad( + [ + "issue", + "open", + "--title", + "This is an issue to edit its title", + "--description", + "We'll give it a title and edit it.", + ], + { cwd: projectFolder }, + ); + await page.goto( + `${authenticatedPeer.uiUrl()}/${rid}/issues/616e240787b6527780636caae581ca9975060733`, + ); + + await expect( + page.getByText("This is an issue to edit its title"), + ).toBeVisible(); + await expect(page.getByPlaceholder("Title")).toBeHidden(); + + await page.getByRole("button", { name: "edit title" }).click(); + await page + .getByPlaceholder("Title") + .fill("This is a modified issue title to be dismissed"); + await page.getByRole("button", { name: "dismiss changes" }).click(); + await expect( + page.getByText("This is an issue to edit its title"), + ).toBeVisible(); + + await page.getByRole("button", { name: "edit title" }).click(); + await page.getByPlaceholder("Title").fill("This is a modified issue title"); + await page.getByRole("button", { name: "save title" }).click(); + await expect(page.getByRole("button", { name: "save title" })).toBeHidden(); + await page.reload(); + await expect(page.getByText("This is a modified issue title")).toBeVisible(); +}); + +test("edit description", async ({ page, authenticatedPeer }) => { + await page.goto(authenticatedPeer.uiUrl()); + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "edit-description", + ); + await authenticatedPeer.rad( + [ + "issue", + "open", + "--title", + "This is an issue to edit its description", + "--description", + "We'll give it a description and edit it.", + ], + { cwd: projectFolder }, + ); + await page.goto( + `${authenticatedPeer.uiUrl()}/${rid}/issues/335e2823a71ac91203913a484dd771fd79f75139`, + ); + + await expect( + page.getByText("We'll give it a description and edit it."), + ).toBeVisible(); + await expect(page.getByPlaceholder("Leave a description")).toBeHidden(); + + await page.getByRole("button", { name: "edit description" }).click(); + await page + .getByPlaceholder("Leave a description") + .fill("This is a modified issue description to be dismissed"); + await page.getByRole("button", { name: "Cancel" }).click(); + await expect( + page.getByText("We'll give it a description and edit it."), + ).toBeVisible(); + + await page.getByRole("button", { name: "edit description" }).click(); + await page + .getByPlaceholder("Leave a description") + .fill("This is a modified issue description"); + await page.getByRole("button", { name: "Save" }).click(); + await expect(page.getByRole("button", { name: "Save" })).toBeHidden(); + await page.reload(); + await expect( + page.getByText("This is a modified issue description"), + ).toBeVisible(); +}); + +test("add and remove reactions", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "handle-reactions", + ); + await authenticatedPeer.rad( + [ + "issue", + "open", + "--title", + "This is an issue to test reactions", + "--description", + "We'll add and remove reactions to them", + ], + { cwd: projectFolder }, + ); + await page.goto( + `${authenticatedPeer.uiUrl()}/${rid}/issues/cb5f9b2de24ecfdd293a607c96d78aacc911b589`, + ); + await expectReactionsToWork(page); +}); diff --git a/tests/e2e/project/issues.spec.ts b/tests/e2e/project/issues.spec.ts index 0d08c4f2e..2c116810c 100644 --- a/tests/e2e/project/issues.spec.ts +++ b/tests/e2e/project/issues.spec.ts @@ -1,6 +1,5 @@ import { test, cobUrl, expect } from "@tests/support/fixtures.js"; -import { createProject } from "@tests/support/project"; -import { readFile } from "node:fs/promises"; +import { addEmbed, createProject } from "@tests/support/project"; test("navigate issue listing", async ({ page }) => { await page.goto(cobUrl); @@ -12,60 +11,7 @@ test("navigate issue listing", async ({ page }) => { await expect(page).toHaveURL(`${cobUrl}/issues?state=closed`); }); -test("navigate single issue", async ({ page }) => { - await page.goto(`${cobUrl}/issues`); - await page.getByText("This title has markdown").click(); - - await expect(page).toHaveURL( - `${cobUrl}/issues/d72196335761c1d5fa7883f6620e7334b34e38f9`, - ); -}); - -test("adding and removing reactions", async ({ page, authenticatedPeer }) => { - await page.goto(authenticatedPeer.uiUrl()); - const { rid, projectFolder } = await createProject( - authenticatedPeer, - "handle-reactions", - ); - await authenticatedPeer.rad( - [ - "issue", - "open", - "--title", - "This is an issue to test reactions", - "--description", - "We'll write some comments and add and remove reactions to them", - ], - { cwd: projectFolder }, - ); - await page.goto( - `${authenticatedPeer.uiUrl()}/${rid}/issues/a9d83773ac2fb8f5f654640477b9225a684cb53f`, - ); - const commentReactionToggle = page - .getByTitle("toggle-reaction-popover") - .last(); - await page.getByRole("button", { name: "Leave your comment" }).click(); - await page.getByPlaceholder("Leave your comment").fill("This is a comment"); - await page.getByRole("button", { name: "Comment" }).first().click(); - await commentReactionToggle.click(); - await page.getByRole("button", { name: "👍" }).click(); - await expect(page.getByRole("button", { name: "👍 1" })).toBeVisible(); - - await commentReactionToggle.click(); - await page.getByRole("button", { name: "🎉" }).click(); - await expect(page.getByRole("button", { name: "🎉 1" })).toBeVisible(); - await expect(page.locator(".reaction")).toHaveCount(2); - - await page.getByRole("button", { name: "👍" }).click(); - await expect(page.locator("span").filter({ hasText: "👍 1" })).toBeHidden(); - await expect(page.locator(".reaction")).toHaveCount(1); - - await page.getByRole("button", { name: "🎉" }).click(); - await expect(page.locator("span").filter({ hasText: "🎉 1" })).toBeHidden(); - await expect(page.locator(".reaction")).toHaveCount(0); -}); - -test("test issue counters", async ({ page, authenticatedPeer }) => { +test("issue counters", async ({ page, authenticatedPeer }) => { const { rid, projectFolder } = await createProject( authenticatedPeer, "issue-counters", @@ -108,48 +54,7 @@ test("test issue counters", async ({ page, authenticatedPeer }) => { await expect(page.getByRole("button", { name: "1 issue" })).toBeVisible(); }); -test("test issue editing failing", async ({ page, authenticatedPeer }) => { - const { rid, projectFolder } = await createProject( - authenticatedPeer, - "issue-editing", - ); - await authenticatedPeer.rad( - [ - "issue", - "open", - "--title", - "This issue is going to fail", - "--description", - "Let's see", - ], - { cwd: projectFolder }, - ); - - await page.route( - `**/v1/projects/${rid}/issues/ecd5f103110b08b93bede17163d35de1e1068148`, - route => { - if (route.request().method() !== "PATCH") { - void route.fallback(); - return; - } - void route.fulfill({ status: 500 }); - }, - ); - - await page.goto( - `${authenticatedPeer.uiUrl()}/${rid}/issues/ecd5f103110b08b93bede17163d35de1e1068148`, - ); - - await page.getByRole("button", { name: "Leave your comment" }).click(); - await page.getByPlaceholder("Leave your comment").fill("This is a comment"); - await page.getByRole("button", { name: "Comment" }).first().click(); - await expect(page.getByText("Comment creation failed")).toBeVisible(); -}); - -test("go through the entire ui issue flow", async ({ - page, - authenticatedPeer, -}) => { +test("create a new issue", async ({ page, authenticatedPeer }) => { const { rid } = await createProject(authenticatedPeer, "commenting"); await page.goto( @@ -185,60 +90,23 @@ test("go through the entire ui issue flow", async ({ page.locator(".badge").filter({ hasText: "documentation" }), ).toBeVisible(); await expect(page.locator(".badge").filter({ hasText: "bug" })).toBeVisible(); - - await page.getByRole("button", { name: "edit title" }).click(); - await page.getByPlaceholder("Title").fill("This is a new title"); - await page.getByRole("button", { name: "save title" }).click(); - await expect(page.getByText("This is a new title")).toBeVisible(); - - await page.getByRole("button", { name: "Leave your comment" }).click(); - await page.getByPlaceholder("Leave your comment").fill("This is a comment"); - await page.getByRole("button", { name: "Comment" }).first().click(); - await expect(page.getByText("This is a comment")).toBeVisible(); - - await page.getByRole("button", { name: "Reply to comment" }).click(); - await page.getByPlaceholder("Reply to comment").fill("This is a reply"); - await page.getByRole("button", { name: "Comment", exact: true }).click(); - await expect(page.getByText("This is a reply")).toBeVisible(); - - await page.getByRole("button", { name: "Close issue as solved" }).click(); - await expect(page.getByText("closed as solved")).toBeVisible(); - - await page.getByRole("button", { name: "Reopen issue" }).click(); - await expect(page.getByText("open", { exact: true })).toBeVisible(); - - await page.getByRole("button", { name: "stateToggle" }).first().click(); - await page.getByText("Close issue as other").click(); - await page.getByRole("button", { name: "Close issue as other" }).click(); - await expect(page.getByText("closed as other")).toBeVisible(); }); test("handling embeds", async ({ page, authenticatedPeer }) => { - const buffer = await readFile("./public/images/radicle-228x228.png"); - const base64Data = buffer.toString("base64"); const { rid } = await createProject(authenticatedPeer, "embeds"); - await page.goto( `/nodes/${authenticatedPeer.httpdBaseUrl.hostname}:${authenticatedPeer.httpdBaseUrl.port}/${rid}/issues/new`, ); - - const dataTransfer = await page.evaluateHandle(data => { - const arrayBuffer = Uint8Array.from(atob(data), c => c.charCodeAt(0)); - const dt = new DataTransfer(); - const file = new File([arrayBuffer.buffer], "radicle-228x228.png", { - type: "image/png", - }); - dt.items.add(file); - return dt; - }, base64Data); - await page.getByPlaceholder("Title").fill("This is a title"); await page .getByPlaceholder("Write a description") .fill("Here is some text\n\n"); - await page.dispatchEvent("textarea[aria-label=textarea-comment]", "drop", { - dataTransfer, - }); + await addEmbed( + page, + "./public/images/radicle-228x228.png", + "radicle-228x228.png", + "image/png", + ); await expect(page.getByPlaceholder("Write a description")).toHaveValue( "Here is some text\n\n![radicle-228x228.png](bae036309c2182c7304c97956969369823b5c6ad)\n", ); diff --git a/tests/e2e/project/labels.spec.ts b/tests/e2e/project/labels.spec.ts new file mode 100644 index 000000000..bfd2abf4b --- /dev/null +++ b/tests/e2e/project/labels.spec.ts @@ -0,0 +1,46 @@ +import { test } from "@tests/support/fixtures.js"; +import { + createProject, + expectLabelEditingToWork, + extractPatchId, +} from "@tests/support/project"; + +test("add and remove labels", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "handle-labels", + ); + await authenticatedPeer.rad( + [ + "issue", + "open", + "--title", + "This is an issue to test label handling", + "--description", + "We'll add and remove labels to them", + ], + { cwd: projectFolder }, + ); + + await page.goto( + `${authenticatedPeer.uiUrl()}/${rid}/issues/5129d02476bc8c85f35e06a7d19dde487b0a8b13`, + ); + await expectLabelEditingToWork(page); + + await authenticatedPeer.git(["switch", "-c", "handle-labels"], { + cwd: projectFolder, + }); + await authenticatedPeer.git( + ["commit", "--allow-empty", "-m", "Some patch title"], + { + cwd: projectFolder, + }, + ); + const patchId = extractPatchId( + await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { + cwd: projectFolder, + }), + ); + await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); + await expectLabelEditingToWork(page); +}); diff --git a/tests/e2e/project/patch.spec.ts b/tests/e2e/project/patch.spec.ts new file mode 100644 index 000000000..fe614ad23 --- /dev/null +++ b/tests/e2e/project/patch.spec.ts @@ -0,0 +1,246 @@ +import { test, cobUrl, expect } from "@tests/support/fixtures.js"; +import { createProject, extractPatchId } from "@tests/support/project"; + +test("navigate patch details", async ({ page }) => { + await page.goto(`${cobUrl}/patches`); + await page.getByText("Add subtitle to README").click(); + await expect(page).toHaveURL( + `${cobUrl}/patches/1cd7fe9598c0a877c32c516bddb3de70dfb53366`, + ); + await page.getByRole("link", { name: "Add subtitle to README" }).click(); + await expect(page).toHaveURL( + `${cobUrl}/commits/8c900d6cb38811e099efb3cbbdbfaba817bcf970`, + ); + await page.goBack(); + { + await page.getByRole("link", { name: "Changes" }).click(); + await expect(page).toHaveURL( + `${cobUrl}/patches/1cd7fe9598c0a877c32c516bddb3de70dfb53366?tab=changes`, + ); + } +}); + +test("use revision selector", async ({ page }) => { + await page.goto(`${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a`); + await page.getByRole("link", { name: "Changes" }).click(); + + // Validating the latest revision state + await expect( + page.getByRole("cell", { name: "Had to push a new revision" }), + ).toBeVisible(); + await page.getByRole("link", { name: "Activity" }).click(); + await expect(page.locator(".commits .teaser")).toHaveCount(2); + await expect(page.getByRole("link", { name: "Add more text" })).toBeVisible(); + + // Open the first revision and close the latest one + await page.getByLabel("expand").first().click(); + await page.getByLabel("expand").last().click(); + + // Validating the initial revision + await expect(page.locator(".commits .teaser")).toHaveCount(1); + await expect( + page.getByRole("link", { name: "Rewrite subtitle to README" }), + ).toBeVisible(); + + await page.getByRole("link", { name: "Changes" }).click(); + // Switching to the initial revision + await page.getByText("Revision 2c2f036").click(); + await expect(page.locator(".dropdown")).toBeVisible(); + await page.getByRole("link", { name: "Revision 679b2c8" }).click(); + await expect(page.locator(".dropdown")).toBeHidden(); + + await expect( + page.getByRole("cell", { name: "Had to push a new revision" }), + ).toBeHidden(); + + await expect(page).toHaveURL( + `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a/679b2c84a8e15ce1f73c4c231b55431b89b2559a?tab=changes`, + ); +}); + +test("navigate through revision diffs", async ({ page }) => { + await page.goto(`${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a`); + + const firstRevision = page.locator(".revision").first(); + const secondRevision = page.locator(".revision").nth(1); + + // Second revision + { + await secondRevision + .getByRole("button", { name: "toggle-context-menu" }) + .first() + .click(); + await secondRevision + .getByRole("link", { name: "Compare to main: 38c225e" }) + .click(); + await expect( + page.getByRole("link", { name: "Compare 38c225..9898da" }), + ).toBeVisible(); + await expect(page).toHaveURL( + `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a?diff=38c225e2a0b47ba59def211f4e4825c31d9463ec..9898da6155467adad511f63bf0fb5aa4156b92ef`, + ); + await page.goBack(); + await secondRevision + .getByRole("button", { name: "toggle-context-menu" }) + .first() + .click(); + await secondRevision + .getByRole("link", { name: "Compare to previous revision: 679b2c8" }) + .click(); + await expect( + page.getByRole("link", { name: "Compare 0dc373..9898da" }), + ).toBeVisible(); + + await expect(page).toHaveURL( + `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a?diff=0dc373db601ccbcffa80dec932e4006516709ca6..9898da6155467adad511f63bf0fb5aa4156b92ef`, + ); + await page.goBack(); + + await secondRevision + .getByRole("link", { name: "Compare 0dc373d..9898da6" }) + .click(); + await expect( + page.getByRole("link", { name: "Compare 0dc373..9898da" }), + ).toBeVisible(); + await page.goBack(); + } + // First revision + { + await firstRevision + .getByRole("button", { name: "toggle-context-menu" }) + .first() + .click(); + await firstRevision + .getByRole("link", { name: "Compare to main: 38c225e" }) + .click(); + await expect( + page.getByRole("link", { name: "Compare 38c225..0dc373" }), + ).toBeVisible(); + await expect(page).toHaveURL( + `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a?diff=38c225e2a0b47ba59def211f4e4825c31d9463ec..0dc373db601ccbcffa80dec932e4006516709ca6`, + ); + } +}); + +test("view file navigation from changes tab", async ({ page }) => { + await page.goto(`${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a`); + await page.getByRole("button", { name: "Changes" }).click(); + await page.getByRole("button", { name: "View file" }).click(); + await expect(page).toHaveURL( + `${cobUrl}/tree/9898da6155467adad511f63bf0fb5aa4156b92ef/README.md`, + ); +}); + +test("change patch state", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "lifecycle", + ); + await authenticatedPeer.git(["switch", "-c", "feature-1"], { + cwd: projectFolder, + }); + await authenticatedPeer.git( + ["commit", "--allow-empty", "-m", "Some patch title"], + { + cwd: projectFolder, + }, + ); + const patchId = extractPatchId( + await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { + cwd: projectFolder, + }), + ); + await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); + await page.getByRole("button", { name: "Archive patch" }).first().click(); + await expect(page.getByText("archived", { exact: true })).toBeVisible(); + await expect(page.getByRole("button", { name: "0 patches" })).toBeVisible(); + + await page.getByLabel("stateToggle").first().click(); + await page.getByText("Convert to draft").click(); + await page.getByText("Convert to draft").click(); + await expect(page.getByText("draft", { exact: true })).toBeVisible(); + await expect(page.getByRole("button", { name: "0 patches" })).toBeVisible(); +}); + +test("edit title", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "edit-title", + ); + await authenticatedPeer.git(["switch", "-c", "edit-title"], { + cwd: projectFolder, + }); + await authenticatedPeer.git( + ["commit", "--allow-empty", "-m", "Some patch title"], + { + cwd: projectFolder, + }, + ); + const patchId = extractPatchId( + await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { + cwd: projectFolder, + }), + ); + await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); + + const titleLocator = page.getByText("Some patch title").first(); + await expect(titleLocator).toBeVisible(); + await expect(page.getByPlaceholder("Title")).toBeHidden(); + + await page.getByRole("button", { name: "edit title" }).click(); + await page + .getByPlaceholder("Title") + .fill("This is a modified patch title to be dismissed"); + await page.getByRole("button", { name: "dismiss changes" }).click(); + await expect(titleLocator).toBeVisible(); + + await page.getByRole("button", { name: "edit title" }).click(); + await page.getByPlaceholder("Title").fill("This is a modified patch title"); + await page.getByRole("button", { name: "save title" }).click(); + await expect(page.getByRole("button", { name: "save title" })).toBeHidden(); + await page.reload(); + await expect(page.getByText("This is a modified patch title")).toBeVisible(); +}); + +test("edit description", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "edit-description", + ); + await authenticatedPeer.git(["switch", "-c", "edit-description"], { + cwd: projectFolder, + }); + await authenticatedPeer.git( + ["commit", "--allow-empty", "-m", "Some patch title"], + { + cwd: projectFolder, + }, + ); + const patchId = extractPatchId( + await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { + cwd: projectFolder, + }), + ); + await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); + + await expect(page.getByText("No description available")).toBeVisible(); + await expect(page.getByPlaceholder("Leave a description")).toBeHidden(); + + await page.getByRole("button", { name: "edit description" }).click(); + await page + .getByPlaceholder("Leave a description") + .fill("This is a modified patch description to be dismissed"); + await page.getByRole("button", { name: "Cancel" }).click(); + await expect(page.getByText("No description available")).toBeVisible(); + + await page.getByRole("button", { name: "edit description" }).click(); + await page + .getByPlaceholder("Leave a description") + .fill("This is a modified patch description"); + await page.getByRole("button", { name: "Save" }).click(); + await expect(page.getByRole("button", { name: "Save" })).toBeHidden(); + await page.reload(); + await expect( + page.getByText("This is a modified patch description"), + ).toBeVisible(); +}); diff --git a/tests/e2e/project/patches.spec.ts b/tests/e2e/project/patches.spec.ts index 73a4db094..ef225635c 100644 --- a/tests/e2e/project/patches.spec.ts +++ b/tests/e2e/project/patches.spec.ts @@ -1,16 +1,6 @@ -import type { ExecaReturnValue } from "execa"; import { test, cobUrl, expect } from "@tests/support/fixtures.js"; import { createProject } from "@tests/support/project"; -function extractPatchId(cmdOutput: ExecaReturnValue) { - const match = cmdOutput.stderr.match(/[0-9a-f]{40}/); - if (match) { - return match[0]; - } else { - throw new Error("Could not get patch id"); - } -} - test("navigate patch listing", async ({ page }) => { await page.goto(cobUrl); await page.getByRole("link", { name: "2 patches" }).click(); @@ -24,165 +14,6 @@ test("navigate patch listing", async ({ page }) => { ).toBeVisible(); }); -test("navigate patch details", async ({ page }) => { - await page.goto(`${cobUrl}/patches`); - await page.getByText("Add subtitle to README").click(); - await expect(page).toHaveURL( - `${cobUrl}/patches/1cd7fe9598c0a877c32c516bddb3de70dfb53366`, - ); - await page.getByRole("link", { name: "Add subtitle to README" }).click(); - await expect(page).toHaveURL( - `${cobUrl}/commits/8c900d6cb38811e099efb3cbbdbfaba817bcf970`, - ); - await page.goBack(); - { - await page.getByRole("link", { name: "Changes" }).click(); - await expect(page).toHaveURL( - `${cobUrl}/patches/1cd7fe9598c0a877c32c516bddb3de70dfb53366?tab=changes`, - ); - } -}); - -test("edit a patch", async ({ page, authenticatedPeer }) => { - const { rid, projectFolder } = await createProject( - authenticatedPeer, - "commenting", - ); - await authenticatedPeer.git(["switch", "-c", "feature-1"], { - cwd: projectFolder, - }); - await authenticatedPeer.git( - ["commit", "--allow-empty", "-m", "Some patch title"], - { - cwd: projectFolder, - }, - ); - const patchId = extractPatchId( - await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { - cwd: projectFolder, - }), - ); - await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); - await expect(page.getByRole("button", { name: "1 patch" })).toBeVisible(); - await expect(page.getByText("open", { exact: true })).toBeVisible(); - - await page.getByRole("button", { name: "edit labels" }).click(); - await page.getByPlaceholder("Add label").fill("bug"); - await page.getByPlaceholder("Add label").press("Enter"); - await page.getByPlaceholder("Add label").fill("documentation"); - await page.getByPlaceholder("Add label").press("Enter"); - await page.getByRole("button", { name: "save labels" }).click(); - - await expect( - page.locator(".badge").filter({ hasText: "documentation" }), - ).toBeVisible(); - await expect(page.locator(".badge").filter({ hasText: "bug" })).toBeVisible(); -}); - -test("leave a comment and reply", async ({ page, authenticatedPeer }) => { - const { rid, projectFolder } = await createProject( - authenticatedPeer, - "commenting", - ); - await authenticatedPeer.git(["switch", "-c", "feature-1"], { - cwd: projectFolder, - }); - await authenticatedPeer.git( - ["commit", "--allow-empty", "-m", "Some patch title"], - { - cwd: projectFolder, - }, - ); - const patchId = extractPatchId( - await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { - cwd: projectFolder, - }), - ); - await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); - await page.getByRole("button", { name: "Leave your comment" }).click(); - await page.getByPlaceholder("Leave your comment").fill("This is a comment"); - await page.getByRole("button", { name: "Comment" }).click(); - await expect(page.getByText("This is a comment")).toBeVisible(); - - await page.getByRole("button", { name: "Reply to comment" }).click(); - await page.getByPlaceholder("Reply to comment").fill("This is a reply"); - await page.getByRole("button", { name: "Comment", exact: true }).click(); - await expect(page.getByText("This is a reply")).toBeVisible(); -}); - -test("add and remove reactions", async ({ page, authenticatedPeer }) => { - const { rid, projectFolder } = await createProject( - authenticatedPeer, - "reactions", - ); - await authenticatedPeer.git(["switch", "-c", "feature-1"], { - cwd: projectFolder, - }); - await authenticatedPeer.git( - ["commit", "--allow-empty", "-m", "Some patch title"], - { - cwd: projectFolder, - }, - ); - const patchId = extractPatchId( - await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { - cwd: projectFolder, - }), - ); - await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); - await page.getByRole("button", { name: "Leave your comment" }).click(); - await page.getByPlaceholder("Leave your comment").fill("This is a comment"); - await page.getByRole("button", { name: "Comment" }).click(); - const commentReactionToggle = page.getByTitle("toggle-reaction").first(); - await commentReactionToggle.click(); - await page.getByRole("button", { name: "👍" }).click(); - await expect(page.getByRole("button", { name: "👍 1" })).toBeVisible(); - - await commentReactionToggle.click(); - await page.getByRole("button", { name: "🎉" }).click(); - await expect(page.getByRole("button", { name: "🎉 1" })).toBeVisible(); - await expect(page.locator(".reaction")).toHaveCount(2); - - await page.getByRole("button", { name: "👍" }).click(); - await expect(page.locator("span").filter({ hasText: "👍 1" })).toBeHidden(); - await expect(page.locator(".reaction")).toHaveCount(1); - - await commentReactionToggle.click(); - await page.getByRole("button", { name: "🎉" }).first().click(); - await expect(page.getByRole("button", { name: "🎉 1" })).toBeHidden(); - await expect(page.locator(".reaction")).toHaveCount(0); -}); -test("change patch state", async ({ page, authenticatedPeer }) => { - const { rid, projectFolder } = await createProject( - authenticatedPeer, - "lifecycle", - ); - await authenticatedPeer.git(["switch", "-c", "feature-1"], { - cwd: projectFolder, - }); - await authenticatedPeer.git( - ["commit", "--allow-empty", "-m", "Some patch title"], - { - cwd: projectFolder, - }, - ); - const patchId = extractPatchId( - await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { - cwd: projectFolder, - }), - ); - await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); - await page.getByRole("button", { name: "Archive patch" }).first().click(); - await expect(page.getByText("archived", { exact: true })).toBeVisible(); - await expect(page.getByRole("button", { name: "0 patches" })).toBeVisible(); - - await page.getByLabel("stateToggle").first().click(); - await page.getByText("Convert to draft").click(); - await page.getByText("Convert to draft").click(); - await expect(page.getByText("draft", { exact: true })).toBeVisible(); - await expect(page.getByRole("button", { name: "0 patches" })).toBeVisible(); -}); - test("patches counters", async ({ page, authenticatedPeer }) => { const { rid, projectFolder, defaultBranch } = await createProject( authenticatedPeer, @@ -218,114 +49,3 @@ test("patches counters", async ({ page, authenticatedPeer }) => { ).toHaveText("2 open"); await expect(page.locator(".list .patch-teaser")).toHaveCount(2); }); - -test("use revision selector", async ({ page }) => { - await page.goto(`${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a`); - await page.getByRole("link", { name: "Changes" }).click(); - - // Validating the latest revision state - await expect( - page.getByRole("cell", { name: "Had to push a new revision" }), - ).toBeVisible(); - await page.getByRole("link", { name: "Activity" }).click(); - await expect(page.locator(".commits .teaser")).toHaveCount(2); - await expect(page.getByRole("link", { name: "Add more text" })).toBeVisible(); - - // Open the first revision and close the latest one - await page.getByLabel("expand").first().click(); - await page.getByLabel("expand").last().click(); - - // Validating the initial revision - await expect(page.locator(".commits .teaser")).toHaveCount(1); - await expect( - page.getByRole("link", { name: "Rewrite subtitle to README" }), - ).toBeVisible(); - - await page.getByRole("link", { name: "Changes" }).click(); - // Switching to the initial revision - await page.getByText("Revision 2c2f036").click(); - await expect(page.locator(".dropdown")).toBeVisible(); - await page.getByRole("link", { name: "Revision 679b2c8" }).click(); - await expect(page.locator(".dropdown")).toBeHidden(); - - await expect( - page.getByRole("cell", { name: "Had to push a new revision" }), - ).toBeHidden(); - - await expect(page).toHaveURL( - `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a/679b2c84a8e15ce1f73c4c231b55431b89b2559a?tab=changes`, - ); -}); - -test("navigate through revision diffs", async ({ page }) => { - await page.goto(`${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a`); - - const firstRevision = page.locator(".revision").first(); - const secondRevision = page.locator(".revision").nth(1); - - // Second revision - { - await secondRevision - .getByRole("button", { name: "toggle-context-menu" }) - .first() - .click(); - await secondRevision - .getByRole("link", { name: "Compare to main: 38c225e" }) - .click(); - await expect( - page.getByRole("link", { name: "Compare 38c225..9898da" }), - ).toBeVisible(); - await expect(page).toHaveURL( - `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a?diff=38c225e2a0b47ba59def211f4e4825c31d9463ec..9898da6155467adad511f63bf0fb5aa4156b92ef`, - ); - await page.goBack(); - await secondRevision - .getByRole("button", { name: "toggle-context-menu" }) - .first() - .click(); - await secondRevision - .getByRole("link", { name: "Compare to previous revision: 679b2c8" }) - .click(); - await expect( - page.getByRole("link", { name: "Compare 0dc373..9898da" }), - ).toBeVisible(); - - await expect(page).toHaveURL( - `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a?diff=0dc373db601ccbcffa80dec932e4006516709ca6..9898da6155467adad511f63bf0fb5aa4156b92ef`, - ); - await page.goBack(); - - await secondRevision - .getByRole("link", { name: "Compare 0dc373d..9898da6" }) - .click(); - await expect( - page.getByRole("link", { name: "Compare 0dc373..9898da" }), - ).toBeVisible(); - await page.goBack(); - } - // First revision - { - await firstRevision - .getByRole("button", { name: "toggle-context-menu" }) - .first() - .click(); - await firstRevision - .getByRole("link", { name: "Compare to main: 38c225e" }) - .click(); - await expect( - page.getByRole("link", { name: "Compare 38c225..0dc373" }), - ).toBeVisible(); - await expect(page).toHaveURL( - `${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a?diff=38c225e2a0b47ba59def211f4e4825c31d9463ec..0dc373db601ccbcffa80dec932e4006516709ca6`, - ); - } -}); - -test("view file navigation from changes tab", async ({ page }) => { - await page.goto(`${cobUrl}/patches/679b2c84a8e15ce1f73c4c231b55431b89b2559a`); - await page.getByRole("button", { name: "Changes" }).click(); - await page.getByRole("button", { name: "View file" }).click(); - await expect(page).toHaveURL( - `${cobUrl}/tree/9898da6155467adad511f63bf0fb5aa4156b92ef/README.md`, - ); -}); diff --git a/tests/e2e/project/threads.spec.ts b/tests/e2e/project/threads.spec.ts new file mode 100644 index 000000000..5068ae467 --- /dev/null +++ b/tests/e2e/project/threads.spec.ts @@ -0,0 +1,69 @@ +import { test } from "@tests/support/fixtures.js"; +import { + createProject, + expectReactionsToWork, + expectThreadCommentingToWork, + extractPatchId, +} from "@tests/support/project"; + +test("leave comments and replies", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "commenting", + ); + await authenticatedPeer.rad( + [ + "issue", + "open", + "--title", + "This is an issue to write comments and replies", + "--description", + "We'll give it a few comments and replies.", + ], + { cwd: projectFolder }, + ); + await page.goto( + `${authenticatedPeer.uiUrl()}/${rid}/issues/017f0c6827fb19e4cfd5103e452ba58665f01798`, + ); + await expectThreadCommentingToWork(page); + + await authenticatedPeer.git(["switch", "-c", "feature-1"], { + cwd: projectFolder, + }); + await authenticatedPeer.git( + ["commit", "--allow-empty", "-m", "Some patch title"], + { + cwd: projectFolder, + }, + ); + const patchId = extractPatchId( + await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { + cwd: projectFolder, + }), + ); + await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); + await expectThreadCommentingToWork(page); +}); + +test("add and remove reactions", async ({ page, authenticatedPeer }) => { + const { rid, projectFolder } = await createProject( + authenticatedPeer, + "reactions", + ); + await authenticatedPeer.git(["switch", "-c", "feature-1"], { + cwd: projectFolder, + }); + await authenticatedPeer.git( + ["commit", "--allow-empty", "-m", "Some patch title"], + { + cwd: projectFolder, + }, + ); + const patchId = extractPatchId( + await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], { + cwd: projectFolder, + }), + ); + await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`); + await expectReactionsToWork(page); +}); diff --git a/tests/support/project.ts b/tests/support/project.ts index 27edc64ec..e0ad2eb2a 100644 --- a/tests/support/project.ts +++ b/tests/support/project.ts @@ -1,6 +1,10 @@ +import type { Page } from "@playwright/test"; import type { RadiclePeer } from "@tests/support/peerManager"; +import type { ExecaReturnValue } from "execa"; import * as Path from "node:path"; +import { expect } from "@playwright/test"; +import { readFileSync } from "node:fs"; // Create a project using the rad CLI. export async function createProject( @@ -39,3 +43,141 @@ export async function createProject( return { rid, projectFolder, defaultBranch }; } + +export function extractPatchId(cmdOutput: ExecaReturnValue) { + const match = cmdOutput.stderr.match(/[0-9a-f]{40}/); + if (match) { + return match[0]; + } else { + throw new Error("Could not get patch id"); + } +} + +export async function expectThreadCommentingToWork(page: Page) { + await page.getByRole("button", { name: "Leave your comment" }).click(); + await page.getByPlaceholder("Leave your comment").fill("This is a comment"); + await page.getByRole("button", { name: "Comment" }).click(); + await expect( + page.getByRole("button", { name: "Comment", exact: true }), + ).toBeHidden(); + await page.reload(); + await expect(page.getByText("This is a comment")).toBeVisible(); + + await page.getByRole("button", { name: "edit comment" }).first().click(); + await page + .getByPlaceholder("Leave your comment") + .fill("This is an edited comment"); + await page.getByRole("button", { name: "Save" }).click(); + await expect(page.getByRole("button", { name: "Save" })).toBeHidden(); + await page.reload(); + await expect(page.getByText("This is an edited comment")).toBeVisible(); + + await page.getByRole("button", { name: "Reply to comment" }).click(); + await page.getByPlaceholder("Reply to comment").fill("This is a reply"); + await page.getByRole("button", { name: "Comment", exact: true }).click(); + await expect( + page.getByRole("button", { name: "Comment", exact: true }), + ).toBeHidden(); + await page.reload(); + await expect(page.getByText("This is a reply")).toBeVisible(); + + await page.getByRole("button", { name: "edit comment" }).nth(1).click(); + await page + .getByPlaceholder("Leave your comment") + .fill("This is an edited reply"); + await page.getByRole("button", { name: "Save" }).click(); + await expect(page.getByRole("button", { name: "Save" })).toBeHidden(); + await page.reload(); + await expect(page.getByText("This is an edited reply")).toBeVisible(); +} + +export async function expectLabelEditingToWork(page: Page) { + await expect(page.getByText("No labels")).toBeVisible(); + + await page.getByRole("button", { name: "edit labels" }).click(); + await page.getByPlaceholder("Add label").fill("bug"); + await page.getByRole("button", { name: "dismiss changes" }).click(); + await expect(page.getByText("No labels")).toBeVisible(); + await page.getByRole("button", { name: "edit labels" }).click(); + await expect(page.getByPlaceholder("Add label")).toHaveValue(""); + + await page.getByPlaceholder("Add label").fill("bug"); + await page.keyboard.press("Enter"); + await page.getByPlaceholder("Add label").fill("bug"); + await expect(page.getByText("This label is already added")).toBeVisible(); + await page.getByPlaceholder("Add label").clear(); + await expect(page.getByText("This label is already added")).toBeHidden(); + + await page.getByPlaceholder("Add label").fill("documentation"); + await page.keyboard.press("Enter"); + await page.getByRole("button", { name: "save labels" }).click(); + await expect(page.getByRole("button", { name: "save labels" })).toBeHidden(); + await page.reload(); + await expect(page.getByRole("button", { name: "bug" })).toBeVisible(); + await expect( + page.getByRole("button", { name: "documentation" }), + ).toBeVisible(); + + await page.getByRole("button", { name: "edit labels" }).click(); + await page + .locator("span") + .filter({ hasText: "documentation" }) + .getByTitle("remove label") + .click(); + await page.getByRole("button", { name: "save labels" }).click(); + await expect(page.getByRole("button", { name: "save labels" })).toBeHidden(); + await page.reload(); + await expect(page.getByRole("button", { name: "bug" })).toBeVisible(); +} + +export async function expectReactionsToWork(page: Page) { + await page.getByRole("button", { name: "Leave your comment" }).click(); + await page.getByPlaceholder("Leave your comment").fill("This is a comment"); + await page.getByRole("button", { name: "Comment" }).click(); + const commentReactionToggle = page.getByTitle("toggle-reaction").first(); + await commentReactionToggle.click(); + await page.getByRole("button", { name: "👍" }).click(); + await expect(page.getByRole("button", { name: "👍 1" })).toBeVisible(); + + await commentReactionToggle.click(); + await page.getByRole("button", { name: "🎉" }).click(); + await expect(page.getByRole("button", { name: "🎉 1" })).toBeVisible(); + await expect(page.locator(".reaction")).toHaveCount(2); + + await page.getByRole("button", { name: "👍" }).click(); + await expect(page.locator("span").filter({ hasText: "👍 1" })).toBeHidden(); + await expect(page.locator(".reaction")).toHaveCount(1); + + await commentReactionToggle.click(); + await page.getByRole("button", { name: "🎉" }).first().click(); + await expect(page.getByRole("button", { name: "🎉 1" })).toBeHidden(); + await expect(page.locator(".reaction")).toHaveCount(0); +} + +export async function addEmbed( + page: Page, + url: string, + fileName: string, + fileType: string, +) { + const buffer = readFileSync(url).toString("base64"); + const dataTransfer = await page.evaluateHandle( + ({ buffer, localFileName, localFileType }) => { + const arrayBuffer = Uint8Array.from(atob(buffer), c => c.charCodeAt(0)); + const dt = new DataTransfer(); + const file = new File([arrayBuffer.buffer], localFileName, { + type: localFileType, + }); + dt.items.add(file); + return dt; + }, + { + buffer, + localFileName: fileName, + localFileType: fileType, + }, + ); + await page.dispatchEvent("textarea[aria-label=textarea-comment]", "drop", { + dataTransfer, + }); +}