diff --git a/src/Browser/BrowserContext.php b/src/Browser/BrowserContext.php index 9f20252..9c42670 100644 --- a/src/Browser/BrowserContext.php +++ b/src/Browser/BrowserContext.php @@ -195,6 +195,48 @@ public function clearCookies(): void ]); } + public function deleteCookie(string $name): void + { + $cookies = $this->cookies(); + if (empty($cookies)) { + return; + } + + $toDelete = []; + foreach ($cookies as $cookie) { + if (!isset($cookie['name']) || !is_string($cookie['name'])) { + continue; + } + if ($cookie['name'] !== $name) { + continue; + } + + $domain = $cookie['domain'] ?? null; + $path = $cookie['path'] ?? null; + if (!is_string($domain) || !is_string($path)) { + continue; + } + + $toDelete[] = [ + 'name' => $name, + 'value' => '', + 'domain' => $domain, + 'path' => $path, + 'expires' => 0, + ]; + } + + if (empty($toDelete)) { + return; + } + + $this->transport->send([ + 'action' => 'context.addCookies', + 'contextId' => $this->contextId, + 'cookies' => $toDelete, + ]); + } + public function clearPermissions(): void { $this->transport->send([ diff --git a/src/Browser/BrowserContextInterface.php b/src/Browser/BrowserContextInterface.php index a7a35aa..61a8024 100644 --- a/src/Browser/BrowserContextInterface.php +++ b/src/Browser/BrowserContextInterface.php @@ -27,6 +27,11 @@ public function addInitScript(string $script): void; public function clearCookies(): void; + /** + * Delete all cookies with the given name across domain and path variants. + */ + public function deleteCookie(string $name): void; + public function clearPermissions(): void; public function close(): void; diff --git a/tests/Unit/Browser/BrowserContextDeleteCookieTest.php b/tests/Unit/Browser/BrowserContextDeleteCookieTest.php new file mode 100644 index 0000000..02ec211 --- /dev/null +++ b/tests/Unit/Browser/BrowserContextDeleteCookieTest.php @@ -0,0 +1,75 @@ +createMock(TransportInterface::class); + + $calledAdd = false; + $that = $this; + $transport->method('send')->willReturnCallback(function (array $payload) use (&$calledAdd, $that) { + if (($payload['action'] ?? null) === 'context.cookies') { + return [ + 'cookies' => [ + [ + 'name' => 'foo', + 'value' => '123', + 'domain' => 'example.com', + 'path' => '/', + 'expires' => time() + 3600, + 'httpOnly' => false, + 'secure' => false, + 'sameSite' => 'Lax', + ], + [ + 'name' => 'bar', + 'value' => 'x', + 'domain' => 'example.com', + 'path' => '/', + 'expires' => time() + 3600, + 'httpOnly' => false, + 'secure' => false, + 'sameSite' => 'Lax', + ], + ], + ]; + } + + if (($payload['action'] ?? null) === 'context.addCookies') { + $that->assertArrayHasKey('cookies', $payload); + $that->assertIsArray($payload['cookies']); + $that->assertSame('foo', $payload['cookies'][0]['name']); + $that->assertSame('example.com', $payload['cookies'][0]['domain']); + $that->assertSame('/', $payload['cookies'][0]['path']); + $that->assertSame(0, $payload['cookies'][0]['expires']); + $calledAdd = true; + + return []; + } + + return []; + }); + + $context = new BrowserContext($transport, 'ctx'); + $context->deleteCookie('foo'); + + $this->assertTrue($calledAdd, 'context.addCookies should be called to expire matching cookies'); + } +}