[api] Launcher: Close gracefully when a userDataDir is specified (#700)
This patch: - makes `browser.close()` return a promise that resolves when browser gets closed - starts closing chrome gracefully if a custom `userDataDir` is supplied Fixes #527
This commit is contained in:
parent
d7e673645a
commit
f398e69dbb
@ -211,6 +211,7 @@ puppeteer.launch().then(async browser => {
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### browser.close()
|
#### browser.close()
|
||||||
|
- returns: <[Promise]>
|
||||||
|
|
||||||
Closes browser with all the pages (if any were opened). The browser object itself is considered to be disposed and could not be used anymore.
|
Closes browser with all the pages (if any were opened). The browser object itself is considered to be disposed and could not be used anymore.
|
||||||
|
|
||||||
|
@ -16,14 +16,16 @@
|
|||||||
|
|
||||||
const {helper} = require('./helper');
|
const {helper} = require('./helper');
|
||||||
const Page = require('./Page');
|
const Page = require('./Page');
|
||||||
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
class Browser {
|
class Browser extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* @param {!Connection} connection
|
* @param {!Connection} connection
|
||||||
* @param {boolean} ignoreHTTPSErrors
|
* @param {boolean} ignoreHTTPSErrors
|
||||||
* @param {function()=} closeCallback
|
* @param {function():Promise=} closeCallback
|
||||||
*/
|
*/
|
||||||
constructor(connection, ignoreHTTPSErrors, closeCallback) {
|
constructor(connection, ignoreHTTPSErrors, closeCallback) {
|
||||||
|
super();
|
||||||
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
|
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
|
||||||
this._screenshotTaskQueue = new TaskQueue();
|
this._screenshotTaskQueue = new TaskQueue();
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
@ -54,9 +56,9 @@ class Browser {
|
|||||||
return version.product;
|
return version.product;
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
async close() {
|
||||||
this._connection.dispose();
|
this._connection.dispose();
|
||||||
this._closeCallback.call(null);
|
await this._closeCallback.call(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +84,14 @@ class Launcher {
|
|||||||
chromeProcess.stderr.pipe(process.stderr);
|
chromeProcess.stderr.pipe(process.stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const waitForChromeToClose = new Promise(fulfill => {
|
||||||
|
chromeProcess.once('close', () => {
|
||||||
// Cleanup as processes exit.
|
// Cleanup as processes exit.
|
||||||
if (temporaryUserDataDir)
|
if (temporaryUserDataDir)
|
||||||
chromeProcess.once('close', () => removeSync(temporaryUserDataDir));
|
removeSync(temporaryUserDataDir);
|
||||||
|
fulfill();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const listeners = [ helper.addEventListener(process, 'exit', killChrome) ];
|
const listeners = [ helper.addEventListener(process, 'exit', killChrome) ];
|
||||||
if (options.handleSIGINT !== false)
|
if (options.handleSIGINT !== false)
|
||||||
@ -102,12 +107,29 @@ class Launcher {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
function killChrome() {
|
function killChrome() {
|
||||||
helper.removeEventListeners(listeners);
|
helper.removeEventListeners(listeners);
|
||||||
|
if (temporaryUserDataDir) {
|
||||||
|
// Force kill chrome.
|
||||||
if (process.platform === 'win32')
|
if (process.platform === 'win32')
|
||||||
childProcess.execSync(`taskkill /pid ${chromeProcess.pid} /T /F`);
|
childProcess.execSync(`taskkill /pid ${chromeProcess.pid} /T /F`);
|
||||||
else
|
else
|
||||||
process.kill(-chromeProcess.pid);
|
process.kill(-chromeProcess.pid, 'SIGKILL');
|
||||||
|
// Attempt to remove temporary profile directory to avoid littering.
|
||||||
|
try {
|
||||||
|
removeSync(temporaryUserDataDir);
|
||||||
|
} catch (e) { }
|
||||||
|
} else {
|
||||||
|
// Terminate chrome gracefully.
|
||||||
|
if (process.platform === 'win32')
|
||||||
|
chromeProcess.kill();
|
||||||
|
else
|
||||||
|
process.kill(-chromeProcess.pid, 'SIGTERM');
|
||||||
|
}
|
||||||
|
return waitForChromeToClose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ describe('Puppeteer', function() {
|
|||||||
const options = Object.assign({userDataDir}, defaultBrowserOptions);
|
const options = Object.assign({userDataDir}, defaultBrowserOptions);
|
||||||
const browser = await puppeteer.launch(options);
|
const browser = await puppeteer.launch(options);
|
||||||
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
||||||
browser.close();
|
await browser.close();
|
||||||
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
||||||
rm(userDataDir);
|
rm(userDataDir);
|
||||||
}));
|
}));
|
||||||
@ -117,7 +117,7 @@ describe('Puppeteer', function() {
|
|||||||
options.args = [`--user-data-dir=${userDataDir}`].concat(options.args);
|
options.args = [`--user-data-dir=${userDataDir}`].concat(options.args);
|
||||||
const browser = await puppeteer.launch(options);
|
const browser = await puppeteer.launch(options);
|
||||||
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
||||||
browser.close();
|
await browser.close();
|
||||||
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
|
||||||
rm(userDataDir);
|
rm(userDataDir);
|
||||||
}));
|
}));
|
||||||
|
@ -165,9 +165,9 @@ function checkDuplicates(doc) {
|
|||||||
classes.add(cls.name);
|
classes.add(cls.name);
|
||||||
const members = new Set();
|
const members = new Set();
|
||||||
for (const member of cls.membersArray) {
|
for (const member of cls.membersArray) {
|
||||||
if (members.has(member.name))
|
if (members.has(member.type + ' ' + member.name))
|
||||||
errors.push(`Duplicate declaration of method ${cls.name}.${member.name}()`);
|
errors.push(`Duplicate declaration of ${member.type} ${cls.name}.${member.name}()`);
|
||||||
members.add(member.name);
|
members.add(member.type + ' ' + member.name);
|
||||||
const args = new Set();
|
const args = new Set();
|
||||||
for (const arg of member.argsArray) {
|
for (const arg of member.argsArray) {
|
||||||
if (args.has(arg.name))
|
if (args.has(arg.name))
|
||||||
|
Loading…
Reference in New Issue
Block a user