Introduce cookies API. 

Fixes #53.
This commit is contained in:
JoelEinbinder 2017-08-24 12:21:46 -07:00 committed by Andrey Lushnikov
parent 9212863b92
commit 0791774faa
5 changed files with 297 additions and 14 deletions

View File

@ -34,6 +34,8 @@
+ [page.click(selector[, options])](#pageclickselector-options)
+ [page.close()](#pageclose)
+ [page.content()](#pagecontent)
+ [page.cookies(...urls)](#pagecookiesurls)
+ [page.deleteCookie(...cookies)](#pagedeletecookiecookies)
+ [page.emulate(options)](#pageemulateoptions)
+ [page.emulateMedia(mediaType)](#pageemulatemediamediatype)
+ [page.evaluate(pageFunction, ...args)](#pageevaluatepagefunction-args)
@ -55,6 +57,7 @@
+ [page.reload(options)](#pagereloadoptions)
+ [page.screenshot([options])](#pagescreenshotoptions)
+ [page.setContent(html)](#pagesetcontenthtml)
+ [page.setCookie(...cookies)](#pagesetcookiecookies)
+ [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
+ [page.setJavaScriptEnabled(enabled)](#pagesetjavascriptenabledenabled)
+ [page.setRequestInterceptionEnabled(value)](#pagesetrequestinterceptionenabledvalue)
@ -338,6 +341,30 @@ If there's no element matching `selector`, the method throws an error.
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.
- `httpOnly` <[boolean]>
- `secure` <[boolean]>
- `sameSite` <[string]> `"Strict"` or `"Lax"`.
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.deleteCookie(...cookies)
- `...cookies` <...[Object]>
- `name` <[string]> **required**
- `url` <[string]>
- `domain` <[string]>
- `path` <[string]>
- `secure` <[boolean]>
- returns: <[Promise]>
#### page.emulate(options)
- `options` <[Object]>
- `viewport` <[Object]>
@ -652,6 +679,19 @@ Shortcut for [`keyboard.down`](#keyboarddownkey-options) and [`keyboard.up`](#ke
- `html` <[string]> HTML markup to assign to the page.
- 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` <[string]> `"Strict"` or `"Lax"`.
- returns: <[Promise]>
#### page.setExtraHTTPHeaders(headers)
- `headers` <[Map]> A map of additional http headers to be sent with every request.
- returns: <[Promise]>

View File

@ -154,6 +154,45 @@ class Page extends EventEmitter {
return this.mainFrame().$$(selector);
}
/**
* @param {!Array<string>} urls
* @return {!Promise<!Array<Network.Cookie>>}
*/
async cookies(...urls) {
return (await this._client.send('Network.getCookies', {
urls: urls.length ? urls : [this.url()]
})).cookies;
}
/**
* @param {Array<Network.CookieParam>} cookies
*/
async deleteCookie(...cookies) {
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);
}
}
/**
* @param {Array<Network.CookieParam>} cookies
*/
async setCookie(...cookies) {
const items = cookies.map(cookie => {
const item = Object.assign({}, cookie);
const pageURL = this.url();
if (!item.url && pageURL.startsWith('http'))
item.url = this.url();
return item;
});
await this.deleteCookie(...items);
if (items.length)
await this._client.send('Network.setCookies', { cookies: items });
}
/**
* @param {string} url
* @return {!Promise}
@ -758,5 +797,34 @@ Page.Events = {
/** @typedef {{width: number, height: number, deviceScaleFactor: number|undefined, isMobile: boolean|undefined, isLandscape: boolean, hasTouch: boolean|undefined}} */
Page.Viewport;
/**
* @typedef {Object} Network.Cookie
* @property {string} name
* @property {string} value
* @property {string} domain
* @property {string} path
* @property {number} expires
* @property {number} size
* @property {boolean} httpOnly
* @property {boolean} secure
* @property {boolean} session
* @property {("Strict"|"Lax")=} sameSite
*/
/**
* @typedef {Object} Network.CookieParam
* @property {string} name
* @property {string=} value
* @property {string=} url
* @property {string=} domain
* @property {string=} path
* @property {number=} expires
* @property {boolean=} httpOnly
* @property {boolean=} secure
* @property {("Strict"|"Lax")=} sameSite
*/
module.exports = Page;
helper.tracePublicAPI(Page);

View File

@ -207,6 +207,25 @@ class WebPage {
this._currentFrame = this._page.mainFrame();
}
get cookies() {
return await(this._page.cookies());
}
set cookies(cookies) {
const cookies2 = await(this._page.cookies());
await(this._page.deleteCookie(...cookies2));
await(this._page.setCookie(...cookies));
}
addCookie(cookie) {
await(this._page.setCookie(cookie));
}
deleteCookie(cookieName) {
await(this._page.deleteCookie({name: cookieName}));
}
get onInitialized() {
return this._onInitialized;
}

View File

@ -1920,6 +1920,162 @@ describe('Page', function() {
await page.tracing.stop();
}));
});
describe('Cookies', function() {
afterEach(SX(async function(){
const cookies = await page.cookies(PREFIX + '/grid.html', CROSS_PROCESS_PREFIX);
for (const cookie of cookies)
await page.deleteCookie(cookie);
}));
it('should set and get cookies', SX(async function(){
await page.goto(PREFIX + '/grid.html');
expect(await page.cookies()).toEqual([]);
await page.evaluate(() => {
document.cookie = 'username=John Doe';
});
expect(await page.cookies()).toEqual([{
name: 'username',
value: 'John Doe',
domain: 'localhost',
path: '/',
expires: 0,
size: 16,
httpOnly: false,
secure: false,
session: true }
]);
await page.setCookie({
name: 'password',
value: '123456'
});
expect(await page.evaluate('document.cookie')).toBe('username=John Doe; password=123456');
expect(await page.cookies()).toEqual([{
name: 'password',
value: '123456',
domain: 'localhost',
path: '/',
expires: 0,
size: 14,
httpOnly: false,
secure: false,
session: true
}, {
name: 'username',
value: 'John Doe',
domain: 'localhost',
path: '/',
expires: 0,
size: 16,
httpOnly: false,
secure: false,
session: true
}]);
}));
it('should set a cookie with a path', SX(async function(){
await page.goto(PREFIX + '/grid.html');
await page.setCookie({
name: 'gridcookie',
value: 'GRID',
path: '/grid.html'
});
expect(await page.cookies()).toEqual([{
name: 'gridcookie',
value: 'GRID',
domain: 'localhost',
path: '/grid.html',
expires: 0,
size: 14,
httpOnly: false,
secure: false,
session: true
}]);
expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID');
await page.goto(PREFIX + '/empty.html');
expect(await page.cookies()).toEqual([]);
expect(await page.evaluate('document.cookie')).toBe('');
await page.goto(PREFIX + '/grid.html');
expect(await page.evaluate('document.cookie')).toBe('gridcookie=GRID');
}));
it('should delete a cookie', SX(async function(){
await page.goto(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 set a cookie on a different domain', SX(async function() {
await page.goto(PREFIX + '/grid.html');
await page.setCookie({name: 'example-cookie', value: 'best', url: 'https://www.example.com'});
expect(await page.evaluate('document.cookie')).toBe('');
expect(await page.cookies()).toEqual([]);
expect(await page.cookies('https://www.example.com')).toEqual([{
name: 'example-cookie',
value: 'best',
domain: 'www.example.com',
path: '/',
expires: 0,
size: 18,
httpOnly: false,
secure: true,
session: true
}]);
}));
it('should set cookies from a frame', SX(async function() {
await page.goto(PREFIX + '/grid.html');
await page.setCookie({name: 'localhost-cookie', value: 'best'});
await page.evaluate(src => {
let fulfill;
const promise = new Promise(x => fulfill = x);
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.onload = fulfill;
iframe.src = src;
return promise;
}, CROSS_PROCESS_PREFIX);
await page.setCookie({name: '127-cookie', value: 'worst', url: 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([{
name: 'localhost-cookie',
value: 'best',
domain: 'localhost',
path: '/',
expires: 0,
size: 20,
httpOnly: false,
secure: false,
session: true
}]);
expect(await page.cookies(CROSS_PROCESS_PREFIX)).toEqual([{
name: '127-cookie',
value: 'worst',
domain: '127.0.0.1',
path: '/',
expires: 0,
size: 15,
httpOnly: false,
secure: false,
session: true
}]);
}));
});
});
if (process.env.COVERAGE) {

View File

@ -1,23 +1,24 @@
//! unsupported
async_test(function () {
var url = TEST_HTTP_BASE + "echo";
var page = new WebPage();
var webpage = require('webpage');
var page = webpage.create();
page.cookies = [{
'name' : 'Valid-Cookie-Name',
'value' : 'Valid-Cookie-Value',
'domain' : 'localhost',
'path' : '/',
'httponly' : true,
'httpOnly' : true,
'secure' : false
},{
'name' : 'Valid-Cookie-Name-Sec',
'value' : 'Valid-Cookie-Value-Sec',
'domain' : 'localhost',
'path' : '/',
'httponly' : true,
'httpOnly' : true,
'secure' : false,
'expires' : Date.now() + 3600 //< expires in 1h
'expires': (Date.now()/1000) + 3600
}];
page.open(url, this.step_func(function (status) {
@ -41,7 +42,9 @@ async_test(function () {
async_test(function () {
var url = TEST_HTTP_BASE + "echo";
var page = new WebPage();
var webpage = require('webpage');
var page = webpage.create();
page.addCookie({
'name' : 'Added-Cookie-Name',
@ -68,7 +71,9 @@ async_test(function () {
async_test(function () {
var url = TEST_HTTP_BASE + "echo";
var page = new WebPage();
var webpage = require('webpage');
var page = webpage.create();
page.cookies = [
{ // domain mismatch.
@ -85,7 +90,7 @@ async_test(function () {
'name' : 'Invalid-Cookie-Name-3',
'value' : 'Invalid-Cookie-Value-3',
'domain' : 'localhost',
'expires' : 'Sat, 01 Jan 2000 00:00:00 GMT'
'expires' : 5
},{ // https only: the cookie will be set,
// but won't be visible from the given URL (not https).
'name' : 'Invalid-Cookie-Name-4',
@ -96,12 +101,7 @@ async_test(function () {
'name' : 'Invalid-Cookie-Name-5',
'value' : 'Invalid-Cookie-Value-5',
'domain' : 'localhost',
'expires' : new Date().getTime() - 1 //< date in the past
},{ // cookie expired (date in "sec since epoch" - using "expiry").
'name' : 'Invalid-Cookie-Name-6',
'value' : 'Invalid-Cookie-Value-6',
'domain' : 'localhost',
'expiry' : new Date().getTime() - 1 //< date in the past
'expires' : (Date.now()/1000) - 10 //< date in the past
}];
page.open(url, this.step_func_done(function (status) {