/** * Tests for the update decision logic. * * TRACES: | DR-217 | UT-208 * * The pure half is tested here; `checkForUpdate`/`installUpdate` talk to the * plugin and are exercised by actually cutting a release (see the Phase 3 * verification steps in docs/build/ci-operations.md). */ import { describe, it, expect } from "vitest"; import { decideUpdateAction, isNewerVersion, updateCapability, RELEASES_URL } from "./updateCheck"; describe("isNewerVersion", () => { it("compares each numeric field in order", () => { expect(isNewerVersion("0.9.2", "0.9.1")).toBe(true); expect(isNewerVersion("0.10.0", "0.9.9")).toBe(true); expect(isNewerVersion("1.0.0", "0.99.99")).toBe(true); expect(isNewerVersion("0.9.1", "0.9.2")).toBe(false); }); it("does not offer the version already installed", () => { expect(isNewerVersion("0.9.1", "0.9.1")).toBe(false); }); it("tolerates a leading v, which is how the tags are written", () => { // build-release.yml derives VERSION from refs/tags/v0.9.1. expect(isNewerVersion("v0.9.2", "0.9.1")).toBe(true); expect(isNewerVersion("0.9.2", "v0.9.1")).toBe(true); }); it("sorts a pre-release below the release of the same number", () => { // Otherwise everyone on 0.9.2 gets offered 0.9.2-rc1 as an "upgrade" — // build-release.yml marks exactly these suffixes as prereleases. expect(isNewerVersion("0.9.2-rc1", "0.9.2")).toBe(false); expect(isNewerVersion("0.9.2", "0.9.2-rc1")).toBe(true); expect(isNewerVersion("0.9.2-rc1", "0.9.1")).toBe(true); }); it("treats a missing patch field as zero rather than NaN", () => { expect(isNewerVersion("1.0", "0.9.9")).toBe(true); expect(isNewerVersion("0.9", "0.9.1")).toBe(false); }); }); describe("updateCapability", () => { it("reports install for the desktop platforms", () => { expect(updateCapability("linux")).toBe("install"); expect(updateCapability("windows")).toBe("install"); expect(updateCapability("macos")).toBe("install"); }); it("reports link-only for mobile", () => { // tauri-plugin-updater is not compiled for Android at all: an app cannot // overwrite its own APK. Calling it there would throw, not degrade. expect(updateCapability("android")).toBe("link-only"); expect(updateCapability("ios")).toBe("link-only"); }); }); describe("decideUpdateAction", () => { it("offers nothing when the endpoint reported nothing", () => { expect(decideUpdateAction("linux", null)).toEqual({ kind: "none" }); expect(decideUpdateAction("android", null)).toEqual({ kind: "none" }); }); it("offers a real install on desktop", () => { expect(decideUpdateAction("linux", { version: "0.9.2", notes: "fixes" })).toEqual({ kind: "install", version: "0.9.2", notes: "fixes", }); }); it("normalises absent notes to null rather than undefined", () => { // The Svelte side renders `{#if notes}`; undefined vs null is the kind of // difference that only shows up as a blank panel in front of a user. expect(decideUpdateAction("windows", { version: "0.9.2" })).toEqual({ kind: "install", version: "0.9.2", notes: null, }); }); it("offers the releases page on Android instead of an install", () => { expect(decideUpdateAction("android", { version: "0.9.2" })).toEqual({ kind: "open-releases", version: "0.9.2", url: RELEASES_URL, }); }); it("points at Gitea, not GitHub", () => { // The release body used to link "GitHub Issues" on a Gitea-hosted project. expect(RELEASES_URL).toContain("gitea.tourolle.paris"); }); });