Skip to content

Commit 81316c9

Browse files
kbonddunglas
andauthored
[Feature] Automatically take screenshot on failure/error (#392)
* add Client::takeScreenshot() test * [feature] allow setting a base screenshot directory * [feature] take screenshot on error/failure * Update README.md Co-authored-by: Kévin Dunglas <[email protected]> * prepend the screenshot on error/failure with timestamp * refactor saving screenshots on failure/error - PantherTestCase::createPantherClient()/createAdditionalPantherClient() registers client with ServerExtension - on failure/error, take screenshots for all instantiated clients in a test (primary and additional) * Update README.md Co-authored-by: Kévin Dunglas <[email protected]> * ensure absolute path can always be used when taking screenshots * simplify Co-authored-by: Kévin Dunglas <[email protected]>
1 parent 016d7ef commit 81316c9

File tree

5 files changed

+116
-2
lines changed

5 files changed

+116
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/composer.phar
55
/composer.lock
66
/phpunit.xml
7+
/screenshots/
78
/vendor/
89
/drivers/
910
/screen.png

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ If you intend to use Panther to test your application, we strongly recommend reg
7676
While not strictly mandatory, this extension dramatically improves the testing experience by boosting the performance and
7777
allowing to use the [interactive debugging mode](#interactive-mode).
7878

79+
When using the extension in conjunction with the `PANTHER_ERROR_SCREENSHOT_DIR` environment variable, tests using the
80+
Panther client that fail or error (after the client is created) will automatically get a screenshot taken to help
81+
debugging.
82+
7983
To register the Panther extension, add the following lines to `phpunit.xml.dist`:
8084

8185
```xml
@@ -339,6 +343,7 @@ The following environment variables can be set to change some Panther's behaviou
339343
* `PANTHER_WEB_SERVER_ROUTER`: to use a web server router script which is run at the start of each HTTP request
340344
* `PANTHER_EXTERNAL_BASE_URI`: to use an external web server (the PHP built-in web server will not be started)
341345
* `PANTHER_APP_ENV`: to override the `APP_ENV` variable passed to the web server running the PHP app
346+
* `PANTHER_ERROR_SCREENSHOT_DIR`: to set a base directory for your failure/error screenshots (e.g. `./screenshots`)
342347

343348
### Changing the Hostname and Port of the Built-in Web Server
344349

src/PantherTestCaseTrait.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ protected static function createPantherClient(array $options = [], array $kernel
186186
static::bootKernel($kernelOptions); // @phpstan-ignore-line
187187
}
188188

189+
ServerExtension::registerClient(self::$pantherClient);
190+
189191
return $callGetClient ? self::getClient(self::$pantherClient) : self::$pantherClient; // @phpstan-ignore-line
190192
}
191193

@@ -198,7 +200,11 @@ protected static function createAdditionalPantherClient(): PantherClient
198200
return self::createPantherClient();
199201
}
200202

201-
return self::$pantherClients[] = self::$pantherClient = new PantherClient(self::$pantherClient->getBrowserManager(), self::$baseUri);
203+
self::$pantherClients[] = self::$pantherClient = new PantherClient(self::$pantherClient->getBrowserManager(), self::$baseUri);
204+
205+
ServerExtension::registerClient(self::$pantherClient);
206+
207+
return self::$pantherClient;
202208
}
203209

204210
/**

src/ServerExtension.php

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,33 @@
1616
use PHPUnit\Runner\AfterLastTestHook;
1717
use PHPUnit\Runner\AfterTestErrorHook;
1818
use PHPUnit\Runner\AfterTestFailureHook;
19+
use PHPUnit\Runner\AfterTestHook;
1920
use PHPUnit\Runner\BeforeFirstTestHook;
21+
use PHPUnit\Runner\BeforeTestHook;
2022

2123
/**
2224
* @author Dany Maillard <[email protected]>
2325
*/
24-
final class ServerExtension implements BeforeFirstTestHook, AfterLastTestHook, AfterTestErrorHook, AfterTestFailureHook
26+
final class ServerExtension implements BeforeFirstTestHook, AfterLastTestHook, BeforeTestHook, AfterTestHook, AfterTestErrorHook, AfterTestFailureHook
2527
{
2628
use ServerTrait;
2729

30+
/** @var bool */
31+
private static $enabled = false;
32+
33+
/** @var Client[] */
34+
private static $registeredClients = [];
35+
36+
public static function registerClient(Client $client): void
37+
{
38+
if (self::$enabled) {
39+
self::$registeredClients[] = $client;
40+
}
41+
}
42+
2843
public function executeBeforeFirstTest(): void
2944
{
45+
self::$enabled = true;
3046
$this->keepServerOnTeardown();
3147
}
3248

@@ -35,13 +51,46 @@ public function executeAfterLastTest(): void
3551
$this->stopWebServer();
3652
}
3753

54+
public function executeBeforeTest(string $test): void
55+
{
56+
self::reset();
57+
}
58+
59+
public function executeAfterTest(string $test, float $time): void
60+
{
61+
self::reset();
62+
}
63+
3864
public function executeAfterTestError(string $test, string $message, float $time): void
3965
{
66+
$this->takeScreenshots('error', $test);
4067
$this->pause(sprintf('Error: %s', $message));
4168
}
4269

4370
public function executeAfterTestFailure(string $test, string $message, float $time): void
4471
{
72+
$this->takeScreenshots('failure', $test);
4573
$this->pause(sprintf('Failure: %s', $message));
4674
}
75+
76+
private static function reset(): void
77+
{
78+
self::$registeredClients = [];
79+
}
80+
81+
private function takeScreenshots(string $type, string $test): void
82+
{
83+
if (!($_SERVER['PANTHER_SCREENSHOT_DIR'] ?? false)) {
84+
return;
85+
}
86+
87+
foreach (self::$registeredClients as $i => $client) {
88+
$client->takeScreenshot(sprintf('%s_%s_%s-%d.png',
89+
(new \DateTime())->format('Y-m-d_H-i-s'),
90+
$type,
91+
strtr($test, ['\\' => '-', ':' => '_']),
92+
$i
93+
));
94+
}
95+
}
4796
}

tests/ScreenshotTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Panther project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Symfony\Component\Panther\Tests;
15+
16+
use Symfony\Component\Filesystem\Filesystem;
17+
18+
/**
19+
* @author Kevin Bond <[email protected]>
20+
*/
21+
class ScreenshotTest extends TestCase
22+
{
23+
private static $screenshotDir = __DIR__.'/../screenshots';
24+
private static $screenshotFile = __DIR__.'/../screenshots/screenshot.jpg';
25+
26+
protected function setUp(): void
27+
{
28+
parent::setUp();
29+
30+
(new Filesystem())->remove(self::$screenshotDir);
31+
}
32+
33+
public function testTakeScreenshot(): void
34+
{
35+
$client = self::createPantherClient();
36+
$client->request('GET', '/basic.html');
37+
38+
$screen = $client->takeScreenshot();
39+
40+
$this->assertIsString($screen);
41+
}
42+
43+
public function testTakeScreenshotAndSaveToFile(): void
44+
{
45+
$this->assertFileDoesNotExist(self::$screenshotFile);
46+
47+
$client = self::createPantherClient();
48+
$client->request('GET', '/basic.html');
49+
$client->takeScreenshot(self::$screenshotFile);
50+
51+
$this->assertFileExists(self::$screenshotFile);
52+
}
53+
}

0 commit comments

Comments
 (0)