Simpl-Resultat/docs/qa-onboarding.html
le king fu a064043c20
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 1m58s
docs(onboarding): eight steps, visit steps and their one-time initialization
- Guide and docs.gettingStarted / docs.dashboard keys (FR, EN): eight
  steps, the two visit steps in the quick-start list, "Got it", 3/8 and
  7/7, a finished path finds them done.
- ADR 0022: acknowledgeStep and initializeVisitSteps do not notify (§2),
  ACKNOWLEDGE among the local actions (§4), the one-time initialization
  admitted like rule D9 (§5).
- architecture.md: eight rows, the amended "never by a click" invariant,
  the two new preferences, the provider's new action and initializer.
- QA list: step numbers moved to eight, five cases for the visit steps.
- CHANGELOG: Added entry in both files.

Resolves #425

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:37:30 -04:00

542 lines
45 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>QA — Parcours d'accueil</title>
<!--
Checklist de parcours de l'accueil : phase 1 (issues #351 à #357) et parcours
guidé de la phase 2 (issues #396 à #401). Page statique, français seulement,
aucune dépendance réseau : tout est inline. L'état (cases + commentaires) vit
dans le localStorage du navigateur qui ouvre le fichier, sous une clé propre à
cette version de la liste ; « Copier le rapport » produit le texte brut à
coller dans Paramètres → Système → Envoyer un feedback.
La liste de la phase 1 telle que publiée avec la v0.17.0 reste lisible par
`git show v0.17.0:docs/qa-onboarding.html`.
-->
<style>
:root {
--bg: #faf9f7;
--card: #ffffff;
--fg: #1f1d1a;
--muted: #6b665f;
--border: #e3dfd9;
--accent: #b5542e;
--accent-fg: #ffffff;
--done-bg: #f0f5ec;
--focus: #2f6fb3;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1c1a18;
--card: #262320;
--fg: #ece8e2;
--muted: #a39d94;
--border: #3a3631;
--accent: #d9774c;
--accent-fg: #1c1a18;
--done-bg: #262d22;
--focus: #7fb0e8;
}
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--fg);
font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
padding: 24px 16px 64px;
}
main { max-width: 860px; margin: 0 auto; }
h1 { font-size: 1.5rem; margin: 0 0 4px; }
h2 { font-size: 1.05rem; margin: 28px 0 8px; }
p { margin: 0 0 10px; }
.lead { color: var(--muted); }
.meta {
display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center;
margin: 16px 0 8px; color: var(--muted); font-size: 0.9rem;
}
.meta label { display: inline-flex; gap: 6px; align-items: center; }
.meta input[type="text"] {
width: 11rem;
}
.progress {
font-variant-numeric: tabular-nums; font-weight: 600; color: var(--fg);
}
.prereq {
background: var(--card); border: 1px solid var(--border); border-radius: 10px;
padding: 12px 16px; margin: 12px 0 20px;
}
.prereq ul { margin: 6px 0 0; padding-left: 20px; }
.intro { color: var(--muted); font-size: 0.92rem; }
ol.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; }
ol.steps li {
background: var(--card); border: 1px solid var(--border); border-radius: 10px;
padding: 12px 14px; margin-bottom: 10px;
display: grid; grid-template-columns: auto 1fr; gap: 6px 12px;
}
ol.steps li.done { background: var(--done-bg); }
ol.steps li .check { grid-row: 1 / span 3; padding-top: 2px; }
ol.steps li input[type="checkbox"] { width: 20px; height: 20px; margin: 0; cursor: pointer; }
ol.steps li .title { font-weight: 600; cursor: pointer; }
ol.steps li .title::before {
counter-increment: step; content: counter(step) ". ";
color: var(--muted); font-weight: 500;
}
ol.steps li .expect { color: var(--muted); font-size: 0.92rem; }
ol.steps li .expect code {
font: 0.88em ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
background: var(--bg); border: 1px solid var(--border); border-radius: 4px; padding: 0 4px;
}
ol.steps li .where { display: grid; gap: 4px; }
ol.steps li .where label { font-size: 0.85rem; color: var(--muted); }
input[type="text"], textarea {
width: 100%; font: inherit; color: var(--fg); background: var(--bg);
border: 1px solid var(--border); border-radius: 6px; padding: 6px 8px;
}
input:focus-visible, textarea:focus-visible, button:focus-visible {
outline: 2px solid var(--focus); outline-offset: 1px;
}
.actions {
display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
margin-top: 20px; position: sticky; bottom: 0; padding: 12px 0;
background: var(--bg);
}
button {
font: inherit; font-weight: 600; cursor: pointer; border-radius: 8px;
padding: 8px 14px; border: 1px solid var(--border);
background: var(--card); color: var(--fg);
}
button.primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
button:hover { filter: brightness(0.97); }
.status { color: var(--muted); font-size: 0.9rem; min-height: 1.4em; }
.fallback { margin-top: 12px; }
.fallback[hidden] { display: none; }
.fallback textarea { min-height: 14rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.85rem; }
.note { font-size: 0.85rem; color: var(--muted); margin-top: 16px; }
@media (max-width: 520px) {
body { padding: 16px 16px 72px; }
.meta input[type="text"] { width: 100%; }
}
</style>
</head>
<body>
<main>
<h1>QA — Parcours d'accueil</h1>
<p class="lead">Première ouverture de Simpl'Résultat jusqu'à la fin du parcours de démarrage guidé. Coche chaque étape quand elle se passe comme décrit, et note où tu as hésité, même une seconde : c'est l'hésitation qu'on cherche, pas l'échec.</p>
<div class="meta">
<label>Testeur <input type="text" id="tester" placeholder="prénom" autocomplete="off"></label>
<label>Version <input type="text" id="version" placeholder="ex. 0.18.0" autocomplete="off"></label>
<label>Système <input type="text" id="os" placeholder="Windows 11, Ubuntu 24.04…" autocomplete="off"></label>
<span class="progress" id="progress"></span>
</div>
<section class="prereq">
<strong>Avant de commencer</strong>
<ul>
<li>Une version publiée ou un build de release : les cas du parcours guidé vérifient le rendu réel du webview, WebKitGTK sous Linux et WebView2 sous Windows.</li>
<li>Une installation neuve, ou un profil neuf : la liste de démarrage n'apparaît que dans un profil sans transaction.</li>
<li>Pour l'étape Budget, une clé Base ou Premium ; sans clé, l'étape se présente verrouillée « Base et plus » et le total passe à 5 — note-le dans le champ, c'est attendu.</li>
<li>Pour le cas de l'édition Gratuite, une session utilisateur ou une machine sans clé : ne retire pas la clé de ta machine habituelle, puisque retirer une clé efface aussi le jeton d'activation.</li>
<li>Pour la règle D9, un profil qui a des transactions, créé avec la v0.17.0 ou avant, et qu'aucune version du parcours guidé n'a encore ouvert (un build de développement de la pile compte).</li>
<li>Les cas d'accessibilité et de rendu se font sous Linux avec Orca, puis sous Windows avec NVDA.</li>
<li>La page garde tes réponses dans ce navigateur. Rien n'est envoyé : c'est toi qui colles le rapport dans l'application.</li>
<li>Pour vérifier la v0.17.0 elle-même, prends la liste publiée avec elle : <code>git show v0.17.0:docs/qa-onboarding.html</code>.</li>
</ul>
</section>
<div id="sections"></div>
<div class="actions">
<button type="button" class="primary" id="copy">Copier le rapport</button>
<button type="button" id="reset">Réinitialiser</button>
<span class="status" id="status" role="status" aria-live="polite"></span>
</div>
<div class="fallback" id="fallback" hidden>
<p>Le presse-papiers n'est pas accessible depuis ce fichier : sélectionne le texte ci-dessous (il est déjà sélectionné) et copie-le avec Ctrl+C, puis colle-le dans Paramètres → Système → Envoyer un feedback.</p>
<textarea id="report" readonly aria-label="Rapport à copier"></textarea>
</div>
<p class="note">Les noms entre guillemets sont ceux des boutons tels qu'ils apparaissent en français. « Exemple Desjardins » et « Exemple Tangerine » sont des relevés inventés : aucune donnée réelle.</p>
</main>
<script>
(function () {
"use strict";
// v2: the guided path (#396 to #401) changed the list; the answers of the
// phase 1 list stay under their own key.
var STORAGE_KEY = "simpl-resultat.qa-onboarding.v2";
// One group per part of the path, one row per case. `expect` is what the
// tester should see. Ids are unique across the groups.
var SECTIONS = [
{
id: "phase-1",
title: "Phase 1 : premier lancement, états vides et dossier d'exemple",
intro: "Les cas de la phase 1 (#351 à #357) qui restent valides avec le parcours guidé. Ils peuvent se faire dans la même passe que la section suivante, sur le même profil neuf.",
steps: [
{ id: "install", title: "Installer et lancer l'application",
expect: "L'installateur s'exécute sans avertissement bloquant et l'application s'ouvre sur la sélection de profil." },
{ id: "profile", title: "Créer un profil",
expect: "Le profil s'ouvre directement après sa création (NIP facultatif)." },
{ id: "dashboard-empty", title: "Tableau de bord vide avec la liste de démarrage à 1 / 8",
expect: "Une carte d'accueil remplace les graphiques, la liste montre huit lignes, seule « Créer un profil » est cochée, le compteur indique 1 / 8 (ou 1 / 7 sans clé)." },
{ id: "cta-folder", title: "Cliquer « Choisir un dossier d'import »",
expect: "Le bouton de la carte d'accueil mène à la page Import." },
{ id: "import-no-folder", title: "Page Import sans dossier",
expect: "Un état vide « Aucun dossier d'import » avec le bouton « Choisir un dossier » et le lien « Comment exporter un CSV depuis ma banque ? »." },
{ id: "pick-folder", title: "Cliquer « Choisir un dossier » et prendre un dossier vide",
expect: "La fenêtre du système s'ouvre ; une fois le dossier choisi, l'état vide devient « Aucune source trouvée » et nomme le dossier." },
{ id: "create-sample", title: "Cliquer « Créer un dossier d'exemple »",
expect: "Un message annonce les deux dossiers créés et invite à cliquer sur l'un d'eux. Dans l'explorateur de fichiers, les deux sous-dossiers contiennent un fichier releve-AAAA-MM.csv." },
{ id: "two-sources", title: "Deux sources apparaissent",
expect: "« Exemple Desjardins » et « Exemple Tangerine » sont listées comme sources, sans actualiser à la main." },
{ id: "import-desjardins", title: "Importer « Exemple Desjardins » : aperçu, signes, doublons, rapport",
expect: "Le format est détecté (bandeau Desjardins), l'aperçu montre des sorties et des entrées dans le bon sens (pas besoin d'« Inverser les signes »), aucun doublon, puis le rapport d'import indique le nombre de transactions importées." },
{ id: "manual-category", title: "Transactions : classer « GARDERIE LES PETITS PAS » à la main",
expect: "La transaction est sans catégorie après l'import ; lui en donner une à la main la garde classée." },
{ id: "budget", title: "Budget (clé Base ou Premium) : saisir un montant",
expect: "La page Budget montre la grille (pas l'état vide, puisqu'il y a des transactions) ; un montant saisi dans une cellule est conservé." },
{ id: "hide-reshow", title: "« Masquer » sur un second profil, puis réaffichage depuis Paramètres",
expect: "Créer un second profil (clé Base ou plus) : sa carte d'accueil montre la liste à 1 / 8. « Masquer » retire la liste de ce profil seulement, ainsi que le bandeau de ses autres pages ; le premier profil n'est pas touché. Paramètres → Utilisateurs montre « Afficher la liste de démarrage », qui ramène le parcours." },
{ id: "guide-link", title: "Ouvrir le guide « Exporter un CSV depuis votre banque » depuis l'état vide d'Import",
expect: "Sur un profil sans dossier ou sans source, le lien de l'état vide ouvre le guide directement sur la sous-section, avec les procédures par banque." }
]
},
{
id: "parcours-guide",
title: "Parcours guidé : un profil neuf de bout en bout",
intro: "Phase 2 (#396 à #401), sur un profil neuf en édition Base ou Premium. De l'étape 2 à l'étape 8, avance seulement par les liens d'étape (ligne de la liste, « Étape suivante »), sans revenir au tableau de bord : chaque page doit dire quoi faire.",
steps: [
{ id: "guided-dashboard", title: "Tableau de bord vide sans bandeau, autres pages avec bandeau",
expect: "Sur le tableau de bord, aucun bandeau de démarrage au-dessus du titre : la carte d'accueil porte déjà la liste. Ouvre Catégories, puis Rapports : chacune commence par le bandeau « Démarrage 1/8 · Étape suivante : Choisir un dossier d'import → », avec « Voir la liste » et « Masquer »." },
{ id: "guided-import-card", title: "Étape 2 : la carte Import, son contour et le focus",
expect: "Suis le lien « Choisir un dossier d'import » du bandeau ou de la liste. La page Import s'ouvre sur la carte « Étape 2 sur 8 · Choisir un dossier d'import », avant le titre et à la place du bandeau, et le focus du clavier est sur le titre de la carte. La phrase nomme le bouton « Choisir un dossier », entouré d'un contour de couleur d'accent qui pulse trois fois, puis reste." },
{ id: "guided-import-folder", title: "Étape 3 : dossier choisi, puis dossier d'exemple",
expect: "Choisis un dossier vide : sans quitter la page, la carte passe à « Étape 3 sur 8 · Configurer une source d'import », nomme le dossier et entoure « Créer un dossier d'exemple ». Après la création, elle demande de cliquer sur la carte d'un compte et entoure la première source." },
{ id: "guided-import-wizard", title: "Étape 4 : l'assistant, écran par écran",
expect: "Clique la source entourée (« Exemple Desjardins »). À chaque écran, la carte dit quoi vérifier et entoure le bouton suivant : « Aperçu », « Vérifier les doublons », « Confirmer », puis « Importer ». Pendant l'import, elle affiche « Import en cours… ». Sur le rapport, elle annonce « Fait. » et propose « Étape suivante : Parcourir les catégories et les mots-clés → » ; après « Terminé », elle garde « Fait. »." },
{ id: "guided-transactions", title: "Étape 6 : Transactions, entrée guidée",
expect: "Clique « Étape suivante » sur la carte Catégories, après « J'ai compris » (étape 5, #432). La page Transactions s'ouvre filtrée sur « Non catégorisées », période « Tout », avec la carte « Étape 6 sur 8 · Classer une transaction à la main » et le focus sur son titre ; le contour entoure la catégorie de la première ligne. Choisis une catégorie pour l'une d'elles (« GARDERIE LES PETITS PAS », par exemple) : sans quitter la page, la carte annonce « Fait. » et propose « Étape suivante : Saisir un premier budget → », et le contour disparaît." },
{ id: "guided-budget", title: "Étape 7 : Budget, « Tout déplier » puis la cellule du mois",
expect: "Clique « Étape suivante » sur la carte Transactions. La page Budget montre la carte « Étape 7 sur 8 · Saisir un premier budget », la grille repliée et le contour sur « Tout déplier ». Clique-le : la phrase change et le contour passe sur la cellule du mois courant de la première catégorie à remplir. Saisis un montant puis Entrée : la carte annonce « Fait. » et propose « Étape suivante : Parcourir les rapports → »." },
{ id: "guided-budget-tab", title: "Budget : Tab enregistre et passe au mois suivant",
expect: "Dans une cellule, saisis un montant puis Tab : le montant est enregistré et la saisie passe au mois suivant, comme le dit la carte." },
{ id: "guided-live", title: "Les étapes se cochent page ouverte",
expect: "Pendant les étapes 2 à 8, chaque étape s'est cochée sur la page même, sans recharger ni changer de page, en moins d'une seconde : passage de l'étape 2 à l'étape 3 au choix du dossier, puis « Fait. » après l'import, chaque « J'ai compris », le classement et le budget. Note tout délai visible, ou une étape qui ne se coche qu'au changement de page." },
{ id: "guided-end", title: "Fin du parcours : bandeau de fin, « Ouvrir le guide » et « Fermer »",
expect: "Après « J'ai compris » sur la carte Rapports (étape 8, #432), quitte la page : en haut de chaque page, tableau de bord compris, le bandeau dit « Démarrage terminé. Le guide d'utilisation vous accompagne pour la suite. ». « Ouvrir le guide » ouvre Paramètres → Utilisateurs sur la section « Premiers pas », qui décrit le parcours (« Le parcours de démarrage »). « Fermer » retire le bandeau de toutes les pages, et Paramètres → Utilisateurs propose alors « Afficher la liste de démarrage »." }
]
},
{
id: "parcours-guide-liste",
title: "Parcours guidé : bandeau, liste, Passer et Reprendre",
intro: "Sur un profil où le parcours n'est pas terminé, par exemple un second profil neuf (clé Base ou plus).",
steps: [
{ id: "guided-list", title: "« Voir la liste » et « Fermer la liste »",
expect: "Sur une page sans carte (Catégories, par exemple), « Voir la liste » déplie les huit étapes sous le bandeau et devient « Fermer la liste », qui les replie. Change de page : la liste est de nouveau repliée. Une étape faite est barrée et sans lien ; une étape à faire mène à sa page. À juger : liste dépliée, le compteur et « Masquer » apparaissent deux fois, dans le bandeau et dans l'en-tête de la liste." },
{ id: "guided-skip-resume", title: "« Passer cette étape », puis « Reprendre »",
expect: "Sur la carte Transactions ou Budget, clique « Passer cette étape » : la carte laisse la place au bandeau (ou au message de fin si c'était la dernière étape) et le compteur avance d'une étape. Sur la page Import, passer une étape fait passer la carte à l'étape suivante de la page. Dans la liste dépliée, l'étape passée montre l'icône « passer », le badge « Passée » et « Reprendre ». Depuis une autre page, « Reprendre » rouvre la page de l'étape avec sa carte, le focus sur son titre, et l'étape redevient à faire." },
{ id: "guided-hide-users", title: "« Masquer » depuis Paramètres → Utilisateurs",
expect: "Sur Paramètres → Utilisateurs, clique « Masquer » dans le bandeau : le bandeau disparaît et, sans quitter la page, la ligne « Parcours de démarrage » apparaît avec « Afficher la liste de démarrage ». Un clic la remplace par « Le parcours de démarrage réapparaît en haut des pages », et le bandeau revient en haut de la page." }
]
},
{
id: "parcours-guide-cas",
title: "Parcours guidé : cas particuliers et limites connues",
intro: "Chaque cas dit sur quel profil le faire. Les limites connues sont à constater et à juger : note si elles gênent.",
steps: [
{ id: "guided-d9", title: "Profil déjà actif masqué d'office, puis réaffiché (règle D9)",
expect: "Ouvre un profil qui avait des transactions avant cette version. Aucun bandeau ni carte, sur aucune page ; le Journal (Paramètres → Système) porte « Onboarding: the profile already had transactions, getting-started path hidden (Settings → Users shows it again) ». Paramètres → Utilisateurs propose « Afficher la liste de démarrage » : un clic ramène le bandeau, avec un compteur fidèle aux données du profil. Rouvrir le profil ne le masque plus." },
{ id: "guided-free", title: "Édition Gratuite : 7 étapes, fin à 7/7",
expect: "Sur une session ou une machine sans clé, avec un profil neuf : le compteur dit 1/7, et la ligne Budget est verrouillée « Base et plus » et mène à la carte Licence. Après le classement d'une transaction, la carte Transactions (« Étape 6 sur 7 ») annonce « Fait. » puis « Étape suivante : Parcourir les rapports → » : aucune carte Budget ; après « J'ai compris » sur la carte Rapports, fin à 7/7." },
{ id: "guided-noop-import", title: "Un import qui n'ajoute rien",
expect: "Sur un profil de test où « Importer un premier fichier » reste à faire, fais un import qui n'ajoute aucune transaction (par exemple un fichier qui n'a que sa ligne d'en-tête, ou un format de date choisi à tort, qui met toutes les lignes en erreur dans l'aperçu). Sur le rapport, la carte dit « L'import n'a ajouté aucune transaction ; le rapport ci-dessous dit pourquoi. » et n'annonce pas « Fait. ». Après « Terminé », la carte reste sur « Étape 4 sur 8 » (« 4 sur 7 » en édition Gratuite), entoure la première source et n'annonce toujours pas « Fait. » ; la liste laisse « Importer un premier fichier » à faire." },
{ id: "guided-skip-folder", title: "Limite connue : « Passer » sur l'étape du dossier, sans dossier",
expect: "Sur un profil neuf, sur la carte Import « Étape 2 sur 8 · Choisir un dossier d'import », clique « Passer cette étape » sans choisir de dossier. La carte passe à « Étape 3 sur 8 · Configurer une source d'import », mais garde la phrase et le contour du choix du dossier ; un second « Passer » mène à l'étape 4, avec la même phrase, et le bandeau revient au troisième. À juger : les étapes de la page dépendent du dossier." },
{ id: "guided-empty-profile", title: "Étapes d'import passées : Transactions et Budget sans transaction",
expect: "Sur un profil neuf en édition Base ou plus, sur un build de production (le mode dev masque le cas Budget), choisis un dossier d'import vide, puis passe les étapes 3, 4 et 5 avec « Passer cette étape » (l'étape 5 sur la carte Catégories, #432). Sur la page Transactions, la carte propose le clic droit et « Ajouter comme mot-clé » au-dessus de l'état vide « Aucune transaction pour l'instant », que la barre de filtres et un bref chargement peuvent précéder (limite connue, à juger). Passe l'étape 6 depuis cette carte. Sur la page Budget, la carte « Étape 7 sur 8 · Saisir un premier budget » garde son titre et « Passer cette étape », sans phrase ni contour, au-dessus de l'état vide « Le budget se construit sur vos transactions » ; elle ne dit jamais « Cliquez « Tout déplier »… »." },
{ id: "guided-fallback", title: "Transactions : aucune transaction à classer",
expect: "Sur un profil de test où l'étape 6 reste à faire, rends toutes les transactions catégorisées sans les classer à la main : ajoute, depuis la page Catégories, un mot-clé pour chaque transaction restée sans catégorie, puis clique « Auto-catégoriser » sur la page Transactions. Depuis une autre page, suis « Étape suivante : Classer une transaction à la main → ». La page montre toutes les transactions, période « Tout », une seule fois, et la carte dit « Faites un clic droit sur une transaction, puis « Ajouter comme mot-clé »… ». « Aucune transaction trouvée. » peut s'afficher un très bref instant entre les deux lectures (limite connue)." },
{ id: "guided-same-page", title: "Limite connue : un lien d'étape suivi depuis la page Transactions",
expect: "Passe l'étape 6 depuis sa carte, change les filtres de la page Transactions, puis, sur cette même page, clique « Reprendre » dans la liste du bandeau. La carte revient, mais la page garde tes filtres au lieu de l'entrée guidée ; la phrase de la carte suit le filtre réellement affiché. À juger." },
{ id: "guided-budget-expanded", title: "Budget : grille déjà dépliée par le profil",
expect: "Sur un profil où l'étape 7 reste à faire, déplie la grille (« Tout déplier ») sans saisir de montant, puis quitte la page Budget. Reviens par le lien de l'étape 7 : la grille est restée dépliée et la carte entoure directement la cellule du mois courant." },
{ id: "guided-budget-offscreen", title: "Limite connue : cellule du mois hors de la zone visible",
expect: "En fenêtre étroite, la grille du budget défile horizontalement et la cellule du mois courant peut être hors de vue (les derniers mois de l'année sont à droite) : rien ne défile tout seul. À juger : la phrase et le contour suffisent-ils pour la trouver ?" },
{ id: "guided-budget-zero", title: "Budget : une cellule quittée vide enregistre 0 $",
expect: "Sur un profil où l'étape 7 reste à faire, clique une cellule puis quitte-la sans rien saisir : 0 $ est enregistré et la carte annonce « Fait. ». C'est le comportement existant de la grille ; à juger." },
{ id: "guided-import-flash", title: "Limite connue : « Aucun dossier configuré » à l'ouverture d'Import",
expect: "À l'ouverture de la page Import, la carte du dossier peut afficher un très bref instant « Aucun dossier configuré » avant la lecture du dossier ; l'état vide et la carte de démarrage, eux, attendent cette lecture. À juger." }
]
},
{
id: "retours-v0171",
title: "Retours de la v0.17.1 : textes et cartes du parcours",
intro: "Jalon planned-2026-10-12-retours-onboarding-v0171. Sur un profil neuf, en français, puis en anglais pour relire les mêmes phrases.",
steps: [
{ id: "v0171-import-structure", title: "Import : l'encadré « Structure attendue » (#422)",
expect: "Sans dossier choisi (« Aucun dossier d'import »), puis dans un dossier vide (« Aucune source trouvée »), l'état vide montre l'encadré « Structure attendue » au-dessus du lien « Comment exporter un CSV depuis ma banque ? » : « Dossier parent : choisissez celui-ci », dessous « Carte de crédit : une source » avec releve-2026-08.csv et releve-2026-09.csv, puis « Compte chèques : une autre source », et la note « Les fichiers posés directement dans le dossier parent sont ignorés. ». Les niveaux se lisent en retrait, dans les deux thèmes ; un lecteur d'écran lit une liste imbriquée, sans annoncer les icônes." },
{ id: "v0171-import-card-folder", title: "Import : cartes « Choisir un dossier d'import » et « Configurer une source d'import » (#422)",
expect: "Sans dossier, la carte dit : « Choisissez avec le bouton « Choisir un dossier » le dossier parent de vos relevés. Simpl'Résultat y lit un sous-dossier par compte : un pour la carte de crédit, un pour le compte chèques, et ainsi de suite. » Dans un dossier vide, elle nomme le dossier entre guillemets, demande un sous-dossier par compte et cite « Actualiser » et « Créer un dossier d'exemple » entre guillemets (« deux comptes fictifs »). Une fois les sources présentes : « Cliquez sur la carte d'un compte… ». Nulle part la carte ne parle d'un sous-dossier par banque." },
{ id: "v0171-import-card-preview", title: "Import : la carte de l'aperçu parle des signes (#422)",
expect: "À l'écran d'aperçu de l'assistant, la carte dit qu'une dépense doit compter parmi les sorties, en négatif, cite « Inverser les signes » comme correction, puis « Vérifier les doublons », chacun entre guillemets ; le contour reste sur « Vérifier les doublons ». Aux écrans suivants, « Confirmer » puis « Importer » sont aussi entre guillemets. En anglais, les mêmes libellés sont entre “ ”." },
{ id: "v0171-import-help", title: "Import : l'aide de la page et le guide (#422)",
expect: "L'aide de la page Import (icône ?) commence par « Choisissez le dossier parent de vos relevés… » et porte, après « Prévisualisez vos données… », la règle des signes avec « Inverser les signes ». Dans le guide d'utilisation (section Import), l'étape 2 dit « Créez un sous-dossier par compte… », l'étape 6 qu'une dépense doit compter parmi les sorties, et l'étape 7 parle des prochains fichiers « de ce compte »." },
{ id: "v0171-import-root-files-with-source", title: "Import : fichier posé à la racine, à côté d'une source (#427)",
expect: "Dans le dossier d'import, pose a.csv directement à la racine et crée un sous-dossier visa avec un relevé, puis « Actualiser » : la carte de la source visa s'affiche, et au-dessus d'elle un avertissement (icône triangle) dit « 1 fichier est posé directement dans « <nom du dossier> » et est ignoré : a.csv. Déplacez-le dans un sous-dossier par compte. ». Le dossier est nommé par son dernier segment, jamais par son chemin." },
{ id: "v0171-import-root-files-no-source", title: "Import : trois fichiers à la racine, aucune source (#427)",
expect: "Dans un dossier sans sous-dossier mais avec trois CSV à la racine, « Actualiser » : l'état vide « Aucune source trouvée » s'affiche, et sous lui l'avertissement au pluriel nomme les trois fichiers, séparés par des virgules. Avec sept fichiers, il en nomme cinq puis « et 2 autres ». En anglais : “… sit directly in “<folder>” and are ignored: … and 2 more.”" },
{ id: "v0171-import-root-files-lifecycle", title: "Import : l'avertissement suit le dossier (#427)",
expect: "Déplace les fichiers de la racine dans un sous-dossier puis « Actualiser » : l'avertissement disparaît. Remets-en un, « Actualiser » : il revient. Ouvre une source puis « Annuler » (ou va au bout d'un import puis « Terminé ») : l'avertissement est toujours là. Dans Paramètres → Systèmes → Journal, aucune ligne ne contient le nom d'un de ces fichiers ni le chemin du dossier." },
{ id: "v0171-import-source-name", title: "Import : le nom de la source est celui de son sous-dossier (#426)",
expect: "Ouvre une source : la configuration affiche sous « Nom de la source » le nom du sous-dossier, en texte, sans champ de saisie, et dessous « Le nom de la source est celui de son sous-dossier. ». La carte de démarrage dit « Vérifiez les fichiers cochés, puis cliquez « Aperçu ». » et ne parle plus du nom. En anglais : “A source is named after its subfolder.” et “Check the selected files, then click “Preview”.”" },
{ id: "v0171-import-source-reopen", title: "Import : la source est retrouvée au prochain import (#426)",
expect: "Importe un fichier d'une source, puis « Terminé » et rouvre la même source : aucun bandeau de détection (le format enregistré est restauré tel quel), le fichier déjà importé porte le badge « Importé » et n'est pas coché. Sur une base créée avant ce correctif, une source déjà renommée garde ce défaut (hors périmètre)." },
{ id: "v0171-transactions-card-keyword", title: "Transactions : la carte propose « Ajouter comme mot-clé » (#430)",
expect: "Par le lien de l'étape 6, la carte dit : « Seules les transactions non catégorisées sont affichées. Faites un clic droit sur l'une d'elles, puis « Ajouter comme mot-clé » : le mot-clé classe cette transaction et les transactions semblables de l'aperçu, et servira aux prochains imports. Gardez un mot propre au commerçant, pas « PAIEMENT », et décochez les transactions déjà bien classées. Vous pouvez aussi cliquer sur sa catégorie et en choisir une. » Avec le filtre « Toutes », la phrase commence par « Faites un clic droit sur une transaction… » et garde la même consigne. Le contour reste sur la catégorie de la première ligne. En anglais, “Add as keyword” et “PAYMENT” sont entre “ ”." },
{ id: "v0171-transactions-keyword-checks", title: "Transactions : la boîte du mot-clé coche l'étape (#430)",
expect: "Sur un profil où l'étape 6 reste à faire, suis la carte : clic droit sur une transaction, « Ajouter comme mot-clé », remplace le mot prérempli par un mot propre au commerçant si besoin, choisis une catégorie, décoche une transaction de l'aperçu, puis « Appliquer et recatégoriser ». La carte annonce « Fait. » sans quitter la page ; la transaction décochée garde sa catégorie. La boîte elle-même n'a pas changé." },
{ id: "v0171-budget-card-leaves", title: "Budget : la carte nomme les feuilles et la colonne « Annuel » (#430)",
expect: "Grille repliée, la carte dit : « Cliquez « Tout déplier » pour afficher vos catégories. Seules celles du dernier niveau, sans chevron, acceptent un montant : cliquez sur un mois et saisissez-le (Entrée enregistre ; Tab enregistre et passe au mois suivant). Un montant saisi dans la colonne « Annuel » est réparti également sur les 12 mois et remplace les montants mensuels. » Après « Tout déplier », la phrase commence par « Seules les catégories du dernier niveau… » et garde la phrase sur « Annuel ». Vérifie dans la grille que l'affirmation tient : une ligne à chevron n'accepte pas de montant ; 120 $ dans « Annuel » donne 10 $ par mois et remplace les montants déjà saisis. En anglais, “Expand all” et “Annual” sont entre “ ”." },
{ id: "v0171-visit-eight-rows", title: "Liste de démarrage : huit lignes, deux étapes de visite (#425)",
expect: "Sur un profil neuf, la liste montre dans l'ordre : « Créer un profil », « Choisir un dossier d'import », « Configurer une source d'import », « Importer un premier fichier », « Parcourir les catégories et les mots-clés », « Classer une transaction à la main », « Saisir un premier budget », « Parcourir les rapports ». Le compteur dit 1 / 8 (1 / 7 sans clé, la ligne Budget verrouillée « Base et plus »). Après l'import, « Étape suivante » mène à « Parcourir les catégories et les mots-clés ». Ouvrir Catégories ou Rapports sans cliquer ne coche rien. En anglais : “Browse categories and keywords”, “Browse the reports”." },
{ id: "v0171-visit-got-it", title: "« J'ai compris » coche une étape de visite (#425, #432)",
expect: "Sur la carte d'une étape de visite (pages Catégories et Rapports), « J'ai compris » s'affiche avant « Passer cette étape ». Un clic coche l'étape : la carte reste, annonce « Fait. » et propose l'étape suivante (ou le message de fin après Rapports) ; dans la liste, la ligne est barrée, sans le badge « Passée ». « Passer cette étape » donne, lui, une ligne « Passée » avec « Reprendre ». En anglais : “Got it”." },
{ id: "v0171-visit-auto-done", title: "Profil au parcours fini : les étapes de visite sont faites d'office (#425)",
expect: "Ouvre, avec cette version, un profil dont les six anciennes étapes étaient faites ou passées et dont le parcours n'est pas masqué (il affichait « Démarrage terminé »). À aucun moment le bandeau ne passe par « Étape suivante : Parcourir les catégories et les mots-clés » : il garde « Démarrage terminé ». Dans la liste, les deux étapes de visite sont barrées. Le Journal (Paramètres → Système) porte « Onboarding: the path was already complete, visit steps marked done ». Rouvrir le profil ne change plus rien." },
{ id: "v0171-visit-incomplete", title: "Profil au parcours incomplet : les étapes de visite restent à faire (#425)",
expect: "Ouvre, avec cette version, un profil dont au moins une des six anciennes étapes restait à faire. Les deux étapes de visite sont à faire, et le restent une fois les six autres terminées : le compteur dit 6/8, et « Étape suivante » mène à la première étape de visite non faite." },
{ id: "v0171-visit-pending", title: "Limite connue : lignes de visite « en attente » avant l'initialisation (#425)",
expect: "À la toute première ouverture d'un profil avec cette version, le temps de lire la licence et d'initialiser les étapes de visite (un instant), la liste peut montrer les deux étapes de visite « en attente » (cercle pâle, lu « en attente » par un lecteur d'écran), jamais avec le badge « Base et plus », et sans compteur. Elles passent ensuite à faire ou faites. À juger si l'instant est visible." }
]
},
{
id: "parcours-guide-a11y",
title: "Parcours guidé : accessibilité et rendu",
intro: "Sous Linux (WebKitGTK, lecteur d'écran Orca), puis sous Windows (WebView2, lecteur d'écran NVDA). Indique le système dans le champ prévu.",
steps: [
{ id: "guided-render-linux", title: "Contour et pulsation sous Linux (WebKitGTK)",
expect: "Un contour de couleur d'accent, d'environ 3 px et décalé de 2 px, entoure le contrôle désigné sur les trois pages ; la pulsation joue trois fois en un peu moins de 4 secondes, puis le contour reste fixe. Note s'il est rogné par la grille ou par un conteneur." },
{ id: "guided-render-windows", title: "Contour et pulsation sous Windows (WebView2)",
expect: "Même attendu que sous Linux : contour de couleur d'accent d'environ 3 px, décalé de 2 px, trois pulsations, puis un contour fixe, jamais rogné." },
{ id: "guided-reduced-motion", title: "Mouvement réduit (prefers-reduced-motion)",
expect: "Active l'option du système qui réduit les animations (GNOME : réduire les animations, dans Accessibilité ; Windows : effets d'animation désactivés, dans Accessibilité → Effets visuels), puis relance l'application si rien ne change : le contour s'affiche, sans aucune pulsation." },
{ id: "guided-contrast", title: "Contraste du contour, thème clair et thème sombre",
expect: "Dans les deux thèmes (bouton de la barre latérale), le contour se distingue nettement du fond de la page, des cartes et du contour de focus du clavier, sur les pages Import, Transactions et Budget." },
{ id: "guided-keyboard", title: "Clavier seul",
expect: "Sans souris, de l'étape 2 à l'étape 8 : Tab atteint « Étape suivante », « Voir la liste », « Masquer », les lignes de la liste, « J'ai compris », « Passer cette étape » et le contrôle entouré, et Entrée ou Espace les active. À l'arrivée par un lien d'étape, le focus est sur le titre de la carte, et Tab repart de là vers le contrôle entouré. Quand le contrôle entouré a le focus, l'anneau de focus du système remplace le contour. Le focus reste visible partout et n'est jamais pris au piège." },
{ id: "guided-focus-after-hide", title: "Limite connue : le focus après « Masquer » et « Fermer »",
expect: "Au clavier, active « Masquer » dans le bandeau, puis, sur un autre profil, « Fermer » au message de fin : le bouton disparaît avec le bandeau et le focus retombe sur la page elle-même, comme avec l'ancienne barre compacte ; note d'où Tab repart. Même chose après un lien du bandeau vers une page sans carte (« Ouvrir le guide », ligne Budget verrouillée). À juger, avec Orca puis NVDA : le lecteur d'écran perd-il le fil ?" },
{ id: "guided-orca", title: "Annonces d'Orca (Linux)",
expect: "Le bandeau et la carte s'annoncent comme la région « Parcours de démarrage » ; « Voir la liste » annonce son état replié ou déplié ; dans la liste, chaque étape est suivie de son état (« faite », « passée », « verrouillée », « en attente »), sauf une étape à faire ; à l'arrivée par « Étape suivante », le titre de la carte est lu ; « Fait. » est annoncé sans déplacer le focus ; la confirmation de Paramètres → Utilisateurs est annoncée." },
{ id: "guided-nvda", title: "Annonces de NVDA (Windows)",
expect: "Mêmes annonces que sous Orca : région « Parcours de démarrage », état replié ou déplié de « Voir la liste », état de chaque étape de la liste, titre de la carte à l'arrivée par « Étape suivante », « Fait. » sans déplacement du focus, confirmation de Paramètres → Utilisateurs." }
]
}
];
var ALL_STEPS = [];
SECTIONS.forEach(function (section) {
section.steps.forEach(function (step) { ALL_STEPS.push(step); });
});
var state = load();
function load() {
var fresh = { meta: { tester: "", version: "", os: "" }, steps: {} };
try {
var raw = window.localStorage.getItem(STORAGE_KEY);
if (!raw) return fresh;
var parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== "object") return fresh;
return {
meta: Object.assign(fresh.meta, parsed.meta || {}),
steps: parsed.steps && typeof parsed.steps === "object" ? parsed.steps : {}
};
} catch (e) {
return fresh;
}
}
function save() {
try {
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (e) {
setStatus("Impossible d'enregistrer dans ce navigateur : le rapport reste copiable, mais l'état sera perdu au rechargement.");
}
}
function stepState(id) {
if (!state.steps[id]) state.steps[id] = { done: false, note: "" };
return state.steps[id];
}
function setStatus(text) {
document.getElementById("status").textContent = text;
}
function countDone() {
var done = 0;
ALL_STEPS.forEach(function (s) { if (stepState(s.id).done) done += 1; });
return done;
}
function updateProgress() {
document.getElementById("progress").textContent = countDone() + " / " + ALL_STEPS.length + " étapes cochées";
}
function renderStep(step, list) {
var st = stepState(step.id);
var li = document.createElement("li");
li.className = st.done ? "done" : "";
var check = document.createElement("div");
check.className = "check";
var box = document.createElement("input");
box.type = "checkbox";
box.id = "done-" + step.id;
box.checked = !!st.done;
box.addEventListener("change", function () {
st.done = box.checked;
li.className = st.done ? "done" : "";
save();
updateProgress();
});
check.appendChild(box);
var title = document.createElement("label");
title.className = "title";
title.htmlFor = box.id;
title.textContent = step.title;
var expect = document.createElement("div");
expect.className = "expect";
expect.textContent = step.expect;
var where = document.createElement("div");
where.className = "where";
var noteLabel = document.createElement("label");
noteLabel.htmlFor = "note-" + step.id;
noteLabel.textContent = "Où as-tu hésité ?";
var note = document.createElement("input");
note.type = "text";
note.id = noteLabel.htmlFor;
note.value = st.note || "";
note.autocomplete = "off";
note.addEventListener("input", function () {
st.note = note.value;
save();
});
where.appendChild(noteLabel);
where.appendChild(note);
li.appendChild(check);
li.appendChild(title);
li.appendChild(expect);
li.appendChild(where);
list.appendChild(li);
}
function render() {
var root = document.getElementById("sections");
root.textContent = "";
SECTIONS.forEach(function (section) {
var block = document.createElement("section");
block.id = section.id;
var heading = document.createElement("h2");
heading.textContent = section.title;
block.appendChild(heading);
var intro = document.createElement("p");
intro.className = "intro";
intro.textContent = section.intro;
block.appendChild(intro);
var list = document.createElement("ol");
list.className = "steps";
section.steps.forEach(function (step) { renderStep(step, list); });
block.appendChild(list);
root.appendChild(block);
});
["tester", "version", "os"].forEach(function (key) {
var input = document.getElementById(key);
input.value = state.meta[key] || "";
input.oninput = function () {
state.meta[key] = input.value;
save();
};
});
updateProgress();
}
function pad(n) { return n < 10 ? "0" + n : String(n); }
function buildReport() {
var now = new Date();
var date = now.getFullYear() + "-" + pad(now.getMonth() + 1) + "-" + pad(now.getDate()) +
" " + pad(now.getHours()) + ":" + pad(now.getMinutes());
var lines = [];
lines.push("QA parcours d'accueil — " + date);
if (state.meta.tester) lines.push("Testeur : " + state.meta.tester);
if (state.meta.version) lines.push("Version : " + state.meta.version);
if (state.meta.os) lines.push("Système : " + state.meta.os);
lines.push("Étapes cochées : " + countDone() + " / " + ALL_STEPS.length);
SECTIONS.forEach(function (section) {
lines.push("");
lines.push("== " + section.title + " ==");
section.steps.forEach(function (step, i) {
var st = stepState(step.id);
lines.push((st.done ? "[x] " : "[ ] ") + (i + 1) + ". " + step.title);
if (st.note && st.note.trim()) lines.push(" Hésitation : " + st.note.trim());
});
});
return lines.join("\n");
}
function showFallback(text) {
var box = document.getElementById("fallback");
var area = document.getElementById("report");
area.value = text;
box.hidden = false;
area.focus();
area.select();
}
document.getElementById("copy").addEventListener("click", function () {
var text = buildReport();
document.getElementById("fallback").hidden = true;
if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
navigator.clipboard.writeText(text).then(function () {
setStatus("Rapport copié. Colle-le dans Paramètres → Système → Envoyer un feedback.");
}, function () {
setStatus("Copie automatique refusée : utilise la zone ci-dessous.");
showFallback(text);
});
} else {
setStatus("Copie automatique indisponible : utilise la zone ci-dessous.");
showFallback(text);
}
});
document.getElementById("reset").addEventListener("click", function () {
if (!window.confirm("Effacer toutes les cases et tous les commentaires ?")) return;
state = { meta: { tester: "", version: "", os: "" }, steps: {} };
try { window.localStorage.removeItem(STORAGE_KEY); } catch (e) { /* nothing to remove */ }
document.getElementById("fallback").hidden = true;
setStatus("Checklist réinitialisée.");
render();
});
render();
})();
</script>
</body>
</html>