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\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,
+ });
+}