Compare commits

...

2 Commits

Author SHA1 Message Date
nuno maduro b52bbb4cca chore: snapshots 2026-07-14 15:11:20 +01:00
nuno maduro 52819501eb chore: fixes tia when not running on root 2026-07-14 14:34:00 +01:00
9 changed files with 495 additions and 24 deletions
+51 -15
View File
@@ -29,22 +29,54 @@ async function loadRolldown() {
return await import(pathToFileURL(path).href)
}
async function readJsonWithComments(path) {
const raw = await readFile(path, 'utf8')
const stripped = raw
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/(^|[^:])\/\/[^\n]*/g, '$1')
return JSON.parse(stripped)
export function stripJsonComments(raw) {
let out = ''
let inString = false
let quote = ''
let inLine = false
let inBlock = false
for (let i = 0; i < raw.length; i++) {
const c = raw[i]
const n = raw[i + 1]
if (inLine) {
if (c === '\n') { inLine = false; out += c }
continue
}
if (inBlock) {
if (c === '*' && n === '/') { inBlock = false; i++ }
continue
}
if (inString) {
out += c
if (c === '\\') { out += n ?? ''; i++; continue }
if (c === quote) inString = false
continue
}
if (c === '"' || c === "'") { inString = true; quote = c; out += c; continue }
if (c === '/' && n === '/') { inLine = true; i++; continue }
if (c === '/' && n === '*') { inBlock = true; i++; continue }
if (c === '}' || c === ']') out = out.replace(/,\s*$/, '')
out += c
}
return out
}
async function loadAliasFromTsconfig() {
async function readJsonWithComments(path) {
const raw = await readFile(path, 'utf8')
return JSON.parse(stripJsonComments(raw))
}
export async function loadAliasFromTsconfig(projectRoot = PROJECT_ROOT) {
const alias = {}
for (const name of ['tsconfig.json', 'jsconfig.json']) {
const p = join(PROJECT_ROOT, name)
const p = join(projectRoot, name)
if (!existsSync(p)) continue
let cfg
try { cfg = await readJsonWithComments(p) } catch { continue }
const baseUrl = resolve(PROJECT_ROOT, cfg?.compilerOptions?.baseUrl ?? '.')
const baseUrl = resolve(projectRoot, cfg?.compilerOptions?.baseUrl ?? '.')
const paths = cfg?.compilerOptions?.paths ?? {}
for (const [key, targets] of Object.entries(paths)) {
if (!key.endsWith('/*')) continue
@@ -230,10 +262,14 @@ async function main() {
process.stdout.write(JSON.stringify(payload))
}
try {
void pathToFileURL
await main()
} catch (err) {
process.stderr.write(String(err?.stack ?? err ?? 'unknown error'))
process.exit(1)
const invokedDirectly = process.argv[1] !== undefined
&& import.meta.url === pathToFileURL(process.argv[1]).href
if (invokedDirectly) {
try {
await main()
} catch (err) {
process.stderr.write(String(err?.stack ?? err ?? 'unknown error'))
process.exit(1)
}
}
+2 -2
View File
@@ -18,7 +18,7 @@
],
"require": {
"php": "^8.4",
"brianium/paratest": "^7.22.4",
"brianium/paratest": "^7.23.0",
"nunomaduro/collision": "^8.9.4",
"nunomaduro/termwind": "^2.4.0",
"pestphp/pest-plugin": "^5.0.0",
@@ -59,7 +59,7 @@
},
"require-dev": {
"mrpunyapal/peststan": "^0.2.11",
"laravel/pao": "^1.1.1",
"laravel/pao": "^1.1.2",
"pestphp/pest-dev-tools": "^5.0.0",
"pestphp/pest-plugin-browser": "^5.0.0",
"pestphp/pest-plugin-type-coverage": "^5.0.0",
+2 -2
View File
@@ -122,9 +122,9 @@ final readonly class Configuration
/**
* Gets the evals configuration.
*/
public function evals(): Evals\Configuration
public function evals(): Evals\Configuration // @phpstan-ignore-line
{
return new Evals\Configuration;
return new Evals\Configuration; // @phpstan-ignore-line
}
/**
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Pest\Exceptions;
use NunoMaduro\Collision\Contracts\RenderlessEditor;
use NunoMaduro\Collision\Contracts\RenderlessTrace;
use Pest\Contracts\Panicable;
use RuntimeException;
use Symfony\Component\Console\Exception\ExceptionInterface;
use Symfony\Component\Console\Output\OutputInterface;
/**
* @internal
*/
final class TiaRequiresRepositoryRoot extends RuntimeException implements ExceptionInterface, Panicable, RenderlessEditor, RenderlessTrace
{
public function __construct(private readonly string $subdirectoryPrefix)
{
parent::__construct(sprintf(
'Tia mode requires the project root to be the git repository root, but it sits in the subdirectory [%s] of a larger repo.',
$this->subdirectoryPrefix,
));
}
public function render(OutputInterface $output): void
{
$output->writeln([
'',
' <fg=white;options=bold;bg=red> ERROR </> Tia mode requires the git repository root.',
'',
sprintf(' This project sits in a subdirectory of a larger repo <fg=yellow>%s</>.', $this->subdirectoryPrefix),
'',
' Give the project its own git repository to use Tia.',
'',
]);
}
public function exitCode(): int
{
return 1;
}
}
+2 -2
View File
@@ -112,7 +112,7 @@ final class HigherOrderExpectation
* Dynamically calls methods on the class with the given arguments.
*
* @param array<int, mixed> $arguments
* @return self<TOriginalValue, mixed>|self<TOriginalValue, TValue>
* @return self<TOriginalValue, mixed>
*/
public function __call(string $name, array $arguments): self
{
@@ -127,7 +127,7 @@ final class HigherOrderExpectation
/**
* Accesses properties in the value or in the expectation.
*
* @return self<TOriginalValue, mixed>|self<TOriginalValue, TValue>
* @return self<TOriginalValue, mixed>
*/
public function __get(string $name): self
{
+29
View File
@@ -9,6 +9,7 @@ use Pest\Contracts\Plugins\AddsOutput;
use Pest\Contracts\Plugins\HandlesArguments;
use Pest\Contracts\Plugins\Terminable;
use Pest\Exceptions\NoAffectedTestsFound;
use Pest\Exceptions\TiaRequiresRepositoryRoot;
use Pest\Panic;
use Pest\Plugins\Concerns\HandleArguments;
use Pest\Plugins\Tia\BaselineSync;
@@ -627,6 +628,13 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
private function handleParent(array $arguments, string $projectRoot, bool $forceRebuild): array
{
$this->watchPatterns->useDefaults($projectRoot);
$subdirectoryPrefix = $this->gitSubdirectoryPrefix($projectRoot);
if ($subdirectoryPrefix !== null) {
Panic::with(new TiaRequiresRepositoryRoot($subdirectoryPrefix));
}
$this->branch = new ChangedFiles($projectRoot)->currentBranch() ?? 'main';
$fingerprint = Fingerprint::compute($projectRoot);
@@ -1643,6 +1651,27 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
return implode(', ', array_keys($seen));
}
/**
* The path from the git repository root down to $projectRoot (e.g.
* `laravel-app`) when the project is nested inside a larger repo, or `null`
* when the project root is itself the repo root (or git is unavailable).
* TIA requires the two to coincide: git reports and addresses paths
* relative to the repo root, while the dependency graph is project-relative.
*/
private function gitSubdirectoryPrefix(string $projectRoot): ?string
{
$process = new Process(['git', 'rev-parse', '--show-prefix'], $projectRoot);
$process->run();
if (! $process->isSuccessful()) {
return null;
}
$prefix = trim($process->getOutput());
return $prefix === '' ? null : rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $prefix), '/');
}
private function composerLockDelta(string $projectRoot, string $sha): string
{
$current = @file_get_contents($projectRoot.'/composer.lock');
+63 -1
View File
@@ -1820,6 +1820,68 @@
✓ does not throw when an integer --random-order-seed is passed as a separate argv element
✓ still detects --tia when an integer argument is present
PASS Tests\Unit\Plugins\Tia\ViteDepsHelper
✓ it strips JSONC down to something JSON.parse accepts with ('plain-object')
✓ it strips JSONC down to something JSON.parse accepts with ('plain-array')
✓ it strips JSONC down to something JSON.parse accepts with ('nested')
✓ it strips JSONC down to something JSON.parse accepts with ('empty-object')
✓ it strips JSONC down to something JSON.parse accepts with ('empty-array')
✓ it strips JSONC down to something JSON.parse accepts with ('line-comment-own-line')
✓ it strips JSONC down to something JSON.parse accepts with ('line-comment-trailing')
✓ it strips JSONC down to something JSON.parse accepts with ('leading-line-comments')
✓ it strips JSONC down to something JSON.parse accepts with ('line-comment-eof-no-newline')
✓ it strips JSONC down to something JSON.parse accepts with ('block-comment-leading')
✓ it strips JSONC down to something JSON.parse accepts with ('block-comment-inline')
✓ it strips JSONC down to something JSON.parse accepts with ('block-comment-multiline')
✓ it strips JSONC down to something JSON.parse accepts with ('block-comment-eof')
✓ it strips JSONC down to something JSON.parse accepts with ('jsdoc-style-block')
✓ it strips JSONC down to something JSON.parse accepts with ('block-contains-double-slash')
✓ it strips JSONC down to something JSON.parse accepts with ('line-then-block')
✓ it strips JSONC down to something JSON.parse accepts with ('comment-with-quotes')
✓ it strips JSONC down to something JSON.parse accepts with ('comment-with-braces-commas')
✓ it strips JSONC down to something JSON.parse accepts with ('trailing-comma-object')
✓ it strips JSONC down to something JSON.parse accepts with ('trailing-comma-array')
✓ it strips JSONC down to something JSON.parse accepts with ('trailing-comma-nested')
✓ it strips JSONC down to something JSON.parse accepts with ('trailing-comma-newline')
✓ it strips JSONC down to something JSON.parse accepts with ('trailing-comma-then-block')
✓ it strips JSONC down to something JSON.parse accepts with ('trailing-comma-then-line')
✓ it strips JSONC down to something JSON.parse accepts with ('crlf-line-comment')
✓ it strips JSONC down to something JSON.parse accepts with ('tabs-whitespace')
✓ it strips JSONC down to something JSON.parse accepts with ('url-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('glob-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('path-alias-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('block-open-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('block-close-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('block-both-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('star-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('single-slashes-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('escaped-quote-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('escaped-backslash-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('backslash-then-slash')
✓ it strips JSONC down to something JSON.parse accepts with ('newline-escape-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('unicode-in-string')
✓ it strips JSONC down to something JSON.parse accepts with ('block-secret')
✓ it never touches comment-looking sequences inside string values
✓ it removes the comment body entirely
✓ it builds the expected alias map from a tsconfig with ('basic')
✓ it builds the expected alias map from a tsconfig with ('multiple-aliases')
✓ it builds the expected alias map from a tsconfig with ('default-baseUrl')
✓ it builds the expected alias map from a tsconfig with ('baseUrl-subdir')
✓ it builds the expected alias map from a tsconfig with ('jsconfig-fallback')
✓ it builds the expected alias map from a tsconfig with ('first-target-wins')
✓ it builds the expected alias map from a tsconfig with ('multiple-keys-mixed')
✓ it builds the expected alias map from a tsconfig with ('no-paths')
✓ it builds the expected alias map from a tsconfig with ('no-compiler-options')
✓ it builds the expected alias map from a tsconfig with ('key-without-glob')
✓ it builds the expected alias map from a tsconfig with ('target-without-glob')
✓ it builds the expected alias map from a tsconfig with ('target-not-array')
✓ it builds the expected alias map from a tsconfig with ('target-empty-array')
✓ it builds the expected alias map from a tsconfig with ('commented-tsconfig')
✓ it builds the expected alias map from a tsconfig with ('trailing-comma-paths')
✓ it builds the expected alias map from a tsconfig with ('malformed-json')
✓ it builds the expected alias map from a tsconfig with ('missing-config')
✓ it builds the expected alias map from a tsconfig with ('tsconfig-precedence')
PASS Tests\Unit\Preset
✓ preset invalid name
✓ preset → myFramework
@@ -2006,4 +2068,4 @@
✓ pass with dataset with ('my-datas-set-value')
✓ within describe → pass with dataset with ('my-datas-set-value')
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 40 todos, 35 skipped, 1389 passed (3097 assertions)
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 40 todos, 35 skipped, 1449 passed (3199 assertions)
+300
View File
@@ -0,0 +1,300 @@
<?php
use Symfony\Component\Process\ExecutableFinder;
use Symfony\Component\Process\Process;
function tiaViteHelperPath(): string
{
return dirname(__DIR__, 4).'/bin/pest-tia-vite-deps.mjs';
}
function tiaJson(mixed $value): string
{
return json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
}
function tiaStripFixtures(): array
{
return [
'plain-object' => ['{"a":1,"b":2}', ['a' => 1, 'b' => 2]],
'plain-array' => ['[1,2,3]', [1, 2, 3]],
'nested' => ['{"a":{"b":[1,2]}}', ['a' => ['b' => [1, 2]]]],
'empty-object' => ['{}', []],
'empty-array' => ['[]', []],
'line-comment-own-line' => ["{\n// comment\n\"a\":1\n}", ['a' => 1]],
'line-comment-trailing' => ["{\"a\":1 // trailing\n}", ['a' => 1]],
'leading-line-comments' => ["// a\n// b\n{\"a\":1}", ['a' => 1]],
'line-comment-eof-no-newline' => ['{"a":1}// end', ['a' => 1]],
'block-comment-leading' => ['{/* c */"a":1}', ['a' => 1]],
'block-comment-inline' => ['{"a":1,/* c */"b":2}', ['a' => 1, 'b' => 2]],
'block-comment-multiline' => ["{\n/* line1\nline2 */\n\"a\":1\n}", ['a' => 1]],
'block-comment-eof' => ['{"a":1}/* end */', ['a' => 1]],
'jsdoc-style-block' => ["{\n/**\n * doc\n */\n\"a\":1\n}", ['a' => 1]],
'block-contains-double-slash' => ['{/* // inside */"a":1}', ['a' => 1]],
'line-then-block' => ["{// l\n/* b */\"a\":1}", ['a' => 1]],
'comment-with-quotes' => ['{/* "b":2 */"a":1}', ['a' => 1]],
'comment-with-braces-commas' => ['{"a":1 /* },{ */,"b":2}', ['a' => 1, 'b' => 2]],
'trailing-comma-object' => ['{"a":1,}', ['a' => 1]],
'trailing-comma-array' => ['[1,2,]', [1, 2]],
'trailing-comma-nested' => ['{"a":[1,2,],"b":{"c":3,},}', ['a' => [1, 2], 'b' => ['c' => 3]]],
'trailing-comma-newline' => ["{\n\"a\":1,\n}", ['a' => 1]],
'trailing-comma-then-block' => ['{"a":1, /* x */ }', ['a' => 1]],
'trailing-comma-then-line' => ["{\"a\":1, // x\n}", ['a' => 1]],
'crlf-line-comment' => ["{\r\n\"a\":1 // c\r\n}", ['a' => 1]],
'tabs-whitespace' => ["{\n\t\"a\":\t1\n}", ['a' => 1]],
'url-in-string' => [tiaJson(['u' => 'https://example.com//x']), ['u' => 'https://example.com//x']],
'glob-in-string' => [tiaJson(['g' => 'resources/js/**/*.ts']), ['g' => 'resources/js/**/*.ts']],
'path-alias-in-string' => [tiaJson(['p' => '@/*']), ['p' => '@/*']],
'block-open-in-string' => [tiaJson(['s' => 'a/*b']), ['s' => 'a/*b']],
'block-close-in-string' => [tiaJson(['s' => 'b*/c']), ['s' => 'b*/c']],
'block-both-in-string' => [tiaJson(['s' => 'x/*y*/z']), ['s' => 'x/*y*/z']],
'star-in-string' => [tiaJson(['s' => '5 * 3']), ['s' => '5 * 3']],
'single-slashes-in-string' => [tiaJson(['s' => 'a/b/c']), ['s' => 'a/b/c']],
'escaped-quote-in-string' => [tiaJson(['s' => 'a"b']), ['s' => 'a"b']],
'escaped-backslash-in-string' => [tiaJson(['s' => 'a\\']), ['s' => 'a\\']],
'backslash-then-slash' => [tiaJson(['s' => 'a\\/b']), ['s' => 'a\\/b']],
'newline-escape-in-string' => [tiaJson(['s' => "a\nb"]), ['s' => "a\nb"]],
'unicode-in-string' => [tiaJson(['s' => 'café ☕']), ['s' => 'café ☕']],
'block-secret' => ['{"a":1/*SECRET*/}', ['a' => 1]],
];
}
function tiaStripResults(): array
{
static $cache = null;
if ($cache !== null) {
return $cache;
}
$payload = [];
foreach (tiaStripFixtures() as $name => [$raw]) {
$payload[] = ['name' => $name, 'raw' => $raw];
}
$inputFile = tempnam(sys_get_temp_dir(), 'tia-strip-');
file_put_contents($inputFile, json_encode($payload));
$helper = str_replace('\\', '/', tiaViteHelperPath());
$input = str_replace('\\', '/', $inputFile);
$script = <<<JS
import { stripJsonComments } from '{$helper}'
import { readFileSync } from 'node:fs'
const cases = JSON.parse(readFileSync('{$input}', 'utf8'))
const out = {}
for (const c of cases) {
const stripped = stripJsonComments(c.raw)
const entry = { stripped }
try { entry.parsed = JSON.parse(stripped); entry.ok = true }
catch (e) { entry.ok = false; entry.error = String(e && e.message ? e.message : e) }
out[c.name] = entry
}
process.stdout.write(JSON.stringify(out))
JS;
$process = new Process(['node', '--input-type=module', '-e', $script]);
$process->mustRun();
@unlink($inputFile);
return $cache = json_decode($process->getOutput(), true, flags: JSON_THROW_ON_ERROR);
}
function tiaAliasFixtures(): array
{
$config = fn (array $compilerOptions): array => ['tsconfig.json' => tiaJson(['compilerOptions' => $compilerOptions])];
return [
'basic' => [
$config(['baseUrl' => '.', 'paths' => ['@/*' => ['./resources/js/*']]]),
['@' => 'resources/js'],
],
'multiple-aliases' => [
$config(['baseUrl' => '.', 'paths' => ['@/*' => ['./resources/js/*'], '~/*' => ['./src/*']]]),
['@' => 'resources/js', '~' => 'src'],
],
'default-baseUrl' => [
$config(['paths' => ['@/*' => ['./resources/js/*']]]),
['@' => 'resources/js'],
],
'baseUrl-subdir' => [
$config(['baseUrl' => 'src', 'paths' => ['@/*' => ['lib/*']]]),
['@' => 'src/lib'],
],
'jsconfig-fallback' => [
['jsconfig.json' => tiaJson(['compilerOptions' => ['baseUrl' => '.', 'paths' => ['@/*' => ['./resources/js/*']]]])],
['@' => 'resources/js'],
],
'first-target-wins' => [
$config(['baseUrl' => '.', 'paths' => ['@/*' => ['./a/*', './b/*']]]),
['@' => 'a'],
],
'multiple-keys-mixed' => [
$config(['baseUrl' => '.', 'paths' => [
'@/*' => ['./resources/js/*'],
'bad' => ['./x/*'],
'~/*' => ['./nope'],
]]),
['@' => 'resources/js'],
],
'no-paths' => [
$config(['baseUrl' => '.']),
[],
],
'no-compiler-options' => [
['tsconfig.json' => '{}'],
[],
],
'key-without-glob' => [
$config(['baseUrl' => '.', 'paths' => ['@' => ['./resources/js/*']]]),
[],
],
'target-without-glob' => [
$config(['baseUrl' => '.', 'paths' => ['@/*' => ['./resources/js']]]),
[],
],
'target-not-array' => [
$config(['baseUrl' => '.', 'paths' => ['@/*' => './resources/js/*']]),
[],
],
'target-empty-array' => [
$config(['baseUrl' => '.', 'paths' => ['@/*' => []]]),
[],
],
'commented-tsconfig' => [
['tsconfig.json' => <<<'JSON'
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more. */
"target": "ESNext", // language target
"baseUrl": ".",
"paths": {
"@/*": ["./resources/js/*"],
},
},
}
JSON],
['@' => 'resources/js'],
],
'trailing-comma-paths' => [
['tsconfig.json' => '{"compilerOptions":{"baseUrl":".","paths":{"@/*":["./resources/js/*",],},},}'],
['@' => 'resources/js'],
],
'malformed-json' => [
['tsconfig.json' => '{ this is not json'],
[],
],
'missing-config' => [
[],
[],
],
'tsconfig-precedence' => [
[
'tsconfig.json' => tiaJson(['compilerOptions' => ['baseUrl' => '.', 'paths' => ['@/*' => ['./a/*']]]]),
'jsconfig.json' => tiaJson(['compilerOptions' => ['baseUrl' => '.', 'paths' => ['@/*' => ['./b/*']]]]),
],
['@' => 'a'],
],
];
}
function tiaAliasResults(): array
{
static $cache = null;
if ($cache !== null) {
return $cache;
}
$roots = [];
$written = [];
$payload = [];
foreach (tiaAliasFixtures() as $name => [$files]) {
$root = sys_get_temp_dir().'/pest-tia-'.bin2hex(random_bytes(6));
mkdir($root, 0755, true);
foreach ($files as $fname => $content) {
file_put_contents($root.'/'.$fname, $content);
$written[] = $root.'/'.$fname;
}
$root = str_replace('\\', '/', $root);
$roots[$name] = $root;
$payload[] = ['name' => $name, 'root' => $root];
}
$inputFile = tempnam(sys_get_temp_dir(), 'tia-alias-');
file_put_contents($inputFile, json_encode($payload));
$helper = str_replace('\\', '/', tiaViteHelperPath());
$input = str_replace('\\', '/', $inputFile);
$script = <<<JS
import { loadAliasFromTsconfig } from '{$helper}'
import { readFileSync } from 'node:fs'
const cases = JSON.parse(readFileSync('{$input}', 'utf8'))
const out = {}
for (const c of cases) out[c.name] = await loadAliasFromTsconfig(c.root)
process.stdout.write(JSON.stringify(out))
JS;
$process = new Process(['node', '--input-type=module', '-e', $script]);
$process->mustRun();
$aliases = json_decode($process->getOutput(), true, flags: JSON_THROW_ON_ERROR);
@unlink($inputFile);
foreach ($written as $f) {
@unlink($f);
}
foreach ($roots as $r) {
@rmdir($r);
}
return $cache = ['roots' => $roots, 'aliases' => $aliases];
}
beforeEach(function () {
if ((new ExecutableFinder)->find('node') === null) {
$this->markTestSkipped('node is not available.');
}
});
it('strips JSONC down to something JSON.parse accepts', function (string $name) {
$result = tiaStripResults()[$name];
[, $expected] = tiaStripFixtures()[$name];
expect($result['ok'])->toBeTrue(
"[{$name}] did not parse after stripping: ".($result['error'] ?? 'unknown').PHP_EOL.
'stripped: '.$result['stripped'],
);
expect($result['parsed'])->toEqual($expected);
})->with(array_keys(tiaStripFixtures()));
it('never touches comment-looking sequences inside string values', function () {
expect(tiaStripResults()['url-in-string']['stripped'])->toContain('https://example.com//x')
->and(tiaStripResults()['glob-in-string']['stripped'])->toContain('resources/js/**/*.ts')
->and(tiaStripResults()['block-both-in-string']['stripped'])->toContain('x/*y*/z');
});
it('removes the comment body entirely', function () {
expect(tiaStripResults()['block-secret']['stripped'])->not->toContain('SECRET');
});
it('builds the expected alias map from a tsconfig', function (string $name) {
$results = tiaAliasResults();
[, $expectedRelative] = tiaAliasFixtures()[$name];
$root = $results['roots'][$name];
$expected = [];
foreach ($expectedRelative as $key => $relative) {
$expected[$key] = $root.'/'.$relative;
}
expect($results['aliases'][$name])->toEqual($expected);
})->with(array_keys(tiaAliasFixtures()));
+2 -2
View File
@@ -24,13 +24,13 @@ test('parallel', function () use ($run) {
$file = file_get_contents(__FILE__);
$file = preg_replace(
'/\$expected = \'.*?\';/',
"\$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1372 passed (3044 assertions)';",
"\$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1432 passed (3146 assertions)';",
$file,
);
file_put_contents(__FILE__, $file);
}
$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1372 passed (3044 assertions)';
$expected = '2 deprecated, 4 warnings, 5 incomplete, 3 notices, 40 todos, 27 skipped, 1432 passed (3146 assertions)';
expect($output)
->toContain("Tests: {$expected}")