mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
feat: pr and issue
This commit is contained in:
68
bin/pest
68
bin/pest
@ -4,7 +4,9 @@
|
|||||||
use Pest\Kernel;
|
use Pest\Kernel;
|
||||||
use Pest\Panic;
|
use Pest\Panic;
|
||||||
use Pest\TestCaseFilters\GitDirtyTestCaseFilter;
|
use Pest\TestCaseFilters\GitDirtyTestCaseFilter;
|
||||||
|
use Pest\TestCaseMethodFilters\IssueTestCaseFilter;
|
||||||
use Pest\TestCaseMethodFilters\NotesTestCaseFilter;
|
use Pest\TestCaseMethodFilters\NotesTestCaseFilter;
|
||||||
|
use Pest\TestCaseMethodFilters\PrTestCaseFilter;
|
||||||
use Pest\TestCaseMethodFilters\TodoTestCaseFilter;
|
use Pest\TestCaseMethodFilters\TodoTestCaseFilter;
|
||||||
use Pest\TestSuite;
|
use Pest\TestSuite;
|
||||||
use Symfony\Component\Console\Input\ArgvInput;
|
use Symfony\Component\Console\Input\ArgvInput;
|
||||||
@ -21,6 +23,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
$notes = false;
|
$notes = false;
|
||||||
|
|
||||||
foreach ($arguments as $key => $value) {
|
foreach ($arguments as $key => $value) {
|
||||||
|
|
||||||
if ($value === '--compact') {
|
if ($value === '--compact') {
|
||||||
$_SERVER['COLLISION_PRINTER_COMPACT'] = 'true';
|
$_SERVER['COLLISION_PRINTER_COMPACT'] = 'true';
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
@ -31,8 +34,14 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str_contains($value, '--test-directory')) {
|
if (str_contains($value, '--test-directory=')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
|
} else if ($value === '--test-directory') {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
|
||||||
|
if (isset($arguments[$key + 1])) {
|
||||||
|
unset($arguments[$key + 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($value === '--dirty') {
|
if ($value === '--dirty') {
|
||||||
@ -50,6 +59,46 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (str_contains($value, '--issue=')) {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
} else if ($value === '--issue') {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
|
||||||
|
if (isset($arguments[$key + 1])) {
|
||||||
|
unset($arguments[$key + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($value, '--ticket=')) {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
} else if ($value === '--ticket') {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
|
||||||
|
if (isset($arguments[$key + 1])) {
|
||||||
|
unset($arguments[$key + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($value, '--pr=')) {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
} else if ($value === '--pr') {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
|
||||||
|
if (isset($arguments[$key + 1])) {
|
||||||
|
unset($arguments[$key + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str_contains($value, '--pull-request=')) {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
} else if ($value === '--pull-request') {
|
||||||
|
unset($arguments[$key]);
|
||||||
|
|
||||||
|
if (isset($arguments[$key + 1])) {
|
||||||
|
unset($arguments[$key + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (str_contains($value, '--teamcity')) {
|
if (str_contains($value, '--teamcity')) {
|
||||||
unset($arguments[$key]);
|
unset($arguments[$key]);
|
||||||
$arguments[] = '--no-output';
|
$arguments[] = '--no-output';
|
||||||
@ -57,6 +106,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Used when Pest is required using composer.
|
// Used when Pest is required using composer.
|
||||||
$vendorPath = dirname(__DIR__, 4).'/vendor/autoload.php';
|
$vendorPath = dirname(__DIR__, 4).'/vendor/autoload.php';
|
||||||
|
|
||||||
@ -92,6 +142,22 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
|||||||
$testSuite->tests->addTestCaseMethodFilter(new NotesTestCaseFilter());
|
$testSuite->tests->addTestCaseMethodFilter(new NotesTestCaseFilter());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($issue = $input->getParameterOption('--issue')) {
|
||||||
|
$testSuite->tests->addTestCaseMethodFilter(new IssueTestCaseFilter((int) $issue));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issue = $input->getParameterOption('--ticket')) {
|
||||||
|
$testSuite->tests->addTestCaseMethodFilter(new IssueTestCaseFilter((int) $issue));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pr = $input->getParameterOption('--pr')) {
|
||||||
|
$testSuite->tests->addTestCaseMethodFilter(new PrTestCaseFilter((int) $pr));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pr = $input->getParameterOption('--pull-request')) {
|
||||||
|
$testSuite->tests->addTestCaseMethodFilter(new PrTestCaseFilter((int) $pr));
|
||||||
|
}
|
||||||
|
|
||||||
$isDecorated = $input->getParameterOption('--colors', 'always') !== 'never';
|
$isDecorated = $input->getParameterOption('--colors', 'always') !== 'never';
|
||||||
|
|
||||||
$output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $isDecorated);
|
$output = new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, $isDecorated);
|
||||||
|
|||||||
@ -50,7 +50,7 @@ final class Laravel extends AbstractPreset
|
|||||||
->classes()
|
->classes()
|
||||||
->toHaveMethod('handle');
|
->toHaveMethod('handle');
|
||||||
|
|
||||||
$this->expectations[] = expect('App\Models')
|
$this->expectations[] = expect('App\Models') // @phpstan-ignore-line
|
||||||
->classes()
|
->classes()
|
||||||
->toExtend('Illuminate\Database\Eloquent\Model')
|
->toExtend('Illuminate\Database\Eloquent\Model')
|
||||||
->not->toHaveSuffix('Model');
|
->not->toHaveSuffix('Model');
|
||||||
@ -62,7 +62,7 @@ final class Laravel extends AbstractPreset
|
|||||||
$this->expectations[] = expect('App\Http\Requests')
|
$this->expectations[] = expect('App\Http\Requests')
|
||||||
->classes()
|
->classes()
|
||||||
->toHaveSuffix('Request')
|
->toHaveSuffix('Request')
|
||||||
->toExtend('Illuminate\Foundation\Http\FormRequest') // @phpstan-ignore-line
|
->toExtend('Illuminate\Foundation\Http\FormRequest')
|
||||||
->toHaveMethod('rules');
|
->toHaveMethod('rules');
|
||||||
|
|
||||||
$this->expectations[] = expect('App')
|
$this->expectations[] = expect('App')
|
||||||
@ -72,7 +72,7 @@ final class Laravel extends AbstractPreset
|
|||||||
$this->expectations[] = expect('App\Console\Commands')
|
$this->expectations[] = expect('App\Console\Commands')
|
||||||
->classes()
|
->classes()
|
||||||
->toHaveSuffix('Command')
|
->toHaveSuffix('Command')
|
||||||
->toExtend('Illuminate\Console\Command') // @phpstan-ignore-line
|
->toExtend('Illuminate\Console\Command')
|
||||||
->toHaveMethod('handle');
|
->toHaveMethod('handle');
|
||||||
|
|
||||||
$this->expectations[] = expect('App')
|
$this->expectations[] = expect('App')
|
||||||
@ -81,7 +81,7 @@ final class Laravel extends AbstractPreset
|
|||||||
|
|
||||||
$this->expectations[] = expect('App\Mail')
|
$this->expectations[] = expect('App\Mail')
|
||||||
->classes()
|
->classes()
|
||||||
->toExtend('Illuminate\Mail\Mailable'); // @phpstan-ignore-line
|
->toExtend('Illuminate\Mail\Mailable');
|
||||||
|
|
||||||
$this->expectations[] = expect('App')
|
$this->expectations[] = expect('App')
|
||||||
->not->toExtend('Illuminate\Mail\Mailable')
|
->not->toExtend('Illuminate\Mail\Mailable')
|
||||||
@ -101,7 +101,7 @@ final class Laravel extends AbstractPreset
|
|||||||
->toHaveMethod('handle');
|
->toHaveMethod('handle');
|
||||||
|
|
||||||
$this->expectations[] = expect('App\Notifications')
|
$this->expectations[] = expect('App\Notifications')
|
||||||
->toExtend('Illuminate\Notifications\Notification'); // @phpstan-ignore-line
|
->toExtend('Illuminate\Notifications\Notification');
|
||||||
|
|
||||||
$this->expectations[] = expect('App')
|
$this->expectations[] = expect('App')
|
||||||
->not->toExtend('Illuminate\Notifications\Notification')
|
->not->toExtend('Illuminate\Notifications\Notification')
|
||||||
@ -109,10 +109,10 @@ final class Laravel extends AbstractPreset
|
|||||||
|
|
||||||
$this->expectations[] = expect('App\Providers') // @phpstan-ignore-line
|
$this->expectations[] = expect('App\Providers') // @phpstan-ignore-line
|
||||||
->toHaveSuffix('ServiceProvider')
|
->toHaveSuffix('ServiceProvider')
|
||||||
->toExtend('Illuminate\Support\ServiceProvider') // @phpstan-ignore-line
|
->toExtend('Illuminate\Support\ServiceProvider')
|
||||||
->not->toBeUsed();
|
->not->toBeUsed();
|
||||||
|
|
||||||
$this->expectations[] = expect('App')
|
$this->expectations[] = expect('App') // @phpstan-ignore-line
|
||||||
->not->toExtend('Illuminate\Support\ServiceProvider')
|
->not->toExtend('Illuminate\Support\ServiceProvider')
|
||||||
->not->toHaveSuffix('ServiceProvider')
|
->not->toHaveSuffix('ServiceProvider')
|
||||||
->ignoring('App\Providers');
|
->ignoring('App\Providers');
|
||||||
|
|||||||
@ -29,15 +29,29 @@ trait Testable
|
|||||||
*/
|
*/
|
||||||
private string $__description;
|
private string $__description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The test's latest description.
|
||||||
|
*/
|
||||||
|
private static string $__latestDescription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The test's notes.
|
* The test's notes.
|
||||||
*/
|
*/
|
||||||
private static array $__latestNotes = [];
|
private static array $__latestNotes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The test's latest description.
|
* The test's issues.
|
||||||
|
*
|
||||||
|
* @var array<int, int>
|
||||||
*/
|
*/
|
||||||
private static string $__latestDescription;
|
private static array $__latestIssues = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The test's PRs.
|
||||||
|
*
|
||||||
|
* @var array<int, int>
|
||||||
|
*/
|
||||||
|
private static array $__latestPrs = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The test's describing, if any.
|
* The test's describing, if any.
|
||||||
@ -79,27 +93,6 @@ trait Testable
|
|||||||
*/
|
*/
|
||||||
private array $__snapshotChanges = [];
|
private array $__snapshotChanges = [];
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new "note" to the Test Case.
|
|
||||||
*/
|
|
||||||
public function note(array|string $note): self
|
|
||||||
{
|
|
||||||
$note = is_array($note) ? $note : [$note];
|
|
||||||
|
|
||||||
self::$__latestNotes = array_merge(self::$__latestNotes, $note);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the test case static properties.
|
|
||||||
*/
|
|
||||||
public static function flush(): void
|
|
||||||
{
|
|
||||||
self::$__beforeAll = null;
|
|
||||||
self::$__afterAll = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Test Case instance.
|
* Creates a new Test Case instance.
|
||||||
*/
|
*/
|
||||||
@ -113,11 +106,34 @@ trait Testable
|
|||||||
$method = $test->getMethod($name);
|
$method = $test->getMethod($name);
|
||||||
$this->__description = self::$__latestDescription = $method->description;
|
$this->__description = self::$__latestDescription = $method->description;
|
||||||
self::$__latestNotes = $method->notes;
|
self::$__latestNotes = $method->notes;
|
||||||
|
self::$__latestIssues = $method->issues;
|
||||||
|
self::$__latestPrs = $method->prs;
|
||||||
$this->__describing = $method->describing;
|
$this->__describing = $method->describing;
|
||||||
$this->__test = $method->getClosure($this);
|
$this->__test = $method->getClosure($this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the test case static properties.
|
||||||
|
*/
|
||||||
|
public static function flush(): void
|
||||||
|
{
|
||||||
|
self::$__beforeAll = null;
|
||||||
|
self::$__afterAll = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new "note" to the Test Case.
|
||||||
|
*/
|
||||||
|
public function note(array|string $note): self
|
||||||
|
{
|
||||||
|
$note = is_array($note) ? $note : [$note];
|
||||||
|
|
||||||
|
self::$__latestNotes = array_merge(self::$__latestNotes, $note);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new "setUpBeforeClass" to the Test Case.
|
* Adds a new "setUpBeforeClass" to the Test Case.
|
||||||
*/
|
*/
|
||||||
@ -243,6 +259,8 @@ trait Testable
|
|||||||
|
|
||||||
$this->__description = self::$__latestDescription = $description;
|
$this->__description = self::$__latestDescription = $description;
|
||||||
self::$__latestNotes = $method->notes;
|
self::$__latestNotes = $method->notes;
|
||||||
|
self::$__latestIssues = $method->issues;
|
||||||
|
self::$__latestPrs = $method->prs;
|
||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
@ -432,4 +450,20 @@ trait Testable
|
|||||||
{
|
{
|
||||||
return self::$__latestNotes;
|
return self::$__latestNotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The latest printable test case issues.
|
||||||
|
*/
|
||||||
|
public static function getPrintableTestCaseMethodIssues(): array
|
||||||
|
{
|
||||||
|
return self::$__latestIssues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The latest printable test case PRs.
|
||||||
|
*/
|
||||||
|
public static function getPrintableTestCaseMethodPrs(): array
|
||||||
|
{
|
||||||
|
return self::$__latestPrs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,4 +75,12 @@ final class Configuration
|
|||||||
{
|
{
|
||||||
return new Configuration\Theme();
|
return new Configuration\Theme();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the context configuration.
|
||||||
|
*/
|
||||||
|
public function context(): Configuration\Context
|
||||||
|
{
|
||||||
|
return new Configuration\Context();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
src/Configuration/Context.php
Normal file
67
src/Configuration/Context.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\Configuration;
|
||||||
|
|
||||||
|
use NunoMaduro\Collision\Adapters\Phpunit\Printers\DefaultPrinter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final readonly class Context
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sets the test context to GitHub.
|
||||||
|
*/
|
||||||
|
public function github(string $project): self
|
||||||
|
{
|
||||||
|
DefaultPrinter::linkIssuesWith("https://github.com/{$project}/issues/%s");
|
||||||
|
DefaultPrinter::linkPrsWith("https://github.com/{$project}/pull/%s");
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the test context to GitLab.
|
||||||
|
*/
|
||||||
|
public function gitlab(string $project): self
|
||||||
|
{
|
||||||
|
DefaultPrinter::linkIssuesWith("https://gitlab.com/{$project}/issues/%s");
|
||||||
|
DefaultPrinter::linkPrsWith("https://gitlab.com/{$project}/merge_requests/%s");
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the test context to Bitbucket.
|
||||||
|
*/
|
||||||
|
public function bitbucket(string $project): self
|
||||||
|
{
|
||||||
|
DefaultPrinter::linkIssuesWith('https://bitbucket.org/{$project}/issues/%s');
|
||||||
|
DefaultPrinter::linkPrsWith("https://bitbucket.org/{$project}/pull-requests/%s");
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the test context to Jira.
|
||||||
|
*/
|
||||||
|
public function jira(string $namespace, string $project): self
|
||||||
|
{
|
||||||
|
DefaultPrinter::linkIssuesWith("https://{$namespace}.atlassian.net/browse/{$project}-%s");
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the test context to custom.
|
||||||
|
*/
|
||||||
|
public function using(string $issues, string $prs): self
|
||||||
|
{
|
||||||
|
DefaultPrinter::linkIssuesWith($issues);
|
||||||
|
DefaultPrinter::linkPrsWith($prs);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -585,8 +585,6 @@ final class Expectation
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target to be subclass of the given class.
|
* Asserts that the given expectation target to be subclass of the given class.
|
||||||
*
|
|
||||||
* @param class-string $class
|
|
||||||
*/
|
*/
|
||||||
public function toExtend(string $class): ArchExpectation
|
public function toExtend(string $class): ArchExpectation
|
||||||
{
|
{
|
||||||
@ -660,7 +658,7 @@ final class Expectation
|
|||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target to only implement the given interfaces.
|
* Asserts that the given expectation target to only implement the given interfaces.
|
||||||
*
|
*
|
||||||
* @param array<int, class-string>|class-string $interfaces
|
* @param array<int, string>|string $interfaces
|
||||||
*/
|
*/
|
||||||
public function toOnlyImplement(array|string $interfaces): ArchExpectation
|
public function toOnlyImplement(array|string $interfaces): ArchExpectation
|
||||||
{
|
{
|
||||||
@ -704,7 +702,7 @@ final class Expectation
|
|||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target to implement the given interfaces.
|
* Asserts that the given expectation target to implement the given interfaces.
|
||||||
*
|
*
|
||||||
* @param array<int, class-string>|class-string $interfaces
|
* @param array<int, string>|string $interfaces
|
||||||
*/
|
*/
|
||||||
public function toImplement(array|string $interfaces): ArchExpectation
|
public function toImplement(array|string $interfaces): ArchExpectation
|
||||||
{
|
{
|
||||||
@ -888,8 +886,6 @@ final class Expectation
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target to have the given attribute.
|
* Asserts that the given expectation target to have the given attribute.
|
||||||
*
|
|
||||||
* @param class-string<Attribute> $attribute
|
|
||||||
*/
|
*/
|
||||||
public function toHaveAttribute(string $attribute): ArchExpectation
|
public function toHaveAttribute(string $attribute): ArchExpectation
|
||||||
{
|
{
|
||||||
|
|||||||
@ -226,8 +226,6 @@ final class OppositeExpectation
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target to be not subclass of the given class.
|
* Asserts that the given expectation target to be not subclass of the given class.
|
||||||
*
|
|
||||||
* @param class-string $class
|
|
||||||
*/
|
*/
|
||||||
public function toExtend(string $class): ArchExpectation
|
public function toExtend(string $class): ArchExpectation
|
||||||
{
|
{
|
||||||
@ -288,7 +286,7 @@ final class OppositeExpectation
|
|||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target not to implement the given interfaces.
|
* Asserts that the given expectation target not to implement the given interfaces.
|
||||||
*
|
*
|
||||||
* @param array<int, class-string>|string $interfaces
|
* @param array<int, string>|string $interfaces
|
||||||
*/
|
*/
|
||||||
public function toImplement(array|string $interfaces): ArchExpectation
|
public function toImplement(array|string $interfaces): ArchExpectation
|
||||||
{
|
{
|
||||||
@ -421,8 +419,6 @@ final class OppositeExpectation
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the given expectation target not to have the given attribute.
|
* Asserts that the given expectation target not to have the given attribute.
|
||||||
*
|
|
||||||
* @param class-string<Attribute> $attribute
|
|
||||||
*/
|
*/
|
||||||
public function toHaveAttribute(string $attribute): ArchExpectation
|
public function toHaveAttribute(string $attribute): ArchExpectation
|
||||||
{
|
{
|
||||||
|
|||||||
@ -49,6 +49,20 @@ final class TestCaseMethodFactory
|
|||||||
*/
|
*/
|
||||||
public bool $todo = false;
|
public bool $todo = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated issue numbers.
|
||||||
|
*
|
||||||
|
* @var array<int, int>
|
||||||
|
*/
|
||||||
|
public array $issues = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The associated PRs numbers.
|
||||||
|
*
|
||||||
|
* @var array<int, int>
|
||||||
|
*/
|
||||||
|
public array $prs = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The test's notes.
|
* The test's notes.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -18,6 +18,11 @@ final class DescribeCall
|
|||||||
*/
|
*/
|
||||||
private static ?string $describing = null;
|
private static ?string $describing = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The describe "before each" call.
|
||||||
|
*/
|
||||||
|
private ?BeforeEachCall $currentBeforeEachCall = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Pending Call.
|
* Creates a new Pending Call.
|
||||||
*/
|
*/
|
||||||
@ -43,6 +48,8 @@ final class DescribeCall
|
|||||||
*/
|
*/
|
||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
|
unset($this->currentBeforeEachCall);
|
||||||
|
|
||||||
self::$describing = $this->description;
|
self::$describing = $this->description;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -57,14 +64,18 @@ final class DescribeCall
|
|||||||
*
|
*
|
||||||
* @param array<int, mixed> $arguments
|
* @param array<int, mixed> $arguments
|
||||||
*/
|
*/
|
||||||
public function __call(string $name, array $arguments): BeforeEachCall
|
public function __call(string $name, array $arguments): self
|
||||||
{
|
{
|
||||||
$filename = Backtrace::file();
|
$filename = Backtrace::file();
|
||||||
|
|
||||||
$beforeEachCall = new BeforeEachCall(TestSuite::getInstance(), $filename);
|
if (! $this->currentBeforeEachCall instanceof \Pest\PendingCalls\BeforeEachCall) {
|
||||||
|
$this->currentBeforeEachCall = new BeforeEachCall(TestSuite::getInstance(), $filename);
|
||||||
|
|
||||||
$beforeEachCall->describing = $this->description;
|
$this->currentBeforeEachCall->describing = $this->description;
|
||||||
|
}
|
||||||
|
|
||||||
return $beforeEachCall->{$name}(...$arguments); // @phpstan-ignore-line
|
$this->currentBeforeEachCall->{$name}(...$arguments); // @phpstan-ignore-line
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -364,6 +364,48 @@ final class TestCall
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates the test with the given issue(s).
|
||||||
|
*
|
||||||
|
* @param array<int, string|int>|string|int $number
|
||||||
|
*/
|
||||||
|
public function issue(array|string|int $number): self
|
||||||
|
{
|
||||||
|
$number = is_array($number) ? $number : [$number];
|
||||||
|
|
||||||
|
$number = array_map(fn (string|int $number): int => (int) ltrim((string) $number, '#'), $number);
|
||||||
|
|
||||||
|
$this->testCaseMethod->issues = array_merge($this->testCaseMethod->issues, $number);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates the test with the given ticket(s). (Alias for `issue`)
|
||||||
|
*
|
||||||
|
* @param array<int, string|int>|string|int $number
|
||||||
|
*/
|
||||||
|
public function ticket(array|string|int $number): self
|
||||||
|
{
|
||||||
|
return $this->issue($number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates the test with the given pull request(s).
|
||||||
|
*
|
||||||
|
* @param array<int, string|int>|string|int $number
|
||||||
|
*/
|
||||||
|
public function pr(array|string|int $number): self
|
||||||
|
{
|
||||||
|
$number = is_array($number) ? $number : [$number];
|
||||||
|
|
||||||
|
$number = array_map(fn (string|int $number): int => (int) ltrim((string) $number, '#'), $number);
|
||||||
|
|
||||||
|
$this->testCaseMethod->prs = array_merge($this->testCaseMethod->issues, $number);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a note to the test.
|
* Adds a note to the test.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -21,7 +21,7 @@ trait HandleArguments
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str_starts_with((string) $arg, "$argument=")) {
|
if (str_starts_with((string) $arg, "$argument=")) { // @phpstan-ignore-line
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -126,6 +126,18 @@ final class Help implements HandlesArguments
|
|||||||
], [
|
], [
|
||||||
'arg' => '--notes',
|
'arg' => '--notes',
|
||||||
'desc' => 'Output to standard output tests with notes',
|
'desc' => 'Output to standard output tests with notes',
|
||||||
|
], [
|
||||||
|
], [
|
||||||
|
'arg' => '--issue',
|
||||||
|
'desc' => 'Output to standard output tests with the given issue number',
|
||||||
|
], [
|
||||||
|
], [
|
||||||
|
'arg' => '--pr',
|
||||||
|
'desc' => 'Output to standard output tests with the given pull request number',
|
||||||
|
], [
|
||||||
|
], [
|
||||||
|
'arg' => '--pull-request',
|
||||||
|
'desc' => 'Output to standard output tests with the given pull request number (alias for --pr)',
|
||||||
], [
|
], [
|
||||||
'arg' => '--retry',
|
'arg' => '--retry',
|
||||||
'desc' => 'Run non-passing tests first and stop execution upon first error or failure',
|
'desc' => 'Run non-passing tests first and stop execution upon first error or failure',
|
||||||
|
|||||||
@ -34,7 +34,7 @@ final class Parallel implements HandlesArguments
|
|||||||
/**
|
/**
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
private const UNSUPPORTED_ARGUMENTS = ['--todo', '--todos', '--retry', '--notes'];
|
private const UNSUPPORTED_ARGUMENTS = ['--todo', '--todos', '--retry', '--notes', '--issue', '--pr', '--pull-request'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the given command line arguments indicate that the test suite should be run in parallel.
|
* Whether the given command line arguments indicate that the test suite should be run in parallel.
|
||||||
|
|||||||
@ -198,6 +198,8 @@ final class Coverage
|
|||||||
|
|
||||||
$array = [];
|
$array = [];
|
||||||
foreach (array_filter($file->lineCoverageData(), is_array(...)) as $line => $tests) {
|
foreach (array_filter($file->lineCoverageData(), is_array(...)) as $line => $tests) {
|
||||||
|
assert(is_array($tests));
|
||||||
|
|
||||||
$array = $eachLine($array, $tests, $line);
|
$array = $eachLine($array, $tests, $line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
27
src/TestCaseMethodFilters/IssueTestCaseFilter.php
Normal file
27
src/TestCaseMethodFilters/IssueTestCaseFilter.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\TestCaseMethodFilters;
|
||||||
|
|
||||||
|
use Pest\Contracts\TestCaseMethodFilter;
|
||||||
|
use Pest\Factories\TestCaseMethodFactory;
|
||||||
|
|
||||||
|
final readonly class IssueTestCaseFilter implements TestCaseMethodFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new filter instance.
|
||||||
|
*/
|
||||||
|
public function __construct(private int $number)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the test case methods.
|
||||||
|
*/
|
||||||
|
public function accept(TestCaseMethodFactory $factory): bool
|
||||||
|
{
|
||||||
|
return in_array($this->number, $factory->issues, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ namespace Pest\TestCaseMethodFilters;
|
|||||||
use Pest\Contracts\TestCaseMethodFilter;
|
use Pest\Contracts\TestCaseMethodFilter;
|
||||||
use Pest\Factories\TestCaseMethodFactory;
|
use Pest\Factories\TestCaseMethodFactory;
|
||||||
|
|
||||||
final class NotesTestCaseFilter implements TestCaseMethodFilter
|
final readonly class NotesTestCaseFilter implements TestCaseMethodFilter
|
||||||
{
|
{
|
||||||
public function accept(TestCaseMethodFactory $factory): bool
|
public function accept(TestCaseMethodFactory $factory): bool
|
||||||
{
|
{
|
||||||
|
|||||||
27
src/TestCaseMethodFilters/PrTestCaseFilter.php
Normal file
27
src/TestCaseMethodFilters/PrTestCaseFilter.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pest\TestCaseMethodFilters;
|
||||||
|
|
||||||
|
use Pest\Contracts\TestCaseMethodFilter;
|
||||||
|
use Pest\Factories\TestCaseMethodFactory;
|
||||||
|
|
||||||
|
final readonly class PrTestCaseFilter implements TestCaseMethodFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new filter instance.
|
||||||
|
*/
|
||||||
|
public function __construct(private int $number)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter the test case methods.
|
||||||
|
*/
|
||||||
|
public function accept(TestCaseMethodFactory $factory): bool
|
||||||
|
{
|
||||||
|
return in_array($this->number, $factory->prs, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,8 +7,11 @@ namespace Pest\TestCaseMethodFilters;
|
|||||||
use Pest\Contracts\TestCaseMethodFilter;
|
use Pest\Contracts\TestCaseMethodFilter;
|
||||||
use Pest\Factories\TestCaseMethodFactory;
|
use Pest\Factories\TestCaseMethodFactory;
|
||||||
|
|
||||||
final class TodoTestCaseFilter implements TestCaseMethodFilter
|
final readonly class TodoTestCaseFilter implements TestCaseMethodFilter
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Filter the test case methods.
|
||||||
|
*/
|
||||||
public function accept(TestCaseMethodFactory $factory): bool
|
public function accept(TestCaseMethodFactory $factory): bool
|
||||||
{
|
{
|
||||||
return $factory->todo;
|
return $factory->todo;
|
||||||
|
|||||||
@ -22,6 +22,9 @@
|
|||||||
--bail ........................... Stop execution upon first not-passed test
|
--bail ........................... Stop execution upon first not-passed test
|
||||||
--todos ........................ Output to standard output the list of todos
|
--todos ........................ Output to standard output the list of todos
|
||||||
--notes ......................... Output to standard output tests with notes
|
--notes ......................... Output to standard output tests with notes
|
||||||
|
--issue ........ Output to standard output tests with the given issue number
|
||||||
|
--pr .... Output to standard output tests with the given pull request number
|
||||||
|
--pull-request Output to standard output tests with the given pull request number (alias for --pr)
|
||||||
--retry Run non-passing tests first and stop execution upon first error or failure
|
--retry Run non-passing tests first and stop execution upon first error or failure
|
||||||
--list-suites ................................... List available test suites
|
--list-suites ................................... List available test suites
|
||||||
--testsuite [name] ......... Only run tests from the specified test suite(s)
|
--testsuite [name] ......... Only run tests from the specified test suite(s)
|
||||||
|
|||||||
@ -991,6 +991,11 @@
|
|||||||
✓ it is not incompleted because of test with assertions
|
✓ it is not incompleted because of test with assertions
|
||||||
… a "describe" group of tests → it is incompleted
|
… a "describe" group of tests → it is incompleted
|
||||||
|
|
||||||
|
PASS Tests\Features\Issue
|
||||||
|
✓ it may be associated with an issue #1, #2
|
||||||
|
✓ nested → it may be associated with an issue #1, #4, #5, #6, #3
|
||||||
|
// an note between an the issue
|
||||||
|
|
||||||
PASS Tests\Features\It
|
PASS Tests\Features\It
|
||||||
✓ it is a test
|
✓ it is a test
|
||||||
✓ it is a higher order message test
|
✓ it is a higher order message test
|
||||||
@ -1027,6 +1032,11 @@
|
|||||||
! notice → This is a notice description // tests/Features/Notices.php:4
|
! notice → This is a notice description // tests/Features/Notices.php:4
|
||||||
! a "describe" group of tests → notice → This is a notice description // tests/Features/Notices.php:11
|
! a "describe" group of tests → notice → This is a notice description // tests/Features/Notices.php:11
|
||||||
|
|
||||||
|
PASS Tests\Features\Pr
|
||||||
|
✓ it may be associated with an pr #2
|
||||||
|
✓ nested → it may be associated with an pr #3
|
||||||
|
// an note between an the pr
|
||||||
|
|
||||||
PASS Tests\Features\Repeat
|
PASS Tests\Features\Repeat
|
||||||
✓ once
|
✓ once
|
||||||
✓ multiple times @ repetition 1 of 5
|
✓ multiple times @ repetition 1 of 5
|
||||||
@ -1212,6 +1222,11 @@
|
|||||||
✓ it allows performing no expectations without being risky
|
✓ it allows performing no expectations without being risky
|
||||||
✓ a "describe" group of tests → it allows performing no expectations without being risky
|
✓ a "describe" group of tests → it allows performing no expectations without being risky
|
||||||
|
|
||||||
|
PASS Tests\Features\Ticket
|
||||||
|
✓ it may be associated with an ticket #1, #2
|
||||||
|
✓ nested → it may be associated with an ticket #1, #4, #5, #6, #3
|
||||||
|
// an note between an the ticket
|
||||||
|
|
||||||
PASS Tests\Features\Todo - 3 todos
|
PASS Tests\Features\Todo - 3 todos
|
||||||
↓ something todo later
|
↓ something todo later
|
||||||
↓ something todo later chained
|
↓ something todo later chained
|
||||||
@ -1501,4 +1516,4 @@
|
|||||||
WARN Tests\Visual\Version
|
WARN Tests\Visual\Version
|
||||||
- visual snapshot of help command output
|
- visual snapshot of help command output
|
||||||
|
|
||||||
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 24 skipped, 1057 passed (2588 assertions)
|
Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 24 skipped, 1063 passed (2602 assertions)
|
||||||
@ -119,7 +119,7 @@ describe('something 2', function () {
|
|||||||
|
|
||||||
$this->count++;
|
$this->count++;
|
||||||
})->after(function () {
|
})->after(function () {
|
||||||
expect($this->count)->toBe(4);
|
expect($this->count)->toBe(6);
|
||||||
|
|
||||||
$this->count++;
|
$this->count++;
|
||||||
});
|
});
|
||||||
|
|||||||
15
tests/Features/Issue.php
Normal file
15
tests/Features/Issue.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->issue(1);
|
||||||
|
|
||||||
|
it('may be associated with an issue', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->issue(2);
|
||||||
|
|
||||||
|
describe('nested', function () {
|
||||||
|
it('may be associated with an issue', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->issue('#3');
|
||||||
|
})->issue(4)->note('an note between an the issue')->issue([5, 6]);
|
||||||
15
tests/Features/Pr.php
Normal file
15
tests/Features/Pr.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->pr(1);
|
||||||
|
|
||||||
|
it('may be associated with an pr', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->pr(2);
|
||||||
|
|
||||||
|
describe('nested', function () {
|
||||||
|
it('may be associated with an pr', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->pr('#3');
|
||||||
|
})->pr(4)->note('an note between an the pr')->pr(['#5', 6]);
|
||||||
15
tests/Features/Ticket.php
Normal file
15
tests/Features/Ticket.php
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->ticket(1);
|
||||||
|
|
||||||
|
it('may be associated with an ticket', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->ticket(2);
|
||||||
|
|
||||||
|
describe('nested', function () {
|
||||||
|
it('may be associated with an ticket', function () {
|
||||||
|
expect(true)->toBeTrue();
|
||||||
|
})->ticket(3);
|
||||||
|
})->ticket(4)->note('an note between an the ticket')->ticket([5, 6]);
|
||||||
@ -7,6 +7,8 @@ error_reporting(E_ALL);
|
|||||||
|
|
||||||
$GLOBALS['__PEST_INTERNAL_TEST_SUITE'] = true;
|
$GLOBALS['__PEST_INTERNAL_TEST_SUITE'] = true;
|
||||||
|
|
||||||
|
pest()->context()->github('pestphp/pest');
|
||||||
|
|
||||||
pest()->in('PHPUnit/CustomTestCaseInSubFolders/SubFolder/SubFolder')->use(CustomTestCaseInSubFolder::class);
|
pest()->in('PHPUnit/CustomTestCaseInSubFolders/SubFolder/SubFolder')->use(CustomTestCaseInSubFolder::class);
|
||||||
|
|
||||||
// test case for all the directories inside PHPUnit/GlobPatternTests/SubFolder/
|
// test case for all the directories inside PHPUnit/GlobPatternTests/SubFolder/
|
||||||
|
|||||||
@ -16,7 +16,7 @@ $run = function () {
|
|||||||
|
|
||||||
test('parallel', function () use ($run) {
|
test('parallel', function () use ($run) {
|
||||||
expect($run('--exclude-group=integration'))
|
expect($run('--exclude-group=integration'))
|
||||||
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 1043 passed (2556 assertions)')
|
->toContain('Tests: 2 deprecated, 4 warnings, 5 incomplete, 2 notices, 13 todos, 19 skipped, 1049 passed (2570 assertions)')
|
||||||
->toContain('Parallel: 3 processes');
|
->toContain('Parallel: 3 processes');
|
||||||
})->skipOnWindows();
|
})->skipOnWindows();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user