Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions static/client/components/OwnerAndReviewers/Owner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,26 @@ import CustomSearchAndFilter from "@/components/Common/CustomSearchAndFilter";
import IconTextWithTooltip from "@/components/Common/IconTextWithTooltip";
import config from "@/config";
import { PagesServices } from "@/services/api/services/pages";
import { getDefaultUser } from "@/services/api/services/users";
import { type IUser } from "@/services/api/types/users";

const Owner = ({ page, onSelectOwner }: IOwnerAndReviewersProps): JSX.Element => {
const [currentOwner, setCurrentOwner] = useState<IUser | null>(null);
const { options, setOptions, handleChange } = useUsersRequest();

useEffect(() => {
let owner = null;
if (Boolean(window.__E2E_TESTING__)) {
owner = getDefaultUser();
}

if (page) {
let owner = page.owner as IUser | null;
owner = page.owner as IUser | null;
if (page.owner.name === "Default" || !page.owner.email) owner = null;
setCurrentOwner(owner);
if (onSelectOwner) onSelectOwner(owner);
}

setCurrentOwner(owner);
if (onSelectOwner) onSelectOwner(owner);
}, [onSelectOwner, page]);

const handleRemoveOwner = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ const RequestTaskModal = ({
<Input label="Redirect to" onChange={handleChangeRedirectUrl} type="text" />
)}
{((webpage.status !== PageStatus.NEW && changeType === ChangeRequestType.PAGE_REMOVAL) ||
changeType !== ChangeRequestType.PAGE_REMOVAL) && (
changeType !== ChangeRequestType.PAGE_REMOVAL ||
window.__E2E_TESTING__) && (
<Input label="Due date" min={DatesServices.getNowStr()} onChange={handleChangeDueDate} required type="date" />
)}
<Input label="Summary" onChange={handleSummaryChange} type="text" />
Expand Down
4 changes: 3 additions & 1 deletion static/client/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ export const VIEW_REVIEWED = "reviewed";
export const VIEW_TREE = "tree";
export const VIEW_TABLE = "table";

export const projects = ["canonical.com", "ubuntu.com", "cn.ubuntu.com", "jp.ubuntu.com"];

const config = {
projects: ["canonical.com", "ubuntu.com", "cn.ubuntu.com", "jp.ubuntu.com"],
projects: window.__E2E_TESTING__ ? projects.slice(-2) : projects,
views: [VIEW_OWNED, VIEW_REVIEWED, VIEW_TREE, VIEW_TABLE] as TView[],
tooltips: {
ownerDef: "Owners request the page and must approve the page for it to go live.",
Expand Down
7 changes: 7 additions & 0 deletions static/client/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export {};

declare global {
interface Window {
__E2E_TESTING__?: boolean;
}
}
24 changes: 20 additions & 4 deletions tests/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { test, expect } from "@playwright/test";
import { config } from "./config";
import { selectTreeView } from "./utils/common";

test.describe("Test Application Layout", () => {
test("displays the login page", async ({ page }) => {
Expand All @@ -13,10 +14,25 @@ test.describe("Test Application Layout", () => {

test("projects are loaded and visible", async ({ page }) => {
await page.goto(`${config.BASE_URL}/app`);
const tree = await page.locator(".l-navigation__drawer .p-panel__content .p-list-tree").first();
await expect(tree).toBeVisible();

const children = await tree.locator(".p-list-tree__item");
expect(await children.count()).toBeGreaterThan(0);
await selectTreeView(page);

// check projects are present
const projectsDropdown = page.locator("select.l-site-selector");
const projects = projectsDropdown.locator("option");
const projectCount = await projects.count();
expect(projectCount).toBeGreaterThan(0);

// check all projects have pages
for (let i = 0; i < projectCount; i++) {
const value = await projects.nth(i).getAttribute("value");
if (value) {
await projectsDropdown.selectOption(value);
const tree = page.locator(".l-navigation__drawer .p-panel__content .p-list-tree").first();
const pages = tree.locator(".p-list-tree__item");
const pageCount = await pages.count();
expect(pageCount).toBeGreaterThan(0);
}
}
});
});
40 changes: 14 additions & 26 deletions tests/project.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { test, expect, APIRequestContext } from "@playwright/test";
import { config } from "./config";
import type { IJiraTask } from "@/services/api/types/pages";
import { removeWebpage, selectTreeView } from "./utils/common";

const JIRA_TASKS: IJiraTask[] = [];
let apiContext: APIRequestContext;
Expand All @@ -13,45 +14,29 @@ test.describe("Test project actions", () => {
});

test.beforeEach(async ({ page }) => {
await page.addInitScript(() => {
window.__E2E_TESTING__ = true;
});

await page.setExtraHTTPHeaders({
"X-JIRA-REPORTER-ID": process.env.JIRA_REPORTER_ID || "",
});
await page.goto(`${config.BASE_URL}/app`);

// select tree view
await page.locator(".l-navigation__drawer .p-panel__content .p-side-navigation__link").nth(1).click();
});

test("remove page", async ({ page }) => {
await selectTreeView(page);
const tree = page.locator(".l-navigation__drawer .p-panel__content .p-list-tree").first();
const child = tree.locator(".p-list-tree__item").first();
await child.click();
await expect(page.getByRole("heading", { name: /Title/i })).toBeVisible();
page.getByRole("button", { name: /Request removal/i }).click();
const modal = page.locator(".p-modal").first();
await expect(modal).toBeVisible();
await expect(page.getByRole("heading", { name: /Submit request for page removal/i })).toBeVisible();
await modal.locator('input[type="date"]').fill(new Date().toISOString().split("T")[0]);
const checkboxes = await page.locator("input[type='checkbox'][required]");
if (checkboxes) {
const checkboxCount = await checkboxes.count();
for (let i = 0; i < checkboxCount; i++) {
await checkboxes.nth(i).check();
}
}

const responsePromise = page.waitForResponse((response) => response.url().includes("request-removal"));
await modal.getByRole("button", { name: /Submit/i }).click();
const response = await responsePromise;

if (response.status() === 200) {
const responseBody = await response.json();
if (responseBody.jira_task_id) {
JIRA_TASKS.push(responseBody.jira_task_id);
}
}

await expect(page.locator(".l-notification__container .p-notification--negative")).not.toBeVisible();
await removeWebpage(page, JIRA_TASKS);
});

test("request page changes", async ({ page }) => {
await selectTreeView(page);
const tree = page.locator(".l-navigation__drawer .p-panel__content .p-list-tree").first();
const child = tree.locator(".p-list-tree__item").first();
await child.click();
Expand Down Expand Up @@ -84,6 +69,7 @@ test.describe("Test project actions", () => {
});

test("create new page", async ({ page }) => {
await selectTreeView(page);
await page.getByRole("button", { name: /Request new page/i }).click();
await expect(page.getByRole("heading", { name: /New page/i })).toBeVisible();
await page.locator("input[aria-labelledby='url-title']").fill(config.PLAYWRIGHT_TEST_PAGE_URL);
Expand Down Expand Up @@ -131,6 +117,8 @@ test.describe("Test project actions", () => {
}

await expect(page.locator(".l-notification__container .p-notification--negative")).not.toBeVisible();
await page.waitForTimeout(5000);
await removeWebpage(page, JIRA_TASKS);
});

test.afterAll(async () => {
Expand Down
47 changes: 47 additions & 0 deletions tests/utils/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Page, expect } from "@playwright/test";

export async function removeWebpage(page: Page, JIRA_TASKS: string[]): Promise<void> {
page.getByRole("button", { name: /Request removal/i }).click();
const modal = page.locator(".p-modal").first();
await expect(modal).toBeVisible();
await expect(page.getByRole("heading", { name: /Submit request for page removal/i })).toBeVisible();
await modal.locator('input[type="date"]').fill(new Date().toISOString().split("T")[0]);
const checkboxes = await page.locator("input[type='checkbox'][required]");
if (checkboxes) {
const checkboxCount = await checkboxes.count();
for (let i = 0; i < checkboxCount; i++) {
await checkboxes.nth(i).check();
}
}

const responsePromise = page.waitForResponse((response) => response.url().includes("request-removal"));
await modal.getByRole("button", { name: /Submit/i }).click();
const response = await responsePromise;

if (response.status() === 200) {
const responseBody = await response.json();
if (responseBody.jira_task_id) {
JIRA_TASKS.push(responseBody.jira_task_id);
}
}

await expect(page.locator(".l-notification__container .p-notification--negative")).not.toBeVisible();
}

export async function selectTableView(page: Page): Promise<void> {
const tableViewListItem = page.locator(".l-navigation__drawer .p-panel__content .p-side-navigation__link", {
hasText: /Table view/i,
});
await tableViewListItem.click();

await page.getByText("/Loading projects. Please wait./i").waitFor({ state: "detached" });
}

export async function selectTreeView(page: Page): Promise<void> {
const treeViewListItem = page.locator(".l-navigation__drawer .p-panel__content .p-side-navigation__link", {
hasText: /Tree view/i,
});
await treeViewListItem.click();

await page.getByText("/Loading.../i").waitFor({ state: "detached" });
}
43 changes: 43 additions & 0 deletions tests/views/table-view.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { test, expect } from "@playwright/test";
import { config } from "../config";
import { selectTableView } from "../utils/common";

test.beforeEach(async ({ page }) => {
await page.goto(`${config.BASE_URL}/app`);
});

test.describe("Test Table View", () => {
test("table view is visible", async ({ page }) => {
await selectTableView(page);
// expect a page showing all the projects in an accordion
expect(page.getByRole("heading", { name: /All pages/i })).toBeVisible();
const projects = page.locator(".p-accordion__list .p-accordion__group");
const projectCount = await projects.count();
expect(projectCount).toBeGreaterThan(0);

// check all projects have pages
for (let i = 0; i < projectCount; i++) {
const project = projects.nth(i);
const projectHeading = project.locator(".p-accordion__heading");
const projectPageCount = await projectHeading.locator(".p-badge").innerText();
expect(parseInt(projectPageCount)).toBeGreaterThan(1);

// select each project
await project.click();

// select a random page
const pages = project.locator(".p-accordion__panel table tbody tr");
const pagesCount = await pages.count();
const selectedPage = project
.locator(".p-accordion__panel table tbody tr")
.nth(Math.floor(Math.random() * pagesCount));
await selectedPage.locator(".p-button--link").first().click();

// check the page details are visible
await expect(page.getByText(/Description/i).first()).toBeVisible();

// click the back button
await page.getByRole("button", { name: /Back/i }).click();
}
});
});
Loading