Skip to content

Commit

Permalink
Merge pull request #4 from clemblanco/click-poc
Browse files Browse the repository at this point in the history
feat: PoC for clicking a link + asserting new URL
  • Loading branch information
nunomaduro authored Feb 14, 2025
2 parents 8830730 + 78e44ea commit 92d8fcb
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ node_modules/
/playwright-report/
/blob-report/
/playwright/.cache/
.temp/e2e
14 changes: 12 additions & 2 deletions src/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function compile(): void
$content = implode(
"\n",
array_map(
static fn (Operation $operation): string => $operation->compile(),
static fn (Operation $operation): string => "\t{$operation->compile()}",
$this->operations,
),
);
Expand All @@ -42,7 +42,17 @@ public function compile(): void
import { test, expect } from '@playwright/test';
test('runtime', async ({ page }) => {
$content
$content
const response = await page.reload();
test.info().annotations.push({
type: '_response',
description: JSON.stringify({
headers: response.headers(),
status: response.status(),
url: response.url(),
})
});
});
JS,
);
Expand Down
27 changes: 27 additions & 0 deletions src/Operations/AssertUrlIs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Pest\Browser\Operations;

use Pest\Browser\Contracts\Operation;

/**
* @internal
*/
final readonly class AssertUrlIs implements Operation
{
/**
* Creates an operation instance.
*/
public function __construct(
private string $url,
) {
//
}

public function compile(): string
{
return sprintf("await expect(page.url()).toBe('%s');", $this->url);
}
}
27 changes: 27 additions & 0 deletions src/Operations/ClickLink.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Pest\Browser\Operations;

use Pest\Browser\Contracts\Operation;

/**
* @internal
*/
final readonly class ClickLink implements Operation
{
/**
* Creates an operation instance.
*/
public function __construct(
private string $text,
) {
//
}

public function compile(): string
{
return sprintf("await page.locator('a').filter({ hasText: /%s/i }).click();", $this->text);
}
}
34 changes: 33 additions & 1 deletion src/PendingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace Pest\Browser;

use Pest\Browser\ValueObjects\TestResult;
use Pest\Browser\ValueObjects\TestResultResponse;
use Pest\Browser\Contracts\Operation;

/**
Expand Down Expand Up @@ -46,10 +48,38 @@ public function toHaveTitle(string $title): self
return $this;
}

/**
* Clicks some text on the page.
*/
public function clickLink(string $text): self
{
$this->operations[] = new Operations\ClickLink($text);

return $this;
}

/**
* Checks if the page url is matching.
*/
public function assertUrlIs(string $url): self
{
$this->operations[] = new Operations\AssertUrlIs($url);

return $this;
}

/**
* Build and return the final response the test received.
*/
public function response(): TestResultResponse
{
return $this->build()->response();

Check failure on line 76 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Cannot call method response() on null.

Check failure on line 76 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Method Pest\Browser\PendingTest::response() should return Pest\Browser\ValueObjects\TestResultResponse but returns mixed.

Check failure on line 76 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Result of method Pest\Browser\PendingTest::build() (void) is used.
}

/**
* Compile the JavaScript test file.
*/
public function compile(): void
public function build(): void
{
$compiler = new Compiler($this->operations);

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

expect($result->ok())->toBeTrue();

return $result;

Check failure on line 94 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 - ubuntu-latest - prefer-lowest -

A void function must not return a value

Check failure on line 94 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 - ubuntu-latest - prefer-lowest - --parallel

A void function must not return a value

Check failure on line 94 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Method Pest\Browser\PendingTest::build() with return type void returns Pest\Browser\ValueObjects\TestResult but should not return anything.

Check failure on line 94 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 - ubuntu-latest - prefer-stable -

A void function must not return a value

Check failure on line 94 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 - ubuntu-latest - prefer-lowest - --parallel

A void function must not return a value

Check failure on line 94 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 - ubuntu-latest - prefer-stable -

A void function must not return a value

Check failure on line 94 in src/PendingTest.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 - ubuntu-latest - prefer-stable - --parallel

A void function must not return a value
}
}
9 changes: 9 additions & 0 deletions src/ValueObjects/TestResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
public function __construct(
private bool $ok,
private TestResultResponse $response,
) {
//
}
Expand All @@ -25,4 +26,12 @@ public function ok(): bool
{
return $this->ok;
}

/**
* Get the final response from the test result.
*/
public function response(): TestResultResponse
{
return $this->response;
}
}
60 changes: 60 additions & 0 deletions src/ValueObjects/TestResultResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Pest\Browser\ValueObjects;

use Pest\Support\Arr;

/**
* @internal
*/
final readonly class TestResultResponse
{
private array $headers;

Check failure on line 14 in src/ValueObjects/TestResultResponse.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Property Pest\Browser\ValueObjects\TestResultResponse::$headers type has no value type specified in iterable type array.

private int $status;

private string $url;

/**
* The test result response.
*/
public function __construct(array $annotations)

Check failure on line 23 in src/ValueObjects/TestResultResponse.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Method Pest\Browser\ValueObjects\TestResultResponse::__construct() has parameter $annotations with no value type specified in iterable type array.
{
/** @todo would be cleaner with collect() and Str facade */
$annotation = Arr::last(array_filter($annotations, function ($annotation) {
return Arr::get($annotation, 'type') === '_response';

Check failure on line 27 in src/ValueObjects/TestResultResponse.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Parameter #1 $array of static method Pest\Support\Arr::get() expects array<mixed>, mixed given.
}));

[

Check failure on line 30 in src/ValueObjects/TestResultResponse.php

View workflow job for this annotation

GitHub Actions / Static Tests (prefer-stable)

Cannot use array destructuring on mixed.
'headers' => $this->headers,
'status' => $this->status,
'url' => $this->url
] = json_decode(Arr::get($annotation, 'description'), true);
}

/**
* Get the test result response headers.
*/
public function headers(): array
{
return $this->headers;
}

/**
* Get the test result response status.
*/
public function status(): int
{
return $this->status;
}

/**
* Get the test result response url.
*/
public function url(): string
{
return $this->url;
}
}
7 changes: 6 additions & 1 deletion src/Worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
namespace Pest\Browser;

use Pest\Browser\ValueObjects\TestResult;
use Pest\Browser\ValueObjects\TestResultResponse;
use Pest\Support\Arr;
use Symfony\Component\Process\Process;

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

return new TestResult($outputAsArray['suites'][0]['specs'][0]['ok']);
$ok = Arr::get($outputAsArray, 'suites.0.specs.0.ok');
$annotations = Arr::get($outputAsArray, 'suites.0.specs.0.tests.0.annotations');

return new TestResult($ok, new TestResultResponse($annotations));
}
}
13 changes: 13 additions & 0 deletions tests/Example.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,16 @@
->toHaveTitle('/Framework/')
->toHaveTitle('/.*Artisans$/');
});

it('may click the "get started" button at laravel', function () {
visit('https://laravel.com')
->clickLink('Get Started')
->assertUrlIs('https://laravel.com/docs/11.x');

// -- or --

$browser = visit('https://laravel.com')
->clickLink('Get Started');

expect($browser->response()->url())->toBe('https://laravel.com/docs/11.x');
});

0 comments on commit 92d8fcb

Please sign in to comment.