Merge branch '4.x' into fix/sibling-describe-blocks

This commit is contained in:
nuno maduro
2025-07-26 04:26:10 +01:00
committed by GitHub
91 changed files with 1617 additions and 489 deletions

View File

@ -0,0 +1,7 @@
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>Snapshot</h1>
</div>
</div>
</div>

View File

@ -0,0 +1,7 @@
<div class="container">
<div class="row">
<div class="col-md-12">
<h1>Snapshot</h1>
</div>
</div>
</div>

View File

@ -1,5 +1,5 @@
Pest Testing Framework 3.7.2.
Pest Testing Framework 4.0.0-alpha.6.
USAGE: pest <file> [options]
@ -53,7 +53,7 @@
--disallow-test-output ................. Be strict about output during tests
--enforce-time-limit ................. Enforce time limit based on test size
--default-time-limit [sec] Timeout in seconds for tests that have no declared size
--dont-report-useless-tests .. Do not report tests that do not test anything
--do-not-report-useless-tests Do not report tests that do not test anything
--stop-on-defect ... Stop after first error, failure, warning, or risky test
--stop-on-error ..................................... Stop after first error
--stop-on-failure ................................. Stop after first failure
@ -68,9 +68,22 @@
--fail-on-risky Signal failure using shell exit code when a test was considered risky
--fail-on-deprecation Signal failure using shell exit code when a deprecation was triggered
--fail-on-phpunit-deprecation Signal failure using shell exit code when a PHPUnit deprecation was triggered
--fail-on-phpunit-notice Signal failure using shell exit code when a PHPUnit notice was triggered
--fail-on-phpunit-warning Signal failure using shell exit code when a PHPUnit warning was triggered
--fail-on-notice Signal failure using shell exit code when a notice was triggered
--fail-on-skipped Signal failure using shell exit code when a test was skipped
--fail-on-incomplete Signal failure using shell exit code when a test was marked incomplete
--fail-on-all-issues Signal failure using shell exit code when an issue is triggered
--do-not-fail-on-empty-test-suite Do not signal failure using shell exit code when no tests were run
--do-not-fail-on-warning Do not signal failure using shell exit code when a warning was triggered
--do-not-fail-on-risky Do not signal failure using shell exit code when a test was considered risky
--do-not-fail-on-deprecation Do not signal failure using shell exit code when a deprecation was triggered
--do-not-fail-on-phpunit-deprecation Do not signal failure using shell exit code when a PHPUnit deprecation was triggered
--do-not-fail-on-phpunit-notice Do not signal failure using shell exit code when a PHPUnit notice was triggered
--do-not-fail-on-phpunit-warning Do not signal failure using shell exit code when a PHPUnit warning was triggered
--do-not-fail-on-notice Do not signal failure using shell exit code when a notice was triggered
--do-not-fail-on-skipped Do not signal failure using shell exit code when a test was skipped
--do-not-fail-on-incomplete Do not signal failure using shell exit code when a test was marked incomplete
--cache-result ............................ Write test results to cache file
--do-not-cache-result .............. Do not write test results to cache file
--order-by [order] Run tests in order: default|defects|depends|duration|no-depends|random|reverse|size
@ -88,18 +101,23 @@
--display-skipped ........................ Display details for skipped tests
--display-deprecations . Display details for deprecations triggered by tests
--display-phpunit-deprecations .... Display details for PHPUnit deprecations
--display-phpunit-notices .............. Display details for PHPUnit notices
--display-errors ............. Display details for errors triggered by tests
--display-notices ........... Display details for notices triggered by tests
--display-warnings ......... Display details for warnings triggered by tests
--display-all-issues ..... Display details for all issues that are triggered
--reverse-list .............................. Print defects in reverse order
--teamcity . Replace default progress and result output with TeamCity format
--testdox ................ Replace default result output with TestDox format
--testdox-summary Repeat TestDox output for tests with errors, failures, or issues
--debug Replace default progress and result output with debugging information
--with-telemetry Include telemetry information in debugging information output
--compact ................ Replace default result output with Compact format
LOGGING OPTIONS:
--log-junit [file] .......... Write test results in JUnit XML format to file
--log-otr [file] Write test results in Open Test Reporting XML format to file
--include-git-information Include Git information in Open Test Reporting XML logfile
--log-teamcity [file] ........ Write test results in TeamCity format to file
--testdox-html [file] .. Write test results in TestDox format (HTML) to file
--testdox-text [file] Write test results in TestDox format (plain text) to file
@ -111,6 +129,7 @@
--coverage ..... Generate code coverage report and output to standard output
--coverage --min Set the minimum required coverage percentage, and fail if not met
--coverage-clover [file] Write code coverage report in Clover XML format to file
--coverage-openclover [file] Write code coverage report in OpenClover XML format to file
--coverage-cobertura [file] Write code coverage report in Cobertura XML format to file
--coverage-crap4j [file] Write code coverage report in Crap4J XML format to file
--coverage-html [dir] Write code coverage report in HTML format to directory

