browserless 10.7.7 → 10.7.9-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/index.js +49 -40
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "browserless",
3
3
  "description": "The headless Chrome/Chromium performance driver for Node.js",
4
4
  "homepage": "https://browserless.js.org",
5
- "version": "10.7.7",
5
+ "version": "10.7.9-beta.0",
6
6
  "main": "src/index.js",
7
7
  "author": {
8
8
  "email": "hello@microlink.io",
@@ -64,5 +64,5 @@
64
64
  "timeout": "2m",
65
65
  "workerThreads": false
66
66
  },
67
- "gitHead": "94347ab5501efdcac49da85f5a670821c37b5173"
67
+ "gitHead": "112999584d7b7137fb0eab858d31396eaf3c52e8"
68
68
  }
package/src/index.js CHANGED
@@ -79,12 +79,13 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
79
79
  const getBrowserContext = () => _contextPromise
80
80
 
81
81
  const createPage = async name => {
82
+ const duration = debug.duration('createPage')
82
83
  const [browserProcess, browserContext] = await Promise.all([
83
84
  getBrowser(),
84
85
  getBrowserContext()
85
86
  ])
86
87
  const page = await browserContext.newPage()
87
- debug('createPage', {
88
+ duration({
88
89
  name,
89
90
  id: page._client().id(),
90
91
  contextId: browserContext.id,
@@ -95,12 +96,13 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
95
96
 
96
97
  const closePage = async (page, name) => {
97
98
  if (page && !page.isClosed()) {
99
+ const duration = debug.duration('closePage')
98
100
  const [browserProcess, browserContext] = await Promise.all([
99
101
  getBrowser(),
100
102
  getBrowserContext(),
101
103
  pReflect(page.close())
102
104
  ])
103
- debug('closePage', {
105
+ duration({
104
106
  name,
105
107
  id: page._client().id(),
106
108
  contextId: browserContext.id,
@@ -109,48 +111,55 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
109
111
  }
110
112
  }
111
113
 
112
- const withPage =
113
- (fn, { timeout: evaluateTimeout } = {}) =>
114
- async (...args) => {
115
- let isRejected = false
116
-
117
- async function run () {
118
- let page
119
-
120
- try {
121
- page = await createPage(fn.name)
122
- setTimeout(() => closePage(page, fn.name), timeout).unref()
123
- const value = await fn(page, goto)(...args)
124
- await closePage(page, fn.name)
125
- return value
126
- } catch (error) {
127
- await closePage(page, fn.name)
128
- if (!isRejected) throw ensureError(error)
129
- }
114
+ /**
115
+ * FIXME: Apparently there is a kind of race condition if you have more than one context and you close the page,
116
+ * the browser context is closed but the browser process is broken
117
+ * Related: https://github.com/search?q=repo%3Apuppeteer%2Fpuppeteer%20waitForScreenshotOperations&type=code
118
+ */
119
+ const withPage = (fn, { closePage: withClosePage = true, timeout: evaluateTimeout } = {}) => {
120
+ const name = fn.name || 'anonymous'
121
+
122
+ return async (...args) => {
123
+ let isRejected = false
124
+
125
+ async function run () {
126
+ let page
127
+
128
+ try {
129
+ page = await createPage(name)
130
+ setTimeout(() => closePage(page, `${name}:timeout`), timeout).unref()
131
+ const value = await fn(page, goto)(...args)
132
+ if (withClosePage) await closePage(page, `${name}:success`)
133
+ return value
134
+ } catch (error) {
135
+ if (withClosePage) await closePage(page, `${name}:error`)
136
+ if (!isRejected) throw ensureError(error)
130
137
  }
138
+ }
131
139
 
132
- const task = () =>
133
- pRetry(run, {
134
- retries: retry,
135
- onFailedAttempt: async error => {
136
- debug('onFailedAttempt', { name: error.name, code: error.code, isRejected })
137
- if (error.name === 'AbortError') throw error
138
- if (isRejected || isDestroyedForced) throw new AbortError()
139
- if (error.code === 'EBRWSRCONTEXTCONNRESET') {
140
- _contextPromise = createBrowserContext(contextOpts)
141
- }
142
- const { message, attemptNumber, retriesLeft } = error
143
- debug('retry', { attemptNumber, retriesLeft, message })
140
+ const task = () =>
141
+ pRetry(run, {
142
+ retries: retry,
143
+ onFailedAttempt: async error => {
144
+ debug('onFailedAttempt', { name: error.name, code: error.code, isRejected })
145
+ if (error.name === 'AbortError') throw error
146
+ if (isRejected || isDestroyedForced) throw new AbortError()
147
+ if (error.code === 'EBRWSRCONTEXTCONNRESET') {
148
+ _contextPromise = createBrowserContext(contextOpts)
144
149
  }
145
- })
150
+ const { message, attemptNumber, retriesLeft } = error
151
+ debug('retry', { attemptNumber, retriesLeft, message })
152
+ }
153
+ })
146
154
 
147
- const timeout = evaluateTimeout || contextTimeout || globalTimeout
155
+ const timeout = evaluateTimeout || contextTimeout || globalTimeout
148
156
 
149
- return pTimeout(task(), timeout, () => {
150
- isRejected = true
151
- throw browserTimeout({ timeout })
152
- })
153
- }
157
+ return pTimeout(task(), timeout, () => {
158
+ isRejected = true
159
+ throw browserTimeout({ timeout })
160
+ })
161
+ }
162
+ }
154
163
 
155
164
  const evaluate = (fn, gotoOpts) =>
156
165
  withPage(
@@ -188,7 +197,7 @@ module.exports = ({ timeout: globalTimeout = 30000, ...launchOpts } = {}) => {
188
197
  html: evaluate(page => page.content()),
189
198
  page: createPage,
190
199
  pdf: withPage(createPdf({ goto })),
191
- screenshot: withPage(createScreenshot({ goto })),
200
+ screenshot: withPage(createScreenshot({ goto }), { closePage: false }),
192
201
  text: evaluate(page => page.evaluate(() => document.body.innerText)),
193
202
  getDevice: goto.getDevice,
194
203
  destroyContext,