Skip to content

Commit

Permalink
feat(webdriver): support Page.deleteCookie() for WebDriver BiDi (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
sadym-chromium committed Mar 4, 2024
1 parent 7284576 commit 7fe22b5
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 26 deletions.
12 changes: 6 additions & 6 deletions docs/api/puppeteer.deletecookiesrequest.md
Expand Up @@ -12,9 +12,9 @@ export interface DeleteCookiesRequest

## Properties

| Property | Modifiers | Type | Description | Default |
| -------- | --------------------- | ------ | --------------------------------------------------------------------------------------------------- | ------- |
| domain | <code>optional</code> | string | If specified, deletes only cookies with the exact domain. | |
| name | | string | Name of the cookies to remove. | |
| path | <code>optional</code> | string | If specified, deletes only cookies with the exact path. | |
| url | <code>optional</code> | string | If specified, deletes all the cookies with the given name where domain and path match provided URL. | |
| Property | Modifiers | Type | Description | Default |
| -------- | --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| domain | <code>optional</code> | string | If specified, deletes only cookies with the exact domain. | |
| name | | string | Name of the cookies to remove. | |
| path | <code>optional</code> | string | If specified, deletes only cookies with the exact path. | |
| url | <code>optional</code> | string | If specified, deletes all the cookies with the given name where domain and path match provided URL. Otherwise, deletes only cookies related to the current page's domain. | |
32 changes: 27 additions & 5 deletions packages/puppeteer-core/src/bidi/Page.ts
Expand Up @@ -28,6 +28,7 @@ import {Coverage} from '../cdp/Coverage.js';
import {EmulationManager} from '../cdp/EmulationManager.js';
import {Tracing} from '../cdp/Tracing.js';
import type {Cookie, CookieParam, CookieSameSite} from '../common/Cookie.js';
import type {DeleteCookiesRequest} from '../common/Cookie.js';
import {UnsupportedOperation} from '../common/Errors.js';
import {EventEmitter} from '../common/EventEmitter.js';
import type {PDFOptions} from '../common/PDFOptions.js';
Expand Down Expand Up @@ -559,9 +560,6 @@ export class BidiPage extends Page {
),
};

// TODO: delete cookie before setting them.
// await this.deleteCookie(bidiCookie);

if (cookie.partitionKey !== undefined) {
await this.browserContext().userContext.setCookie(
bidiCookie,
Expand All @@ -573,8 +571,32 @@ export class BidiPage extends Page {
}
}

override deleteCookie(): never {
throw new UnsupportedOperation();
override async deleteCookie(
...cookies: DeleteCookiesRequest[]
): Promise<void> {
await Promise.all(
cookies.map(async deleteCookieRequest => {
const cookieUrl = deleteCookieRequest.url ?? this.url();
const normalizedUrl = URL.canParse(cookieUrl)
? new URL(cookieUrl)
: undefined;

const domain = deleteCookieRequest.domain ?? normalizedUrl?.hostname;
assert(
domain !== undefined,
`At least one of the url and domain needs to be specified`
);

const filter = {
domain: domain,
name: deleteCookieRequest.name,
...(deleteCookieRequest.path !== undefined
? {path: deleteCookieRequest.path}
: {}),
};
await this.#frame.browsingContext.deleteCookie(filter);
})
);
}

override async removeExposedFunction(name: string): Promise<void> {
Expand Down
20 changes: 20 additions & 0 deletions packages/puppeteer-core/src/bidi/core/BrowsingContext.ts
Expand Up @@ -547,4 +547,24 @@ export class BrowsingContext extends EventEmitter<{
this.#disposables.dispose();
super[disposeSymbol]();
}

@throwIfDisposed<BrowsingContext>(context => {
// SAFETY: Disposal implies this exists.
return context.#reason!;
})
async deleteCookie(
...cookieFilters: Bidi.Storage.CookieFilter[]
): Promise<void> {
await Promise.all(
cookieFilters.map(async filter => {
await this.#session.send('storage.deleteCookies', {
filter: filter,
partition: {
type: 'context',
context: this.id,
},
});
})
);
}
}
4 changes: 4 additions & 0 deletions packages/puppeteer-core/src/bidi/core/Connection.ts
Expand Up @@ -137,6 +137,10 @@ export interface Commands {
returnType: Bidi.EmptyResult;
};