View File

@ -1,3 +1,3 @@
Pest Testing Framework 3.7.2.
Pest Testing Framework 4.0.0-alpha.6.

View File

@ -4,7 +4,6 @@
✓ preset → strict → ignoring ['usleep']
✓ preset → security → ignoring ['eval', 'str_shuffle', 'exec', …]
✓ globals
✓ dependencies
✓ contracts
PASS Tests\Environments\Windows
@ -81,14 +80,24 @@
✓ it adds coverage if --min exist
✓ it generates coverage based on file input
PASS Tests\Features\Covers
PASS Tests\Features\Covers\ClassCoverage
✓ it uses the correct PHPUnit attribute for class
✓ it uses the correct PHPUnit attribute for function
✓ it guesses if the given argument is a class or function
✓ it uses the correct PHPUnit attribute for trait
PASS Tests\Features\Covers\CoversNothing
✓ it uses the correct PHPUnit attribute for covers nothing
PASS Tests\Features\Covers\ExceptionHandling
✓ it throws exception if no class nor method has been found
PASS Tests\Features\Covers\FunctionCoverage
✓ it uses the correct PHPUnit attribute for function
PASS Tests\Features\Covers\GuessCoverage
✓ it guesses if the given argument is a class or function
PASS Tests\Features\Covers\TraitCoverage
✓ it uses the correct PHPUnit attribute for trait
PASS Tests\Features\DatasetsTests - 1 todo
✓ it throws exception if dataset does not exist
✓ it throws exception if dataset already exist
@ -637,6 +646,13 @@
✓ pass
✓ failures
✓ failures with custom message
✓ not failures
PASS Tests\Features\Expect\toBeSlug
✓ pass
✓ failures
✓ failures with custom message
✓ failures with default message
✓ not failures
PASS Tests\Features\Expect\toBeSnakeCase
@ -1048,6 +1064,10 @@
✓ it may fail
✓ it may fail with the given message
PASS Tests\Features\Fixture
✓ it may return a file path
✓ it may throw an exception if the file does not exist
WARN Tests\Features\Helpers
✓ it can set/get properties on $this
! it gets null if property do not exist → Undefined property Tests\Features\Helpers::$wqdwqdqw
@ -1156,6 +1176,10 @@
✓ nested → it may be associated with an pr #1, #4, #5, #6, #3
// an note between an the pr
PASS Tests\Features\References
✓ it can reference a specific class
✓ it can reference a specific class method
PASS Tests\Features\Repeat
✓ once
✓ multiple times @ repetition 1 of 5
@ -1336,6 +1360,10 @@
✓ it can see datasets defined in Pest.php file with ('B')
✓ Pest.php dataset is taken
PASS Tests\Features\See
✓ it can reference a specific class
✓ it can reference a specific class method
WARN Tests\Features\Skip
✓ it do not skips
- it skips with truthy → 1
@ -1475,19 +1503,14 @@
✓ nested → nested afterEach execution order
✓ global afterEach execution order
PASS Tests\Hooks\BeforeAllTest
✓ it gets called before all tests 1 @ repetition 1 of 2
✓ it gets called before all tests 1 @ repetition 2 of 2
✓ it gets called before all tests 2
PASS Tests\Hooks\BeforeEachTest
✓ global beforeEach execution order
PASS Tests\Overrides\VersionsTest
✓ versions with dataset "Runner/Filter/NameFilterIterator.php"
✓ versions with dataset "Runner/ResultCache/DefaultResultCache.php"
✓ versions with dataset "Runner/TestSuiteLoader.php"
✓ versions with dataset "TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php"
✓ versions with dataset "TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php"
✓ versions with dataset "TextUI/TestSuiteFilterProcessor.php"
✓ versions with dataset "Event/Value/ThrowableBuilder.php"
✓ versions with dataset "Logging/JUnit/JunitXmlLogger.php"
PASS Tests\PHPUnit\CustomAffixes\InvalidTestName
✓ it runs file names like @#$%^&()-_=+.php
@ -1758,4 +1781,9 @@
WARN Tests\Visual\Version
- visual snapshot of help command output
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 39 todos, 35 skipped, 1182 passed (2785 assertions)
PASS Testsexternal\Features\Expect\toMatchSnapshot
✓ 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, 38 todos, 33 skipped, 1159 passed (2774 assertions)

View File

