desktop: migrate tests to vitest 3

This commit is contained in:
Abdullah Atta
2025-07-19 11:01:57 +05:00
parent 69776f26d8
commit fe1e3bb847
3 changed files with 212 additions and 211 deletions

View File

@@ -17,214 +17,210 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { test } from "vitest"; import { test, testCleanup } from "./utils.js";
import { harness } from "./utils.js";
import { writeFile } from "fs/promises"; import { writeFile } from "fs/promises";
import { Page } from "playwright"; import { Page } from "playwright";
import { gt, lt } from "semver"; import { gt, lt } from "semver";
import { describe } from "vitest";
test("update starts downloading if version is outdated", async (t) => { test("update starts downloading if version is outdated", async ({
await harness( ctx: { page },
t, expect,
async ({ page }) => { onTestFinished
await page.waitForSelector("#authForm"); }) => {
onTestFinished(testCleanup);
t.expect( await page.waitForSelector("#authForm");
await page.getByRole("button", { name: "Create account" }).isVisible() expect(
).toBe(true); await page.getByRole("button", { name: "Create account" }).isVisible()
).toBe(true);
await page await page
.getByRole("button", { name: "Skip & go directly to the app" }) .getByRole("button", { name: "Skip & go directly to the app" })
.click(); .click();
await skipDialog(page); await skipDialog(page);
await page.waitForSelector(".ProseMirror"); await page.waitForSelector(".ProseMirror");
await page await page
.locator(".theme-scope-statusBar") .locator(".theme-scope-statusBar")
.getByRole("button", { name: /updating/i }) .getByRole("button", { name: /updating/i })
.waitFor({ state: "attached" }); .waitFor({ state: "attached" });
},
{ version: "3.0.0" }
);
}); });
test("update is only shown if version is outdated and auto updates are disabled", async (t) => { test("update is only shown if version is outdated and auto updates are disabled", async ({
await harness( ctx,
t, expect,
async (ctx) => { onTestFinished
await ctx.app.close(); }) => {
await writeFile( onTestFinished(testCleanup);
ctx.configPath,
JSON.stringify({
automaticUpdates: false
})
);
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.waitForSelector("#authForm");
await page.getByRole("button", { name: "Create account" }).isVisible()
).toBe(true);
await page expect(
.getByRole("button", { name: "Skip & go directly to the app" }) await page.getByRole("button", { name: "Create account" }).isVisible()
.click(); ).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 await page
.locator(".theme-scope-statusBar") .locator(".theme-scope-statusBar")
.getByRole("button", { name: /available/i }) .getByRole("button", { name: /available/i })
.waitFor({ state: "attached" }); .isHidden()
}, ).toBe(true);
{ version: "3.0.0" } });
);
}); });
test("update to stable if it is newer", async (t) => { describe("downgrade to stable on switching to stable release track", () => {
await harness( test.scoped({ options: { version: "99.0.0-beta.0" } });
t, test("test", async ({ ctx, expect, onTestFinished }) => {
async (ctx) => { onTestFinished(testCleanup);
await ctx.app.close();
await writeFile(
ctx.configPath,
JSON.stringify({
automaticUpdates: false,
releaseTrack: "beta"
})
);
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.waitForSelector("#authForm");
await page.getByRole("button", { name: "Create account" }).isVisible()
).toBe(true);
await page expect(
.getByRole("button", { name: "Skip & go directly to the app" }) await page.getByRole("button", { name: "Create account" }).isVisible()
.click(); ).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 await page.waitForSelector(".ProseMirror");
.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" }
);
});
test("update is not available if it latest stable version is older", async (t) => { await page
await harness( .locator(".theme-scope-statusBar")
t, .getByRole("button", { name: /checking for updates/i })
async (ctx) => { .waitFor({ state: "hidden" });
await ctx.app.close();
await writeFile(
ctx.configPath,
JSON.stringify({
automaticUpdates: false,
releaseTrack: "beta"
})
);
await ctx.relaunch(); const updateButton = page
.locator(".theme-scope-statusBar")
const { page } = ctx; .getByRole("button", { name: /available/i });
await updateButton.waitFor({ state: "visible" });
await page.waitForSelector("#authForm"); const content = await updateButton.textContent();
const version = content?.split(" ")?.[0] || "";
t.expect( expect(lt(version, "99.0.0-beta.0")).toBe(true);
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" }
);
}); });
async function skipDialog(page: Page) { async function skipDialog(page: Page) {
@@ -237,9 +233,9 @@ async function skipDialog(page: Page) {
"button[data-role='negative-button']" "button[data-role='negative-button']"
); );
if (await positiveButton.isVisible()) if (await positiveButton.isVisible())
await positiveButton.click({ timeout: 2000 }); await positiveButton.click({ timeout: 1000 });
else if (await negativeButton.isVisible()) else if (await negativeButton.isVisible())
await negativeButton.click({ timeout: 2000 }); await negativeButton.click({ timeout: 1000 });
} catch (e) { } catch (e) {
// ignore error // ignore error
} }

View File

@@ -17,22 +17,24 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
import { test } from "vitest"; import { testCleanup, test } from "./utils.js";
import { harness } from "./utils.js";
import assert from "assert";
test("make sure app loads", async (t) => { test("make sure app loads", async ({
await harness(t, async ({ page }) => { ctx: { page },
await page.waitForSelector("#authForm"); expect,
onTestFinished
}) => {
onTestFinished(testCleanup);
assert.ok( await page.waitForSelector("#authForm");
await page.getByRole("button", { name: "Create account" }).isVisible()
);
await page expect(
.getByRole("button", { name: "Skip & go directly to the app" }) await page.getByRole("button", { name: "Create account" }).isVisible()
.click(); ).toBe(true);
await page.waitForSelector(".ProseMirror"); await page
}); .getByRole("button", { name: "Skip & go directly to the app" })
.click();
await page.waitForSelector(".ProseMirror");
}); });

View File

@@ -23,7 +23,7 @@ import { fileURLToPath } from "node:url";
import path from "path"; import path from "path";
import { _electron as electron } from "playwright"; import { _electron as electron } from "playwright";
import slugify from "slugify"; import slugify from "slugify";
import { TaskContext } from "vitest"; import { test as vitestTest, TestContext } from "vitest";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@@ -42,31 +42,34 @@ interface TestOptions {
version: string; version: string;
} }
export async function harness( interface Fixtures {
t: TaskContext, options: TestOptions;
cb: (ctx: AppContext) => Promise<void>, ctx: AppContext;
options?: TestOptions }
) {
const ctx = await buildAndLaunchApp(options);
t.onTestFinished(async (result) => { export const test = vitestTest.extend<Fixtures>({
if (result.state === "fail") { options: { version: "3.0.0" } as TestOptions,
await mkdir("test-results", { recursive: true }); ctx: async ({ options }, use) => {
await ctx.page.screenshot({ const ctx = await buildAndLaunchApp(options);
path: path.join( await use(ctx);
"test-results",
`${slugify(t.task.name)}-${process.platform}-${
process.arch
}-error.png`
)
});
}
await ctx.app.close(); await ctx.app.close();
await rm(ctx.userDataDir, { recursive: true, force: true }); await rm(ctx.userDataDir, { recursive: true, force: true });
await rm(ctx.outputDir, { 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<AppContext> { async function buildAndLaunchApp(options?: TestOptions): Promise<AppContext> {