Skip to content

Commit 5aee398

Browse files
committed
feat: enhance JSHandle and JavaScriptSerializer with additional functionality and tests
1 parent 21f6688 commit 5aee398

6 files changed

Lines changed: 165 additions & 53 deletions

File tree

src/Playwright/JSHandle.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ public function dispose(): void
6565
*/
6666
public function toString(): string
6767
{
68-
return $this->jsonValue();
68+
$value = $this->jsonValue();
69+
70+
if (is_string($value)) {
71+
return $value;
72+
}
73+
74+
return (string) $value;
6975
}
7076
}

src/Playwright/Page.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ public function __construct(
2626
public string $guid,
2727
public string $frameGuid,
2828
public string $url = '',
29-
) {}
29+
) {
30+
//
31+
}
3032

3133
/**
3234
* Get the current URL of the page.
@@ -555,7 +557,8 @@ public function evaluateHandle(string $pageFunction, mixed $arg = null): JSHandl
555557
'arg' => JavaScriptSerializer::serializeArgument($arg),
556558
];
557559

558-
$response = $this->sendMessage('evaluateExpressionHandle', $params); /** @var array{method?: string|null, params: array{type?: string|null, guid?: string}} $message */
560+
$response = $this->sendMessage('evaluateExpressionHandle', $params);
561+
559562
foreach ($response as $message) {
560563
if (
561564
isset($message['method'], $message['params']['type'], $message['params']['guid'])

src/Support/JavaScriptSerializer.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Pest\Browser\Support;
66

77
use DateTimeImmutable;
8-
use stdClass;
98

109
/**
1110
* Handles serialization and deserialization of JavaScript values.
@@ -85,7 +84,6 @@ public static function serializeValue(mixed $value): array
8584
return ['o' => $result];
8685
}
8786

88-
// Fallback for unsupported types
8987
return ['s' => (string) $value];
9088
}
9189

tests/Browser/Playwright/JSHandle/EvaluateTest.php

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,38 @@
33
declare(strict_types=1);
44

55
use Pest\Browser\Playwright\JSHandle;
6-
use Pest\Browser\Support\JavaScriptSerializer;
76

87
it('can evaluate basic expressions on a JSHandle', function (): void {
98
$page = page('/test/frame-tests');
109

11-
// Create a JSHandle for a DOM element
1210
$handle = $page->evaluateHandle('document.querySelector("#test-content")');
1311
expect($handle)->toBeInstanceOf(JSHandle::class);
1412

15-
// Evaluate a simple property access on the handle
1613
$textContent = $handle->evaluate('node => node.textContent');
1714
expect($textContent)->toContain('This is the main content for testing');
1815
});
1916

2017
it('can evaluate expressions that modify a JSHandle element', function (): void {
2118
$page = page('/test/frame-tests');
2219

23-
// Create a JSHandle for an input element
2420
$handle = $page->evaluateHandle('document.querySelector("#test-input")');
2521
expect($handle)->toBeInstanceOf(JSHandle::class);
2622

27-
// Set the value of the input
2823
$handle->evaluate('input => { input.value = "test value"; return true; }');
2924

30-
// Verify the value was changed
3125
$value = $page->inputValue('#test-input');
3226
expect($value)->toBe('test value');
3327
});
3428

3529
it('can pass arguments when evaluating expressions on a JSHandle', function (): void {
3630
$page = page('/test/frame-tests');
3731

38-
// Create a JSHandle
3932
$handle = $page->evaluateHandle('document.querySelector("#test-content")');
4033
expect($handle)->toBeInstanceOf(JSHandle::class);
4134

42-
// Pass a simple string argument
4335
$result = $handle->evaluate('(node, text) => { node.textContent = text; return node.textContent; }', 'Updated content');
4436
expect($result)->toBe('Updated content');
4537

46-
// Verify the content was actually changed in the page
4738
$content = $page->textContent('#test-content');
4839
expect($content)->toBe('Updated content');
4940
});
@@ -54,16 +45,81 @@
5445
$handle = $page->evaluateHandle('document.querySelector("h1")');
5546
expect($handle)->toBeInstanceOf(JSHandle::class);
5647

57-
// Return a string
5848
$text = $handle->evaluate('h1 => h1.textContent');
5949
expect($text)->toBeString();
6050
expect($text)->toContain('PESTPHP');
6151

62-
// Return a boolean
6352
$hasChildren = $handle->evaluate('h1 => h1.hasChildNodes()');
6453
expect($hasChildren)->toBeTrue();
6554

66-
// Return a number
6755
$childCount = $handle->evaluate('h1 => h1.childNodes.length');
6856
expect($childCount)->toBeGreaterThan(0);
6957
});
58+
59+
it('can get JSON value from JSHandle with objects', function (): void {
60+
$page = page('/test/frame-tests');
61+
62+
$handle = $page->evaluateHandle('({name: "test", value: 42, active: true})');
63+
expect($handle)->toBeInstanceOf(JSHandle::class);
64+
65+
$jsonValue = $handle->jsonValue();
66+
expect($jsonValue)->toBeArray();
67+
expect($jsonValue)->toHaveKey('name');
68+
expect($jsonValue)->toHaveKey('value');
69+
expect($jsonValue['name'])->toBe('test');
70+
expect($jsonValue['value'])->toBe(42);
71+
expect($jsonValue['active'])->toBeTrue();
72+
});
73+
74+
it('can get JSON value from JSHandle with different data types', function (): void {
75+
$page = page('/test/frame-tests');
76+
77+
$arrayHandle = $page->evaluateHandle('[1, 2, "test"]');
78+
expect($arrayHandle->jsonValue())->toBe([1, 2, 'test']);
79+
80+
$numberHandle = $page->evaluateHandle('42');
81+
expect($numberHandle->jsonValue())->toBe(42);
82+
});
83+
84+
it('can get JSON value from JSHandle for DOM elements', function (): void {
85+
$page = page('/test/frame-tests');
86+
87+
$handle = $page->evaluateHandle('document.querySelector("#test-content")');
88+
expect($handle)->toBeInstanceOf(JSHandle::class);
89+
90+
$jsonValue = $handle->jsonValue();
91+
expect($jsonValue)->toBeString();
92+
expect($jsonValue)->toContain('ref:');
93+
});
94+
95+
it('can convert JSHandle to string representation', function (): void {
96+
$page = page('/test/frame-tests');
97+
98+
$stringHandle = $page->evaluateHandle('"hello world"');
99+
expect($stringHandle->toString())->toBe('hello world');
100+
101+
$numberHandle = $page->evaluateHandle('42');
102+
expect($numberHandle->toString())->toBe('42');
103+
});
104+
105+
it('can dispose JSHandle', function (): void {
106+
$page = page('/test/frame-tests');
107+
108+
$handle = $page->evaluateHandle('document.querySelector("#test-content")');
109+
expect($handle)->toBeInstanceOf(JSHandle::class);
110+
111+
$handle->dispose();
112+
expect(true)->toBeTrue();
113+
});
114+
115+
it('can evaluate complex expressions with various argument types', function (): void {
116+
$page = page('/test/frame-tests');
117+
118+
$handle = $page->evaluateHandle('document');
119+
expect($handle)->toBeInstanceOf(JSHandle::class);
120+
121+
expect($handle->evaluate('(doc, arg) => arg === null', null))->toBeTrue();
122+
expect($handle->evaluate('(doc, num) => num * 2', 21))->toBe(42);
123+
expect($handle->evaluate('(doc, arr) => arr.length', [1, 2, 3]))->toBe(3);
124+
expect($handle->evaluate('(doc, obj) => obj.name + ":" + obj.value', ['name' => 'test', 'value' => 123]))->toBe('test:123');
125+
});
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Pest\Browser\Playwright\JSHandle;
6+
7+
test('constructs JSHandle with guid correctly', function (): void {
8+
$guid = 'test-guid-12345';
9+
$handle = new JSHandle($guid);
10+
11+
expect($handle->guid)->toBe($guid);
12+
});
13+
14+
test('has correct class properties', function (): void {
15+
$guid = 'test-guid';
16+
$handle = new JSHandle($guid);
17+
18+
expect($handle)->toBeInstanceOf(JSHandle::class);
19+
expect(property_exists($handle, 'guid'))->toBeTrue();
20+
});
21+
22+
test('can be created with different guid formats', function (): void {
23+
$guidFormats = [
24+
'simple-guid',
25+
'uuid-v4-format-12345',
26+
'handle-with-numbers-123',
27+
'CamelCaseGuid',
28+
'guid_with_underscores',
29+
];
30+
31+
foreach ($guidFormats as $guid) {
32+
$handle = new JSHandle($guid);
33+
expect($handle->guid)->toBe($guid);
34+
expect($handle)->toBeInstanceOf(JSHandle::class);
35+
}
36+
});
37+
38+
test('has unique guid for different instances', function (): void {
39+
$handle1 = new JSHandle('guid-1');
40+
$handle2 = new JSHandle('guid-2');
41+
42+
expect($handle1->guid)->not()->toBe($handle2->guid);
43+
expect($handle1)->not()->toBe($handle2);
44+
});

tests/Unit/Support/JavaScriptSerializerTest.php

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,19 @@
44

55
use Pest\Browser\Support\JavaScriptSerializer;
66

7-
it('serializes null values correctly', function (): void {
8-
$value = null;
9-
$result = JavaScriptSerializer::serializeValue($value);
10-
11-
expect($result)->toBe(['v' => 'null']);
12-
});
13-
14-
it('serializes boolean values correctly', function (): void {
15-
$true = JavaScriptSerializer::serializeValue(true);
16-
$false = JavaScriptSerializer::serializeValue(false);
17-
18-
expect($true)->toBe(['b' => true]);
19-
expect($false)->toBe(['b' => false]);
20-
});
21-
22-
it('serializes numeric values correctly', function (): void {
23-
$int = JavaScriptSerializer::serializeValue(42);
24-
$float = JavaScriptSerializer::serializeValue(3.14);
25-
26-
expect($int)->toBe(['n' => 42]);
27-
expect($float)->toBe(['n' => 3.14]);
7+
it('serializes primitive values correctly', function (): void {
8+
expect(JavaScriptSerializer::serializeValue(null))->toBe(['v' => 'null']);
9+
expect(JavaScriptSerializer::serializeValue(true))->toBe(['b' => true]);
10+
expect(JavaScriptSerializer::serializeValue(false))->toBe(['b' => false]);
11+
expect(JavaScriptSerializer::serializeValue(42))->toBe(['n' => 42]);
12+
expect(JavaScriptSerializer::serializeValue(3.14))->toBe(['n' => 3.14]);
13+
expect(JavaScriptSerializer::serializeValue('hello'))->toBe(['s' => 'hello']);
2814
});
2915

3016
it('serializes special numeric values correctly', function (): void {
31-
$nan = JavaScriptSerializer::serializeValue(NAN);
32-
$infinity = JavaScriptSerializer::serializeValue(INF);
33-
$negInfinity = JavaScriptSerializer::serializeValue(-INF);
34-
35-
expect($nan)->toBe(['v' => 'NaN']);
36-
expect($infinity)->toBe(['v' => 'Infinity']);
37-
expect($negInfinity)->toBe(['v' => '-Infinity']);
38-
});
39-
40-
it('serializes strings correctly', function (): void {
41-
$string = JavaScriptSerializer::serializeValue('hello world');
42-
43-
expect($string)->toBe(['s' => 'hello world']);
17+
expect(JavaScriptSerializer::serializeValue(NAN))->toBe(['v' => 'NaN']);
18+
expect(JavaScriptSerializer::serializeValue(INF))->toBe(['v' => 'Infinity']);
19+
expect(JavaScriptSerializer::serializeValue(-INF))->toBe(['v' => '-Infinity']);
4420
});
4521

4622
it('serializes arrays correctly', function (): void {
@@ -59,7 +35,6 @@
5935
expect($assoc)->toHaveKey('o');
6036
expect($assoc['o'])->toBeArray();
6137

62-
// Check for the name key-value pair
6338
$hasName = false;
6439
$hasAge = false;
6540

@@ -86,7 +61,6 @@
8661
expect($result)->toHaveKey('o');
8762
expect($result['o'])->toBeArray();
8863

89-
// Check for the needed properties
9064
$hasName = false;
9165
$hasActive = false;
9266

@@ -222,3 +196,34 @@
222196
expect($result['user']['name'])->toBe('Alice');
223197
expect($result['user']['hobbies'])->toBe(['reading', 'coding']);
224198
});
199+
200+
it('serializes DateTimeImmutable objects correctly', function (): void {
201+
$date = new DateTimeImmutable('2023-01-01T12:00:00Z');
202+
$result = JavaScriptSerializer::serializeValue($date);
203+
204+
expect($result)->toHaveKey('d');
205+
expect($result['d'])->toBe('2023-01-01T12:00:00+00:00');
206+
});
207+
208+
it('parses DateTimeImmutable values correctly', function (): void {
209+
$dateValue = ['d' => '2023-01-01T12:00:00+00:00'];
210+
$result = JavaScriptSerializer::parseValue($dateValue);
211+
212+
expect($result)->toBeInstanceOf(DateTimeImmutable::class);
213+
expect($result->format('Y-m-d\TH:i:s\Z'))->toBe('2023-01-01T12:00:00Z');
214+
});
215+
216+
it('serializes big integers correctly', function (): void {
217+
$bigInt = 9007199254740993;
218+
$result = JavaScriptSerializer::serializeValue($bigInt);
219+
220+
expect($result)->toHaveKey('bi');
221+
expect($result['bi'])->toBe('9007199254740993');
222+
});
223+
224+
it('parses big integer values correctly', function (): void {
225+
$bigIntValue = ['bi' => '9007199254740993'];
226+
$result = JavaScriptSerializer::parseValue($bigIntValue);
227+
228+
expect($result)->toBe('9007199254740993');
229+
});

0 commit comments

Comments
 (0)