Change Page.navigate to return main resource response
This patch changes Page.navigate API: - Page.navigate now resolves to the main page response - Page.navigate throws errors if there's no main page response, e.g. in case of SSL errors, max navigation timeout, or invalid url. This patch also adds httpsServer with a self-signed certificates for the testing purposes. Fixes #10.
This commit is contained in:
parent
a7e91dc126
commit
50d9c186b5
20
docs/api.md
20
docs/api.md
@ -21,7 +21,7 @@
|
||||
* [page.httpHeaders()](#pagehttpheaders)
|
||||
* [page.injectFile(filePath)](#pageinjectfilefilepath)
|
||||
* [page.mainFrame()](#pagemainframe)
|
||||
* [page.navigate(url)](#pagenavigateurl)
|
||||
* [page.navigate(url, options)](#pagenavigateurl-options)
|
||||
* [page.plainText()](#pageplaintext)
|
||||
* [page.printToPDF(filePath[, options])](#pageprinttopdffilepath-options)
|
||||
* [page.screenshot([options])](#pagescreenshotoptions)
|
||||
@ -162,12 +162,22 @@ Pages could be closed by `page.close()` method.
|
||||
|
||||
#### page.mainFrame()
|
||||
|
||||
#### page.navigate(url)
|
||||
#### page.navigate(url, options)
|
||||
|
||||
- `url` <[string]> URL to navigate page to
|
||||
- returns: <[Promise]<[boolean]>> Promise which resolves when the page is navigated. The promise resolves to:
|
||||
- `true` if the navigation succeeds and page's `load` event is fired.
|
||||
- `false` if the navigation fails due to bad URL or SSL errors.
|
||||
- `options` <[Object]> Navigation parameters which might have the following properties:
|
||||
- `maxTime` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds.
|
||||
- `waitFor` <[string]> When to consider navigation succeeded, defaults to `load`. Could be either:
|
||||
- `load` - consider navigation to be finished when the `load` event is fired.
|
||||
- `networkidle` - consider navigation to be finished when the network activity stays "idle" for at least `networkIdleTimeout`ms.
|
||||
- `networkIdleInflight` <[number]> Maximum amount of inflight requests which are considered "idle". Takes effect only with `waitFor: 'networkidle'` parameter.
|
||||
- `networkIdleTimeout` <[number]> A timeout to wait before completing navigation. Takes effect only with `waitFor: 'networkidle'` parameter.
|
||||
- returns: <[Promise]<[Response]>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
|
||||
|
||||
The `page.navigate` will throw an error if:
|
||||
- there's an SSL error (e.g. in case of self-signed certificates).
|
||||
- target URL is invalid.
|
||||
- the `maxTime` is exceeded during navigation.
|
||||
|
||||
#### page.plainText()
|
||||
|
||||
|
@ -34,26 +34,28 @@ class Navigator {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<boolean>}
|
||||
* @return {!Promise}
|
||||
*/
|
||||
async navigate() {
|
||||
this._init();
|
||||
let certificateError = new Promise(fulfill => this._client.once('Security.certificateError', fulfill)).then(() => false);
|
||||
let networkIdle = new Promise(fulfill => this._networkIdleCallback = fulfill).then(() => true);
|
||||
let loadEventFired = new Promise(fulfill => this._client.once('Page.loadEventFired', fulfill)).then(() => true);
|
||||
let watchdog = new Promise(fulfill => this._maximumTimer = setTimeout(fulfill, this._maxTime)).then(() => false);
|
||||
let certificateError = new Promise(fulfill => this._client.once('Security.certificateError', fulfill))
|
||||
.then(error => new Error('SSL Certiciate error: ' + error.errorType));
|
||||
let networkIdle = new Promise(fulfill => this._networkIdleCallback = fulfill).then(() => null);
|
||||
let loadEventFired = new Promise(fulfill => this._client.once('Page.loadEventFired', fulfill)).then(() => null);
|
||||
let watchdog = new Promise(fulfill => this._maximumTimer = setTimeout(fulfill, this._maxTime)).then(() => new Error('Navigation Timeout Exceeded: ' + this._maxTime + 'ms exceeded'));
|
||||
|
||||
// Await for the command to throw exception in case of illegal arguments.
|
||||
try {
|
||||
await this._client.send('Page.navigate', {url: this._url, referrer: this._referrer});
|
||||
} catch (e) {
|
||||
this._cleanup();
|
||||
return false;
|
||||
throw e;
|
||||
}
|
||||
|
||||
let result = await Promise.race([certificateError, watchdog, this._waitFor === 'load' ? loadEventFired : networkIdle]);
|
||||
const error = await Promise.race([certificateError, watchdog, this._waitFor === 'load' ? loadEventFired : networkIdle]);
|
||||
this._cleanup();
|
||||
return result;
|
||||
if (error)
|
||||
throw error;
|
||||
}
|
||||
|
||||
/**
|
||||
|
22
lib/Page.js
22
lib/Page.js
@ -260,10 +260,26 @@ class Page extends EventEmitter {
|
||||
/**
|
||||
* @param {string} html
|
||||
* @param {!Object=} options
|
||||
* @return {!Promise<boolean>}
|
||||
* @return {!Promise<!Response>}
|
||||
*/
|
||||
navigate(url, options) {
|
||||
return new Navigator(this._client, url, this._networkManager.httpHeaders().referer, options).navigate();
|
||||
async navigate(url, options) {
|
||||
/** @type {!Map<string, !Response>} */
|
||||
const responses = new Map();
|
||||
const onResponse = response => responses.set(response.url, response);
|
||||
const navigator = new Navigator(this._client, url, this._networkManager.httpHeaders().referer, options);
|
||||
|
||||
try {
|
||||
this._networkManager.on(NetworkManager.Events.Response, onResponse);
|
||||
await navigator.navigate();
|
||||
} catch (e) {
|
||||
this._networkManager.removeListener(NetworkManager.Events.Response, onResponse);
|
||||
throw e;
|
||||
}
|
||||
|
||||
this._networkManager.removeListener(NetworkManager.Events.Response, onResponse);
|
||||
const response = responses.get(this.mainFrame().url());
|
||||
console.assert(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -355,22 +355,25 @@ class WebPage {
|
||||
this._deferEvaluate = false;
|
||||
this.loading = true;
|
||||
this.loadingProgress = 50;
|
||||
this._page.navigate(url).then(result => {
|
||||
|
||||
const handleNavigation = (error, response) => {
|
||||
this.loadingProgress = 100;
|
||||
this.loading = false;
|
||||
let status = result ? 'success' : 'fail';
|
||||
if (!result) {
|
||||
if (error) {
|
||||
this.onResourceError.call(null, {
|
||||
url,
|
||||
errorString: 'SSL handshake failed'
|
||||
});
|
||||
}
|
||||
let status = error ? 'fail' : 'success';
|
||||
if (this.onLoadFinished)
|
||||
this.onLoadFinished.call(null, status);
|
||||
if (callback)
|
||||
callback.call(null, status);
|
||||
this.loadingProgress = 0;
|
||||
});
|
||||
};
|
||||
this._page.navigate(url).then(response => handleNavigation(null, response))
|
||||
.catch(e => handleNavigation(e, null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
let http = require('http');
|
||||
let https = require('https');
|
||||
let url = require('url');
|
||||
let fs = require('fs');
|
||||
let path = require('path');
|
||||
@ -39,9 +40,28 @@ class SimpleServer {
|
||||
/**
|
||||
* @param {string} dirPath
|
||||
* @param {number} port
|
||||
* @return {!SimpleServer}
|
||||
*/
|
||||
constructor(dirPath, port) {
|
||||
this._server = http.createServer(this._onRequest.bind(this));
|
||||
static async createHTTPS(dirPath, port) {
|
||||
let server = new SimpleServer(dirPath, port, {
|
||||
key: fs.readFileSync(path.join(__dirname, 'key.pem')),
|
||||
cert: fs.readFileSync(path.join(__dirname, 'cert.pem')),
|
||||
passphrase: 'aaaa',
|
||||
});
|
||||
await new Promise(x => server._server.once('listening', x));
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} dirPath
|
||||
* @param {number} port
|
||||
* @param {!Object=} sslOptions
|
||||
*/
|
||||
constructor(dirPath, port, sslOptions) {
|
||||
if (sslOptions)
|
||||
this._server = https.createServer(sslOptions, this._onRequest.bind(this));
|
||||
else
|
||||
this._server = http.createServer(this._onRequest.bind(this));
|
||||
this._server.on('connection', socket => this._onSocket(socket));
|
||||
this._wsServer = new WebSocketServer({server: this._server});
|
||||
this._wsServer.on('connection', this._onWebSocketConnection.bind(this));
|
31
test/server/cert.pem
Normal file
31
test/server/cert.pem
Normal file
@ -0,0 +1,31 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFXzCCA0egAwIBAgIJAM+8uXXn61zZMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwIBcNMTcwNzEwMjI1MDA2WhgPMzAxNjExMTAyMjUwMDZa
|
||||
MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ
|
||||
bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
|
||||
ggIKAoICAQCfsIbw1Q91wooUdSu5tDiyrSYB6ZQmY49Y141KQ0ll0ZXzf1sPTpPg
|
||||
OuBjJE8Fre2Wn3jJ0SfLFyQBMvE49hqWyY/U5Xc367ujqKFQVoItnoV5MM2TPu5J
|
||||
/zhtf26Vq0Pcrujt5LfRe1JSYKdJ21Tquqa0MAGI0HghaCdSdtyo2xuotnukirKb
|
||||
QrvP/YNa+ONZT6KW8MFAwfoCOJMo1idrkBA1Wve5xcCd7J9Oy5mWCBxTSR67W2vQ
|
||||
izoOTSkzD0xoXpFF5V/34zJGWU9t6Z5qytV/w5ROY3Tk9EaKs0NcQmXlCxSmkXil
|
||||
KSTlZ/VDeDliI92jGn4hT+apisglm3aaTnVVAP0EbZ/CF9Fwb601M7IcAP9ejaeB
|
||||
EEs+smXpuzhAfxPa5SpZCWeaXLcFq6Ewi2LXrMaChWvbu9AUi3QjuT3u9PW3B0w5
|
||||
C54FLfvcy9X9dQQ/jCgydF3eyhiO3SuLZqrhofHUn53z4UCEYgbC7uQSv08ep2UD
|
||||
kT2ARN6aetXVgiQBYS8hcGaFrdsUTSAmT0flt0g8ZoHn+NmuAWxbAx8UnPd0p/EP
|
||||
B4cZByDOUDGgDMSOEluheiCFlZBQEJnvOhim6rwSje87EzQazGkwRpOrBtzGIGcM
|
||||
xmotG9IrMbzKb4Z+yg5pOEW2WKEy3f2h8P2bisbbHwYa/tgTHVWbGwIDAQABo1Aw
|
||||
TjAdBgNVHQ4EFgQUZvIOJVkyQTAd0fpUkpqgcXVID+4wHwYDVR0jBBgwFoAUZvIO
|
||||
JVkyQTAd0fpUkpqgcXVID+4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
|
||||
AgEASmqzfr4TOVFbNo3r85QlCQB8W4xaArRpY6k7ugxJm2/9iyyovMKMhCcRvmPV
|
||||
HZXDTV8WEbLDg3uNF56WU39YmtfjghnsYcGQ/UhnH2PoHQxGIKzOoalLew7kP0Uc
|
||||
HCmXi7OPjqeFQgjWVhLkL/RIzZ3vOVFQfqodTVIdYDe0O1cNRD0U0rtGa0MHzZlD
|
||||
y/ZaksiB0E3UL/GsgyJoCxCAF1E80PU9aw1K9COyTOChpUKnhSHC964KlhnJKyOe
|
||||
HKCYtb5RVrF7ryBcGneLTcQm/oNUp8aRyiwyQIDH7djFSp11MakXBF+EeGR523pp
|
||||
u+sleR7ZFBGyb3Z5K9NdRdUk0SWu7Hu4jQtJHn+PmIZ1qjfbPv5qDfVd1vmFwqsu
|
||||
7NfsLoNm0dQNu5WOMLISQHmQiT86AH2wWQ3l5Sm+g8/BdNLQLklhtZcRhp2efyiL
|
||||
ciUmGugKqoX+nPIZ36kuoRTZy++AnTiid011vZFe1qrfug/ykWiqWmBSvD/cfRU4
|
||||
ydoK87cfjIixqmpRZ7j2q+/cDK2SbYN0t/Xrufw3L6TjDgUEL7ZCImcwqqWJz9I8
|
||||
ASnnL5PhX8bbsUrtE21Ugqk2zYnVnqRO5FjINtlTb07y9pGC/QpBkb1AasF5okhe
|
||||
7lw/sMiryKKzS4A10nRV/+gErDBsIBj+cpGPM8brLfZuy2o=
|
||||
-----END CERTIFICATE-----
|
54
test/server/key.pem
Normal file
54
test/server/key.pem
Normal file
@ -0,0 +1,54 @@
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
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
|
||||
4Ig=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
135
test/test.js
135
test/test.js
@ -17,12 +17,14 @@
|
||||
let fs = require('fs');
|
||||
let path = require('path');
|
||||
let Browser = require('../lib/Browser');
|
||||
let SimpleServer = require('./SimpleServer');
|
||||
let SimpleServer = require('./server/SimpleServer');
|
||||
let GoldenUtils = require('./golden-utils');
|
||||
|
||||
let PORT = 8907;
|
||||
let STATIC_PREFIX = 'http://localhost:' + PORT;
|
||||
let EMPTY_PAGE = STATIC_PREFIX + '/empty.html';
|
||||
let PREFIX = 'http://localhost:' + PORT;
|
||||
let EMPTY_PAGE = PREFIX + '/empty.html';
|
||||
let HTTPS_PORT = 8908;
|
||||
let HTTPS_PREFIX = 'https://localhost:' + HTTPS_PORT;
|
||||
|
||||
if (process.env.DEBUG_TEST)
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 1000 * 1000;
|
||||
@ -32,22 +34,29 @@ else
|
||||
describe('Puppeteer', function() {
|
||||
let browser;
|
||||
let server;
|
||||
let httpsServer;
|
||||
let page;
|
||||
|
||||
beforeAll(SX(async function() {
|
||||
browser = new Browser({args: ['--no-sandbox']});
|
||||
server = await SimpleServer.create(path.join(__dirname, 'assets'), PORT);
|
||||
const assetsPath = path.join(__dirname, 'assets');
|
||||
server = await SimpleServer.create(assetsPath, PORT);
|
||||
httpsServer = await SimpleServer.createHTTPS(assetsPath, HTTPS_PORT);
|
||||
GoldenUtils.removeOutputDir();
|
||||
}));
|
||||
|
||||
afterAll(SX(async function() {
|
||||
await server.stop();
|
||||
await Promise.all([
|
||||
server.stop(),
|
||||
httpsServer.stop(),
|
||||
]);
|
||||
browser.close();
|
||||
}));
|
||||
|
||||
beforeEach(SX(async function() {
|
||||
page = await browser.newPage();
|
||||
server.reset();
|
||||
httpsServer.reset();
|
||||
GoldenUtils.addMatchers(jasmine);
|
||||
}));
|
||||
|
||||
@ -186,12 +195,54 @@ describe('Puppeteer', function() {
|
||||
|
||||
describe('Page.navigate', function() {
|
||||
it('should fail when navigating to bad url', SX(async function() {
|
||||
let success = await page.navigate('asdfasdf');
|
||||
expect(success).toBe(false);
|
||||
let error = null;
|
||||
try {
|
||||
await page.navigate('asdfasdf');
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error.message).toContain('Cannot navigate to invalid URL');
|
||||
}));
|
||||
it('should succeed when navigating to good url', SX(async function() {
|
||||
let success = await page.navigate(EMPTY_PAGE);
|
||||
expect(success).toBe(true);
|
||||
it('should fail when navigating to bad SSL', SX(async function() {
|
||||
let error = null;
|
||||
try {
|
||||
await page.navigate(HTTPS_PREFIX + '/empty.html');
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error.message).toContain('SSL Certiciate error');
|
||||
}));
|
||||
it('should fail when exceeding maximum navigation timeout', SX(async function() {
|
||||
let error = null;
|
||||
// Hang for request to the empty.html
|
||||
server.setRoute('/empty.html', (req, res) => { });
|
||||
try {
|
||||
await page.navigate(PREFIX + '/empty.html', {maxTime: 59});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error.message).toContain('Navigation Timeout Exceeded: 59ms');
|
||||
}));
|
||||
it('should work when navigating to valid url', SX(async function() {
|
||||
const response = await page.navigate(EMPTY_PAGE);
|
||||
expect(response.ok).toBe(true);
|
||||
}));
|
||||
it('should work when navigating to data url', SX(async function() {
|
||||
const response = await page.navigate('data:text/html,hello');
|
||||
expect(response.ok).toBe(true);
|
||||
}));
|
||||
it('should work when navigating to 404', SX(async function() {
|
||||
const response = await page.navigate(PREFIX + '/not-found');
|
||||
expect(response.ok).toBe(false);
|
||||
expect(response.status).toBe(404);
|
||||
}));
|
||||
it('should return last response in redirect chain', SX(async function() {
|
||||
server.setRedirect('/redirect/1.html', '/redirect/2.html');
|
||||
server.setRedirect('/redirect/2.html', '/redirect/3.html');
|
||||
server.setRedirect('/redirect/3.html', EMPTY_PAGE);
|
||||
const response = await page.navigate(PREFIX + '/redirect/1.html');
|
||||
expect(response.ok).toBe(true);
|
||||
expect(response.url).toBe(EMPTY_PAGE);
|
||||
}));
|
||||
it('should wait for network idle to succeed navigation', SX(async function() {
|
||||
let responses = [];
|
||||
@ -209,7 +260,7 @@ describe('Puppeteer', function() {
|
||||
|
||||
// Navigate to a page which loads immediately and then does a bunch of
|
||||
// requests via javascript's fetch method.
|
||||
let navigationPromise = page.navigate(STATIC_PREFIX + '/networkidle.html', {
|
||||
let navigationPromise = page.navigate(PREFIX + '/networkidle.html', {
|
||||
waitFor: 'networkidle',
|
||||
networkIdleTimeout: 100,
|
||||
networkIdleInflight: 0, // Only be idle when there are 0 inflight requests
|
||||
@ -248,9 +299,9 @@ describe('Puppeteer', function() {
|
||||
response.end(`File not found`);
|
||||
}
|
||||
|
||||
let success = await navigationPromise;
|
||||
const response = await navigationPromise;
|
||||
// Expect navigation to succeed.
|
||||
expect(success).toBe(true);
|
||||
expect(response.ok).toBe(true);
|
||||
}));
|
||||
it('should wait for websockets to succeed navigation', SX(async function() {
|
||||
let responses = [];
|
||||
@ -259,7 +310,7 @@ describe('Puppeteer', function() {
|
||||
let fetchResourceRequested = server.waitForRequest('/fetch-request.js');
|
||||
// Navigate to a page which loads immediately and then opens a bunch of
|
||||
// websocket connections and then a fetch request.
|
||||
let navigationPromise = page.navigate(STATIC_PREFIX + '/websocket.html', {
|
||||
let navigationPromise = page.navigate(PREFIX + '/websocket.html', {
|
||||
waitFor: 'networkidle',
|
||||
networkIdleTimeout: 100,
|
||||
networkIdleInflight: 0, // Only be idle when there are 0 inflight requests/connections
|
||||
@ -283,9 +334,9 @@ describe('Puppeteer', function() {
|
||||
response.statusCode = 404;
|
||||
response.end(`File not found`);
|
||||
}
|
||||
let success = await navigationPromise;
|
||||
const response = await navigationPromise;
|
||||
// Expect navigation to succeed.
|
||||
expect(success).toBe(true);
|
||||
expect(response.ok).toBe(true);
|
||||
}));
|
||||
});
|
||||
|
||||
@ -331,8 +382,8 @@ describe('Puppeteer', function() {
|
||||
expect(request.postData).toBe(undefined);
|
||||
request.continue();
|
||||
});
|
||||
let success = await page.navigate(EMPTY_PAGE);
|
||||
expect(success).toBe(true);
|
||||
const response = await page.navigate(EMPTY_PAGE);
|
||||
expect(response.ok).toBe(true);
|
||||
}));
|
||||
it('should show custom HTTP headers', SX(async function() {
|
||||
await page.setHTTPHeaders({
|
||||
@ -342,8 +393,8 @@ describe('Puppeteer', function() {
|
||||
expect(request.headers.get('foo')).toBe('bar');
|
||||
request.continue();
|
||||
});
|
||||
let success = await page.navigate(EMPTY_PAGE);
|
||||
expect(success).toBe(true);
|
||||
const response = await page.navigate(EMPTY_PAGE);
|
||||
expect(response.ok).toBe(true);
|
||||
}));
|
||||
it('should be abortable', SX(async function() {
|
||||
page.setRequestInterceptor(request => {
|
||||
@ -354,8 +405,8 @@ describe('Puppeteer', function() {
|
||||
});
|
||||
let failedRequests = 0;
|
||||
page.on('requestfailed', event => ++failedRequests);
|
||||
let success = await page.navigate(STATIC_PREFIX + '/one-style.html');
|
||||
expect(success).toBe(true);
|
||||
const response = await page.navigate(PREFIX + '/one-style.html');
|
||||
expect(response.ok).toBe(true);
|
||||
expect(failedRequests).toBe(1);
|
||||
}));
|
||||
it('should amend HTTP headers', SX(async function() {
|
||||
@ -400,7 +451,7 @@ describe('Puppeteer', function() {
|
||||
expect(error.message).toContain('Fancy');
|
||||
done();
|
||||
});
|
||||
page.navigate(STATIC_PREFIX + '/error.html');
|
||||
page.navigate(PREFIX + '/error.html');
|
||||
});
|
||||
});
|
||||
|
||||
@ -417,13 +468,13 @@ describe('Puppeteer', function() {
|
||||
describe('Page.screenshot', function() {
|
||||
it('should work', SX(async function() {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.navigate(STATIC_PREFIX + '/grid.html');
|
||||
await page.navigate(PREFIX + '/grid.html');
|
||||
let screenshot = await page.screenshot();
|
||||
expect(screenshot).toBeGolden('screenshot-sanity.png');
|
||||
}));
|
||||
it('should clip rect', SX(async function() {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.navigate(STATIC_PREFIX + '/grid.html');
|
||||
await page.navigate(PREFIX + '/grid.html');
|
||||
let screenshot = await page.screenshot({
|
||||
clip: {
|
||||
x: 50,
|
||||
@ -436,7 +487,7 @@ describe('Puppeteer', function() {
|
||||
}));
|
||||
it('should work for offscreen clip', SX(async function() {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.navigate(STATIC_PREFIX + '/grid.html');
|
||||
await page.navigate(PREFIX + '/grid.html');
|
||||
let screenshot = await page.screenshot({
|
||||
clip: {
|
||||
x: 50,
|
||||
@ -449,7 +500,7 @@ describe('Puppeteer', function() {
|
||||
}));
|
||||
it('should run in parallel', SX(async function() {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.navigate(STATIC_PREFIX + '/grid.html');
|
||||
await page.navigate(PREFIX + '/grid.html');
|
||||
let promises = [];
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
promises.push(page.screenshot({
|
||||
@ -466,7 +517,7 @@ describe('Puppeteer', function() {
|
||||
}));
|
||||
it('should take fullPage screenshots', SX(async function() {
|
||||
await page.setViewportSize({width: 500, height: 500});
|
||||
await page.navigate(STATIC_PREFIX + '/grid.html');
|
||||
await page.navigate(PREFIX + '/grid.html');
|
||||
let screenshot = await page.screenshot({
|
||||
fullPage: true
|
||||
});
|
||||
@ -477,7 +528,7 @@ describe('Puppeteer', function() {
|
||||
describe('Frame Management', function() {
|
||||
let FrameUtils = require('./frame-utils');
|
||||
it('should handle nested frames', SX(async function() {
|
||||
await page.navigate(STATIC_PREFIX + '/frames/nested-frames.html');
|
||||
await page.navigate(PREFIX + '/frames/nested-frames.html');
|
||||
expect(FrameUtils.dumpFrames(page.mainFrame())).toBeGolden('nested-frames.txt');
|
||||
}));
|
||||
it('should send events when frames are manipulated dynamically', SX(async function() {
|
||||
@ -523,7 +574,7 @@ describe('Puppeteer', function() {
|
||||
page.on('frameattached', frame => attachedFrames.push(frame));
|
||||
page.on('framedetached', frame => detachedFrames.push(frame));
|
||||
page.on('framenavigated', frame => navigatedFrames.push(frame));
|
||||
await page.navigate(STATIC_PREFIX + '/frames/nested-frames.html');
|
||||
await page.navigate(PREFIX + '/frames/nested-frames.html');
|
||||
expect(attachedFrames.length).toBe(4);
|
||||
expect(detachedFrames.length).toBe(0);
|
||||
expect(navigatedFrames.length).toBe(5);
|
||||
@ -540,12 +591,12 @@ describe('Puppeteer', function() {
|
||||
|
||||
describe('input', function() {
|
||||
it('should click the button', SX(async function() {
|
||||
await page.navigate(STATIC_PREFIX + '/input/button.html');
|
||||
await page.navigate(PREFIX + '/input/button.html');
|
||||
await page.click('button');
|
||||
expect(await page.evaluate(() => result)).toBe('Clicked');
|
||||
}));
|
||||
it('should fail to click a missing button', SX(async function() {
|
||||
await page.navigate(STATIC_PREFIX + '/input/button.html');
|
||||
await page.navigate(PREFIX + '/input/button.html');
|
||||
try {
|
||||
await page.click('button.does-not-exist');
|
||||
fail('Clicking the button did not throw.');
|
||||
@ -554,20 +605,20 @@ describe('Puppeteer', function() {
|
||||
}
|
||||
}));
|
||||
it('should type into the textarea', SX(async function() {
|
||||
await page.navigate(STATIC_PREFIX + '/input/textarea.html');
|
||||
await page.navigate(PREFIX + '/input/textarea.html');
|
||||
await page.focus('textarea');
|
||||
await page.type('Type in this text!');
|
||||
expect(await page.evaluate(() => result)).toBe('Type in this text!');
|
||||
}));
|
||||
it('should click the button after navigation ', SX(async function() {
|
||||
await page.navigate(STATIC_PREFIX + '/input/button.html');
|
||||
await page.navigate(PREFIX + '/input/button.html');
|
||||
await page.click('button');
|
||||
await page.navigate(STATIC_PREFIX + '/input/button.html');
|
||||
await page.navigate(PREFIX + '/input/button.html');
|
||||
await page.click('button');
|
||||
expect(await page.evaluate(() => result)).toBe('Clicked');
|
||||
}));
|
||||
it('should upload the file', SX(async function(){
|
||||
await page.navigate(STATIC_PREFIX + '/input/fileupload.html');
|
||||
await page.navigate(PREFIX + '/input/fileupload.html');
|
||||
await page.uploadFile('input', __dirname + '/assets/file-to-upload.txt');
|
||||
expect(await page.evaluate(() => {
|
||||
let input = document.querySelector('input');
|
||||
@ -626,7 +677,7 @@ describe('Puppeteer', function() {
|
||||
it('should work', SX(async function() {
|
||||
let response = null;
|
||||
page.on('response', r => response = r);
|
||||
await page.navigate(STATIC_PREFIX + '/simple.json');
|
||||
await page.navigate(PREFIX + '/simple.json');
|
||||
expect(response).toBeTruthy();
|
||||
expect(response.bodyUsed).toBe(false);
|
||||
expect(await response.text()).toBe('{"foo": "bar"}\n');
|
||||
@ -663,7 +714,7 @@ describe('Puppeteer', function() {
|
||||
});
|
||||
let failedRequests = [];
|
||||
page.on('requestfailed', request => failedRequests.push(request));
|
||||
await page.navigate(STATIC_PREFIX + '/one-style.html');
|
||||
await page.navigate(PREFIX + '/one-style.html');
|
||||
expect(failedRequests.length).toBe(1);
|
||||
expect(failedRequests[0].url).toContain('one-style.css');
|
||||
expect(failedRequests[0].response()).toBe(null);
|
||||
@ -691,7 +742,7 @@ describe('Puppeteer', function() {
|
||||
page.on('requestfinished', request => events.push(`DONE ${request.url}`));
|
||||
page.on('requestfailed', request => events.push(`FAIL ${request.url}`));
|
||||
server.setRedirect('/foo.html', '/empty.html');
|
||||
const FOO_URL = STATIC_PREFIX + '/foo.html';
|
||||
const FOO_URL = PREFIX + '/foo.html';
|
||||
await page.navigate(FOO_URL);
|
||||
expect(events).toEqual([
|
||||
`GET ${FOO_URL}`,
|
||||
@ -733,7 +784,7 @@ describe('Puppeteer', function() {
|
||||
await page.evaluateOnInitialized(function(){
|
||||
window.injected = 123;
|
||||
});
|
||||
await page.navigate(STATIC_PREFIX + '/tamperable.html');
|
||||
await page.navigate(PREFIX + '/tamperable.html');
|
||||
expect(await page.evaluate(() => window.result)).toBe(123);
|
||||
}));
|
||||
});
|
||||
@ -745,7 +796,7 @@ describe('Puppeteer', function() {
|
||||
});
|
||||
|
||||
it('should print to pdf', SX(async function() {
|
||||
await page.navigate(STATIC_PREFIX + '/grid.html');
|
||||
await page.navigate(PREFIX + '/grid.html');
|
||||
await page.printToPDF(outputFile);
|
||||
expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0);
|
||||
}));
|
||||
@ -760,7 +811,7 @@ describe('Puppeteer', function() {
|
||||
|
||||
describe('Page.title', function() {
|
||||
it('should return the page title', SX(async function(){
|
||||
await page.navigate(STATIC_PREFIX + '/input/button.html');
|
||||
await page.navigate(PREFIX + '/input/button.html');
|
||||
expect(await page.title()).toBe('Button test');
|
||||
}));
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user