Testes com oráculo
Toda decisão de implementação em Phasis depende de uma pergunta: V8 produz o mesmo resultado?
JavaScript tem semânticas sutis — NaN !== NaN, -0 === 0, [1] + 1 === "11", a ordem exata da enumeração de propriedades e o momento das microtarefas de Promise. Rededuzir esses comportamentos pela leitura da especificação é lento e propenso a erros. Phasis evita isso tratando Node.js (V8) como oráculo: escreva um cenário JS, execute-o em V8 e registre a saída como verdade; execute-o em Phasis, registre novamente a saída e compare.
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
Dois níveis de testes
Nível 1 — Cenários personalizados
Cada cenário em scenarios/ é um pequeno programa JS com saída conhecida. Execute um único cenário:
./bin/test-scenario operators/arithmetic
Execute todos, apenas uma categoria ou em paralelo:
./bin/test-regression
./bin/test-regression --jobs 4
./bin/test-regression --category expressions
Atualize o oráculo (e.g, por exemplo, após uma atualização de versão do Node.js):
./bin/oracle --refresh operators/arithmetic
Os cenários são organizados por capítulo do ECMAScript: literais, operadores, variáveis, fluxo de controle, funções, objetos, arrays, classes, recursos integrados, erros, interoperabilidade e casos extremos.
Nível 2 — test262
A suíte oficial de conformidade do TC39 é obtida como um submódulo git em test262/. Cada teste verifica a si próprio: é aprovado se não lançar uma exceção e reprovado se lançar (ou o contrário nos testes negative). O harness carrega assert.js e sta.js antes de cada teste.
./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
O snapshot da suíte completa fica em COMPAT.md e é regenerado por bin/compat-report. Na CI, o fluxo de trabalho compat-matrix.yml executa os testes em partes e registra o resultado; esse fluxo é iniciado manualmente, não a cada envio.
Verificação local antes de enviar
./bin/verify-all executa a verificação de qualidade exigida pela CI:
=== PHPStan === level 6, zero errors
=== Code Standards === PHPCS, zero warnings
=== PHPUnit === unit suite passes
=== Oracle Regression === scenarios under `scenarios/` pass
Isso não basta por si só — test262 também deve ser testado para qualquer alteração no parser, interpretador ou nos recursos integrados. Em cada pull request, a CI executa PHPStan, PHPCS, a suíte unitária e a regressão do oráculo; as suítes WPT e de pacotes populares são executadas quando um pull request altera src/ ou seus fixtures. A matriz test262 completa não faz parte da CI de pull requests, então teste localmente as categorias afetadas.
Por que funciona
Tratar V8 como fonte de verdade elimina quase toda a leitura da especificação durante o ciclo de desenvolvimento. Uma divergência em relação a V8 sempre indica um bug Phasis — nunca uma ambiguidade na especificação que possa ser debatida. Depois que uma correção é integrada, as entradas correspondentes de test262 tornam-se testes de regressão permanentes.
A taxa de aprovação de 100 % é resultado dessa disciplina: cada PR é avaliado em relação a V8, a CI rejeita regressões nas suítes do oráculo, WPT e pacotes populares, e a matriz test262 confirma o resultado da suíte completa quando é executada.