Testování pomocí referenční implementace
Každé rozhodnutí při implementaci Phasis závisí na jediné otázce: vytváří V8 stejný výstup?
JavaScript má jemné sémantické nuance — NaN !== NaN, -0 === 0, [1] + 1 === "11", přesné pořadí výčtu vlastností a načasování úloh fronty microtasků Promise. Odvozovat je znovu čtením specifikace je pomalé a náchylné k chybám. Phasis tento problém obchází tím, že Node.js (V8) považuje za referenční implementaci: napíšete scénář JS, spustíte ho přes V8 a výstup uložíte jako správný výsledek; poté jej spustíte přes Phasis, znovu zachytíte výstup a porovnáte je.
1. SETUP → a JavaScript source file or snippet
2. ORACLE → Node.js executes it, output captured as truth
3. ACTUAL → Phasis executes it, output captured
4. COMPARE → oracle vs actual, diff measures the gap
Dvě úrovně testování
Úroveň 1 — Vlastní scénáře
Každý scénář v scenarios/ je krátký program JS se známým výstupem. Spusťte jeden scénář:
./bin/test-scenario operators/arithmetic
Spusťte všechny scénáře, jen jednu kategorii nebo je spusťte paralelně:
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
Obnovte referenční výstupy (e.g, například po aktualizaci verze Node.js):
./bin/oracle --refresh operators/arithmetic
Scénáře jsou uspořádány podle kapitol ECMAScriptu: literály, operátory, proměnné, řízení toku, funkce, objekty, pole, třídy, vestavěné funkce, chyby, interoperabilita a okrajové případy.
Úroveň 2 — test262
Oficiální sada testů shody TC39 je připojena jako git submodul pod test262/. Každý test ověřuje sám sebe: projde, pokud nevyvolá chybu, a selže, pokud ji vyvolá (u testů negative je to naopak). Testovací prostředí před každým testem načte assert.js a sta.js.
./bin/test262 # full suite
./bin/test262 --category built-ins/Array # subset
./bin/test262 --jobs 4 # parallel
./bin/test262 --failures # one line per failing test
./bin/compat-report # full COMPAT.md + compat.json
Snímek celé sady testů je v souboru COMPAT.md a znovu jej vytvoří bin/compat-report. V CI jej pracovní postup compat-matrix.yml spouští po částech a ukládá výsledek; tento postup se spouští ručně, nikoli při každém pushi.
Lokální kontrola před odesláním změn
./bin/verify-all spouští kontrolu kvality vyžadovanou CI:
=== PHPStan === level 6, zero errors
=== Code Standards === PHPCS, zero warnings
=== PHPUnit === unit suite passes
=== Oracle Regression === scenarios under `scenarios/` pass
Sama o sobě nestačí — při každé změně parseru, interpretu nebo vestavěných funkcí je nutné otestovat i vybrané testy test262. Při každém pull requestu CI spouští PHPStan, PHPCS, unit testy a regresní test referenční implementace; sady WPT a popular se spouští při změnách v src/ nebo v jejich přípravcích. Úplná matice test262 není součástí CI pro pull requesty, proto lokálně vyberte dotčené kategorie.
Proč to funguje
Když V8 považujeme za zdroj pravdy, vývojový cyklus téměř nevyžaduje čtení specifikace. Neshoda s V8 vždy ukazuje na chybu v Phasis, nikdy na sporný výklad specifikace. Po vydání opravy se příslušné testy test262 stanou trvalými regresními testy.
Míra úspěšnosti 100 % je výsledkem tohoto přístupu: každý PR se hodnotí vůči V8, CI odmítá regrese v testech referenční implementace, WPT a popular a matice test262 potvrzuje výsledek celé sady, když se spustí.