diff --git a/docs/src/api/class-browsercontext.md b/docs/src/api/class-browsercontext.md index 87f6369b5c..275114d1e8 100644 --- a/docs/src/api/class-browsercontext.md +++ b/docs/src/api/class-browsercontext.md @@ -1010,6 +1010,21 @@ Creates a new page in the browser context. Returns all open pages in the context. +## async method: BrowserContext.removeCookies +* since: v1.42 + +Removes cookies from context. + +**Usage** + +```js +await browserContext.removeCookies([cookieName1, cookieName2]); +``` + +### param: BrowserContext.removeCookies.cookieNames +* since: v1.42 +- `cookieNames` <[string]|[Array]<[string]>> - list of cookie names to remove from context + ## property: BrowserContext.request * since: v1.16 * langs: diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 6f32385ee8..3d37054415 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -269,6 +269,13 @@ export class BrowserContext extends ChannelOwner await this._channel.clearCookies(); } + async removeCookies(cookieNames: string | string[]): Promise { + if (typeof cookieNames === 'string') + cookieNames = [cookieNames]; + + await this._channel.removeCookies({ cookieNames: cookieNames as string[] }); + } + async grantPermissions(permissions: string[], options?: { origin?: string }): Promise { await this._channel.grantPermissions({ permissions, ...options }); } diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index f33a3891b6..d017147867 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -828,6 +828,10 @@ scheme.BrowserContextAddInitScriptParams = tObject({ scheme.BrowserContextAddInitScriptResult = tOptional(tObject({})); scheme.BrowserContextClearCookiesParams = tOptional(tObject({})); scheme.BrowserContextClearCookiesResult = tOptional(tObject({})); +scheme.BrowserContextRemoveCookiesParams = tObject({ + cookieNames: tArray(tString), +}); +scheme.BrowserContextRemoveCookiesResult = tOptional(tObject({})); scheme.BrowserContextClearPermissionsParams = tOptional(tObject({})); scheme.BrowserContextClearPermissionsResult = tOptional(tObject({})); scheme.BrowserContextCloseParams = tObject({ diff --git a/packages/playwright-core/src/server/browserContext.ts b/packages/playwright-core/src/server/browserContext.ts index 0bc14f45e1..abf604c668 100644 --- a/packages/playwright-core/src/server/browserContext.ts +++ b/packages/playwright-core/src/server/browserContext.ts @@ -276,6 +276,15 @@ export abstract class BrowserContext extends SdkObject { return await this.doGetCookies(urls as string[]); } + async removeCookies(cookieNames: string | string[]): Promise { + const setCookies = await this.cookies(); + + const newCookiesSet = setCookies.filter(c => !cookieNames.includes(c.name)); + + await this.clearCookies(); + await this.addCookies(newCookiesSet); + } + setHTTPCredentials(httpCredentials?: types.Credentials): Promise { return this.doSetHTTPCredentials(httpCredentials); } diff --git a/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts b/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts index b4a06a67b5..73f03f12d9 100644 --- a/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/browserContextDispatcher.ts @@ -224,6 +224,10 @@ export class BrowserContextDispatcher extends Dispatcher { + await this._context.removeCookies(params.cookieNames); + } + async grantPermissions(params: channels.BrowserContextGrantPermissionsParams): Promise { await this._context.grantPermissions(params.permissions, params.origin); } diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 95c0ddcdd0..f9841c3822 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -8438,6 +8438,19 @@ export interface BrowserContext { */ pages(): Array; + /** + * Removes cookies from context. + * + * **Usage** + * + * ```js + * await browserContext.removeCookies([cookieName1, cookieName2]); + * ``` + * + * @param cookieNames + */ + removeCookies(cookieNames: string|ReadonlyArray): Promise; + /** * Routing provides the capability to modify network requests that are made by any page in the browser context. Once * route is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted. diff --git a/packages/protocol/src/channels.ts b/packages/protocol/src/channels.ts index 379b5a48e8..b8df94ddc3 100644 --- a/packages/protocol/src/channels.ts +++ b/packages/protocol/src/channels.ts @@ -1427,6 +1427,7 @@ export interface BrowserContextChannel extends BrowserContextEventTarget, EventT addCookies(params: BrowserContextAddCookiesParams, metadata?: CallMetadata): Promise; addInitScript(params: BrowserContextAddInitScriptParams, metadata?: CallMetadata): Promise; clearCookies(params?: BrowserContextClearCookiesParams, metadata?: CallMetadata): Promise; + removeCookies(params: BrowserContextRemoveCookiesParams, metadata?: CallMetadata): Promise; clearPermissions(params?: BrowserContextClearPermissionsParams, metadata?: CallMetadata): Promise; close(params: BrowserContextCloseParams, metadata?: CallMetadata): Promise; cookies(params: BrowserContextCookiesParams, metadata?: CallMetadata): Promise; @@ -1523,6 +1524,13 @@ export type BrowserContextAddInitScriptResult = void; export type BrowserContextClearCookiesParams = {}; export type BrowserContextClearCookiesOptions = {}; export type BrowserContextClearCookiesResult = void; +export type BrowserContextRemoveCookiesParams = { + cookieNames: string[], +}; +export type BrowserContextRemoveCookiesOptions = { + +}; +export type BrowserContextRemoveCookiesResult = void; export type BrowserContextClearPermissionsParams = {}; export type BrowserContextClearPermissionsOptions = {}; export type BrowserContextClearPermissionsResult = void; diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index c21cd006e9..b47f5692ee 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -1032,6 +1032,12 @@ BrowserContext: clearCookies: + removeCookies: + parameters: + cookieNames: + type: array + items: string + clearPermissions: close: @@ -3222,7 +3228,7 @@ ElectronApplication: events: close: console: - parameters: + parameters: $mixin: ConsoleMessage Android: diff --git a/tests/library/browsercontext-remove-cookies.spec.ts b/tests/library/browsercontext-remove-cookies.spec.ts new file mode 100644 index 0000000000..72b8b1c8ef --- /dev/null +++ b/tests/library/browsercontext-remove-cookies.spec.ts @@ -0,0 +1,47 @@ +/** + * Copyright 2018 Google Inc. All rights reserved. + * Modifications copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { contextTest as it, expect } from '../config/browserTest'; + +it('should remove cookies', async ({ context, page, server }) => { + await page.goto(server.EMPTY_PAGE); + await context.addCookies([{ + url: server.EMPTY_PAGE, + name: 'cookie1', + value: '1' + }, + { + url: server.EMPTY_PAGE, + name: 'cookie2', + value: '2' + }, + { + url: server.EMPTY_PAGE, + name: 'cookie3', + value: '3' + }]); + expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie2=2; cookie3=3'); + await context.removeCookies(['cookie1', 'cookie2']); + expect(await page.evaluate('document.cookie')).toBe('cookie3=3'); + await page.reload(); + expect(await page.evaluate('document.cookie')).toBe('cookie3=3'); + await context.removeCookies('cookie3'); + expect(await page.evaluate('document.cookie')).toBe(''); + await page.reload(); + expect(await page.evaluate('document.cookie')).toBe(''); +}); +