Tests navigateur : accueil, tutoriel, aide, installation, mise à jour ; plan : résultat
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
441bca1bd7
commit
5fdca812d9
+24
-11
@@ -1289,13 +1289,21 @@ export function startApp(options: AppOptions): void {
|
||||
// ----------------------------------------------------------- Adresses
|
||||
|
||||
let menuReturnFocus: HTMLElement | null = null;
|
||||
// L'écran sous la feuille d'installation : le dernier écran affiché.
|
||||
let underSheet: Route = { screen: "game" };
|
||||
|
||||
/** Dessine l'écran que désigne l'adresse (ADR 0013, amendement). */
|
||||
function applyRoute(route: Route): void {
|
||||
const help = isHelpScreen(route);
|
||||
const position = route.screen === "position";
|
||||
const home = route.screen === "home";
|
||||
const tutorial = route.screen === "tutorial" || route.screen === "tutorialEnd";
|
||||
// La feuille d'installation s'ouvre par-dessus l'écran d'où l'on
|
||||
// vient (l'accueil, le plus souvent), qui reste dessous.
|
||||
if (route.screen !== "install") {
|
||||
underSheet = route;
|
||||
}
|
||||
const below = underSheet;
|
||||
const help = isHelpScreen(below);
|
||||
const position = below.screen === "position";
|
||||
const home = below.screen === "home";
|
||||
const tutorial = below.screen === "tutorial" || below.screen === "tutorialEnd";
|
||||
const page = help || position || home || tutorial;
|
||||
const wasPage = ui.game.hidden;
|
||||
const wasScreen = ui.root.dataset.screen;
|
||||
@@ -1307,12 +1315,14 @@ export function startApp(options: AppOptions): void {
|
||||
ui.root.classList.toggle("page-open", page);
|
||||
// Le tutoriel et le premier lancement ont leur propre en-tête.
|
||||
ui.root.classList.toggle("bare", tutorial || (home && isFirstLaunch(settings)));
|
||||
ui.root.dataset.screen = route.screen;
|
||||
if ((wasPage && !ui.game.hidden) || (page && wasScreen !== route.screen)) {
|
||||
ui.root.dataset.screen = below.screen;
|
||||
if ((wasPage && !ui.game.hidden) || (page && wasScreen !== below.screen)) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
if (tutorial) {
|
||||
void tutorialView.show(route);
|
||||
if (route.screen !== "install") {
|
||||
void tutorialView.show(below);
|
||||
}
|
||||
} else {
|
||||
tutorialView.hide();
|
||||
}
|
||||
@@ -1361,11 +1371,14 @@ export function startApp(options: AppOptions): void {
|
||||
gamesView?.hide();
|
||||
}
|
||||
|
||||
if (help) {
|
||||
void helpView.show(route);
|
||||
const sheet = route.screen === "install";
|
||||
if (isHelpScreen(below) && !sheet) {
|
||||
void helpView.show(below);
|
||||
}
|
||||
if (position) {
|
||||
void showPosition(route);
|
||||
if (below.screen === "position") {
|
||||
if (!sheet) {
|
||||
void showPosition(below);
|
||||
}
|
||||
} else {
|
||||
positionRequest++;
|
||||
shownPosition = null;
|
||||
|
||||
@@ -252,7 +252,13 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
// à l'écran (le joueur est déjà ailleurs).
|
||||
let shown = 0;
|
||||
let autoplay: ReturnType<typeof setTimeout> | null = null;
|
||||
// Un coup illustré se joue, ou un geste est jugé : les touchers
|
||||
// attendent (data-busy, pour les tests dans un navigateur).
|
||||
let busy = false;
|
||||
const setBusy = (value: boolean) => {
|
||||
busy = value;
|
||||
section.toggleAttribute("data-busy", value);
|
||||
};
|
||||
|
||||
// L'écran affiché.
|
||||
let screen: TutorialScreen | null = null;
|
||||
@@ -349,7 +355,7 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
if (shownMove === null || id !== shown) {
|
||||
return;
|
||||
}
|
||||
busy = true;
|
||||
setBusy(true);
|
||||
replay.disabled = true;
|
||||
illustrated = false;
|
||||
try {
|
||||
@@ -376,7 +382,7 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
}
|
||||
} finally {
|
||||
if (id === shown) {
|
||||
busy = false;
|
||||
setBusy(false);
|
||||
illustrated = true;
|
||||
replay.disabled = false;
|
||||
draw();
|
||||
@@ -419,7 +425,7 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
return;
|
||||
}
|
||||
const id = shown;
|
||||
busy = true;
|
||||
setBusy(true);
|
||||
selected = null;
|
||||
try {
|
||||
const verdict = await session.play(halfMove);
|
||||
@@ -445,7 +451,7 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
await refreshTargets();
|
||||
} finally {
|
||||
if (id === shown) {
|
||||
busy = false;
|
||||
setBusy(false);
|
||||
draw(practice === null ? null : await practice.board());
|
||||
}
|
||||
}
|
||||
@@ -487,7 +493,7 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
return;
|
||||
}
|
||||
const id = shown;
|
||||
busy = true;
|
||||
setBusy(true);
|
||||
try {
|
||||
const right = (await access.shouldTake(current.position)) === takes;
|
||||
if (id !== shown) {
|
||||
@@ -498,7 +504,7 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
}
|
||||
setVerdict(right ? "right" : "wrong", right ? current.right : current.wrong);
|
||||
} finally {
|
||||
busy = false;
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
take.addEventListener("click", () => void answer(true));
|
||||
@@ -535,8 +541,10 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
return {
|
||||
async show(route) {
|
||||
const id = ++shown;
|
||||
// Prêt (pour les tests dans un navigateur) une fois ce plateau dessiné.
|
||||
delete section.dataset.ready;
|
||||
clearTimer();
|
||||
busy = false;
|
||||
setBusy(false);
|
||||
practice = null;
|
||||
illustration = null;
|
||||
illustrated = false;
|
||||
@@ -696,7 +704,7 @@ export function createTutorialView(options: TutorialViewOptions): TutorialView {
|
||||
hide() {
|
||||
shown++;
|
||||
clearTimer();
|
||||
busy = false;
|
||||
setBusy(false);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// Licence : GPLv3 ou ultérieure (voir LICENSE).
|
||||
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { test } from "node:test";
|
||||
import { installPlatform } from "../src/ui/install.js";
|
||||
import {
|
||||
@@ -15,7 +16,18 @@ import {
|
||||
isFirstLaunch,
|
||||
parseSettings,
|
||||
type Settings,
|
||||
TUTORIAL_DONE,
|
||||
} from "../src/ui/settings.js";
|
||||
import {
|
||||
nextPlace,
|
||||
placeOf,
|
||||
previousPlace,
|
||||
progress,
|
||||
seenAfter,
|
||||
} from "../src/ui/tutorial-nav.js";
|
||||
import { parseTutorial } from "../src/ui/tutorial-text.js";
|
||||
|
||||
const root = new URL("../../../", import.meta.url);
|
||||
|
||||
test("réglages d'une version précédente : les nouveaux champs prennent leur valeur par défaut", () => {
|
||||
const old = parseSettings('{"vibrations": false, "theme": "dark", "gamesStarted": 4}');
|
||||
@@ -66,6 +78,31 @@ test("invitation à installer : après la première partie terminée, une seule
|
||||
assert.ok(!at({ installDismissals: 2, installDismissedAt: 4, gamesFinished: 40 }));
|
||||
});
|
||||
|
||||
test("tutoriel : écran suivant, précédent, adresse ramenée à un écran qui existe", () => {
|
||||
const tutorial = parseTutorial(readFileSync(new URL("docs/tutoriel/regles.md", root), "utf8"));
|
||||
const explain = (step: number) => ({ step, practice: false });
|
||||
const practice = (step: number) => ({ step, practice: true });
|
||||
assert.deepEqual(nextPlace(tutorial, explain(2)), explain(3));
|
||||
assert.deepEqual(nextPlace(tutorial, explain(3)), practice(3));
|
||||
assert.deepEqual(nextPlace(tutorial, practice(3)), explain(4));
|
||||
assert.equal(nextPlace(tutorial, practice(8)), "end");
|
||||
assert.equal(previousPlace(tutorial, explain(1)), null);
|
||||
assert.deepEqual(previousPlace(tutorial, explain(4)), practice(3));
|
||||
assert.deepEqual(previousPlace(tutorial, explain(3)), explain(2));
|
||||
assert.deepEqual(previousPlace(tutorial, "end"), practice(8));
|
||||
assert.deepEqual(placeOf(tutorial, { screen: "tutorial", step: null, practice: false }), explain(1));
|
||||
assert.deepEqual(placeOf(tutorial, { screen: "tutorial", step: 2, practice: true }), explain(2));
|
||||
assert.deepEqual(placeOf(tutorial, { screen: "tutorial", step: 42, practice: false }), explain(1));
|
||||
assert.equal(placeOf(tutorial, { screen: "tutorialEnd" }), "end");
|
||||
assert.equal(seenAfter(5, explain(3)), 5);
|
||||
assert.equal(seenAfter(0, "end"), TUTORIAL_DONE);
|
||||
// La barre : des liens vers les étapes vues seulement, pas l'actuelle.
|
||||
const bar = progress(8, explain(3), 5);
|
||||
assert.deepEqual(bar.filter((s) => s.link).map((s) => s.step), [1, 2, 4, 5]);
|
||||
assert.deepEqual(bar.filter((s) => s.done).map((s) => s.step), [1, 2, 3]);
|
||||
assert.deepEqual(bar.filter((s) => s.current).map((s) => s.step), [3]);
|
||||
});
|
||||
|
||||
test("la marche à suivre pour installer dépend du navigateur", () => {
|
||||
const iphone =
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 " +
|
||||
|
||||
Reference in New Issue
Block a user