Add e2e tests for editing patches, issues, comments, labels and assignees

This commit is contained in:
Sebastian Martinez
2023-11-15 09:32:12 +01:00
parent 1188e84c87
commit 56c87787ed
11 changed files with 759 additions and 426 deletions
+5 -2
View File
@@ -98,6 +98,7 @@
<div class="actions">
{#if mode === "readEdit"}
<IconButton
title="save assignees"
loading={submitInProgress}
on:click={() => {
dispatch("save", updatedAssignees);
@@ -106,6 +107,7 @@
<IconSmall name="checkmark" />
</IconButton>
<IconButton
title="dismiss changes"
loading={submitInProgress}
on:click={() => {
updatedAssignees = assignees;
@@ -116,6 +118,7 @@
</IconButton>
{:else if mode !== "readCreate"}
<IconButton
title="edit assignees"
loading={submitInProgress}
on:click={() => (mode = "readEdit")}>
<IconSmall name="edit" />
@@ -131,11 +134,11 @@
<div class="assignee">
<Avatar inline nodeId={assignee} />
<span>{formatNodeId(assignee)}</span>
<span style:cursor="pointer">
<IconButton title="remove assignee">
<IconSmall
name="cross"
on:click={() => removeAssignee(assignee)} />
</span>
</IconButton>
</div>
</Badge>
{:else}
+2 -2
View File
@@ -120,9 +120,9 @@
{#each updatedLabels as label}
<Badge variant="neutral">
<div aria-label="chip" class="label">{label}</div>
<span style:cursor="pointer">
<IconButton title="remove label">
<IconSmall name="cross" on:click={() => removeLabel(label)} />
</span>
</IconButton>
</Badge>
{:else}
<div class="txt-missing">No labels</div>
+1 -1
View File
@@ -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";
+78
View File
@@ -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();
});
+161
View File
@@ -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);
});
+9 -141
View File
@@ -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",
);
+46
View File
@@ -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);
});
+246
View File
@@ -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();
});
-280
View File
@@ -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<string>) {
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`,
);
});
+69
View File
@@ -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);
});
+142
View File
@@ -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<string>) {
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,
});
}