@ -27,26 +27,6 @@ arch('globals')
->not->toBeUsed()
->ignoring(Expectation::class);
arch('dependencies')
->expect('Pest')
->toOnlyUse([
'dd',
'dump',
'expect',
'uses',
'Termwind',
'ParaTest',
'Pest\Arch',
'Pest\Mutate\Contracts\Configuration',
'Pest\Mutate\Decorators\TestCallDecorator',
'Pest\Mutate\Repositories\ConfigurationRepository',
'Pest\Plugin',
'NunoMaduro\Collision',
'Whoops',
'Symfony\Component\Console',
'Symfony\Component\Process',
])->ignoring(['Composer', 'PHPUnit', 'SebastianBergmann']);
arch('contracts')
->expect('Pest\Contracts')
->toOnlyUse([

View File

@ -1,59 +0,0 @@
<?php
use Pest\PendingCalls\TestCall;
use Pest\TestSuite;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversFunction;
use Tests\Fixtures\Covers\CoversClass1;
use Tests\Fixtures\Covers\CoversClass3;
use Tests\Fixtures\Covers\CoversTrait;
$runCounter = 0;
function testCoversFunction() {}
covers([CoversClass1::class]);
it('uses the correct PHPUnit attribute for class', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[1]->getName())->toBe('PHPUnit\Framework\Attributes\CoversClass');
expect($attributes[1]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversClass1');
});
it('uses the correct PHPUnit attribute for function', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversFunction');
expect($attributes[3]->getArguments()[0])->toBe('testCoversFunction');
})->coversFunction('testCoversFunction');
it('guesses if the given argument is a class or function', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[5]->getName())->toBe(CoversClass::class);
expect($attributes[5]->getArguments()[0])->toBe(CoversClass3::class);
expect($attributes[6]->getName())->toBe(CoversFunction::class);
expect($attributes[6]->getArguments()[0])->toBe('testCoversFunction');
})->covers(CoversClass3::class, 'testCoversFunction');
it('uses the correct PHPUnit attribute for trait', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[8]->getName())->toBe('PHPUnit\Framework\Attributes\CoversTrait');
expect($attributes[8]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversTrait');
})->coversTrait(CoversTrait::class);
it('uses the correct PHPUnit attribute for covers nothing', function () {
$attributes = (new ReflectionMethod($this, $this->name()))->getAttributes();
expect($attributes[3]->getName())->toBe('PHPUnit\Framework\Attributes\CoversNothing');
expect($attributes[3]->getArguments())->toHaveCount(0);
})->coversNothing();
it('throws exception if no class nor method has been found', function () {
$testCall = new TestCall(TestSuite::getInstance(), 'filename', 'description', fn () => 'closure');
$testCall->covers('fakeName');
})->throws(InvalidArgumentException::class, 'No class, trait or method named "fakeName" has been found.');

View File

@ -0,0 +1,13 @@
<?php
use PHPUnit\Framework\Attributes\CoversClass;
use Tests\Fixtures\Covers\CoversClass1;
covers([CoversClass1::class]);
it('uses the correct PHPUnit attribute for class', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[1]->getName())->toBe(CoversClass::class);
expect($attributes[1]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversClass1');
});

View File

@ -0,0 +1,10 @@
<?php
use PHPUnit\Framework\Attributes\CoversNothing;
it('uses the correct PHPUnit attribute for covers nothing', function () {
$attributes = (new ReflectionMethod($this, $this->name()))->getAttributes();
expect($attributes[2]->getName())->toBe(CoversNothing::class);
expect($attributes[2]->getArguments())->toHaveCount(0);
})->coversNothing();

View File

@ -0,0 +1,10 @@
<?php
use Pest\PendingCalls\TestCall;
use Pest\TestSuite;
it('throws exception if no class nor method has been found', function () {
$testCall = new TestCall(TestSuite::getInstance(), 'filename', 'description', fn () => 'closure');
$testCall->covers('fakeName');
})->throws(InvalidArgumentException::class, 'No class, trait or method named "fakeName" has been found.');

View File

@ -0,0 +1,12 @@
<?php
use PHPUnit\Framework\Attributes\CoversFunction;
function testCoversFunction() {}
it('uses the correct PHPUnit attribute for function', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[1]->getName())->toBe(CoversFunction::class);
expect($attributes[1]->getArguments()[0])->toBe('testCoversFunction');
})->coversFunction('testCoversFunction');

View File

@ -0,0 +1,17 @@
<?php
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversFunction;
use Tests\Fixtures\Covers\CoversClass3;
function testCoversFunction2() {}
it('guesses if the given argument is a class or function', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[1]->getName())->toBe(CoversClass::class);
expect($attributes[1]->getArguments()[0])->toBe(CoversClass3::class);
expect($attributes[2]->getName())->toBe(CoversFunction::class);
expect($attributes[2]->getArguments()[0])->toBe('testCoversFunction2');
})->covers(CoversClass3::class, 'testCoversFunction2');

View File

