Réutilise l'API Releases de Forgejo (publique, sans authentification) comme source de vérité pour "quelle est la dernière version" — zéro nouvel endpoint backend : useAppUpdateCheck compare App.getInfo().version (@capacitor/app, nouvelle dépendance) au tag_name de GET .../releases/latest, et pointe "Mettre à jour" vers l'URL stable de téléchargement (issue #65). Comparaison de version en logique pure (version-compare.ts), séparée du hook effectful — testée isolément via un test de composant Cypress (version-compare.cy.tsx, même patron que highlight-tech-steps.cy.tsx : aucun montage, juste describe/it/expect sur des fonctions pures). Natif uniquement (Capacitor.isNativePlatform()) : @capacitor/app et @capacitor/preferences restent en import dynamique dans le hook, jamais dans le bundle web (même patron que capacitor-token-store.ts) — vérifié dans le build (deux petits chunks séparés, pas dans le bundle principal). Vérification au démarrage à froid + à la reprise depuis l'arrière-plan (appStateChange), avec un throttle de 6h et une mémorisation de la version déjà rejetée dans @capacitor/preferences pour ne jamais re-harceler sur la même version. Bannière discrète (pas une Dialog modale), bouton "Mettre à jour" ouvrant le lien de téléchargement dans le navigateur système plutôt qu'un flux PackageInstaller in-app. Vérifié : pnpm lint, pnpm --filter web build, le test de composant (9/9), et layout/smoke/planning-page e2e (18/18, la bannière étant un no-op sur le web ne devait rien casser — confirmé). Closes #66 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
51 lines
1.9 KiB
TypeScript
51 lines
1.9 KiB
TypeScript
import { isNewerVersion, parseVersion } from "../../src/features/app-update/version-compare";
|
|
|
|
// Pure logic, no DOM/mount needed — same posture as highlight-tech-steps.cy.tsx:
|
|
// reuses the component-test runner (Cypress's Mocha/Chai) purely for `expect`.
|
|
// `.cy.tsx` (not `.cy.ts`) only because that's what cypress.config.ts's
|
|
// component `specPattern` looks for.
|
|
|
|
describe("parseVersion", () => {
|
|
it("parses a v-prefixed tag into its three integer components", () => {
|
|
expect(parseVersion("v1.4.2")).to.deep.equal({ major: 1, minor: 4, patch: 2 });
|
|
});
|
|
|
|
it("also accepts a bare X.Y.Z string (no leading v)", () => {
|
|
expect(parseVersion("1.4.2")).to.deep.equal({ major: 1, minor: 4, patch: 2 });
|
|
});
|
|
|
|
it("returns null for anything that doesn't match exactly", () => {
|
|
expect(parseVersion("")).to.be.null;
|
|
expect(parseVersion("not-a-version")).to.be.null;
|
|
expect(parseVersion("v1.4")).to.be.null;
|
|
expect(parseVersion("v1.4.2-beta")).to.be.null;
|
|
});
|
|
});
|
|
|
|
describe("isNewerVersion", () => {
|
|
it("is true when the major version is higher", () => {
|
|
expect(isNewerVersion("1.4.2", "v2.0.0")).to.be.true;
|
|
});
|
|
|
|
it("is true when the minor version is higher, major equal", () => {
|
|
expect(isNewerVersion("1.4.2", "v1.5.0")).to.be.true;
|
|
});
|
|
|
|
it("is true when only the patch version is higher", () => {
|
|
expect(isNewerVersion("1.4.2", "v1.4.3")).to.be.true;
|
|
});
|
|
|
|
it("is false for the exact same version", () => {
|
|
expect(isNewerVersion("1.4.2", "v1.4.2")).to.be.false;
|
|
});
|
|
|
|
it("is false when the candidate is actually older", () => {
|
|
expect(isNewerVersion("1.4.2", "v1.4.1")).to.be.false;
|
|
expect(isNewerVersion("2.0.0", "v1.9.9")).to.be.false;
|
|
});
|
|
|
|
it("fails closed (false) when either side doesn't parse", () => {
|
|
expect(isNewerVersion("1.0", "v2.0.0")).to.be.false;
|
|
expect(isNewerVersion("1.0.0", "not-a-tag")).to.be.false;
|
|
});
|
|
});
|