Fusion de origin/lecons (recette 1g) dans progression
Conflit sur la ligne de progression de l'accueil : le texte de 1g (« Aucune leçon terminée sur 5 », majuscule en tête) dans le lien vers #/progression. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
||||
import { chromium, firefox } from "playwright";
|
||||
import { hiddenUnderActionBar, tutorialWidthProblems, tutorialWidths } from "./recette.mjs";
|
||||
import { hiddenUnderActionBar, missingTopbar, tutorialWidthProblems, tutorialWidths } from "./recette.mjs";
|
||||
|
||||
const [base, browserName, shots, updateBase, updateDir] = process.argv.slice(2);
|
||||
const browserType = { chromium, firefox }[browserName];
|
||||
@@ -117,6 +117,8 @@ async function capture(page, name, settle = async () => {}, sizes = SIZES) {
|
||||
await settle();
|
||||
const hidden = await hiddenUnderActionBar(page);
|
||||
check(hidden.length === 0, `${name} ${width}x${height} : caché sous la barre d'action : ${hidden.join(", ")}`);
|
||||
const topbar = await missingTopbar(page);
|
||||
check(topbar === null, `${name} : ${topbar}`);
|
||||
await page.screenshot({ path: `${dir}/${name}-${width}x${height}.png`, fullPage: true });
|
||||
captures++;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import { mkdirSync } from "node:fs";
|
||||
import { chromium, firefox } from "playwright";
|
||||
import { hiddenUnderActionBar, tallButtons } from "./recette.mjs";
|
||||
import { hiddenUnderActionBar, missingTopbar, tallButtons } from "./recette.mjs";
|
||||
|
||||
const [base, browserName, shots] = process.argv.slice(2);
|
||||
const browserType = { chromium, firefox }[browserName];
|
||||
@@ -68,6 +68,8 @@ async function capture(page, name, settle = async () => {}) {
|
||||
await settle();
|
||||
const hidden = await hiddenUnderActionBar(page);
|
||||
check(hidden.length === 0, `${name} ${width}x${height} : caché sous la barre d'action : ${hidden.join(", ")}`);
|
||||
const topbar = await missingTopbar(page);
|
||||
check(topbar === null, `${name} : ${topbar}`);
|
||||
const tall = await tallButtons(page);
|
||||
check(tall.length === 0, `${name} ${width}x${height} : boutons étirés : ${tall.join(", ")}`);
|
||||
await page.screenshot({ path: `${dir}/${name}-${width}x${height}.png`, fullPage: true });
|
||||
@@ -155,7 +157,8 @@ try {
|
||||
await until(page, "carte de la leçon", () => {
|
||||
const card = document.getElementById("home-lesson");
|
||||
return location.hash === "#/accueil" && !card.hidden && !card.closest("[hidden]") &&
|
||||
card.textContent.includes("Leçon 1") && !document.getElementById("home-new").disabled;
|
||||
card.textContent.includes("Leçon 1") && !document.getElementById("home-new").disabled &&
|
||||
document.getElementById("home-progress").textContent.includes(" · ");
|
||||
});
|
||||
const home = await page.evaluate(() => ({
|
||||
go: document.getElementById("home-lesson-go").getAttribute("href"),
|
||||
@@ -170,7 +173,7 @@ try {
|
||||
}));
|
||||
check(home.go === "#/lecons/1/1" && home.goText === "Commencer" && home.goClass.includes("secondary") &&
|
||||
home.all === "#/lecons" && home.title === "Les ouvertures" && home.state === "À commencer · 4 exercices" &&
|
||||
home.summary.startsWith("0 leçon terminée sur 5") && home.primaries === 1,
|
||||
home.summary.startsWith("Aucune leçon terminée sur 5 · ") && home.primaries === 1,
|
||||
`carte de l'accueil : ${JSON.stringify(home)}`);
|
||||
await capture(page, "01-accueil-carte", async () => {
|
||||
await page.locator("#home-lesson").scrollIntoViewIfNeeded();
|
||||
@@ -188,6 +191,8 @@ try {
|
||||
[...document.querySelectorAll("#lessons a.button:not(.secondary)")].filter((el) => !el.closest("[hidden]")).length);
|
||||
check(primaries === 1, `liste : ${primaries} actions principales`);
|
||||
check(await page.getAttribute("#lessons-rules", "href") === "#/tutoriel/1", "liste : rappel des règles");
|
||||
const rulesHeight = await page.evaluate(() => document.getElementById("lessons-rules").getBoundingClientRect().height);
|
||||
check(rulesHeight >= 44, `liste : rappel des règles haut de ${rulesHeight} px`);
|
||||
await capture(page, "02-liste");
|
||||
log("liste : cinq leçons, la première proposée, une seule action principale, rappel des règles");
|
||||
|
||||
@@ -208,6 +213,18 @@ try {
|
||||
explain.segments === 4 && explain.skip === "#/lecons" && explain.back === "#/lecons" &&
|
||||
explain.next === "#/lecons/1/1/a-vous" && explain.topbar === "none" &&
|
||||
explain.glossary.includes("#/glossaire/jan-interieur"), `explication : ${JSON.stringify(explain)}`);
|
||||
// « Revoir » sur la ligne du titre ; « Retour » et « Continuer » en bas
|
||||
// de l'écran, sous le pouce (recette 1g).
|
||||
const layout = await page.evaluate(() => {
|
||||
const title = document.getElementById("lesson-title").getBoundingClientRect();
|
||||
const replay = document.getElementById("lesson-replay").getBoundingClientRect();
|
||||
const next = document.getElementById("lesson-next").getBoundingClientRect();
|
||||
return { titleTop: title.top, titleBottom: title.bottom, replayTop: replay.top,
|
||||
replayBottom: replay.bottom, nextBottom: next.bottom, height: innerHeight };
|
||||
});
|
||||
check(layout.replayTop < layout.titleBottom && layout.replayBottom > layout.titleTop,
|
||||
`« Revoir » hors de la ligne du titre : ${JSON.stringify(layout)}`);
|
||||
check(layout.nextBottom > layout.height - 64, `« Continuer » loin du bas : ${JSON.stringify(layout)}`);
|
||||
check(await page.locator("#lesson-board .trace-arrow").count() > 0, "le coup illustré n'a pas laissé de traces");
|
||||
await capture(page, "03-explication");
|
||||
log("explication : coup illustré 8/5 6/5 joué tout seul, barre de quatre étapes, liens du glossaire");
|
||||
|
||||
@@ -99,6 +99,27 @@ export async function hiddenUnderActionBar(target) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* La barre haute (Aide, Plein écran, Menu) hors de l'écran de jeu : sur une
|
||||
* page (accueil, leçons, aide…) qui n'a pas son propre en-tête, elle doit
|
||||
* rester visible, en paysage comme en portrait ; sans elle, le menu est
|
||||
* inaccessible (recette 1g). Renvoie un problème décrit, ou null.
|
||||
*/
|
||||
export async function missingTopbar(target) {
|
||||
return target.evaluate(() => {
|
||||
const root = document.documentElement;
|
||||
if (!root.classList.contains("page-open") || root.classList.contains("bare")) {
|
||||
return null;
|
||||
}
|
||||
const bar = document.querySelector(".topbar");
|
||||
const r = bar?.getBoundingClientRect();
|
||||
const shown = bar !== null && getComputedStyle(bar).display !== "none" && r.height > 0;
|
||||
return shown
|
||||
? null
|
||||
: `barre haute absente sur ${root.dataset.screen} (${innerWidth}x${innerHeight})`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Les largeurs d'un écran du tutoriel, en px CSS : le plateau, la colonne
|
||||
* de texte, et la largeur de la page (scrollWidth) face à celle de l'écran.
|
||||
|
||||
Reference in New Issue
Block a user