From fe1e3bb84763f973ff5629b0ad00aa20b3a6817a Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Sat, 19 Jul 2025 11:01:57 +0500 Subject: [PATCH] desktop: migrate tests to vitest 3 --- apps/desktop/__tests__/auto-updates.test.ts | 348 ++++++++++---------- apps/desktop/__tests__/launch.test.ts | 30 +- apps/desktop/__tests__/utils.ts | 45 +-- 3 files changed, 212 insertions(+), 211 deletions(-) diff --git a/apps/desktop/__tests__/auto-updates.test.ts b/apps/desktop/__tests__/auto-updates.test.ts index ef36cbc37..cab7a2ca0 100644 --- a/apps/desktop/__tests__/auto-updates.test.ts +++ b/apps/desktop/__tests__/auto-updates.test.ts @@ -17,214 +17,210 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -import { test } from "vitest"; -import { harness } from "./utils.js"; +import { test, testCleanup } from "./utils.js"; import { writeFile } from "fs/promises"; import { Page } from "playwright"; import { gt, lt } from "semver"; +import { describe } from "vitest"; -test("update starts downloading if version is outdated", async (t) => { - await harness( - t, - async ({ page }) => { - await page.waitForSelector("#authForm"); +test("update starts downloading if version is outdated", async ({ + ctx: { page }, + expect, + onTestFinished +}) => { + onTestFinished(testCleanup); - t.expect( - await page.getByRole("button", { name: "Create account" }).isVisible() - ).toBe(true); + await page.waitForSelector("#authForm"); + expect( + await page.getByRole("button", { name: "Create account" }).isVisible() + ).toBe(true); - await page - .getByRole("button", { name: "Skip & go directly to the app" }) - .click(); + await page + .getByRole("button", { name: "Skip & go directly to the app" }) + .click(); - await skipDialog(page); + await skipDialog(page); - await page.waitForSelector(".ProseMirror"); + await page.waitForSelector(".ProseMirror"); - await page - .locator(".theme-scope-statusBar") - .getByRole("button", { name: /updating/i }) - .waitFor({ state: "attached" }); - }, - { version: "3.0.0" } - ); + await page + .locator(".theme-scope-statusBar") + .getByRole("button", { name: /updating/i }) + .waitFor({ state: "attached" }); }); -test("update is only shown if version is outdated and auto updates are disabled", async (t) => { - await harness( - t, - async (ctx) => { - await ctx.app.close(); - await writeFile( - ctx.configPath, - JSON.stringify({ - automaticUpdates: false - }) - ); +test("update is only shown if version is outdated and auto updates are disabled", async ({ + ctx, + expect, + onTestFinished +}) => { + onTestFinished(testCleanup); - await ctx.relaunch(); + await ctx.app.close(); + await writeFile( + ctx.configPath, + JSON.stringify({ + automaticUpdates: false + }) + ); - const { page } = ctx; + await ctx.relaunch(); - await page.waitForSelector("#authForm"); + const { page } = ctx; - t.expect( - await page.getByRole("button", { name: "Create account" }).isVisible() - ).toBe(true); + await page.waitForSelector("#authForm"); - await page - .getByRole("button", { name: "Skip & go directly to the app" }) - .click(); + expect( + await page.getByRole("button", { name: "Create account" }).isVisible() + ).toBe(true); - await skipDialog(page); + await page + .getByRole("button", { name: "Skip & go directly to the app" }) + .click(); - await page.waitForSelector(".ProseMirror"); + await skipDialog(page); + await page.waitForSelector(".ProseMirror"); + + await page + .locator(".theme-scope-statusBar") + .getByRole("button", { name: /available/i }) + .waitFor({ state: "attached" }); +}); + +describe("update to stable if it is newer", () => { + test.scoped({ options: { version: "3.0.0-beta.0" } }); + test("test", async ({ ctx, expect, onTestFinished }) => { + onTestFinished(testCleanup); + + await ctx.app.close(); + await writeFile( + ctx.configPath, + JSON.stringify({ + automaticUpdates: false, + releaseTrack: "beta" + }) + ); + + await ctx.relaunch(); + + const { page } = ctx; + + await page.waitForSelector("#authForm"); + + expect( + await page.getByRole("button", { name: "Create account" }).isVisible() + ).toBe(true); + + await page + .getByRole("button", { name: "Skip & go directly to the app" }) + .click(); + + await skipDialog(page); + + await page.waitForSelector(".ProseMirror"); + + const updateButton = page + .locator(".theme-scope-statusBar") + .getByRole("button", { name: /available/i }); + await updateButton.waitFor({ state: "visible" }); + const content = await updateButton.textContent(); + const version = content?.split(" ")?.[0] || ""; + expect(gt(version, "3.0.0-beta.0")).toBe(true); + }); +}); + +describe("update is not available if it latest stable version is older", () => { + test.scoped({ options: { version: "99.0.0-beta.0" } }); + test("test", async ({ ctx, expect, onTestFinished }) => { + onTestFinished(testCleanup); + + await ctx.app.close(); + await writeFile( + ctx.configPath, + JSON.stringify({ + automaticUpdates: false, + releaseTrack: "beta" + }) + ); + + await ctx.relaunch(); + + const { page } = ctx; + + await page.waitForSelector("#authForm"); + + expect( + await page.getByRole("button", { name: "Create account" }).isVisible() + ).toBe(true); + + await page + .getByRole("button", { name: "Skip & go directly to the app" }) + .click(); + + await skipDialog(page); + + await page.waitForSelector(".ProseMirror"); + + await page + .locator(".theme-scope-statusBar") + .getByRole("button", { name: /checking for updates/i }) + .waitFor({ state: "hidden" }); + + expect( await page .locator(".theme-scope-statusBar") .getByRole("button", { name: /available/i }) - .waitFor({ state: "attached" }); - }, - { version: "3.0.0" } - ); + .isHidden() + ).toBe(true); + }); }); -test("update to stable if it is newer", async (t) => { - await harness( - t, - async (ctx) => { - await ctx.app.close(); - await writeFile( - ctx.configPath, - JSON.stringify({ - automaticUpdates: false, - releaseTrack: "beta" - }) - ); +describe("downgrade to stable on switching to stable release track", () => { + test.scoped({ options: { version: "99.0.0-beta.0" } }); + test("test", async ({ ctx, expect, onTestFinished }) => { + onTestFinished(testCleanup); - await ctx.relaunch(); + await ctx.app.close(); + await writeFile( + ctx.configPath, + JSON.stringify({ + automaticUpdates: false, + releaseTrack: "stable" + }) + ); - const { page } = ctx; + await ctx.relaunch(); - await page.waitForSelector("#authForm"); + const { page } = ctx; - t.expect( - await page.getByRole("button", { name: "Create account" }).isVisible() - ).toBe(true); + await page.waitForSelector("#authForm"); - await page - .getByRole("button", { name: "Skip & go directly to the app" }) - .click(); + expect( + await page.getByRole("button", { name: "Create account" }).isVisible() + ).toBe(true); - await skipDialog(page); + await page + .getByRole("button", { name: "Skip & go directly to the app" }) + .click(); - await page.waitForSelector(".ProseMirror"); + await skipDialog(page); - const updateButton = page - .locator(".theme-scope-statusBar") - .getByRole("button", { name: /available/i }); - await updateButton.waitFor({ state: "visible" }); - const content = await updateButton.textContent(); - const version = content?.split(" ")?.[0] || ""; - t.expect(gt(version, "3.0.0-beta.0")).toBe(true); - }, - { version: "3.0.0-beta.0" } - ); -}); + await page.waitForSelector(".ProseMirror"); -test("update is not available if it latest stable version is older", async (t) => { - await harness( - t, - async (ctx) => { - await ctx.app.close(); - await writeFile( - ctx.configPath, - JSON.stringify({ - automaticUpdates: false, - releaseTrack: "beta" - }) - ); + await page + .locator(".theme-scope-statusBar") + .getByRole("button", { name: /checking for updates/i }) + .waitFor({ state: "hidden" }); - await ctx.relaunch(); - - const { page } = ctx; - - await page.waitForSelector("#authForm"); - - t.expect( - await page.getByRole("button", { name: "Create account" }).isVisible() - ).toBe(true); - - await page - .getByRole("button", { name: "Skip & go directly to the app" }) - .click(); - - await skipDialog(page); - - await page.waitForSelector(".ProseMirror"); - - await page - .locator(".theme-scope-statusBar") - .getByRole("button", { name: /checking for updates/i }) - .waitFor({ state: "hidden" }); - - t.expect( - await page - .locator(".theme-scope-statusBar") - .getByRole("button", { name: /available/i }) - .isHidden() - ).toBe(true); - }, - { version: "99.0.0-beta.0" } - ); -}); - -test("downgrade to stable on switching to stable release track", async (t) => { - await harness( - t, - async (ctx) => { - await ctx.app.close(); - await writeFile( - ctx.configPath, - JSON.stringify({ - automaticUpdates: false, - releaseTrack: "stable" - }) - ); - - await ctx.relaunch(); - - const { page } = ctx; - - await page.waitForSelector("#authForm"); - - t.expect( - await page.getByRole("button", { name: "Create account" }).isVisible() - ).toBe(true); - - await page - .getByRole("button", { name: "Skip & go directly to the app" }) - .click(); - - await skipDialog(page); - - await page.waitForSelector(".ProseMirror"); - - await page - .locator(".theme-scope-statusBar") - .getByRole("button", { name: /checking for updates/i }) - .waitFor({ state: "hidden" }); - - const updateButton = page - .locator(".theme-scope-statusBar") - .getByRole("button", { name: /available/i }); - await updateButton.waitFor({ state: "visible" }); - const content = await updateButton.textContent(); - const version = content?.split(" ")?.[0] || ""; - t.expect(lt(version, "99.0.0-beta.0")).toBe(true); - }, - { version: "99.0.0-beta.0" } - ); + const updateButton = page + .locator(".theme-scope-statusBar") + .getByRole("button", { name: /available/i }); + await updateButton.waitFor({ state: "visible" }); + const content = await updateButton.textContent(); + const version = content?.split(" ")?.[0] || ""; + expect(lt(version, "99.0.0-beta.0")).toBe(true); + }); }); async function skipDialog(page: Page) { @@ -237,9 +233,9 @@ async function skipDialog(page: Page) { "button[data-role='negative-button']" ); if (await positiveButton.isVisible()) - await positiveButton.click({ timeout: 2000 }); + await positiveButton.click({ timeout: 1000 }); else if (await negativeButton.isVisible()) - await negativeButton.click({ timeout: 2000 }); + await negativeButton.click({ timeout: 1000 }); } catch (e) { // ignore error } diff --git a/apps/desktop/__tests__/launch.test.ts b/apps/desktop/__tests__/launch.test.ts index 938a0ed01..0617be6df 100644 --- a/apps/desktop/__tests__/launch.test.ts +++ b/apps/desktop/__tests__/launch.test.ts @@ -17,22 +17,24 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -import { test } from "vitest"; -import { harness } from "./utils.js"; -import assert from "assert"; +import { testCleanup, test } from "./utils.js"; -test("make sure app loads", async (t) => { - await harness(t, async ({ page }) => { - await page.waitForSelector("#authForm"); +test("make sure app loads", async ({ + ctx: { page }, + expect, + onTestFinished +}) => { + onTestFinished(testCleanup); - assert.ok( - await page.getByRole("button", { name: "Create account" }).isVisible() - ); + await page.waitForSelector("#authForm"); - await page - .getByRole("button", { name: "Skip & go directly to the app" }) - .click(); + expect( + await page.getByRole("button", { name: "Create account" }).isVisible() + ).toBe(true); - await page.waitForSelector(".ProseMirror"); - }); + await page + .getByRole("button", { name: "Skip & go directly to the app" }) + .click(); + + await page.waitForSelector(".ProseMirror"); }); diff --git a/apps/desktop/__tests__/utils.ts b/apps/desktop/__tests__/utils.ts index d1c2d2eb1..c4d31f0a2 100644 --- a/apps/desktop/__tests__/utils.ts +++ b/apps/desktop/__tests__/utils.ts @@ -23,7 +23,7 @@ import { fileURLToPath } from "node:url"; import path from "path"; import { _electron as electron } from "playwright"; import slugify from "slugify"; -import { TaskContext } from "vitest"; +import { test as vitestTest, TestContext } from "vitest"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -42,31 +42,34 @@ interface TestOptions { version: string; } -export async function harness( - t: TaskContext, - cb: (ctx: AppContext) => Promise, - options?: TestOptions -) { - const ctx = await buildAndLaunchApp(options); +interface Fixtures { + options: TestOptions; + ctx: AppContext; +} - t.onTestFinished(async (result) => { - if (result.state === "fail") { - await mkdir("test-results", { recursive: true }); - await ctx.page.screenshot({ - path: path.join( - "test-results", - `${slugify(t.task.name)}-${process.platform}-${ - process.arch - }-error.png` - ) - }); - } +export const test = vitestTest.extend({ + options: { version: "3.0.0" } as TestOptions, + ctx: async ({ options }, use) => { + const ctx = await buildAndLaunchApp(options); + await use(ctx); await ctx.app.close(); await rm(ctx.userDataDir, { recursive: true, force: true }); await rm(ctx.outputDir, { recursive: true, force: true }); - }); + } +}); - await cb(ctx); +export async function testCleanup(context: TestContext) { + if (context.task.result?.state === "fail") { + await mkdir("test-results", { recursive: true }); + await (context.task.context as unknown as Fixtures).ctx.page.screenshot({ + path: path.join( + "test-results", + `${slugify(context.task.name)}-${process.platform}-${ + process.arch + }-error.png` + ) + }); + } } async function buildAndLaunchApp(options?: TestOptions): Promise {