feat(cookies): move cookie management to BrowserContext (#82)

This commit is contained in:
Pavel Feldman 2019-11-26 11:23:13 -08:00 committed by GitHub
parent 3decf1f996
commit a4e24c718b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 268 additions and 308 deletions

View File

@ -50,11 +50,14 @@
* [event: 'targetcreated'](#event-targetcreated-1)
* [event: 'targetdestroyed'](#event-targetdestroyed-1)
* [browserContext.browser()](#browsercontextbrowser)
* [browserContext.clearCookies()](#browsercontextclearcookies)
* [browserContext.close()](#browsercontextclose)
* [browserContext.cookies([...urls])](#browsercontextcookiesurls)
* [browserContext.isIncognito()](#browsercontextisincognito)
* [browserContext.newPage()](#browsercontextnewpage)
* [browserContext.pages()](#browsercontextpages)
* [browserContext.permissions](#browsercontextpermissions)
* [browserContext.setCookies(cookies)](#browsercontextsetcookiescookies)
* [browserContext.targets()](#browsercontexttargets)
* [browserContext.waitForTarget(predicate[, options])](#browsercontextwaitfortargetpredicate-options)
- [class: Geolocation](#class-geolocation)
@ -91,10 +94,8 @@
* [page.click(selector[, options])](#pageclickselector-options)
* [page.close([options])](#pagecloseoptions)
* [page.content()](#pagecontent)
* [page.cookies([...urls])](#pagecookiesurls)
* [page.coverage](#pagecoverage)
* [page.dblclick(selector[, options])](#pagedblclickselector-options)
* [page.deleteCookie(...cookies)](#pagedeletecookiecookies)
* [page.emulate(options)](#pageemulateoptions)
* [page.emulateMedia(options)](#pageemulatemediaoptions)
* [page.emulateTimezone(timezoneId)](#pageemulatetimezonetimezoneid)
@ -122,7 +123,6 @@
* [page.setBypassCSP(enabled)](#pagesetbypasscspenabled)
* [page.setCacheEnabled([enabled])](#pagesetcacheenabledenabled)
* [page.setContent(html[, options])](#pagesetcontenthtml-options)
* [page.setCookie(...cookies)](#pagesetcookiecookies)
* [page.setDefaultNavigationTimeout(timeout)](#pagesetdefaultnavigationtimeouttimeout)
* [page.setDefaultTimeout(timeout)](#pagesetdefaulttimeouttimeout)
* [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
@ -757,6 +757,11 @@ Emitted when a target inside the browser context is destroyed, for example when
The browser this browser context belongs to.
#### browserContext.clearCookies()
- returns: <[Promise]>
Clears context bookies.
#### browserContext.close()
- returns: <[Promise]>
@ -765,6 +770,23 @@ will be closed.
> **NOTE** only incognito browser contexts can be closed.
#### browserContext.cookies([...urls])
- `...urls` <...[string]>
- returns: <[Promise]<[Array]<[Object]>>>
- `name` <[string]>
- `value` <[string]>
- `domain` <[string]>
- `path` <[string]>
- `expires` <[number]> Unix time in seconds.
- `size` <[number]>
- `httpOnly` <[boolean]>
- `secure` <[boolean]>
- `session` <[boolean]>
- `sameSite` <"Strict"|"Lax"|"None">
If no URLs are specified, this method returns all cookies.
If URLs are specified, only cookies that affect those URLs are returned.
#### browserContext.isIncognito()
- returns: <[boolean]>
@ -786,6 +808,23 @@ An array of all pages inside the browser context.
#### browserContext.permissions
- returns: <[Permissions]>
#### browserContext.setCookies(cookies)
- `cookies` <[Array]<[Object]>>
- `name` <[string]> **required**
- `value` <[string]> **required**
- `url` <[string]> either url or domain / path are **required**
- `domain` <[string]> either url or domain / path are **required**
- `path` <[string]> either url or domain / path are **required**
- `expires` <[number]> Unix time in seconds.
- `httpOnly` <[boolean]>
- `secure` <[boolean]>
- `sameSite` <"Strict"|"Lax"|"None">
- returns: <[Promise]>
```js
await browserContext.setCookies([cookieObject1, cookieObject2]);
```
#### browserContext.targets()
- returns: <[Array]<[Target]>>
@ -1145,23 +1184,6 @@ By default, `page.close()` **does not** run beforeunload handlers.
Gets the full HTML contents of the page, including the doctype.
#### page.cookies([...urls])
- `...urls` <...[string]>
- returns: <[Promise]<[Array]<[Object]>>>
- `name` <[string]>
- `value` <[string]>
- `domain` <[string]>
- `path` <[string]>
- `expires` <[number]> Unix time in seconds.
- `size` <[number]>
- `httpOnly` <[boolean]>
- `secure` <[boolean]>
- `session` <[boolean]>
- `sameSite` <"Strict"|"Lax"|"Extended"|"None">
If no URLs are specified, this method returns cookies for the current page URL.
If URLs are specified, only cookies for those URLs are returned.
#### page.coverage
- returns: <[Coverage]>
@ -1186,14 +1208,6 @@ Bear in mind that if the first click of the `dblclick()` triggers a navigation e
Shortcut for [page.mainFrame().dblclick(selector[, options])](#framedblclickselector-options).
#### page.deleteCookie(...cookies)
- `...cookies` <...[Object]>
- `name` <[string]> **required**
- `url` <[string]>
- `domain` <[string]>
- `path` <[string]>
- returns: <[Promise]>
#### page.emulate(options)
- `options` <[Object]>
- `viewport` <[Object]>
@ -1614,23 +1628,6 @@ Toggles ignoring cache for each request based on the enabled state. By default,
- `networkidle2` - consider setting content to be finished when there are no more than 2 network connections for at least `500` ms.
- returns: <[Promise]>
#### page.setCookie(...cookies)
- `...cookies` <...[Object]>
- `name` <[string]> **required**
- `value` <[string]> **required**
- `url` <[string]>
- `domain` <[string]>
- `path` <[string]>
- `expires` <[number]> Unix time in seconds.
- `httpOnly` <[boolean]>
- `secure` <[boolean]>
- `sameSite` <"Strict"|"Lax">
- returns: <[Promise]>
```js
await page.setCookie(cookieObject1, cookieObject2);
```
#### page.setDefaultNavigationTimeout(timeout)
- `timeout` <[number]> Maximum navigation time in milliseconds

View File

@ -8,7 +8,7 @@
},
"playwright": {
"chromium_revision": "718525",
"firefox_revision": "1003",
"firefox_revision": "1004",
"webkit_revision": "2"
},
"scripts": {

View File

@ -33,7 +33,7 @@ export class Browser extends EventEmitter {
private _process: childProcess.ChildProcess;
private _screenshotTaskQueue = new TaskQueue();
private _connection: Connection;
private _client: CDPSession;
_client: CDPSession;
private _closeCallback: () => Promise<void>;
private _defaultContext: BrowserContext;
private _contexts = new Map<string, BrowserContext>();
@ -146,7 +146,7 @@ export class Browser extends EventEmitter {
async _createPageInContext(contextId: string | null): Promise<Page> {
const { targetId } = await this._client.send('Target.createTarget', { url: 'about:blank', browserContextId: contextId || undefined });
const target = await this._targets.get(targetId);
const target = this._targets.get(targetId);
assert(await target._initializedPromise, 'Failed to create target for page');
const page = await target.page();
return page;

View File

@ -17,6 +17,7 @@
import { EventEmitter } from 'events';
import { assert } from '../helper';
import { NetworkCookie, SetNetworkCookieParam, filterCookies } from '../network';
import { Browser } from './Browser';
import { CDPSession } from './Connection';
import { Permissions } from './features/permissions';
@ -65,6 +66,25 @@ export class BrowserContext extends EventEmitter {
return this._browser;
}
async cookies(...urls: string[]): Promise<NetworkCookie[]> {
const { cookies } = await this._browser._client.send('Storage.getCookies', { browserContextId: this._id || undefined });
return filterCookies(cookies.map(c => ({ sameSite: 'None', ...c })), urls);
}
async clearCookies() {
await this._browser._client.send('Storage.clearCookies', { browserContextId: this._id || undefined });
}
async setCookies(cookies: SetNetworkCookieParam[]) {
const items = cookies.map(cookie => {
const item = Object.assign({}, cookie);
assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
return item;
});
await this._browser._client.send('Storage.setCookies', { cookies: items, browserContextId: this._id || undefined });
}
async close() {
assert(this._id, 'Non-incognito profiles cannot be closed!');
await this._browser._disposeContext(this._id);

View File

@ -254,40 +254,6 @@ export class Page extends EventEmitter {
return this.mainFrame().$x(expression);
}
async cookies(...urls: string[]): Promise<NetworkCookie[]> {
const {cookies} = await this._client.send('Network.getCookies', {
urls: urls.length ? urls : [this.url()]
});
// Chromiums's cookies are missing sameSite when it is 'None'
return cookies.map(cookie => ({sameSite: 'None', ...cookie}));
}
async deleteCookie(...cookies: Protocol.Network.deleteCookiesParameters[]) {
const pageURL = this.url();
for (const cookie of cookies) {
const item = Object.assign({}, cookie);
if (!cookie.url && pageURL.startsWith('http'))
item.url = pageURL;
await this._client.send('Network.deleteCookies', item);
}
}
async setCookie(...cookies: NetworkCookieParam[]) {
const pageURL = this.url();
const startsWithHTTP = pageURL.startsWith('http');
const items = cookies.map(cookie => {
const item = Object.assign({}, cookie);
if (!item.url && startsWithHTTP)
item.url = pageURL;
assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
return item;
});
await this.deleteCookie(...items);
if (items.length)
await this._client.send('Network.setCookies', { cookies: items });
}
async addScriptTag(options: { url?: string; path?: string; content?: string; type?: string; }): Promise<ElementHandle> {
return this.mainFrame().addScriptTag(options);
}
@ -747,31 +713,6 @@ type MediaFeature = {
value: string
}
type NetworkCookie = {
name: string,
value: string,
domain: string,
path: string,
expires: number,
size: number,
httpOnly: boolean,
secure: boolean,
session: boolean,
sameSite: 'Strict'|'Lax'|'Extended'|'None'
};
type NetworkCookieParam = {
name: string,
value: string,
url?: string,
domain?: string,
path?: string,
expires?: number,
httpOnly?: boolean,
secure?: boolean,
sameSite?: 'Strict'|'Lax'
};
type ConsoleMessageLocation = {
url?: string,
lineNumber?: number,

View File

@ -56,8 +56,6 @@ export class Coverage {
}
}
module.exports = {Coverage};
class JSCoverage {
_client: CDPSession;
_enabled: boolean;

View File

@ -16,9 +16,10 @@
*/
import { EventEmitter } from 'events';
import { Events } from './events';
import { assert, helper, RegisteredListener } from '../helper';
import { filterCookies, NetworkCookie, SetNetworkCookieParam } from '../network';
import { Connection, ConnectionEvents } from './Connection';
import { Events } from './events';
import { Permissions } from './features/permissions';
import { Page, Viewport } from './Page';
@ -289,10 +290,34 @@ export class BrowserContext extends EventEmitter {
return this._browser;
}
async cookies(...urls: string[]): Promise<NetworkCookie[]> {
const { cookies } = await this._connection.send('Browser.getCookies', {
browserContextId: this._browserContextId || undefined
});
return filterCookies(cookies, urls);
}
async clearCookies() {
await this._connection.send('Browser.clearCookies', {
browserContextId: this._browserContextId || undefined,
});
}
async setCookies(cookies: SetNetworkCookieParam[]) {
const items = cookies.map(cookie => {
const item = Object.assign({}, cookie);
assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
return item;
});
await this._connection.send('Browser.setCookies', {
browserContextId: this._browserContextId || undefined,
cookies
});
}
async close() {
assert(this._browserContextId, 'Non-incognito contexts cannot be closed!');
await this._browser._disposeContext(this._browserContextId);
}
}
module.exports = {Browser, BrowserContext, Target};

View File

@ -94,59 +94,6 @@ export class Page extends EventEmitter {
});
}
async cookies(...urls: Array<string>): Promise<Array<any>> {
const connection = Connection.fromSession(this._session);
const {cookies} = await connection.send('Browser.getCookies', {
browserContextId: this._target._context._browserContextId || undefined,
urls: urls.length ? urls : [this.url()]
});
// Firefox's cookies are missing sameSite when it is 'None'
return cookies.map(cookie => ({sameSite: 'None', ...cookie}));
}
async deleteCookie(...cookies: Array<any>) {
const pageURL = this.url();
const items = [];
for (const cookie of cookies) {
const item = {
url: cookie.url,
domain: cookie.domain,
path: cookie.path,
name: cookie.name,
};
if (!item.url && pageURL.startsWith('http'))
item.url = pageURL;
items.push(item);
}
const connection = Connection.fromSession(this._session);
await connection.send('Browser.deleteCookies', {
browserContextId: this._target._context._browserContextId || undefined,
cookies: items,
});
}
async setCookie(...cookies: Array<any>) {
const pageURL = this.url();
const startsWithHTTP = pageURL.startsWith('http');
const items = cookies.map(cookie => {
const item = Object.assign({}, cookie);
if (!item.url && startsWithHTTP)
item.url = pageURL;
assert(item.url !== 'about:blank', `Blank page can not have cookie "${item.name}"`);
assert(!String.prototype.startsWith.call(item.url || '', 'data:'), `Data URL page can not have cookie "${item.name}"`);
return item;
});
await this.deleteCookie(...items);
if (items.length) {
const connection = Connection.fromSession(this._session);
await connection.send('Browser.setCookies', {
browserContextId: this._target._context._browserContextId || undefined,
cookies: items
});
}
}
async setExtraHTTPHeaders(headers) {
await this._networkManager.setExtraHTTPHeaders(headers);
}

46
src/network.ts Normal file
View File

@ -0,0 +1,46 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
export type NetworkCookie = {
name: string,
value: string,
domain: string,
path: string,
expires: number,
size: number,
httpOnly: boolean,
secure: boolean,
session: boolean,
sameSite: 'Strict' | 'Lax' | 'None'
};
export type SetNetworkCookieParam = {
name: string,
value: string,
url?: string,
domain?: string,
path?: string,
expires?: number,
httpOnly?: boolean,
secure?: boolean,
sameSite?: 'Strict' | 'Lax' | 'None'
};
export function filterCookies(cookies: NetworkCookie[], urls: string[]) {
const parsedURLs = urls.map(s => new URL(s));
// Chromiums's cookies are missing sameSite when it is 'None'
return cookies.filter(c => {
if (!parsedURLs.length)
return true;
for (const parsedURL of parsedURLs) {
if (parsedURL.hostname !== c.domain)
continue;
if (!parsedURL.pathname.startsWith(c.path))
continue;
if ((parsedURL.protocol === 'https:') !== c.secure)
continue;
return true;
}
return false;
});
}

View File

@ -17,9 +17,10 @@
import * as childProcess from 'child_process';
import { EventEmitter } from 'events';
import { assert, helper, RegisteredListener } from '../helper';
import { filterCookies, NetworkCookie } from '../network';
import { Connection } from './Connection';
import { Events } from './events';
import { RegisteredListener, assert, helper } from '../helper';
import { Page, Viewport } from './Page';
import { Target } from './Target';
import { TaskQueue } from './TaskQueue';
@ -255,4 +256,30 @@ export class BrowserContext extends EventEmitter {
assert(this._id, 'Non-incognito profiles cannot be closed!');
await this._browser._disposeContext(this._id);
}
async cookies(...urls: string[]): Promise<NetworkCookie[]> {
const page = (await this.pages())[0];
const response = await page._session.send('Page.getCookies');
const cookies = response.cookies.map(cookie => {
// Webkit returns 0 for a cookie without an expiration
if (cookie.expires === 0)
cookie.expires = -1;
return cookie;
});
return filterCookies(cookies, urls);
}
async clearCookies() {
const page = (await this.pages())[0];
const response = await page._session.send('Page.getCookies');
const promises = [];
for (const cookie of response.cookies) {
const item = {
cookieName: cookie.name,
url: (cookie.secure ? 'https://' : 'http://') + cookie.domain + cookie.path
};
promises.push(page._session.send('Page.deleteCookie', item));
}
await Promise.all(promises);
}
}

View File

@ -44,7 +44,7 @@ export type Viewport = {
export class Page extends EventEmitter {
private _closed = false;
private _session: TargetSession;
_session: TargetSession;
private _target: Target;
private _keyboard: input.Keyboard;
private _mouse: input.Mouse;
@ -222,29 +222,6 @@ export class Page extends EventEmitter {
return this.mainFrame().$x(expression);
}
async cookies(...urls: string[]): Promise<NetworkCookie[]> {
const response = await this._session.send('Page.getCookies');
return response.cookies.map(cookie => {
// Webkit returns 0 for a cookie without an expiration
if (cookie.expires === 0)
cookie.expires = -1;
return cookie;
});
}
async deleteCookie(...cookies: DeleteNetworkCookieParam[]) {
const pageURL = this.url();
for (const cookie of cookies) {
const item = {
cookieName: cookie.name,
url: cookie.url
};
if (!cookie.url && pageURL.startsWith('http'))
item.url = pageURL;
await this._session.send('Page.deleteCookie', item).catch(e => debugError('deleting ' + JSON.stringify(item) + ' => ' + e));
}
}
async addScriptTag(options: { url?: string; path?: string; content?: string; type?: string; }): Promise<ElementHandle> {
return this.mainFrame().addScriptTag(options);
}
@ -525,24 +502,6 @@ type ScreenshotOptions = {
encoding?: string,
}
type NetworkCookie = {
name: string,
value: string,
domain: string,
path: string,
expires: number,
size: number,
httpOnly: boolean,
secure: boolean,
session: boolean,
sameSite?: 'Strict'|'Lax'|'Extended'|'None'
};
type DeleteNetworkCookieParam = {
name: string,
url?: string,
};
type ConsoleMessageLocation = {
url?: string,
lineNumber?: number,

View File

@ -19,17 +19,17 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
const {it, fit, xit} = testRunner;
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
describe('Page.cookies', function() {
it('should return no cookies in pristine browser context', async({page, server}) => {
describe('BrowserContext.cookies', function() {
it('should return no cookies in pristine browser context', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
expect(await page.cookies()).toEqual([]);
expect(await context.cookies()).toEqual([]);
});
it('should get a cookie', async({page, server}) => {
it('should get a cookie', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => {
document.cookie = 'username=John Doe';
});
expect(await page.cookies()).toEqual([{
expect(await context.cookies()).toEqual([{
name: 'username',
value: 'John Doe',
domain: 'localhost',
@ -42,43 +42,43 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
sameSite: 'None',
}]);
});
it('should properly report httpOnly cookie', async({page, server}) => {
it('should properly report httpOnly cookie', async({context, page, server}) => {
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', ';HttpOnly; Path=/');
res.end();
});
await page.goto(server.EMPTY_PAGE);
const cookies = await page.cookies();
const cookies = await context.cookies();
expect(cookies.length).toBe(1);
expect(cookies[0].httpOnly).toBe(true);
});
it.skip(FFOX || WEBKIT)('should properly report "Strict" sameSite cookie', async({page, server}) => {
it.skip(WEBKIT)('should properly report "Strict" sameSite cookie', async({context, page, server}) => {
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', ';SameSite=Strict');
res.end();
});
await page.goto(server.EMPTY_PAGE);
const cookies = await page.cookies();
const cookies = await context.cookies();
expect(cookies.length).toBe(1);
expect(cookies[0].sameSite).toBe('Strict');
});
it.skip(FFOX || WEBKIT)('should properly report "Lax" sameSite cookie', async({page, server}) => {
it.skip(WEBKIT)('should properly report "Lax" sameSite cookie', async({context, page, server}) => {
server.setRoute('/empty.html', (req, res) => {
res.setHeader('Set-Cookie', ';SameSite=Lax');
res.end();
});
await page.goto(server.EMPTY_PAGE);
const cookies = await page.cookies();
const cookies = await context.cookies();
expect(cookies.length).toBe(1);
expect(cookies[0].sameSite).toBe('Lax');
});
it('should get multiple cookies', async({page, server}) => {
it('should get multiple cookies', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.evaluate(() => {
document.cookie = 'username=John Doe';
document.cookie = 'password=1234';
});
const cookies = await page.cookies();
const cookies = await context.cookies();
cookies.sort((a, b) => a.name.localeCompare(b.name));
expect(cookies).toEqual([
{
@ -107,8 +107,8 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
},
]);
});
it.skip(WEBKIT)('should get cookies from multiple urls', async({page, server}) => {
await page.setCookie({
it.skip(WEBKIT)('should get cookies from multiple urls', async({context}) => {
await context.setCookies([{
url: 'https://foo.com',
name: 'doggo',
value: 'woofs',
@ -120,8 +120,8 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
url: 'https://baz.com',
name: 'birdo',
value: 'tweets',
});
const cookies = await page.cookies('https://foo.com', 'https://baz.com');
}]);
const cookies = await context.cookies('https://foo.com', 'https://baz.com');
cookies.sort((a, b) => a.name.localeCompare(b.name));
expect(cookies).toEqual([{
name: 'birdo',
@ -149,27 +149,23 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
});
});
describe.skip(WEBKIT)('Page.setCookie', function() {
it('should work', async({page, server}) => {
describe.skip(WEBKIT)('BrowserContext.setCookies', function() {
it('should work', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.setCookie({
await context.setCookies([{
url: server.EMPTY_PAGE,
name: 'password',
value: '123456'
});
}]);
expect(await page.evaluate(() => document.cookie)).toEqual('password=123456');
});
it('should isolate cookies in browser contexts', async({page, server, browser}) => {
it('should isolate cookies in browser contexts', async({context, server, browser}) => {
const anotherContext = await browser.createIncognitoBrowserContext();
const anotherPage = await anotherContext.newPage();
await context.setCookies([{url: server.EMPTY_PAGE, name: 'page1cookie', value: 'page1value'}]);
await anotherContext.setCookies([{url: server.EMPTY_PAGE, name: 'page2cookie', value: 'page2value'}]);
await page.goto(server.EMPTY_PAGE);
await anotherPage.goto(server.EMPTY_PAGE);
await page.setCookie({name: 'page1cookie', value: 'page1value'});
await anotherPage.setCookie({name: 'page2cookie', value: 'page2value'});
const cookies1 = await page.cookies();
const cookies2 = await anotherPage.cookies();
const cookies1 = await context.cookies();
const cookies2 = await anotherContext.cookies();
expect(cookies1.length).toBe(1);
expect(cookies2.length).toBe(1);
expect(cookies1[0].name).toBe('page1cookie');
@ -178,15 +174,17 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
expect(cookies2[0].value).toBe('page2value');
await anotherContext.close();
});
it('should set multiple cookies', async({page, server}) => {
it('should set multiple cookies', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.setCookie({
await context.setCookies([{
url: server.EMPTY_PAGE,
name: 'password',
value: '123456'
}, {
url: server.EMPTY_PAGE,
name: 'foo',
value: 'bar'
});
}]);
expect(await page.evaluate(() => {
const cookies = document.cookie.split(';');
return cookies.map(cookie => cookie.trim()).sort();
@ -195,23 +193,23 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
'password=123456',
]);
});
it('should have |expires| set to |-1| for session cookies', async({page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.setCookie({
it('should have |expires| set to |-1| for session cookies', async({context, server}) => {
await context.setCookies([{
url: server.EMPTY_PAGE,
name: 'password',
value: '123456'
});
const cookies = await page.cookies();
}]);
const cookies = await context.cookies();
expect(cookies[0].session).toBe(true);
expect(cookies[0].expires).toBe(-1);
});
it('should set cookie with reasonable defaults', async({page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.setCookie({
it('should set cookie with reasonable defaults', async({context, server}) => {
await context.setCookies([{
url: server.EMPTY_PAGE,
name: 'password',
value: '123456'
});
const cookies = await page.cookies();
}]);
const cookies = await context.cookies();
expect(cookies.sort((a, b) => a.name.localeCompare(b.name))).toEqual([{
name: 'password',
value: '123456',
@ -225,14 +223,15 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
sameSite: 'None',
}]);
});
it('should set a cookie with a path', async({page, server}) => {
it('should set a cookie with a path', async({context, page, server}) => {
await page.goto(server.PREFIX + '/grid.html');
await page.setCookie({
await context.setCookies([{
domain: 'localhost',
path: '/grid.html',
name: 'gridcookie',
value: 'GRID',
path: '/grid.html'
});
expect(await page.cookies()).toEqual([{
}]);
expect(await context.cookies()).toEqual([{
name: 'gridcookie',
value: 'GRID',
domain: 'localhost',
@ -246,29 +245,17 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
}]);
expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID');
await page.goto(server.EMPTY_PAGE);
expect(await page.cookies()).toEqual([]);
expect(await page.evaluate('document.cookie')).toBe('');
await page.goto(server.PREFIX + '/grid.html');
expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID');
});
it('should not set a cookie on a blank page', async function({page}) {
await page.goto('about:blank');
it('should not set a cookie with blank page URL', async function({context, server}) {
let error = null;
try {
await page.setCookie({name: 'example-cookie', value: 'best'});
} catch (e) {
error = e;
}
expect(error.message).toContain('At least one of the url and domain needs to be specified');
});
it('should not set a cookie with blank page URL', async function({page, server}) {
let error = null;
await page.goto(server.EMPTY_PAGE);
try {
await page.setCookie(
{name: 'example-cookie', value: 'best'},
await context.setCookies([
{url: server.EMPTY_PAGE, name: 'example-cookie', value: 'best'},
{url: 'about:blank', name: 'example-cookie-blank', value: 'best'}
);
]);
} catch (e) {
error = e;
}
@ -276,48 +263,46 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
`Blank page can not have cookie "example-cookie-blank"`
);
});
it('should not set a cookie on a data URL page', async function({page}) {
it('should not set a cookie on a data URL page', async function({context}) {
let error = null;
await page.goto('data:,Hello%2C%20World!');
try {
await page.setCookie({name: 'example-cookie', value: 'best'});
await context.setCookies([{url: 'data:,Hello%2C%20World!', name: 'example-cookie', value: 'best'}]);
} catch (e) {
error = e;
}
expect(error.message).toContain('At least one of the url and domain needs to be specified');
expect(error.message).toContain('Data URL page can not have cookie "example-cookie"');
});
it('should default to setting secure cookie for HTTPS websites', async({page, server}) => {
it('should default to setting secure cookie for HTTPS websites', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
const SECURE_URL = 'https://example.com';
await page.setCookie({
await context.setCookies([{
url: SECURE_URL,
name: 'foo',
value: 'bar',
});
const [cookie] = await page.cookies(SECURE_URL);
}]);
const [cookie] = await context.cookies(SECURE_URL);
expect(cookie.secure).toBe(true);
});
it('should be able to set unsecure cookie for HTTP website', async({page, server}) => {
it('should be able to set unsecure cookie for HTTP website', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
const HTTP_URL = 'http://example.com';
await page.setCookie({
await context.setCookies([{
url: HTTP_URL,
name: 'foo',
value: 'bar',
});
const [cookie] = await page.cookies(HTTP_URL);
}]);
const [cookie] = await context.cookies(HTTP_URL);
expect(cookie.secure).toBe(false);
});
it('should set a cookie on a different domain', async({page, server}) => {
it('should set a cookie on a different domain', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.setCookie({
await context.setCookies([{
url: 'https://www.example.com',
name: 'example-cookie',
value: 'best',
});
}]);
expect(await page.evaluate('document.cookie')).toBe('');
expect(await page.cookies()).toEqual([]);
expect(await page.cookies('https://www.example.com')).toEqual([{
expect(await context.cookies('https://www.example.com')).toEqual([{
name: 'example-cookie',
value: 'best',
domain: 'www.example.com',
@ -330,9 +315,12 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
sameSite: 'None',
}]);
});
it('should set cookies from a frame', async({page, server}) => {
it('should set cookies from a frame', async({context, page, server}) => {
await page.goto(server.PREFIX + '/grid.html');
await page.setCookie({name: 'localhost-cookie', value: 'best'});
await context.setCookies([
{url: server.PREFIX, name: 'localhost-cookie', value: 'best'},
{url: server.CROSS_PROCESS_PREFIX, name: '127-cookie', value: 'worst'}
]);
await page.evaluate(src => {
let fulfill;
const promise = new Promise(x => fulfill = x);
@ -342,11 +330,10 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
iframe.src = src;
return promise;
}, server.CROSS_PROCESS_PREFIX);
await page.setCookie({name: '127-cookie', value: 'worst', url: server.CROSS_PROCESS_PREFIX});
expect(await page.evaluate('document.cookie')).toBe('localhost-cookie=best');
expect(await page.frames()[1].evaluate('document.cookie')).toBe('127-cookie=worst');
expect(await page.cookies()).toEqual([{
expect(await context.cookies(server.PREFIX)).toEqual([{
name: 'localhost-cookie',
value: 'best',
domain: 'localhost',
@ -359,7 +346,7 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
sameSite: 'None',
}]);
expect(await page.cookies(server.CROSS_PROCESS_PREFIX)).toEqual([{
expect(await context.cookies(server.CROSS_PROCESS_PREFIX)).toEqual([{
name: '127-cookie',
value: 'worst',
domain: '127.0.0.1',
@ -374,22 +361,35 @@ module.exports.addTests = function({testRunner, expect, FFOX, CHROME, WEBKIT}) {
});
});
describe('Page.deleteCookie', function() {
it.skip(WEBKIT)('should work', async({page, server}) => {
describe.skip(WEBKIT)('BrowserContext.setCookies', function() {
it.skip(WEBKIT)('should clear cookies', async({context, page, server}) => {
await page.goto(server.EMPTY_PAGE);
await page.setCookie({
await context.setCookies([{
url: server.EMPTY_PAGE,
name: 'cookie1',
value: '1'
}, {
name: 'cookie2',
value: '2'
}, {
name: 'cookie3',
value: '3'
});
expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie2=2; cookie3=3');
await page.deleteCookie({name: 'cookie2'});
expect(await page.evaluate('document.cookie')).toBe('cookie1=1; cookie3=3');
}]);
expect(await page.evaluate('document.cookie')).toBe('cookie1=1');
await context.clearCookies();
expect(await page.evaluate('document.cookie')).toBe('');
});
it('should isolate cookies when clearing', async({context, server, browser}) => {
const anotherContext = await browser.createIncognitoBrowserContext();
await context.setCookies([{url: server.EMPTY_PAGE, name: 'page1cookie', value: 'page1value'}]);
await anotherContext.setCookies([{url: server.EMPTY_PAGE, name: 'page2cookie', value: 'page2value'}]);
expect((await context.cookies()).length).toBe(1);
expect((await anotherContext.cookies()).length).toBe(1);
await context.clearCookies();
expect((await context.cookies()).length).toBe(0);
expect((await anotherContext.cookies()).length).toBe(1);
await anotherContext.clearCookies();
expect((await context.cookies()).length).toBe(0);
expect((await anotherContext.cookies()).length).toBe(0);
await anotherContext.close();
});
});
};