'storage.deleteCookies': {
params: Bidi.Storage.DeleteCookiesParameters;
returnType: Bidi.Storage.DeleteCookiesResult;
};
'storage.getCookies': {
params: Bidi.Storage.GetCookiesParameters;
returnType: Bidi.Storage.GetCookiesResult;
Expand Down
2 changes: 1 addition & 1 deletion packages/puppeteer-core/src/common/Cookie.ts
Expand Up @@ -172,7 +172,7 @@ export interface DeleteCookiesRequest {
name: string;
/**
* If specified, deletes all the cookies with the given name where domain and path match
* provided URL.
* provided URL. Otherwise, deletes only cookies related to the current page's domain.
*/
url?: string;
/**
Expand Down
51 changes: 38 additions & 13 deletions test/TestExpectations.json
Expand Up @@ -276,6 +276,13 @@
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["SKIP"]
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie for specified URL regardless of the current page",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox"],
"expectations": ["SKIP"],
"comment": "The test relies on the default page partition key do not contain the source origin. This is not the case for Firefox."
},
{
"testIdPattern": "[coverage.spec] *",
"platforms": ["darwin", "linux", "win32"],
Expand Down Expand Up @@ -1081,22 +1088,46 @@
"expectations": ["FAIL"]
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should work",
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["FAIL"]
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"],
"comment": "Firefox default partition key is inconsistent: #12004"
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should work",
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"]
"expectations": ["FAIL"],
"comment": "Not supported with cdp"
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should work",
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie for specified URL",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"]
"expectations": ["FAIL"],
"comment": "Firefox default partition key is inconsistent: #12004"
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should delete cookie for specified URL",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"],
"comment": "Not supported with cdp"
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should not delete cookie for different domain",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["firefox", "webDriverBiDi"],
"expectations": ["FAIL"],
"comment": "Firefox default partition key is inconsistent: #12004"
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.deleteCookie should not delete cookie for different domain",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL"],
"comment": "Not supported with cdp"
},
{
"testIdPattern": "[cookies.spec] Cookie specs Page.setCookie should be able to set insecure cookie for HTTP website",
Expand Down Expand Up @@ -1194,12 +1225,6 @@
"parameters": ["cdp", "firefox"],
"expectations": ["FAIL", "PASS"]
},
{
"testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work",
"platforms": ["darwin", "linux", "win32"],
"parameters": ["chrome", "webDriverBiDi"],
"expectations": ["FAIL"]
},
{
"testIdPattern": "[defaultbrowsercontext.spec] DefaultBrowserContext page.deleteCookie() should work",
"platforms": ["darwin", "linux", "win32"],
Expand Down
136 changes: 135 additions & 1 deletion test/src/cookies.spec.ts
Expand Up @@ -558,7 +558,7 @@ describe('Cookie specs', () => {
});

describe('Page.deleteCookie', function () {
it('should work', async () => {
it('should delete cookie', async () => {
const {page, server} = await getTestState();

await page.goto(server.EMPTY_PAGE);
Expand All @@ -584,5 +584,139 @@ describe('Cookie specs', () => {
'cookie1=1; cookie3=3'
);
});
it('should not delete cookie for different domain', async () => {
const {page, server} = await getTestState();
const COOKIE_DESTINATION_URL = 'https://example.com';
const COOKIE_NAME = 'some_cookie_name';

await page.goto(server.EMPTY_PAGE);
// Set a cookie for the current page.
await page.setCookie({
name: COOKIE_NAME,
value: 'local page cookie value',
});
expect(await page.cookies()).toHaveLength(1);

// Set a cookie for different domain.
await page.setCookie({
url: COOKIE_DESTINATION_URL,
name: COOKIE_NAME,
value: 'COOKIE_DESTINATION_URL cookie value',
});
expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1);

await page.deleteCookie({name: COOKIE_NAME});

// Verify the cookie is deleted for the current page.
expect(await page.cookies()).toHaveLength(0);

// Verify the cookie is not deleted for different domain.
await expectCookieEquals(await page.cookies(COOKIE_DESTINATION_URL), [
{
name: COOKIE_NAME,
value: 'COOKIE_DESTINATION_URL cookie value',
domain: 'example.com',
path: '/',
sameParty: false,
expires: -1,
size: 51,
httpOnly: false,
secure: true,
session: true,
sourceScheme: 'Secure',
},
]);
});
it('should delete cookie for specified URL', async () => {
const {page, server} = await getTestState();
const COOKIE_DESTINATION_URL = 'https://example.com';
const COOKIE_NAME = 'some_cookie_name';

await page.goto(server.EMPTY_PAGE);
// Set a cookie for the current page.
await page.setCookie({
name: COOKIE_NAME,
value: 'some_cookie_value',
});
expect(await page.cookies()).toHaveLength(1);

// Set a cookie for specified URL.
await page.setCookie({
url: COOKIE_DESTINATION_URL,
name: COOKIE_NAME,
value: 'another_cookie_value',
});
expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1);

// Delete the cookie for specified URL.
await page.deleteCookie({
url: COOKIE_DESTINATION_URL,
name: COOKIE_NAME,
});

// Verify the cookie is deleted for specified URL.
expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0);

// Verify the cookie is not deleted for the current page.
await expectCookieEquals(await page.cookies(), [
{
name: COOKIE_NAME,
value: 'some_cookie_value',
domain: 'localhost',
path: '/',
sameParty: false,
expires: -1,
size: 33,
httpOnly: false,
secure: false,
session: true,
sourceScheme: 'NonSecure',
},
]);
});
it('should delete cookie for specified URL regardless of the current page', async () => {
// This test verifies the page.deleteCookie method deletes cookies for the custom
// destination URL, even if it was set from another page. Depending on the cookie
// partitioning implementation, this test case does not pass, if source origin is in
// the default cookie partition.

const {page, server} = await getTestState();
const COOKIE_DESTINATION_URL = 'https://example.com';
const COOKIE_NAME = 'some_cookie_name';
const URL_1 = server.EMPTY_PAGE;
const URL_2 = server.CROSS_PROCESS_PREFIX + '/empty.html';

await page.goto(URL_1);
// Set a cookie for the COOKIE_DESTINATION from URL_1.
await page.setCookie({
url: COOKIE_DESTINATION_URL,
name: COOKIE_NAME,
value: 'Cookie from URL_1',
});
expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1);

await page.goto(URL_2);
// Set a cookie for the COOKIE_DESTINATION from URL_2.
await page.setCookie({
url: COOKIE_DESTINATION_URL,
name: COOKIE_NAME,
value: 'Cookie from URL_2',
});
expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(1);

// Delete the cookie for the COOKIE_DESTINATION from URL_2.
await page.deleteCookie({
name: COOKIE_NAME,
url: COOKIE_DESTINATION_URL,
});

// Expect the cookie for the COOKIE_DESTINATION from URL_2 is deleted.
expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0);

// Navigate back to the URL_1.
await page.goto(server.EMPTY_PAGE);
// Expect the cookie for the COOKIE_DESTINATION from URL_1 is deleted.
expect(await page.cookies(COOKIE_DESTINATION_URL)).toHaveLength(0);
});
});
});

0 comments on commit 7fe22b5

Please sign in to comment.