Skip to content

Commit 92d8fcb

Browse files
authored
Merge pull request #4 from clemblanco/click-poc
feat: PoC for clicking a link + asserting new URL
2 parents 8830730 + 78e44ea commit 92d8fcb

File tree

9 files changed

+188
-4
lines changed

9 files changed

+188
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ node_modules/
1616
/playwright-report/
1717
/blob-report/
1818
/playwright/.cache/
19+
.temp/e2e

src/Compiler.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function compile(): void
3333
$content = implode(
3434
"\n",
3535
array_map(
36-
static fn (Operation $operation): string => $operation->compile(),
36+
static fn (Operation $operation): string => "\t{$operation->compile()}",
3737
$this->operations,
3838
),
3939
);
@@ -42,7 +42,17 @@ public function compile(): void
4242
import { test, expect } from '@playwright/test';
4343
4444
test('runtime', async ({ page }) => {
45-
$content
45+
$content
46+
47+
const response = await page.reload();
48+
test.info().annotations.push({
49+
type: '_response',
50+
description: JSON.stringify({
51+
headers: response.headers(),
52+
status: response.status(),
53+
url: response.url(),
54+
})
55+
});
4656
});
4757
JS,
4858
);

src/Operations/AssertUrlIs.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pest\Browser\Operations;
6+
7+
use Pest\Browser\Contracts\Operation;
8+
9+
/**
10+
* @internal
11+
*/
12+
final readonly class AssertUrlIs implements Operation
13+
{
14+
/**
15+
* Creates an operation instance.
16+
*/
17+
public function __construct(
18+
private string $url,
19+
) {
20+
//
21+
}
22+
23+
public function compile(): string
24+
{
25+
return sprintf("await expect(page.url()).toBe('%s');", $this->url);
26+
}
27+
}

src/Operations/ClickLink.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pest\Browser\Operations;
6+
7+
use Pest\Browser\Contracts\Operation;
8+
9+
/**
10+
* @internal
11+
*/
12+
final readonly class ClickLink implements Operation
13+
{
14+
/**
15+
* Creates an operation instance.
16+
*/
17+
public function __construct(
18+
private string $text,
19+
) {
20+
//
21+
}
22+
23+
public function compile(): string
24+
{
25+
return sprintf("await page.locator('a').filter({ hasText: /%s/i }).click();", $this->text);
26+
}
27+
}

src/PendingTest.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Pest\Browser;
66

7+
use Pest\Browser\ValueObjects\TestResult;
8+
use Pest\Browser\ValueObjects\TestResultResponse;
79
use Pest\Browser\Contracts\Operation;
810

911
/**
@@ -46,10 +48,38 @@ public function toHaveTitle(string $title): self
4648
return $this;
4749
}
4850

51+
/**
52+
* Clicks some text on the page.
53+
*/
54+
public function clickLink(string $text): self
55+
{
56+
$this->operations[] = new Operations\ClickLink($text);
57+
58+
return $this;
59+
}
60+
61+
/**
62+
* Checks if the page url is matching.
63+
*/
64+
public function assertUrlIs(string $url): self
65+
{
66+
$this->operations[] = new Operations\AssertUrlIs($url);
67+
68+
return $this;
69+
}
70+
71+
/**
72+
* Build and return the final response the test received.
73+
*/
74+
public function response(): TestResultResponse
75+
{
76+
return $this->build()->response();
77+
}
78+
4979
/**
5080
* Compile the JavaScript test file.
5181
*/
52-
public function compile(): void
82+
public function build(): void
5383
{
5484
$compiler = new Compiler($this->operations);
5585

@@ -60,5 +90,7 @@ public function compile(): void
6090
$result = $worker->run();
6191

6292
expect($result->ok())->toBeTrue();
93+
94+
return $result;
6395
}
6496
}

src/ValueObjects/TestResult.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
public function __construct(
1616
private bool $ok,
17+
private TestResultResponse $response,
1718
) {
1819
//
1920
}
@@ -25,4 +26,12 @@ public function ok(): bool
2526
{
2627
return $this->ok;
2728
}
29+
30+
/**
31+
* Get the final response from the test result.
32+
*/
33+
public function response(): TestResultResponse
34+
{
35+
return $this->response;
36+
}
2837
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pest\Browser\ValueObjects;
6+
7+
use Pest\Support\Arr;
8+
9+
/**
10+
* @internal
11+
*/
12+
final readonly class TestResultResponse
13+
{
14+
private array $headers;
15+
16+
private int $status;
17+
18+
private string $url;
19+
20+
/**
21+
* The test result response.
22+
*/
23+
public function __construct(array $annotations)
24+
{
25+
/** @todo would be cleaner with collect() and Str facade */
26+
$annotation = Arr::last(array_filter($annotations, function ($annotation) {
27+
return Arr::get($annotation, 'type') === '_response';
28+
}));
29+
30+
[
31+
'headers' => $this->headers,
32+
'status' => $this->status,
33+
'url' => $this->url
34+
] = json_decode(Arr::get($annotation, 'description'), true);
35+
}
36+
37+
/**
38+
* Get the test result response headers.
39+
*/
40+
public function headers(): array
41+
{
42+
return $this->headers;
43+
}
44+
45+
/**
46+
* Get the test result response status.
47+
*/
48+
public function status(): int
49+
{
50+
return $this->status;
51+
}
52+
53+
/**
54+
* Get the test result response url.
55+
*/
56+
public function url(): string
57+
{
58+
return $this->url;
59+
}
60+
}

src/Worker.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
namespace Pest\Browser;
66

77
use Pest\Browser\ValueObjects\TestResult;
8+
use Pest\Browser\ValueObjects\TestResultResponse;
9+
use Pest\Support\Arr;
810
use Symfony\Component\Process\Process;
911

1012
/**
@@ -26,6 +28,9 @@ public function run(): TestResult
2628
// @phpstan-ignore-next-line
2729
$outputAsArray = json_decode($output, true);
2830

29-
return new TestResult($outputAsArray['suites'][0]['specs'][0]['ok']);
31+
$ok = Arr::get($outputAsArray, 'suites.0.specs.0.ok');
32+
$annotations = Arr::get($outputAsArray, 'suites.0.specs.0.tests.0.annotations');
33+
34+
return new TestResult($ok, new TestResultResponse($annotations));
3035
}
3136
}

tests/Example.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,16 @@
1717
->toHaveTitle('/Framework/')
1818
->toHaveTitle('/.*Artisans$/');
1919
});
20+
21+
it('may click the "get started" button at laravel', function () {
22+
visit('https://laravel.com')
23+
->clickLink('Get Started')
24+
->assertUrlIs('https://laravel.com/docs/11.x');
25+
26+
// -- or --
27+
28+
$browser = visit('https://laravel.com')
29+
->clickLink('Get Started');
30+
31+
expect($browser->response()->url())->toBe('https://laravel.com/docs/11.x');
32+
});

0 commit comments

Comments
 (0)