|
4 | 4 |
|
5 | 5 | namespace Pest\Browser\Playwright; |
6 | 6 |
|
| 7 | +use DateTimeImmutable; |
7 | 8 | use Generator; |
8 | 9 | use Pest\Browser\Playwright\Concerns\InteractsWithPlaywright; |
9 | 10 | use Pest\Browser\ServerManager; |
@@ -536,31 +537,29 @@ public function selectOption( |
536 | 537 | */ |
537 | 538 | public function evaluate(string $pageFunction, mixed $arg = null): mixed |
538 | 539 | { |
539 | | - $params = ['expression' => $pageFunction]; |
540 | | - |
541 | | - if ($arg !== null) { |
542 | | - $params['arg'] = $arg; |
543 | | - } |
| 540 | + $params = [ |
| 541 | + 'expression' => $pageFunction, |
| 542 | + 'arg' => $this->serializeArgument($arg), |
| 543 | + ]; |
544 | 544 |
|
545 | | - $response = $this->sendMessage('evaluate', $params); |
| 545 | + $response = $this->sendMessage('evaluateExpression', $params); |
546 | 546 |
|
547 | 547 | return $this->processResultResponse($response); |
548 | 548 | } |
549 | 549 |
|
550 | 550 | /** |
551 | 551 | * Evaluates a JavaScript expression and returns a JSHandle. |
552 | 552 | */ |
553 | | - public function evaluateHandle(string $pageFunction, mixed $arg = null): mixed |
| 553 | + public function evaluateHandle(string $pageFunction, mixed $arg = null): ?JSHandle |
554 | 554 | { |
555 | | - $params = ['expression' => $pageFunction]; |
556 | | - |
557 | | - if ($arg !== null) { |
558 | | - $params['arg'] = $arg; |
559 | | - } |
| 555 | + $params = [ |
| 556 | + 'expression' => $pageFunction, |
| 557 | + 'arg' => $this->serializeArgument($arg), |
| 558 | + ]; |
560 | 559 |
|
561 | | - $response = $this->sendMessage('evaluateHandle', $params); |
| 560 | + $response = $this->sendMessage('evaluateExpressionHandle', $params); |
562 | 561 |
|
563 | | - return $this->processResultResponse($response); |
| 562 | + return $this->processJSHandleResponse($response); |
564 | 563 | } |
565 | 564 |
|
566 | 565 | /** |
@@ -628,6 +627,25 @@ private function processNavigationResponse(Generator $response): void |
628 | 627 | } |
629 | 628 | } |
630 | 629 |
|
| 630 | + /** |
| 631 | + * Process response to handle JSHandle creation. |
| 632 | + */ |
| 633 | + private function processJSHandleResponse(Generator $response): ?JSHandle |
| 634 | + { |
| 635 | + /** @var array{method?: string|null, params: array{type?: string|null, guid?: string}} $message */ |
| 636 | + foreach ($response as $message) { |
| 637 | + if ( |
| 638 | + isset($message['method'], $message['params']['type'], $message['params']['guid']) |
| 639 | + && $message['method'] === '__create__' |
| 640 | + && $message['params']['type'] === 'JSHandle' |
| 641 | + ) { |
| 642 | + return new JSHandle($message['params']['guid']); |
| 643 | + } |
| 644 | + } |
| 645 | + |
| 646 | + return null; |
| 647 | + } |
| 648 | + |
631 | 649 | /** |
632 | 650 | * Send a message to the frame (for frame-related operations) |
633 | 651 | * |
@@ -657,4 +675,74 @@ private function isPageLevelOperation(string $method): bool |
657 | 675 |
|
658 | 676 | return in_array($method, $pageLevelOperations, true); |
659 | 677 | } |
| 678 | + |
| 679 | + /** |
| 680 | + * Serialize arguments for JavaScript evaluation according to Playwright protocol. |
| 681 | + * Based on the Ruby ValueSerializer implementation. |
| 682 | + */ |
| 683 | + private function serializeArgument(mixed $value): array |
| 684 | + { |
| 685 | + return [ |
| 686 | + 'value' => $this->serializeValue($value), |
| 687 | + 'handles' => [], // JSHandles would be added here in a full implementation |
| 688 | + ]; |
| 689 | + } |
| 690 | + |
| 691 | + /** |
| 692 | + * Serialize a value according to Playwright's serialization format. |
| 693 | + */ |
| 694 | + private function serializeValue(mixed $value): array |
| 695 | + { |
| 696 | + if ($value === null) { |
| 697 | + return ['v' => 'null']; |
| 698 | + } |
| 699 | + |
| 700 | + if (is_bool($value)) { |
| 701 | + return ['b' => $value]; |
| 702 | + } |
| 703 | + |
| 704 | + if (is_int($value) || is_float($value)) { |
| 705 | + if (is_float($value) && is_nan($value)) { |
| 706 | + return ['v' => 'NaN']; |
| 707 | + } |
| 708 | + if (is_float($value) && is_infinite($value)) { |
| 709 | + return ['v' => $value > 0 ? 'Infinity' : '-Infinity']; |
| 710 | + } |
| 711 | + if (is_int($value) && ($value < -9007199254740992 || $value > 9007199254740991)) { |
| 712 | + return ['bi' => (string) $value]; |
| 713 | + } |
| 714 | + |
| 715 | + return ['n' => $value]; |
| 716 | + } |
| 717 | + |
| 718 | + if (is_string($value)) { |
| 719 | + return ['s' => $value]; |
| 720 | + } |
| 721 | + |
| 722 | + if (is_array($value)) { |
| 723 | + $result = []; |
| 724 | + foreach ($value as $item) { |
| 725 | + $result[] = $this->serializeValue($item); |
| 726 | + } |
| 727 | + |
| 728 | + return ['a' => $result]; |
| 729 | + } |
| 730 | + |
| 731 | + if (is_object($value)) { |
| 732 | + if ($value instanceof DateTimeImmutable) { |
| 733 | + return ['d' => $value->format('c')]; |
| 734 | + } |
| 735 | + |
| 736 | + // Convert object to associative array |
| 737 | + $result = []; |
| 738 | + foreach (get_object_vars($value) as $key => $val) { |
| 739 | + $result[] = ['k' => $key, 'v' => $this->serializeValue($val)]; |
| 740 | + } |
| 741 | + |
| 742 | + return ['o' => $result]; |
| 743 | + } |
| 744 | + |
| 745 | + // Fallback for unsupported types |
| 746 | + return ['s' => (string) $value]; |
| 747 | + } |
660 | 748 | } |
0 commit comments