feat(firefox): implement cookies api (#4076)
This patch implements `page.setCookie()`, `page.deleteCookie()` and `page.cookies()` and doubles the test coverage for cookies so that we can feel safer on cross-browser compatibility.
This commit is contained in:
parent
03d06f54d6
commit
9ef23b1754
@ -8,6 +8,7 @@ const util = require('util');
|
||||
const EventEmitter = require('events');
|
||||
const {createHandle} = require('./JSHandle');
|
||||
const {Events} = require('./Events');
|
||||
const {Connection} = require('./Connection');
|
||||
const {FrameManager, normalizeWaitUntil} = require('./FrameManager');
|
||||
const {NetworkManager} = require('./NetworkManager');
|
||||
const {TimeoutSettings} = require('./TimeoutSettings');
|
||||
@ -80,6 +81,67 @@ class Page extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<string>} urls
|
||||
* @return {!Promise<!Array<Network.Cookie>>}
|
||||
*/
|
||||
async cookies(...urls) {
|
||||
const connection = Connection.fromSession(this._session);
|
||||
return (await connection.send('Browser.getCookies', {
|
||||
browserContextId: this._target._context._browserContextId,
|
||||
urls: urls.length ? urls : [this.url()]
|
||||
})).cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<Protocol.Network.deleteCookiesParameters>} cookies
|
||||
*/
|
||||
async deleteCookie(...cookies) {
|
||||
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,
|
||||
cookies: items,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<Network.CookieParam>} cookies
|
||||
*/
|
||||
async setCookie(...cookies) {
|
||||
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,
|
||||
cookies: items
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async setRequestInterception(enabled) {
|
||||
await this._networkManager.setRequestInterception(enabled);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
"node": ">=8.9.4"
|
||||
},
|
||||
"puppeteer": {
|
||||
"firefox_revision": "d69636bbb91f42286e81ef673b33a1459bcdfcea"
|
||||
"firefox_revision": "fd63770c54de8a6e4ac28bd9f010405c12105d63"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node install.js",
|
||||
|
10
lib/Page.js
10
lib/Page.js
@ -388,14 +388,8 @@ class Page extends EventEmitter {
|
||||
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}"`
|
||||
);
|
||||
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);
|
||||
|
@ -18,7 +18,7 @@ const utils = require('./utils');
|
||||
|
||||
module.exports.addTests = function({testRunner, expect, puppeteer, Errors}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit, it_fails_ffox} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
const {TimeoutError} = Errors;
|
||||
|
||||
|
@ -15,14 +15,17 @@
|
||||
*/
|
||||
|
||||
module.exports.addTests = function({testRunner, expect}) {
|
||||
const {describe, xdescribe, fdescribe, describe_fails_ffox} = testRunner;
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
|
||||
describe_fails_ffox('Cookies', function() {
|
||||
it('should set and get cookies', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
describe('Page.cookies', function() {
|
||||
it('should return no cookies in pristine browser context', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(await page.cookies()).toEqual([]);
|
||||
});
|
||||
it('should get a cookie', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.evaluate(() => {
|
||||
document.cookie = 'username=John Doe';
|
||||
});
|
||||
@ -35,13 +38,144 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
size: 16,
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
session: true }
|
||||
session: true
|
||||
}]);
|
||||
});
|
||||
it('should get multiple cookies', async({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();
|
||||
cookies.sort((a, b) => a.name.localeCompare(b.name));
|
||||
expect(cookies).toEqual([
|
||||
{
|
||||
name: 'password',
|
||||
value: '1234',
|
||||
domain: 'localhost',
|
||||
path: '/',
|
||||
expires: -1,
|
||||
size: 12,
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
session: true
|
||||
},
|
||||
{
|
||||
name: 'username',
|
||||
value: 'John Doe',
|
||||
domain: 'localhost',
|
||||
path: '/',
|
||||
expires: -1,
|
||||
size: 16,
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
session: true
|
||||
},
|
||||
]);
|
||||
});
|
||||
it('should get cookies from multiple urls', async({page, server}) => {
|
||||
await page.setCookie({
|
||||
url: 'https://foo.com',
|
||||
name: 'doggo',
|
||||
value: 'woofs',
|
||||
}, {
|
||||
url: 'https://bar.com',
|
||||
name: 'catto',
|
||||
value: 'purrs',
|
||||
}, {
|
||||
url: 'https://baz.com',
|
||||
name: 'birdo',
|
||||
value: 'tweets',
|
||||
});
|
||||
const cookies = await page.cookies('https://foo.com', 'https://baz.com');
|
||||
cookies.sort((a, b) => a.name.localeCompare(b.name));
|
||||
expect(cookies).toEqual([{
|
||||
name: 'birdo',
|
||||
value: 'tweets',
|
||||
domain: 'baz.com',
|
||||
path: '/',
|
||||
expires: -1,
|
||||
size: 11,
|
||||
httpOnly: false,
|
||||
secure: true,
|
||||
session: true
|
||||
}, {
|
||||
name: 'doggo',
|
||||
value: 'woofs',
|
||||
domain: 'foo.com',
|
||||
path: '/',
|
||||
expires: -1,
|
||||
size: 10,
|
||||
httpOnly: false,
|
||||
secure: true,
|
||||
session: true
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.setCookie', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setCookie({
|
||||
name: 'password',
|
||||
value: '123456'
|
||||
});
|
||||
expect(await page.evaluate(() => document.cookie)).toEqual('password=123456');
|
||||
});
|
||||
it('should isolate cookies in browser contexts', async({page, server, browser}) => {
|
||||
const anotherContext = await browser.createIncognitoBrowserContext();
|
||||
const anotherPage = await anotherContext.newPage();
|
||||
|
||||
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();
|
||||
expect(cookies1.length).toBe(1);
|
||||
expect(cookies2.length).toBe(1);
|
||||
expect(cookies1[0].name).toBe('page1cookie');
|
||||
expect(cookies1[0].value).toBe('page1value');
|
||||
expect(cookies2[0].name).toBe('page2cookie');
|
||||
expect(cookies2[0].value).toBe('page2value');
|
||||
await anotherContext.close();
|
||||
});
|
||||
it('should set multiple cookies', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setCookie({
|
||||
name: 'password',
|
||||
value: '123456'
|
||||
}, {
|
||||
name: 'foo',
|
||||
value: 'bar'
|
||||
});
|
||||
expect(await page.evaluate(() => {
|
||||
const cookies = document.cookie.split(';');
|
||||
return cookies.map(cookie => cookie.trim()).sort();
|
||||
})).toEqual([
|
||||
'foo=bar',
|
||||
'password=123456',
|
||||
]);
|
||||
});
|
||||
it('should have |expires| set to |-1| for session cookies', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setCookie({
|
||||
name: 'password',
|
||||
value: '123456'
|
||||
});
|
||||
const cookies = await page.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({
|
||||
name: 'password',
|
||||
value: '123456'
|
||||
});
|
||||
expect(await page.evaluate('document.cookie')).toBe('username=John Doe; password=123456');
|
||||
const cookies = await page.cookies();
|
||||
expect(cookies.sort((a, b) => a.name.localeCompare(b.name))).toEqual([{
|
||||
name: 'password',
|
||||
@ -53,19 +187,8 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
session: true
|
||||
}, {
|
||||
name: 'username',
|
||||
value: 'John Doe',
|
||||
domain: 'localhost',
|
||||
path: '/',
|
||||
expires: -1,
|
||||
size: 16,
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
session: true
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should set a cookie with a path', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.setCookie({
|
||||
@ -85,46 +208,25 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
session: true
|
||||
}]);
|
||||
expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID');
|
||||
await page.goto(server.PREFIX + '/empty.html');
|
||||
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 delete a cookie', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.setCookie({
|
||||
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');
|
||||
});
|
||||
|
||||
it('should not set a cookie on a blank page', async function({page}) {
|
||||
let error = null;
|
||||
await page.goto('about:blank');
|
||||
let error = null;
|
||||
try {
|
||||
await page.setCookie({name: 'example-cookie', value: 'best'});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toEqual('Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified');
|
||||
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.PREFIX + '/grid.html');
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
try {
|
||||
await page.setCookie(
|
||||
{name: 'example-cookie', value: 'best'},
|
||||
@ -133,12 +235,10 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toEqual(
|
||||
`Blank page can not have cookie "example-cookie-blank"`
|
||||
);
|
||||
});
|
||||
|
||||
it('should not set a cookie on a data URL page', async function({page}) {
|
||||
let error = null;
|
||||
await page.goto('data:,Hello%2C%20World!');
|
||||
@ -147,15 +247,37 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error).toBeTruthy();
|
||||
expect(error.message).toEqual(
|
||||
'Protocol error (Network.deleteCookies): At least one of the url and domain needs to be specified'
|
||||
);
|
||||
expect(error.message).toContain('At least one of the url and domain needs to be specified');
|
||||
});
|
||||
it('should default to setting secure cookie for HTTPS websites', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const SECURE_URL = 'https://example.com';
|
||||
await page.setCookie({
|
||||
url: SECURE_URL,
|
||||
name: 'foo',
|
||||
value: 'bar',
|
||||
});
|
||||
const [cookie] = await page.cookies(SECURE_URL);
|
||||
expect(cookie.secure).toBe(true);
|
||||
});
|
||||
it('should be able to set unsecure cookie for HTTPS website', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const SECURE_URL = 'http://example.com';
|
||||
await page.setCookie({
|
||||
url: SECURE_URL,
|
||||
name: 'foo',
|
||||
value: 'bar',
|
||||
});
|
||||
const [cookie] = await page.cookies(SECURE_URL);
|
||||
expect(cookie.secure).toBe(false);
|
||||
});
|
||||
|
||||
it('should set a cookie on a different domain', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.setCookie({name: 'example-cookie', value: 'best', url: 'https://www.example.com'});
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setCookie({
|
||||
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([{
|
||||
@ -170,7 +292,6 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
session: true
|
||||
}]);
|
||||
});
|
||||
|
||||
it('should set cookies from a frame', async({page, server}) => {
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.setCookie({name: 'localhost-cookie', value: 'best'});
|
||||
@ -210,7 +331,25 @@ module.exports.addTests = function({testRunner, expect}) {
|
||||
secure: false,
|
||||
session: true
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.deleteCookie', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setCookie({
|
||||
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');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -236,6 +236,17 @@ module.exports.addTests = function({testRunner, expect, CHROME}) {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Response.statusText', function() {
|
||||
it('should work', async({page, server}) => {
|
||||
server.setRoute('/cool', (req, res) => {
|
||||
res.writeHead(200, 'cool!');
|
||||
res.end();
|
||||
});
|
||||
const response = await page.goto(server.PREFIX + '/cool');
|
||||
expect(response.statusText()).toBe('cool!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Network Events', function() {
|
||||
it('Page.Events.Request', async({page, server}) => {
|
||||
const requests = [];
|
||||
@ -264,15 +275,6 @@ module.exports.addTests = function({testRunner, expect, CHROME}) {
|
||||
expect(remoteAddress.port).toBe(server.PORT);
|
||||
});
|
||||
|
||||
it('Response.statusText', async({page, server}) => {
|
||||
server.setRoute('/cool', (req, res) => {
|
||||
res.writeHead(200, 'cool!');
|
||||
res.end();
|
||||
});
|
||||
const response = await page.goto(server.PREFIX + '/cool');
|
||||
expect(response.statusText()).toBe('cool!');
|
||||
});
|
||||
|
||||
it('Page.Events.RequestFailed', async({page, server}) => {
|
||||
await page.setRequestInterception(true);
|
||||
page.on('request', request => {
|
||||
@ -422,7 +424,7 @@ module.exports.addTests = function({testRunner, expect, CHROME}) {
|
||||
expect(requests[1].url()).toContain('/one-style.css');
|
||||
expect(requests[1].headers().referer).toContain('/one-style.html');
|
||||
});
|
||||
it_fails_ffox('should properly return navigation response when URL has cookies', async({page, server}) => {
|
||||
it('should properly return navigation response when URL has cookies', async({page, server}) => {
|
||||
// Setup cookie.
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setCookie({ name: 'foo', value: 'bar'});
|
||||
|
Loading…
Reference in New Issue
Block a user