mirror of
https://github.com/pestphp/pest.git
synced 2026-03-06 07:47:22 +01:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ddc08cf0f9 | |||
| 88d2391d2e | |||
| bd02196950 | |||
| 4de6019206 | |||
| 85630b0aa2 | |||
| 0fda39467c | |||
| 415f571910 | |||
| 8284219035 | |||
| d0d34c7872 | |||
| 2869f11ae5 | |||
| 340c7ca04e | |||
| 81a646d64e | |||
| c23f2e4bd6 | |||
| 4496e9d9ee | |||
| ce14ffd49a | |||
| c18c481628 | |||
| 0695ea5d33 | |||
| 2e321f5465 | |||
| cbeec31bfc | |||
| 69f6a22121 | |||
| 9a179d2891 | |||
| 6c4be0190e | |||
| 5c6bb43d8d | |||
| e536c28e34 | |||
| 67bb23cda3 | |||
| 59398cfcf8 | |||
| 182377abe3 | |||
| 242e74964b | |||
| 9a2c7e45f7 | |||
| 99205c4aa8 | |||
| 1268384fb3 | |||
| c97fd17120 | |||
| 9288490613 | |||
| dc9f70cd5c | |||
| 7a0bf9db97 | |||
| 4f89a2ae16 | |||
| 28d8822de0 | |||
| af3ca742c2 | |||
| 0bf3471968 | |||
| 6fc55becc8 | |||
| 2d85842777 |
@ -1,18 +1,19 @@
|
||||
name: Continuous Integration
|
||||
name: Formats
|
||||
|
||||
on: ['push', 'pull_request']
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
php: [7.3, 7.4]
|
||||
os: [ubuntu-latest]
|
||||
php: [7.4]
|
||||
dependency-version: [prefer-lowest, prefer-stable]
|
||||
|
||||
name: CI - PHP ${{ matrix.php }} (${{ matrix.dependency-version }})
|
||||
name: Formats P${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }}
|
||||
|
||||
steps:
|
||||
|
||||
@ -43,9 +44,3 @@ jobs:
|
||||
|
||||
- name: Type Checks
|
||||
run: vendor/bin/phpstan analyse --ansi
|
||||
|
||||
- name: Unit Tests
|
||||
run: bin/pest --colors=always --exclude-group=integration
|
||||
|
||||
- name: Integration Tests
|
||||
run: bin/pest --colors=always --group=integration
|
||||
42
.github/workflows/tests.yml
vendored
Normal file
42
.github/workflows/tests.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
name: Tests
|
||||
|
||||
on: ['push', 'pull_request']
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
php: [7.3, 7.4]
|
||||
dependency-version: [prefer-lowest, prefer-stable]
|
||||
|
||||
name: Tests P${{ matrix.php }} - ${{ matrix.os }} - ${{ matrix.dependency-version }}
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.composer/cache/files
|
||||
key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: mbstring, zip
|
||||
coverage: none
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer update --${{ matrix.dependency-version }} --no-interaction --prefer-dist
|
||||
|
||||
- name: Unit Tests
|
||||
run: bin/pest --colors=always --exclude-group=integration
|
||||
|
||||
- name: Integration Tests
|
||||
run: bin/pest --colors=always --group=integration
|
||||
26
CHANGELOG.md
26
CHANGELOG.md
@ -6,6 +6,32 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.1.5 (2020-05-24)](https://github.com/pestphp/pest/compare/v0.1.4...v0.1.5)
|
||||
### Fixed
|
||||
- Missing default decorated output on coverage ([88d2391(https://github.com/pestphp/pest/commit/88d2391d2e6fe9c9416462734b9b523cb418f469))
|
||||
|
||||
## [v0.1.4 (2020-05-24)](https://github.com/pestphp/pest/compare/v0.1.3...v0.1.4)
|
||||
### Added
|
||||
- Support to Lumen on artisan commands ([#18](https://github.com/pestphp/pest/pull/18))
|
||||
|
||||
### Fixed
|
||||
- Mockery tests without assertions being considered risky ([415f571](https://github.com/pestphp/pest/commit/415f5719101b30c11d87f74810a71686ef2786c6))
|
||||
|
||||
## [v0.1.3 (2020-05-21)](https://github.com/pestphp/pest/compare/v0.1.2...v0.1.3)
|
||||
### Added
|
||||
- `Plugin::uses()` method for making traits globally available ([6c4be01](https://github.com/pestphp/pest/commit/6c4be0190e9493702a976b996bbbf5150cc6bb53))
|
||||
|
||||
## [v0.1.2 (2020-05-15)](https://github.com/pestphp/pest/compare/v0.1.1...v0.1.2)
|
||||
### Added
|
||||
- Support to custom helpers ([#7](https://github.com/pestphp/pest/pull/7))
|
||||
|
||||
## [v0.1.1 (2020-05-14)](https://github.com/pestphp/pest/compare/v0.1.0...v0.1.1)
|
||||
### Added
|
||||
- `test` function without any arguments returns the current test case ([6fc55be](https://github.com/pestphp/pest/commit/6fc55becc8aecff685a958617015be1a4c118b01))
|
||||
|
||||
### Fixed
|
||||
- "No coverage driver error" now returns proper error on Laravel ([28d8822](https://github.com/pestphp/pest/commit/28d8822de01f4fa92c62d8b8e019313f382b97e9))
|
||||
|
||||
## [v0.1.0 (2020-05-09)](https://github.com/pestphp/pest/commit/de2929077b344a099ef9c2ddc2f48abce14e248f)
|
||||
### Added
|
||||
- First version
|
||||
|
||||
17
README.md
17
README.md
@ -1,17 +1,18 @@
|
||||
<p align="center">
|
||||
<img src="https://next.pestphp.com/assets/img/og.png" width="600" alt="PEST Preview">
|
||||
<img src="https://raw.githubusercontent.com/pestphp/art/master/readme.png" width="600" alt="PEST">
|
||||
<p align="center">
|
||||
<a href="https://github.com/pestphp/pest/actions"><img src="https://github.com/pest/pestphp/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/pestphp/pest"><img src="https://poser.pugx.org/pestphp/pest/d/total.svg" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/pestphp/pest"><img src="https://poser.pugx.org/pestphp/pest/v/stable.svg" alt="Latest Version"></a>
|
||||
<a href="https://packagist.org/packages/pestphp/pest"><img src="https://poser.pugx.org/pestphp/pest/license.svg" alt="License"></a>
|
||||
<a href="https://github.com/pestphp/pest/actions"><img alt="GitHub Workflow Status (master)" src="https://img.shields.io/github/workflow/status/pestphp/pest/Continuous Integration/master"></a>
|
||||
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Total Downloads" src="https://img.shields.io/packagist/dt/pestphp/pest"></a>
|
||||
<a href="https://packagist.org/packages/pestphp/pest"><img alt="Latest Version" src="https://img.shields.io/packagist/v/pestphp/pest"></a>
|
||||
<a href="https://packagist.org/packages/pestphp/pest"><img alt="License" src="https://img.shields.io/packagist/l/pestphp/pest"></a>
|
||||
</p>
|
||||
</p>
|
||||
|
||||
------
|
||||
**Pest** it's an elegant PHP Testing Framework with a focus on simplicity. It was carefully crafted to bring the joy of testing to PHP.
|
||||
**Pest** is an elegant PHP Testing Framework with a focus on simplicity. It was carefully crafted to bring the joy of testing to PHP.
|
||||
|
||||
- Explore the docs: **[pestphp.com »](https://pestphp.com)**
|
||||
- Join the Discord Server: **[discord.gg/4UMHUb5 »](https://discord.gg/4UMHUb5)**
|
||||
- Follow us on Twitter: **[@pestphp »](https://twitter.com/pestphp)**
|
||||
- Join us on the Discord Server: **[discord.gg/bMAJv82 »](https://discord.gg/bMAJv82)**
|
||||
|
||||
Pest was created by **[Nuno Maduro](https://twitter.com/enunomaduro)** and is open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
|
||||
Pest was created by **[Nuno Maduro](https://twitter.com/enunomaduro)** under the **[Sponsorware license](https://github.com/sponsorware/docs)**. It got open-sourced and is now licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
|
||||
|
||||
2
bin/pest
2
bin/pest
@ -27,5 +27,5 @@ use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
ValidatesEnvironment::in($testSuite);
|
||||
|
||||
exit((new Command($testSuite, new ConsoleOutput()))->run($_SERVER['argv']));
|
||||
exit((new Command($testSuite, new ConsoleOutput(ConsoleOutput::VERBOSITY_NORMAL, true)))->run($_SERVER['argv']));
|
||||
})();
|
||||
|
||||
@ -34,7 +34,10 @@
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/PHPUnit/"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"tests/Autoload.php"
|
||||
]
|
||||
},
|
||||
"require-dev": {
|
||||
"ergebnis/phpstan-rules": "^0.14.4",
|
||||
|
||||
@ -22,6 +22,7 @@ final class LoadStructure
|
||||
*/
|
||||
private const STRUCTURE = [
|
||||
'Datasets.php',
|
||||
'Helpers.php',
|
||||
'Pest.php',
|
||||
'Datasets',
|
||||
];
|
||||
|
||||
@ -92,6 +92,8 @@ trait TestCase
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
TestSuite::getInstance()->test = $this;
|
||||
|
||||
parent::setUp();
|
||||
|
||||
$beforeEach = TestSuite::getInstance()->beforeEach->get(self::$__filename);
|
||||
@ -109,6 +111,8 @@ trait TestCase
|
||||
$this->__callClosure($afterEach, func_get_args());
|
||||
|
||||
parent::tearDown();
|
||||
|
||||
TestSuite::getInstance()->test = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -9,7 +9,6 @@ use Pest\Actions\AddsDefaults;
|
||||
use Pest\Actions\AddsTests;
|
||||
use Pest\Actions\LoadStructure;
|
||||
use Pest\Actions\ValidatesConfiguration;
|
||||
use Pest\Exceptions\CodeCoverageDriverNotAvailable;
|
||||
use Pest\TestSuite;
|
||||
use PHPUnit\Framework\TestSuite as BaseTestSuite;
|
||||
use PHPUnit\TextUI\Command as BaseCommand;
|
||||
@ -122,7 +121,10 @@ final class Command extends BaseCommand
|
||||
|
||||
if ($result === 0 && $this->testSuite->coverage) {
|
||||
if (!Coverage::isAvailable()) {
|
||||
throw new CodeCoverageDriverNotAvailable();
|
||||
$this->output->writeln(
|
||||
"\n <fg=white;bg=red;options=bold> ERROR </> No code coverage driver is available.</>",
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$coverage = Coverage::report($this->output);
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Exceptions;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use NunoMaduro\Collision\Contracts\RenderlessEditor;
|
||||
use NunoMaduro\Collision\Contracts\RenderlessTrace;
|
||||
use Symfony\Component\Console\Exception\ExceptionInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class CodeCoverageDriverNotAvailable extends InvalidArgumentException implements ExceptionInterface, RenderlessEditor, RenderlessTrace
|
||||
{
|
||||
/**
|
||||
* Creates a new instance of test already exist.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('No code coverage driver is available');
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ namespace Pest\Laravel\Commands;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Pest\Exceptions\InvalidConsoleArgument;
|
||||
use Pest\Support\Str;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -33,18 +34,39 @@ final class PestInstallCommand extends Command
|
||||
public function handle(): void
|
||||
{
|
||||
/* @phpstan-ignore-next-line */
|
||||
$target = base_path('tests/Pest.php');
|
||||
$pest = base_path('tests/Pest.php');
|
||||
/* @phpstan-ignore-next-line */
|
||||
$helpers = base_path('tests/Helpers.php');
|
||||
$stubs = $this->isLumen() ? 'stubs/Lumen' : 'stubs/Laravel';
|
||||
|
||||
if (File::exists($target)) {
|
||||
throw new InvalidConsoleArgument(sprintf('%s already exist', $target));
|
||||
foreach ([$pest, $helpers] as $file) {
|
||||
if (File::exists($file)) {
|
||||
throw new InvalidConsoleArgument(sprintf('%s already exist', $file));
|
||||
}
|
||||
}
|
||||
|
||||
File::copy(implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__DIR__, 3),
|
||||
'stubs',
|
||||
$stubs,
|
||||
'Pest.php',
|
||||
]), $target);
|
||||
]), $pest);
|
||||
|
||||
File::copy(implode(DIRECTORY_SEPARATOR, [
|
||||
dirname(__DIR__, 3),
|
||||
$stubs,
|
||||
'Helpers.php',
|
||||
]), $helpers);
|
||||
|
||||
$this->output->success('`tests/Pest.php` created successfully.');
|
||||
$this->output->success('`tests/Helpers.php` created successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this is a Lumen application.
|
||||
*/
|
||||
private function isLumen(): bool
|
||||
{
|
||||
/* @phpstan-ignore-next-line */
|
||||
return Str::startsWith(app()->version(), 'Lumen');
|
||||
}
|
||||
}
|
||||
|
||||
28
src/Plugin.php
Normal file
28
src/Plugin.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest;
|
||||
|
||||
final class Plugin
|
||||
{
|
||||
/**
|
||||
* The lazy callables to be executed
|
||||
* once the test suite boots.
|
||||
*
|
||||
* @var array<int, callable>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static $callables = [];
|
||||
|
||||
/**
|
||||
* Lazy loads an `uses` call on the context of plugins.
|
||||
*/
|
||||
public static function uses(string ...$traits): void
|
||||
{
|
||||
self::$callables[] = function () use ($traits): void {
|
||||
uses(...$traits)->in(TestSuite::getInstance()->rootPath . DIRECTORY_SEPARATOR . 'tests');
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -41,6 +41,12 @@ final class AfterEachRepository
|
||||
|
||||
return ChainableClosure::from(function (): void {
|
||||
if (class_exists(Mockery::class)) {
|
||||
/* @phpstan-ignore-next-line */
|
||||
if ($container = Mockery::getContainer()) {
|
||||
/* @phpstan-ignore-next-line */
|
||||
$this->addToAssertionCount($container->mockery_getExpectationCount());
|
||||
}
|
||||
|
||||
Mockery::close();
|
||||
}
|
||||
}, $afterEach);
|
||||
|
||||
@ -4,11 +4,16 @@ declare(strict_types=1);
|
||||
|
||||
namespace Pest\Support;
|
||||
|
||||
use ReflectionClass;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class HigherOrderMessage
|
||||
{
|
||||
public const UNDEFINED_METHOD = 'Method %s does not exist';
|
||||
|
||||
/**
|
||||
* The filename where the function was originally called.
|
||||
*
|
||||
@ -57,4 +62,27 @@ final class HigherOrderMessage
|
||||
$this->methodName = $methodName;
|
||||
$this->arguments = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-throws the given `$throwable` with the good line and filename.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function call(object $target)
|
||||
{
|
||||
try {
|
||||
return Reflection::call($target, $this->methodName, $this->arguments);
|
||||
} catch (Throwable $throwable) {
|
||||
Reflection::setPropertyValue($throwable, 'file', $this->filename);
|
||||
Reflection::setPropertyValue($throwable, 'line', $this->line);
|
||||
|
||||
if ($throwable->getMessage() === sprintf(self::UNDEFINED_METHOD, $this->methodName)) {
|
||||
/** @var \ReflectionClass $reflection */
|
||||
$reflection = (new ReflectionClass($target))->getParentClass();
|
||||
Reflection::setPropertyValue($throwable, 'message', sprintf('Call to undefined method %s::%s()', $reflection->getName(), $this->methodName));
|
||||
}
|
||||
|
||||
throw $throwable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,16 +4,11 @@ declare(strict_types=1);
|
||||
|
||||
namespace Pest\Support;
|
||||
|
||||
use ReflectionClass;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class HigherOrderMessageCollection
|
||||
{
|
||||
public const UNDEFINED_METHOD = 'Method %s does not exist';
|
||||
|
||||
/**
|
||||
* @var array<int, HigherOrderMessage>
|
||||
*/
|
||||
@ -35,7 +30,7 @@ final class HigherOrderMessageCollection
|
||||
public function chain(object $target): void
|
||||
{
|
||||
foreach ($this->messages as $message) {
|
||||
$target = $this->attempt($target, $message);
|
||||
$target = $message->call($target);
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,30 +40,7 @@ final class HigherOrderMessageCollection
|
||||
public function proxy(object $target): void
|
||||
{
|
||||
foreach ($this->messages as $message) {
|
||||
$this->attempt($target, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-throws the given `$throwable` with the good line and filename.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function attempt(object $target, HigherOrderMessage $message)
|
||||
{
|
||||
try {
|
||||
return Reflection::call($target, $message->methodName, $message->arguments);
|
||||
} catch (Throwable $throwable) {
|
||||
Reflection::setPropertyValue($throwable, 'file', $message->filename);
|
||||
Reflection::setPropertyValue($throwable, 'line', $message->line);
|
||||
|
||||
if ($throwable->getMessage() === sprintf(self::UNDEFINED_METHOD, $message->methodName)) {
|
||||
/** @var \ReflectionClass $reflection */
|
||||
$reflection = (new ReflectionClass($target))->getParentClass();
|
||||
Reflection::setPropertyValue($throwable, 'message', sprintf('Call to undefined method %s::%s()', $reflection->getName(), $message->methodName));
|
||||
}
|
||||
|
||||
throw $throwable;
|
||||
$message->call($target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
83
src/Support/HigherOrderTapProxy.php
Normal file
83
src/Support/HigherOrderTapProxy.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Pest\Support;
|
||||
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class HigherOrderTapProxy
|
||||
{
|
||||
private const UNDEFINED_PROPERTY = 'Undefined property: P\\';
|
||||
|
||||
/**
|
||||
* The target being tapped.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $target;
|
||||
|
||||
/**
|
||||
* Create a new tap proxy instance.
|
||||
*
|
||||
* @param mixed $target
|
||||
*/
|
||||
public function __construct($target)
|
||||
{
|
||||
$this->target = $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically sets properties on the target.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set(string $property, $value): void
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
$this->target->{$property} = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically pass properties gets to the target.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $property)
|
||||
{
|
||||
try {
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->target->{$property};
|
||||
} catch (\Throwable $throwable) {
|
||||
Reflection::setPropertyValue($throwable, 'file', Backtrace::file());
|
||||
Reflection::setPropertyValue($throwable, 'line', Backtrace::line());
|
||||
|
||||
if (Str::startsWith($message = $throwable->getMessage(), self::UNDEFINED_PROPERTY)) {
|
||||
/** @var \ReflectionClass $reflection */
|
||||
$reflection = (new ReflectionClass($this->target))->getParentClass();
|
||||
Reflection::setPropertyValue($throwable, 'message', sprintf('Undefined property %s::$%s', $reflection->getName(), $property));
|
||||
}
|
||||
|
||||
throw $throwable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically pass method calls to the target.
|
||||
*
|
||||
* @param array<int, mixed> $arguments
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $methodName, array $arguments)
|
||||
{
|
||||
$filename = Backtrace::file();
|
||||
$line = Backtrace::line();
|
||||
|
||||
return (new HigherOrderMessage($filename, $line, $methodName, $arguments))
|
||||
->call($this->target);
|
||||
}
|
||||
}
|
||||
@ -16,6 +16,13 @@ use Pest\Repositories\TestRepository;
|
||||
*/
|
||||
final class TestSuite
|
||||
{
|
||||
/**
|
||||
* Holds the current test case.
|
||||
*
|
||||
* @var \PHPUnit\Framework\TestCase|null
|
||||
*/
|
||||
public $test;
|
||||
|
||||
/**
|
||||
* Holds the tests repository.
|
||||
*
|
||||
@ -99,7 +106,13 @@ final class TestSuite
|
||||
public static function getInstance(string $rootPath = null): TestSuite
|
||||
{
|
||||
if (is_string($rootPath)) {
|
||||
return self::$instance ?? self::$instance = new TestSuite($rootPath);
|
||||
self::$instance = new TestSuite($rootPath);
|
||||
|
||||
foreach (Plugin::$callables as $callable) {
|
||||
$callable();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
if (self::$instance === null) {
|
||||
|
||||
@ -8,11 +8,12 @@ use Pest\PendingObjects\BeforeEachCall;
|
||||
use Pest\PendingObjects\TestCall;
|
||||
use Pest\PendingObjects\UsesCall;
|
||||
use Pest\Support\Backtrace;
|
||||
use Pest\Support\HigherOrderTapProxy;
|
||||
use Pest\TestSuite;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Runs the given closure after all tests in the current file.
|
||||
* Runs the given closure before all tests in the current file.
|
||||
*/
|
||||
function beforeAll(Closure $closure): void
|
||||
{
|
||||
@ -59,8 +60,12 @@ function uses(string ...$classAndTraits): UsesCall
|
||||
*
|
||||
* @return TestCall|TestCase|mixed
|
||||
*/
|
||||
function test(string $description, Closure $closure = null): TestCall
|
||||
function test(string $description = null, Closure $closure = null)
|
||||
{
|
||||
if ($description === null && TestSuite::getInstance()->test) {
|
||||
return new HigherOrderTapProxy(TestSuite::getInstance()->test);
|
||||
}
|
||||
|
||||
$filename = Backtrace::file();
|
||||
|
||||
return new TestCall(TestSuite::getInstance(), $filename, $description, $closure);
|
||||
|
||||
12
stubs/Laravel/Helpers.php
Normal file
12
stubs/Laravel/Helpers.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Set the currently logged in user for the application.
|
||||
*/
|
||||
function actingAs(Authenticatable $user, string $driver = null): TestCase
|
||||
{
|
||||
return test()->actingAs($user, $driver);
|
||||
}
|
||||
11
stubs/Lumen/Helpers.php
Normal file
11
stubs/Lumen/Helpers.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
|
||||
/**
|
||||
* Set the currently logged in user for the application.
|
||||
*/
|
||||
function actingAs(Authenticatable $user, string $driver = null): TestCase
|
||||
{
|
||||
return test()->actingAs($user, $driver);
|
||||
}
|
||||
3
stubs/Lumen/Pest.php
Normal file
3
stubs/Lumen/Pest.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
uses(TestCase::class)->in(__DIR__);
|
||||
17
stubs/Lumen/phpunit.xml
Normal file
17
stubs/Lumen/phpunit.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Application Test Suite">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">./app</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
@ -47,6 +47,12 @@
|
||||
✓ it catch exceptions
|
||||
✓ it catch exceptions and messages
|
||||
|
||||
PASS Tests\Features\Helpers
|
||||
✓ it can set/get properties on $this
|
||||
✓ it throws error if property do not exist
|
||||
✓ it allows to call underlying protected/private methods
|
||||
✓ it throws error if method do not exist
|
||||
|
||||
PASS Tests\Features\HigherOrderMessages
|
||||
✓ it proxies calls to object
|
||||
|
||||
@ -64,7 +70,7 @@
|
||||
s it skips with message → skipped because bar
|
||||
s it skips with truthy closure condition
|
||||
✓ it do not skips with falsy closure condition
|
||||
s it skips with condition and messsage → skipped because foo
|
||||
s it skips with condition and message → skipped because foo
|
||||
|
||||
PASS Tests\Features\Test
|
||||
✓ a test
|
||||
@ -89,6 +95,9 @@
|
||||
PASS Tests\Playground
|
||||
✓ basic
|
||||
|
||||
PASS Tests\Plugins\Traits
|
||||
✓ it allows global uses
|
||||
|
||||
PASS Tests\Unit\Actions\AddsCoverage
|
||||
✓ it adds coverage if --coverage exist
|
||||
✓ it adds coverage if --min exist
|
||||
@ -126,5 +135,5 @@
|
||||
WARN Tests\Visual\Success
|
||||
s visual snapshot of test suite on success
|
||||
|
||||
Tests: 6 skipped, 65 passed
|
||||
Time: 2.50s
|
||||
Tests: 6 skipped, 70 passed
|
||||
Time: 2.68s
|
||||
|
||||
@ -3,3 +3,13 @@
|
||||
if (class_exists(NunoMaduro\Collision\Provider::class)) {
|
||||
(new NunoMaduro\Collision\Provider())->register();
|
||||
}
|
||||
|
||||
trait PluginTrait
|
||||
{
|
||||
public function assertPluginTraitGotRegistered(): void
|
||||
{
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
Pest\Plugin::uses(PluginTrait::class);
|
||||
|
||||
43
tests/Features/Helpers.php
Normal file
43
tests/Features/Helpers.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
function addUser()
|
||||
{
|
||||
test()->user = 'nuno';
|
||||
}
|
||||
|
||||
it('can set/get properties on $this', function () {
|
||||
addUser();
|
||||
assertEquals('nuno', $this->user);
|
||||
});
|
||||
|
||||
it('throws error if property do not exist', function () {
|
||||
test()->user;
|
||||
})->throws(\Whoops\Exception\ErrorException::class, 'Undefined property PHPUnit\Framework\TestCase::$user');
|
||||
|
||||
class User
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'nuno';
|
||||
}
|
||||
}
|
||||
|
||||
function mockUser()
|
||||
{
|
||||
$mock = test()->createMock(User::class);
|
||||
|
||||
$mock->method('getName')
|
||||
->willReturn('maduro');
|
||||
|
||||
return $mock;
|
||||
}
|
||||
|
||||
it('allows to call underlying protected/private methods', function () {
|
||||
$user = mockUser();
|
||||
|
||||
assertEquals('maduro', $user->getName());
|
||||
});
|
||||
|
||||
it('throws error if method do not exist', function () {
|
||||
test()->name();
|
||||
})->throws(\ReflectionException::class, 'Call to undefined method PHPUnit\Framework\TestCase::name()');
|
||||
@ -6,10 +6,10 @@ interface Foo
|
||||
}
|
||||
|
||||
it('has bar', function () {
|
||||
$mock = Mockery::mock(Foo::class);
|
||||
$mock = mock(Foo::class);
|
||||
$mock->shouldReceive('bar')
|
||||
->times(1)
|
||||
->andReturn(2);
|
||||
|
||||
assertEquals(2, $mock->bar());
|
||||
$mock->bar();
|
||||
});
|
||||
|
||||
@ -24,6 +24,6 @@ it('do not skips with falsy closure condition')
|
||||
->skip(function () { return false; })
|
||||
->assertTrue(true);
|
||||
|
||||
it('skips with condition and messsage')
|
||||
it('skips with condition and message')
|
||||
->skip(true, 'skipped because foo')
|
||||
->assertTrue(false);
|
||||
|
||||
8
tests/Helpers.php
Normal file
8
tests/Helpers.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Mockery\MockInterface;
|
||||
|
||||
function mock(string $class): MockInterface
|
||||
{
|
||||
return Mockery::mock($class);
|
||||
}
|
||||
3
tests/Plugins/Traits.php
Normal file
3
tests/Plugins/Traits.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
it('allows global uses')->assertPluginTraitGotRegistered();
|
||||
Reference in New Issue
Block a user