Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 2 additions & 6 deletions tests/hash-playwright/tests/features/inbox-page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
systemEntityTypes,
systemLinkEntityTypes,
} from "@local/hash-isomorphic-utils/ontology-type-ids";
import { sleep } from "@local/hash-isomorphic-utils/sleep";

import { createEntity, getUser } from "../shared/api-queries";
import { expect, test } from "../shared/runtime";
Expand Down Expand Up @@ -102,7 +101,6 @@ const createNotification = async ({

test("new notifications are shown on notifications page", async ({ page }) => {
await page.goto("/");
test.setTimeout(60_000);

await expect(page.locator("text=Get support")).toBeVisible();

Expand All @@ -123,8 +121,7 @@ test("new notifications are shown on notifications page", async ({ page }) => {
targetEntityTitle: draftNotificationTitle,
});

/** Wait for the notification poll interval to expire */
await sleep(12_000);
await page.reload();

await expect(page.locator(`text=${draftNotificationTitle}`)).toBeVisible();

Expand All @@ -141,8 +138,7 @@ test("new notifications are shown on notifications page", async ({ page }) => {
targetEntityTitle: nonDraftNotificationTitle,
});

/** Wait for the notification poll interval to expire */
await sleep(12_000);
await page.reload();

await expect(page.locator(`text=${nonDraftNotificationTitle}`)).toBeVisible();
});
93 changes: 59 additions & 34 deletions tests/hash-playwright/tests/features/page-creation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// import { blockProtocolHubOrigin } from "@local/hash-isomorphic-utils/blocks";
import { sleep } from "@local/hash-isomorphic-utils/sleep";

import { openHomeReadyToCreatePage } from "../shared/open-home-ready-to-create-page";
import { expect, test } from "../shared/runtime";

import type { Response } from "../shared/runtime";

const pageNameSuffix = Date.now();
const pageNameFallback = "Untitled";

Expand All @@ -13,26 +14,52 @@ const placeholderSelector =
"text=Type / to browse blocks, or @ to browse entities";
const modifierKey = process.platform === "darwin" ? "Meta" : "Control";

const isBlockCollectionSaveWithBlockCount = async (
response: Response,
blockCount: number,
) => {
if (
!response.url().includes("/graphql") ||
!(response.request().postData() ?? "").includes(
"updateBlockCollectionContents",
)
) {
return false;
}

const body = (await response.json()) as {
data?: {
updateBlockCollectionContents?: {
blockCollection: { contents: unknown[] };
};
};
};

return (
body.data?.updateBlockCollectionContents?.blockCollection.contents
.length === blockCount
);
};

// @todo fix this test
test.skip("user can create page", async ({ page }) => {
await page.goto("/");
await openHomeReadyToCreatePage(page);
await page.waitForURL("/");
await expect(page.locator("text=Get support")).toBeVisible();

// TODO: investigate why delay is required for create page button to work
await sleep(500);
const listOfPages = page.locator(listOfPagesSelector);

await page.locator(createPageButtonSelector).click();

await page.waitForURL((url) => !!url.pathname.match(/^\/@[\w-]+\/[\w-]+$/));

const blockRegion = page.locator("#root");
const listOfPages = page.locator(listOfPagesSelector);
const blockHandles = blockRegion.locator('[data-testid="block-handle"]');
const hardBreaks = blockRegion.locator("br:not(.ProseMirror-trailingBreak)");

// Wait for ProseMirror to load
// TODO: investigate why page renaming before block loading is unstable
await expect(blockRegion.locator('[data-testid="block-handle"]')).toHaveCount(
1,
);
await expect(blockHandles).toHaveCount(1);
await expect(listOfPages).toContainText(pageNameFallback);

// Type in a paragraph block
Expand All @@ -47,13 +74,14 @@ test.skip("user can create page", async ({ page }) => {
await page.keyboard.press(`${modifierKey}+i`);

// Insert a divider
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(blockRegion.locator("em")).toHaveText("italics");
await page.keyboard.press("Enter");
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(blockHandles).toHaveCount(2);
await page.keyboard.type("/divider");
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(
page.getByRole("listitem").filter({ hasText: /divider/i }),
).toBeVisible();
await page.keyboard.press("Enter");
await sleep(100); // TODO: investigate flakiness in FF and Webkit

// Wait for divider block to load
await expect(blockRegion).not.toContainText("Loading...", {
Expand All @@ -64,18 +92,18 @@ test.skip("user can create page", async ({ page }) => {
// TODO: Move the cursor below the new divider and update the test?

// Insert a paragraph creation with newlines
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(blockHandles).toHaveCount(3);
await page.keyboard.type("Second paragraph");
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(blockRegion).toContainText("Second paragraph");
await page.keyboard.press("Shift+Enter");
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(hardBreaks).toHaveCount(1);
await page.keyboard.press("Shift+Enter");
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(hardBreaks).toHaveCount(2);
await page.keyboard.type("with");
await page.keyboard.press("Shift+Enter");
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(hardBreaks).toHaveCount(3);
await page.keyboard.type("line breaks");
await sleep(100); // TODO: investigate flakiness in FF and Webkit
await expect(blockRegion).toContainText("line breaks");

// Expect just inserted content to be present on the page
await expect(blockRegion).toContainText(
Expand All @@ -85,16 +113,15 @@ test.skip("user can create page", async ({ page }) => {
);

// Check number of blocks
await expect(blockRegion.locator('[data-testid="block-handle"]')).toHaveCount(
3,
await expect(blockHandles).toHaveCount(3);

const finalSave = page.waitForResponse((response) =>
isBlockCollectionSaveWithBlockCount(response, 4),
);

await page.keyboard.press("Enter");
await sleep(100); // TODO: investigate flakiness in FF and Webkit

await expect(blockRegion.locator('[data-testid="block-handle"]')).toHaveCount(
4,
);
await expect(blockHandles).toHaveCount(4);

const blockChanger = blockRegion
.locator('[data-testid="block-changer"]')
Expand Down Expand Up @@ -125,8 +152,7 @@ test.skip("user can create page", async ({ page }) => {
// blockRegion.locator(`[data-testid="block"]:nth-child(3) p`),
// ).toHaveCount(0);
//
// Give collab some time to sync data
await sleep(2000);
await finalSave;

// Check content stability after page reload
await page.reload();
Expand Down Expand Up @@ -156,16 +182,15 @@ test.skip("user can create page", async ({ page }) => {

// @todo fix this test
test.skip("user can rename page", async ({ page }) => {
await page.goto("/");
await openHomeReadyToCreatePage(page);
const pageName1 = `Page ${pageNameSuffix}`;
const pageName2 = `Page 2 ${pageNameSuffix}`;
// TODO: investigate why delay is required for create page button to work
await sleep(500);
const listOfPages = page.locator(listOfPagesSelector);

await page.locator(createPageButtonSelector).click();

await page.waitForURL((url) => !!url.pathname.match(/^\/@[\w-]+\/[\w-]+$/));

const listOfPages = page.locator(listOfPagesSelector);
const pageTitle = page.locator(pageTitleInputSelector);

// Change page name (using Enter)
Expand All @@ -175,19 +200,19 @@ test.skip("user can rename page", async ({ page }) => {
await expect(listOfPages).toContainText(pageName2);

// Revert page name change (using Tab)
await sleep(500); // TODO: Investigate why delay is required for <PageTitle /> state to work
await expect(page).toHaveTitle(`${pageName2} | HASH`);
await pageTitle.fill(pageName1);
await pageTitle.press("Tab");
await expect(listOfPages).toContainText(pageName1);

// Change page name (by clicking outside)
await sleep(500); // TODO: Investigate why delay is required for <PageTitle /> state to work
await expect(page).toHaveTitle(`${pageName1} | HASH`);
await pageTitle.fill(pageName2);
await page.click("main");
await expect(listOfPages).toContainText(pageName2);

// Revert page name change (using Esc)
await sleep(500); // TODO: Investigate why delay is required for <PageTitle /> state to work
await expect(page).toHaveTitle(`${pageName2} | HASH`);
await pageTitle.fill(pageName1);
await pageTitle.press("Escape");
await expect(listOfPages).not.toContainText(pageName2);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { sleep } from "@local/hash-isomorphic-utils/sleep";

import { openHomeReadyToCreatePage } from "../shared/open-home-ready-to-create-page";
import { expect, test } from "../shared/runtime";

const placeholderSelector =
Expand All @@ -12,8 +11,7 @@ const placeholderSelector =
test.skip("user can view page in read-only mode but not update", async ({
page,
}) => {
// TODO: investigate why delay is required for create page button to work
await sleep(500);
await openHomeReadyToCreatePage(page);
await page.locator('[data-testid="create-page-btn"]').click();

await page.waitForURL((url) => !!url.pathname.match(/^\/@[\w-]+\/[\w-]+$/));
Expand Down
33 changes: 22 additions & 11 deletions tests/hash-playwright/tests/features/profile-page.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
// eslint-disable-next-line no-restricted-imports
import { test as testTolerateConsoleErrors } from "@playwright/test";

import { sleep } from "@local/hash-isomorphic-utils/sleep";

import { expect } from "../shared/runtime";

import type { Page } from "../shared/runtime";

testTolerateConsoleErrors.beforeEach(async () => {});

const blockCollectionMountTimeout = 5_000;
const placeholderSelector =
"text=Type / to browse blocks, or @ to browse entities";

const waitForBioSave = (page: Page, bioText: string) =>
page.waitForResponse((response) => {
const postData = response.request().postData() ?? "";

return (
response.url().includes("/graphql") &&
postData.includes("updateBlockCollectionContents") &&
postData.includes(bioText)
);
});

/**
* @todo H-2006 fix bugs on profile page and revert to using 'test' from ./shared/runtime
Expand All @@ -23,20 +35,19 @@ testTolerateConsoleErrors.skip(

await page.click("text=Add a bio for Alice...");

await sleep(blockCollectionMountTimeout);
await expect(page.locator(placeholderSelector)).toBeVisible();

const bioText = "Alice's bio";
const bioSaved = waitForBioSave(page, bioText);

await page.keyboard.type(bioText);

await page.click("[aria-label='Save Bio']");

await sleep(2_000);
await bioSaved;

await page.reload();

await sleep(2_000);

await expect(page.locator("text=@alice")).toBeVisible();
await expect(page.locator(`text=${bioText}`)).toBeVisible();
},
Expand All @@ -56,19 +67,19 @@ testTolerateConsoleErrors.skip(

await page.click("text=Add a bio for Example...");

await sleep(blockCollectionMountTimeout);
await expect(page.locator(placeholderSelector)).toBeVisible();

const bioText = "Example Org's bio";
const bioSaved = waitForBioSave(page, bioText);

await page.keyboard.type(bioText);

await page.click("[aria-label='Save Bio']");

await sleep(2_000);
await bioSaved;

await page.reload();

await sleep(2_000);

await expect(page.locator("text=@example-org")).toBeVisible();
await expect(page.locator(`text=${bioText}`)).toBeVisible();
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { extractWebIdFromEntityId } from "@blockprotocol/type-system";
import { systemEntityTypes } from "@local/hash-isomorphic-utils/ontology-type-ids";

import { getUser } from "./api-queries";
import { expect } from "./runtime";

import type { Page } from "./runtime";

/**
* Open the home page and wait until the sidebar's create-page button will
* navigate to the page it creates. `useCreatePage` only navigates once the
* web owner's shortname has been fetched, and nothing in the sidebar renders
* from that query, so wait for its response as well as for the page list.
*/
export const openHomeReadyToCreatePage = async (page: Page) => {
const user = await getUser(page.request);
if (!user) {
throw new Error("Cannot create a page without an authenticated user");
}

const webId = extractWebIdFromEntityId(user.metadata.recordId.entityId);

const webOwnerFetched = page.waitForResponse((response) => {
const postData = response.request().postData() ?? "";

return (
response.url().includes("/graphql") &&
postData.includes("queryEntitySubgraph") &&
postData.includes(`{"path":["uuid"]},{"parameter":"${webId}"}`) &&
postData.includes(systemEntityTypes.user.entityTypeBaseUrl) &&
postData.includes('"traversalPaths":[]')
);
});

await page.goto("/");
await webOwnerFetched;
await expect(page.getByTestId("pages-tree")).toBeAttached();
};
Loading