Skip to content

Commit

Permalink
Cookies (puppeteer#314)
Browse files Browse the repository at this point in the history
Introduce cookies API. 

Fixes puppeteer#53.
  • Loading branch information
JoelEinbinder authored and aslushnikov committed Aug 24, 2017
1 parent 9212863 commit 0791774
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 14 deletions.
40 changes: 40 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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]>
Expand Down Expand Up @@ -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]>
Expand Down
68 changes: 68 additions & 0 deletions lib/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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);
19 changes: 19 additions & 0 deletions phantom_shim/WebPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
156 changes: 156 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit 0791774

Please sign in to comment.