@ -0,0 +1,11 @@
<?php
use PHPUnit\Framework\Attributes\CoversTrait as PHPUnitCoversTrait;
use Tests\Fixtures\Covers\CoversTrait;
it('uses the correct PHPUnit attribute for trait', function () {
$attributes = (new ReflectionClass($this))->getAttributes();
expect($attributes[1]->getName())->toBe(PHPUnitCoversTrait::class);
expect($attributes[1]->getArguments()[0])->toBe('Tests\Fixtures\Covers\CoversTrait');
})->coversTrait(CoversTrait::class);

View File

@ -0,0 +1,24 @@
<?php
use PHPUnit\Framework\ExpectationFailedException;
test('pass', function () {
expect('This is a Test String!')->toBeSlug()
->and('Another Test String')->toBeSlug();
});
test('failures', function () {
expect('')->toBeSlug();
})->throws(ExpectationFailedException::class);
test('failures with custom message', function () {
expect('')->toBeSlug('oh no!');
})->throws(ExpectationFailedException::class, 'oh no!');
test('failures with default message', function () {
expect('')->toBeSlug();
})->throws(ExpectationFailedException::class, 'Failed asserting that can be converted to a slug.');
test('not failures', function () {
expect('This is a Test String!')->not->toBeSlug();
})->throws(ExpectationFailedException::class);

View File

@ -74,7 +74,8 @@ test('pass with dataset', function ($data) {
TestSuite::getInstance()->snapshots->save($this->snapshotable);
[$filename] = TestSuite::getInstance()->snapshots->get();
expect($filename)->toEndWith('pass_with_dataset_with_data_set____my_datas_set_value______my_datas_set_value__.snap')
expect($filename)->toStartWith('tests/.pest/snapshots/')
->toEndWith('pass_with_dataset_with_data_set____my_datas_set_value______my_datas_set_value__.snap')
->and($this->snapshotable)->toMatchSnapshot();
})->with(['my-datas-set-value']);
@ -83,7 +84,8 @@ describe('within describe', function () {
TestSuite::getInstance()->snapshots->save($this->snapshotable);
[$filename] = TestSuite::getInstance()->snapshots->get();
expect($filename)->toEndWith('pass_with_dataset_with_data_set____my_datas_set_value______my_datas_set_value__.snap')
expect($filename)->toStartWith('tests/.pest/snapshots/')
->toEndWith('pass_with_dataset_with_data_set____my_datas_set_value______my_datas_set_value__.snap')
->and($this->snapshotable)->toMatchSnapshot();
});
})->with(['my-datas-set-value']);

View File

@ -0,0 +1,12 @@
<?php
it('may return a file path', function () {
$file = fixture('phpunit-in-isolation.xml');
expect($file)->toBeString()
->toBeFile();
});
it('may throw an exception if the file does not exist', function () {
fixture('file-that-does-not-exist.php');
})->throws(InvalidArgumentException::class);

View File

@ -0,0 +1,11 @@
<?php
use Pest\Panic;
it('can reference a specific class', function () {
expect(Panic::class)->toBeString();
})->references(Panic::class);
it('can reference a specific class method', function () {
expect(Panic::with(...))->toBeCallable();
})->references([Panic::class, 'with']);

11
tests/Features/See.php Normal file
View File

@ -0,0 +1,11 @@
<?php
use Pest\Panic;
it('can reference a specific class', function () {
expect(Panic::class)->toBeString();
})->see(Panic::class);
it('can reference a specific class method', function () {
expect(Panic::with(...))->toBeCallable();
})->see([Panic::class, 'with']);

View File

@ -0,0 +1,16 @@
<?php
pest()->beforeAll(function () {
expect($_SERVER['globalHook']->calls->beforeAll)
->toBe(0);
$_SERVER['globalHook']->calls->beforeAll++;
});
it('gets called before all tests 1', function () {
expect($_SERVER['globalHook']->calls->beforeAll)->toBe(1);
})->repeat(2);
it('gets called before all tests 2', function () {
expect($_SERVER['globalHook']->calls->beforeAll)->toBe(1);
});

View File

@ -1,18 +0,0 @@
<?php
declare(strict_types=1);
use Pest\Bootstrappers\BootOverrides;
test('versions', function (string $vendorPath, string $expectedHash) {
expect(hash_file('sha256', $vendorPath))->toBe($expectedHash);
})->with(function () {
foreach (BootOverrides::FILES as $hash => $file) {
$path = implode(DIRECTORY_SEPARATOR, [
dirname(__DIR__, 2),
'vendor/phpunit/phpunit/src',
$file,
]);
yield $file => [$path, $hash];
}
});

View File

@ -29,7 +29,6 @@ pest()
})
->beforeAll(function () {
$_SERVER['globalHook']->beforeAll = 0;
$_SERVER['globalHook']->calls->beforeAll++;
})
->afterEach(function () {
if (! isset($this->ith)) {