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
53 changes: 51 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ shift-backends = { path = "crates/shift-backends" }
shift-bridge = { path = "crates/shift-bridge" }
shift-font = { path = "crates/shift-font" }
shift-slug = { path = "crates/shift-slug" }
shift-specimen = { path = "crates/shift-specimen" }
shift-store = { path = "crates/shift-store" }
shift-workspace = { path = "crates/shift-workspace" }

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified apps/desktop/e2e/__screenshots__/tools.spec.ts/tool-pen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion apps/desktop/e2e/application-menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const convertiblePreviewTest = launcherTest.extend({

async function openSelectedPreview(page: Page, electronApp: ElectronApplication): Promise<Page> {
const workspaceWindow = electronApp.waitForEvent("window");
await page.getByRole("button", { name: /Load font/ }).click();
await page.getByRole("button", { name: "Open Font…", exact: true }).click();

const workspacePage = await workspaceWindow;
await workspacePage.waitForURL(/#\/home$/);
Expand Down
10 changes: 5 additions & 5 deletions apps/desktop/e2e/document-lifecycle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ const failedPreviewSaveTest = convertiblePreviewTest.extend({

async function openSelectedPreview(page: Page, electronApp: ElectronApplication): Promise<Page> {
const workspaceWindow = electronApp.waitForEvent("window");
await page.getByRole("button", { name: /Load font/ }).click();
await page.getByRole("button", { name: "Open Font…", exact: true }).click();

const workspacePage = await workspaceWindow;
await workspacePage.waitForURL(/#\/home$/);
Expand Down Expand Up @@ -216,7 +216,7 @@ test.describe("unsupported file activation", () => {
test.use({ electronArgs: [path.join(path.dirname(FONT_PATH), "ignored.txt")] });

test("keeps the launcher for unsupported extensions", async ({ electronApp, page }) => {
await expect(page.getByRole("button", { name: /Load font/ })).toBeVisible();
await expect(page.getByRole("button", { name: "Open Font…", exact: true })).toBeVisible();
await expect(page).toHaveURL(/#\/launcher$/);
expect(electronApp.windows()).toHaveLength(1);
});
Expand Down Expand Up @@ -436,7 +436,7 @@ convertiblePreviewTest(
const launcherPage = await relaunchedApp.firstWindow();
await launcherPage.waitForURL(/#\/launcher$/);
const reopenedWindow = relaunchedApp.waitForEvent("window");
await launcherPage.getByRole("button", { name: /Load font/ }).click();
await launcherPage.getByRole("button", { name: "Open Font…", exact: true }).click();
const reopenedPage = await reopenedWindow;
await waitForWorkspaceReady(reopenedPage);

Expand Down Expand Up @@ -576,7 +576,7 @@ test.describe("document lifecycle through the application shell", () => {
await launcherPage.waitForURL(/#\/launcher$/);

const reopenedWindow = relaunchedApp.waitForEvent("window");
await launcherPage.getByRole("button", { name: /Load font/ }).click();
await launcherPage.getByRole("button", { name: "Open Font…", exact: true }).click();
const reopenedPage = await reopenedWindow;
await reopenedPage.waitForURL(/#\/home$/);
await expect(reopenedPage.getByLabel("Glyph catalog", { exact: true })).toBeVisible();
Expand Down Expand Up @@ -702,7 +702,7 @@ discardTest(
const launcherPage = await relaunchedApp.firstWindow();
await launcherPage.waitForURL(/#\/launcher$/);
const reopenedWindow = relaunchedApp.waitForEvent("window");
await launcherPage.getByRole("button", { name: /Load font/ }).click();
await launcherPage.getByRole("button", { name: "Open Font…", exact: true }).click();
const reopenedPage = await reopenedWindow;
await waitForWorkspaceReady(reopenedPage);

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/e2e/fixtures/documentLifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { waitForWorkspaceReady } from "./electronApp";

export async function createNewFont(page: Page, electronApp: ElectronApplication): Promise<Page> {
const workspaceWindow = electronApp.waitForEvent("window");
await page.getByRole("button", { name: "New font", exact: true }).click();
await page.getByRole("button", { name: "New Font", exact: true }).click();

const workspacePage = await workspaceWindow;
await waitForWorkspaceReady(workspacePage);
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/e2e/handle-styling.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ previewTest(
"TTF source handles keep source styling without becoming hoverable",
async ({ page, electronApp }) => {
const workspaceWindow = electronApp.waitForEvent("window");
await page.getByRole("button", { name: /Load font/ }).click();
await page.getByRole("button", { name: "Open Font…", exact: true }).click();
const workspacePage = await workspaceWindow;
await workspacePage.waitForURL(/#\/home$/);
await clickFirstCatalogGlyph(workspacePage);
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/e2e/landing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ test.describe("Landing view", () => {
test("creates an editable font through New font", async ({ electronApp, page }) => {
const workspaceWindow = electronApp.waitForEvent("window");

await page.getByRole("button", { name: "New font", exact: true }).click();
await page.getByRole("button", { name: "New Font", exact: true }).click();

const workspacePage = await workspaceWindow;
await workspacePage.waitForURL(/#\/home$/);
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/e2e/platform-integration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ async function reopenAndVerify(
const launcherPage = await relaunchedApp.firstWindow();
await launcherPage.waitForURL(/#\/launcher$/);
const workspaceWindow = relaunchedApp.waitForEvent("window");
await launcherPage.getByRole("button", { name: /Load font/ }).click();
await launcherPage.getByRole("button", { name: "Open Font…", exact: true }).click();
const workspacePage = await workspaceWindow;
await waitForWorkspaceReady(workspacePage);
const editor = new EditorDriver(workspacePage);
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/e2e/preview-notice.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const test = documentTest.extend({

test("read-only preview notice matches snapshot", async ({ electronApp, page }) => {
const workspaceWindow = electronApp.waitForEvent("window");
await page.getByRole("button", { name: /Load font/ }).click();
await page.getByRole("button", { name: "Open Font…", exact: true }).click();
const workspacePage = await workspaceWindow;
await expect(workspacePage.getByLabel("Glyph catalog", { exact: true })).toBeVisible();
await expect.poll(() => workspacePage.evaluate(() => window.shiftSession?.mode)).toBe("preview");
Expand Down
92 changes: 92 additions & 0 deletions apps/desktop/e2e/recent-files.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type { ElectronApplication, Page } from "@playwright/test";
import { documentTest, expect, FONT_PATH } from "./fixtures/electronApp";

const test = documentTest.extend({
openFontPath: FONT_PATH,
});

const FONT_NAME = "MutatorSans.ttf";

async function openFontFromLauncher(page: Page, electronApp: ElectronApplication): Promise<Page> {
const workspaceWindow = electronApp.waitForEvent("window");
await page.getByRole("button", { name: "Open Font…", exact: true }).click();

const workspacePage = await workspaceWindow;
await workspacePage.waitForURL(/#\/home$/);
await expect(workspacePage.getByLabel("Glyph catalog", { exact: true })).toBeVisible();
return workspacePage;
}

function recentFile(launcher: Page) {
return launcher
.getByRole("list", { name: "Recent files" })
.getByRole("listitem")
.filter({ hasText: FONT_NAME });
}

test("a font opened once is listed in Recent files after relaunch and reopens from its card", async ({
electronApp,
page,
relaunch,
}) => {
await openFontFromLauncher(page, electronApp);
await electronApp.close();

const restarted = await relaunch();
const launcher = await restarted.firstWindow();
await launcher.waitForURL(/#\/launcher$/);
await expect(recentFile(launcher)).toHaveCount(1);
// MutatorSans has capitals only, so its thumbnail specimen is "AG".
await expect(recentFile(launcher)).toHaveAttribute("data-specimen-text", "AG");

const workspaceWindow = restarted.waitForEvent("window");
await recentFile(launcher)
.getByRole("button", { name: new RegExp(FONT_NAME) })
.click();
const workspacePage = await workspaceWindow;
await workspacePage.waitForURL(/#\/home$/);
await expect.poll(() => workspacePage.evaluate(() => window.shiftSession?.mode)).toBe("preview");
});

test("removing a recent file can be undone from the toast", async ({
electronApp,
page,
relaunch,
}) => {
await openFontFromLauncher(page, electronApp);
await electronApp.close();

const restarted = await relaunch();
const launcher = await restarted.firstWindow();
await expect(recentFile(launcher)).toHaveCount(1);

await recentFile(launcher).getByRole("button", { name: "More actions" }).click();
await launcher.getByRole("menuitem", { name: "Remove from Recents" }).click();
await expect(recentFile(launcher)).toHaveCount(0);

await launcher.getByRole("button", { name: "Undo", exact: true }).click();
await expect(recentFile(launcher)).toHaveCount(1);
});

test("File › Open Recent lists opened fonts and clears them", async ({ electronApp, page }) => {
await openFontFromLauncher(page, electronApp);

const openRecentLabels = () =>
electronApp.evaluate(({ Menu }) => {
const file = Menu.getApplicationMenu()?.items.find((item) => item.label === "File");
const openRecent = file?.submenu?.items.find((item) => item.label === "Open Recent");
return openRecent?.submenu?.items.map((item) => item.label) ?? null;
});

await expect.poll(openRecentLabels).toEqual([FONT_NAME, "", "Clear Menu"]);

await electronApp.evaluate(({ Menu }) => {
const file = Menu.getApplicationMenu()?.items.find((item) => item.label === "File");
const openRecent = file?.submenu?.items.find((item) => item.label === "Open Recent");
const clear = openRecent?.submenu?.items.find((item) => item.label === "Clear Menu");
if (!clear) throw new Error("Missing Clear Menu item");
clear.click();
});

await expect.poll(openRecentLabels).toEqual(["Clear Menu"]);
});
13 changes: 8 additions & 5 deletions apps/desktop/e2e/window-behavior.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import { runCommand } from "./fixtures/documentLifecycle";
// Window behavior must be observed before visual normalization changes native geometry.
test.use({ windowSizing: "native" });

test("opens the launcher at its compact native size", async ({ electronApp, page }) => {
await expect(page.getByRole("button", { name: "New font", exact: true })).toBeVisible();
test("opens the launcher at 960×720, within 90% of the screen", async ({ electronApp, page }) => {
await expect(page.getByRole("button", { name: "New Font", exact: true })).toBeVisible();
const browserWindow = await electronApp.browserWindow(page);
const workArea = await electronApp.evaluate(({ screen }) => screen.getPrimaryDisplay().workArea);
const expected = [
Math.min(960, Math.round(workArea.width * 0.9)),
Math.min(720, Math.round(workArea.height * 0.9)),
];

try {
await expect
.poll(() => browserWindow.evaluate((window) => window.getSize()))
.toEqual([800, 600]);
await expect.poll(() => browserWindow.evaluate((window) => window.getSize())).toEqual(expected);
} finally {
await browserWindow.dispose();
}
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const PLATFORM_SPECS = [
"document-lifecycle.spec.ts",
"document-recovery.spec.ts",
"platform-integration.spec.ts",
"recent-files.spec.ts",
"variable-font-recovery.spec.ts",
"window-behavior.spec.ts",
"window-isolation.spec.ts",
Expand Down
Loading
Loading