Intégration continue Windows / Linux
La version 0.1.18 consolide la matrice GitHub Actions introduite en 0.1.17 dans .github/workflows/ci.yml. Elle sépare les contrôles de qualité, les scénarios Chromium et la fabrication du package npm afin qu’un échec soit immédiatement attribuable à une frontière précise.
Matrice de qualité
Les runners ubuntu-latest et windows-latest exécutent tous deux :
bun install --frozen-lockfile
bun run ci:qualityci:quality couvre notamment :
- invariants statiques et runtime ;
- typecheck Nuxt/Vue et TypeScript E2E ;
- build de la documentation VitePress ;
- build Nuxt/Nitro du playground ;
- budget des chunks, CSS et polices ;
- build SSR d’une application Nuxt hôte distincte ;
- vérification de la liste des fichiers du package npm.
Le lockfile est obligatoire. Une modification de package.json doit être suivie de bun install, puis du commit de bun.lock.
Isolation du serveur Playwright
Chaque commande navigateur passe par scripts/run-playwright.mjs. Le wrapper choisit une seule fois un port libre à partir de son PID, puis transmet exactement le même QFORM_E2E_PORT et le même QFORM_E2E_BASE_URL au runner, au serveur Nuxt et aux workers Playwright. Cette propagation évite qu'une seconde évaluation de playwright.config.ts calcule un autre port sous Windows. Il est possible de fixer le port explicitement :
$env:QFORM_E2E_PORT = '4721'
bun run e2e:ci:functionalLe serveur est considéré prêt uniquement lorsque /qform-e2e-ready répond. reuseExistingServer est désactivé : un ancien Nuxt, VitePress ou autre service présent sur le port ne peut plus produire une suite de faux échecs où toutes les routes semblent absentes.
Pour tester une application déjà démarrée :
$env:QFORM_E2E_BASE_URL = 'http://127.0.0.1:4173'
$env:QFORM_E2E_NO_SERVER = '1'
bun run e2e:ci:functionalBootstrap des captures visuelles
ci:quality exécute les contrôles statiques, typechecks, builds, budgets, application hôte et package sans exiger des PNG qui n’existent pas encore dans une archive complète.
La première initialisation se fait explicitement :
bun run ci:quality
bun run e2e:ci:functional
bun run e2e:visual:bootstrap
# inspection humaine de tests/e2e/__screenshots__
bun run e2e:snapshots:check
bun run release:browser:checkrelease:check et release:browser:check continuent à échouer lorsqu’une baseline manque. Le bootstrap n’est jamais exécuté automatiquement par la CI.
Matrice Chromium
La CI exécute Chromium sur les deux systèmes :
- Linux : scénarios fonctionnels, migrations, modèles, Theme Builder et audit axe ;
- Windows : audit axe et suite visuelle complète utilisant les baselines Chromium validées.
Les captures Playwright sont sensibles au moteur de rendu des polices. Les baselines officielles restent donc celles de Windows, tandis que Linux valide les mêmes parcours sans comparaison pixel à pixel.
Application hôte de release candidate
tests/host-app est une véritable application Nuxt distincte :
export default defineNuxtConfig({
extends: ['../../'],
ssr: true,
})Elle n’importe que les sous-chemins publics :
import type { FormBuilderSchema } from '@vevedh/qform-builder-layer/types'
import type { QFormBuilderThemeInput } from '@vevedh/qform-builder-layer/theme'Le build vérifie que :
- le layer fonctionne hors du playground ;
- SSR reste activé ;
FormBuilderetFormViewersont auto-importés ;- le thème et les types publics sont résolus depuis le contrat npm ;
- aucune dépendance à un chemin interne
app/...n’est nécessaire.
Commande locale :
bun run host:build:checkAvant le build, host:clean appelle scripts/clean-host-generated.mjs. Ce nettoyeur Node supprime uniquement tests/host-app/.nuxt et tests/host-app/.output avec des retries bornés pour les erreurs Windows transitoires (ENOTEMPTY, EPERM, EBUSY). Il ne dépend pas de rm -rf, dont l’implémentation sous Windows peut échouer sur les jonctions node_modules générées par Nitro.
Budget de bundle
Après le build du playground :
bun run bundle:budget:inspectLe gate limite actuellement :
| Ressource | Budget individuel |
|---|---|
| JavaScript | 800 000 octets |
| JavaScript gzip | 300 000 octets |
| CSS | 300 000 octets |
| CSS gzip | 70 000 octets |
| Police | 512 000 octets |
| Total des polices | 650 000 octets |
Le rapport est écrit dans .artifacts/bundle-budget.json.
La version 0.1.17 supprime les familles material-icons-outlined et material-symbols-outlined. Les rares icônes préfixées ont été remplacées par leurs équivalents Material Icons standards. Iconify reste embarqué via le catalogue UnoCSS contrôlé.
Artifact npm vérifié
Trois commandes sont disponibles :
bun run pack:verify
bun run pack:artifact
bun run package:ci:artifactpack:verify inspecte la liste du tarball sans le conserver. pack:artifact produit dans .artifacts/ le fichier .tgz, package-manifest.json et le SHA-256 du tarball. package:ci:artifact est la commande utilisée par GitHub Actions : elle nettoie .artifacts, construit le tarball, lance le dry-run npm depuis ce tarball, crée release-candidate-evidence.json, puis vérifie que les trois fichiers uploadés existent réellement.
Le gate refuse notamment .playground, tests, .github, les journaux internes, les archives ZIP et les lockfiles.
Validation locale avant push
bun run clean
bun install
bun run ci:quality
bun run e2e:ci:functional
bun run release:browser:check
bun run package:ci:artifactLes douze baselines visuelles doivent être présentes et inspectées avant l’exécution de release:browser:check.
Vérifier la complétude du workspace
bun run workspace:checkUn overlay est incrémental. S’il est extrait dans un dossier vide, les commandes déclarées dans package.json peuvent exister alors que les scripts et scénarios ciblés sont absents. Le garde de complétude échoue avant la CI avec la liste des frontières manquantes. Pour une initialisation ou une récupération, repartir de l’archive complète puis appliquer l’overlay.
Gate finale de release candidate
Le workflow expose un job Automated release candidate gate dépendant des jobs qualité, Chromium et package. Il fournit une cible de protection pour les contrôles automatisés ; la preuve humaine reste imposée par release:evidence:verify.
Le contrôle local équivalent est :
bun run release:candidate:checkLe gel d’API est vérifié par api:contract:check pendant les jobs qualité, tandis que typecheck:contract compile un consommateur externe.
Registre de preuves RC — 0.1.21
Avant bun install --frozen-lockfile, chaque job CI exécute désormais :
node scripts/check-bun-lockfile.mjsCette étape fournit un diagnostic lisible lorsque package.json et le workspace racine de bun.lock divergent. Elle ne remplace pas l’installation gelée, qui reste l’autorité finale.
Le job package génère ensuite, dans le même job et avant upload-artifact :
bun run package:ci:artifactCette commande conserve .artifacts/release-candidate-evidence.json avec le tarball et son manifeste. Le registre peut être blocked dans une CI ordinaire lorsque la revue manuelle n’est pas encore terminée. La promotion locale stricte exige :
bun run release:evidence:verifyVoir Préflight de la release candidate.
Artefact du guide illustré
Le job navigateur Linux régénère le guide après la suite fonctionnelle :
bun run docs:guide:ciCette commande produit les douze captures FR/EN, recalcule leur manifeste SHA-256 et exécute la vérification stricte. GitHub Actions publie ensuite docs/public/guide/screenshots/ comme artefact qform-automated-user-guide pour inspection avant intégration.
FormKit 2.1 et validation du polish des panneaux
La version 0.1.33 conserve 2.1.0 comme baseline exacte de développement pour @formkit/core, @formkit/i18n, @formkit/inputs, @formkit/nuxt, @formkit/utils et @formkit/vue. Les peer dependencies restent bornées à ^2.1.0 : les mises à jour compatibles de la série 2 sont acceptées, mais une future série 3 exige un patch explicite et une nouvelle matrice de validation.
Le contrôle ciblé est :
bun run formkit:upgrade:checkLe nouveau rendu des panneaux gauche et droit modifie volontairement des pixels. L'archive candidate conserve les anciennes images uniquement comme références bootstrap et la gate stricte doit rester bloquée jusqu'à la régénération autoritaire sous Windows 11 :
bun run clean
bun install --frozen-lockfile
bun run formkit:upgrade:check
bun run e2e:visual:update
# inspecter manuellement les 12 PNG dans tests/e2e/__screenshots__
bun run docs:screenshots
# inspecter les 12 captures FR/EN du guide
bun run release:browser:check
bun run docs:screenshots:strict
bun run release:publish:checkLes PNG ne doivent être commités qu'après inspection du mode clair, du mode sombre, des états clavier, des panneaux dédiés QEditor/QSelect/QRating/QBtn et du reflow des deux drawers. Aucun seuil global ne doit être augmenté pour accepter le nouveau design.
Critères de la seconde passe polished
La revue visuelle Windows 11 impose une hiérarchie plus nette sans modifier le fonctionnement :
- catalogue gauche plat et compact, avec recherche permanente et compteurs filtrés ;
- accent primaire réservé au survol, au focus et à la sélection ;
- largeurs fluides et bornées, calculées depuis le conteneur réel du builder ;
- en-tête du champ sélectionné composé du libellé utilisateur, du nom technique et du type d’adaptateur ;
- sections principales visuellement prioritaires, sans suppression des réglages avancés ;
- shell commun aux configurations de champ, colonne et étape.
Le contrat public doit rester identique. Toute acceptation visuelle nécessite encore la régénération autoritaire des captures sur Windows 11.
Contraste axe et contrat DOM du champ sélectionné
Le rejeu Windows 11 a identifié deux contrats précis : les tabs inactifs ne doivent pas conserver l’opacité Quasar par défaut, et le scénario de renommage ne doit pas dépendre d’un niveau de titre HTML. Le token secondaire renforcé est #526174 en mode clair et #cbd5e1 en mode sombre. Il dépasse 4,5:1 sur les surfaces #ffffff, #f1f5f9 et #fbf5f0.
Le nom technique du champ sélectionné est exposé par :
[data-qform-selected-field-name]Les tests E2E doivent utiliser ce contrat stable. Après modification des couleurs, relancer bun run e2e:visual:update et inspecter les baselines avant de poursuivre.
Drawers responsives et auto-fit
Le mode par défaut n'utilise pas la largeur globale du navigateur. Un ResizeObserver mesure le conteneur réel de FormBuilder, ce qui couvre aussi les intégrations dans une carte, un onglet ou un panneau d'application hôte.
Le résolveur protège les bornes suivantes :
- panneau gauche : 220 à 320 px en mode persistant ;
- panneau droit : 280 à 480 px en mode persistant, avec une préférence de 360 px ;
- canvas central : au moins 480 px lorsque les deux panneaux sont ouverts ;
- en dessous de la capacité minimale, les panneaux deviennent des overlays et conservent une marge latérale de 16 px ;
- sur une largeur étroite, ouvrir un panneau ferme l'autre afin d'éviter leur superposition.
Le panneau de propriétés utilise des grilles auto-fit, des contrôles min-width: 0 et des container queries : les groupes d’alignement passent de quatre à deux colonnes sous 390 px, puis les sélecteurs se replient sur une colonne sous 300 px. Les deux drawers conservent chacun une seule zone de scroll interne et ne doivent créer aucun débordement horizontal du document.
La gate dédiée est :
bun run drawers:responsive:checkLe scénario Playwright d'accessibilité vérifie aussi les états 1024 px, 860 px et 375 px, la largeur minimale du canvas, le passage persistant/overlay et l'exclusion mutuelle des drawers mobiles. Le scénario Styles mesure en plus le panneau à 1600 px, 1024 px et 375 px et refuse tout overflow horizontal visible de son QScrollArea et tout contrôle Quasar sortant de la vue ; le JSON de diagnostic conserve au besoin son scroll local. La largeur est comparée à la valeur résolue depuis le conteneur réel du builder, et non à un seuil dérivé du viewport.
Un seul ascenseur dans le panneau gauche
Le shell du drawer gauche est une colonne flex bornée. Les onglets principaux restent fixes et l'unique QScrollArea consomme seulement la hauteur restante. Il ne doit jamais conserver la classe Quasar fit, car 100% ajouté sous les onglets recrée un débordement du drawer et donc un second ascenseur natif.
Le contrat navigateur stable est :
[data-qform-elements-scroll-area]Après toute modification du catalogue, vérifier visuellement qu'un seul ascenseur vertical est visible à gauche, puis rejouer bun run formkit:compat:check et la suite Playwright. Le drawer externe doit rester en overflow: hidden, tandis que la zone interne conserve le scroll des éléments, modèles et de l'arborescence.
Interop runtime QSelect et HMR sous Windows 11
Le playground doit exposer le WebSocket HMR sur le même port public que Nuxt. Le port est résolu depuis l’option CLI --port, puis NUXT_PORT ou PORT; 3000 n’est qu’un fallback local. Le navigateur ne doit jamais tenter une connexion directe au port privé Vite 5173, et la configuration doit continuer à accepter les ports aléatoires utilisés par Playwright.
Le custom input FormKit q-select utilise la valeur vivante context._value. Avant de transmettre cette valeur à Quasar ou de la réinjecter avec node.input(), l’adaptateur normalise les modèles simples/multiples et détache les objets réactifs ou à prototype nul que String(value) ne peut pas convertir. Avec emitValue, seul le chemin optionValue attendu est conservé.
Validation Windows ciblée :
bun run clean
bun install --frozen-lockfile
bun run formkit:upgrade:check
bun devDans /, passer en aperçu, changer Objet de la demande, puis saisir du texte dans Message. La console ne doit contenir aucun des messages suivants :
[vite] failed to connect to websocket
Cannot convert object to primitive value
Cannot read properties of null (reading 'emitsOptions')Terminer avec bun run e2e:visual:update. Le scénario QSelect existant vérifie la valeur scalaire contrôlée par l’hôte, une saisie suivante et l’absence de pageerror; la matrice doit rester à 24/24.
Artifact npm dans GitHub Actions
Le job Package artifact génère les preuves avec bun run package:ci:artifact, puis les publie depuis le dossier canonique .artifacts. Comme ce dossier commence par un point, les étapes actions/upload-artifact qui ciblent .artifacts/*.tgz, .artifacts/package-manifest.json ou .artifacts/release-candidate-evidence.json doivent garder include-hidden-files: true. Sans cette option, l'upload peut échouer avec No files were found with the provided path alors que la génération du package a réussi.