codeceptjs 4.2.1-beta.1 → 4.2.1-beta.2

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.
@@ -62,7 +62,7 @@ These are set automatically and only need overriding for unusual setups:
62
62
 
63
63
  ## Limitations
64
64
 
65
- * No screenshots and no screencast: `saveScreenshot` throws.
65
+ * No screenshots and no screencast: `saveScreenshot` and `saveElementScreenshot` do nothing (a debug message is printed).
66
66
  * No frames or popups.
67
67
  * No scrolling: scroll positions always stay at 0.
68
68
  * Computed styles cover what visibility checks need (`display`, `visibility`, `opacity`,
@@ -7,7 +7,9 @@ import Helper from '@codeceptjs/helper'
7
7
  import CDPConnection from './extras/CDPConnection.js'
8
8
  import installCodeceptClient from './clientscripts/cdpBrowserClient.js'
9
9
  import xpathPolyfillSource from './clientscripts/xpathPolyfill.js'
10
+ import layoutProbe from './clientscripts/layoutProbe.js'
10
11
  import Locator from '../locator.js'
12
+ import output from '../output.js'
11
13
  import store from '../store.js'
12
14
  import { xpathLocator, normalizePath, resolveUrl, toCamelCase, convertCssPropertiesToCamelCase, normalizeSpacesInString, fileExists, base64EncodeFile, getMimeType, isFile, isWindows } from '../utils.js'
13
15
  import ElementNotFound from './errors/ElementNotFound.js'
@@ -357,8 +359,20 @@ class CDPBrowser extends Helper {
357
359
  await this.cdp.connect()
358
360
  }
359
361
 
362
+ _beforeStep() {
363
+ if (this._connectError) throw new Error(this._connectError.message)
364
+ }
365
+
360
366
  async _before() {
361
- if (!this.cdp || !this.cdp.isConnected) await this._connect()
367
+ this._connectError = null
368
+ if (!this.cdp || !this.cdp.isConnected) {
369
+ try {
370
+ await this._connect()
371
+ } catch (err) {
372
+ this._connectError = err
373
+ throw err
374
+ }
375
+ }
362
376
  this._navStartWaiters = []
363
377
  this._lastMainFrameNav = { loaderId: null, events: {} }
364
378
  const { targetId } = await this.cdp.send('Target.createTarget', { url: 'about:blank' })
@@ -595,8 +609,8 @@ class CDPBrowser extends Helper {
595
609
 
596
610
  async _probeCapabilities() {
597
611
  if (this.capabilities.layout === null) {
598
- const display = await this._evaluate(`getComputedStyle(document.documentElement).display`)
599
- this.capabilities.layout = display === '' ? 'none' : 'real'
612
+ const display = await this._evaluate(`(${layoutProbe.toString()})()`)
613
+ this.capabilities.layout = display === 'none' ? 'real' : 'none'
600
614
  }
601
615
  if (this.capabilities.screenshot === null) {
602
616
  this.capabilities.screenshot = this.capabilities.layout === 'real'
@@ -610,6 +624,13 @@ class CDPBrowser extends Helper {
610
624
  if (this.capabilities.innerText === null) {
611
625
  await this._needsVisibleTextFallback()
612
626
  }
627
+ if (!this._engineReported) {
628
+ this._engineReported = true
629
+ let engine = 'render (layout and screenshots)'
630
+ if (this.capabilities.layout === 'none') engine = 'no-render (DOM only: no layout, visibility checks or screenshots)'
631
+ else if (!this.capabilities.screenshot) engine = 'layout without screenshots'
632
+ output.print(`${this.constructor.name} engine: ${engine}`)
633
+ }
613
634
  }
614
635
 
615
636
  async _run(candidates, action, payload, context = null) {
@@ -807,7 +828,8 @@ class CDPBrowser extends Helper {
807
828
  const useWalker = await this._needsVisibleTextFallback()
808
829
  const res = await this._runTextCheck(text, { ignoreCase, useWalker })
809
830
  if (negate ? !res.found : res.found) return
810
- let source = await this._textSource(null)
831
+ let source = res.text
832
+ if (source === undefined) source = await this._textSource(null)
811
833
  let needle = text
812
834
  if (ignoreCase) {
813
835
  needle = needle.toLowerCase()
@@ -1343,7 +1365,8 @@ class CDPBrowser extends Helper {
1343
1365
  */
1344
1366
  async saveScreenshot(fileName) {
1345
1367
  if (this.capabilities.screenshot === false) {
1346
- throw new Error('saveScreenshot is not supported: this browser has no rendering engine')
1368
+ this.debug('saveScreenshot skipped: this browser has no rendering engine')
1369
+ return
1347
1370
  }
1348
1371
  const outputDir = global.output_dir || '.'
1349
1372
  const res = await this.cdp.send('Page.captureScreenshot', { format: 'png' }, this.sessionId)
@@ -1355,7 +1378,8 @@ class CDPBrowser extends Helper {
1355
1378
  */
1356
1379
  async saveElementScreenshot(locator, fileName) {
1357
1380
  if (this.capabilities.screenshot === false) {
1358
- throw new Error('saveElementScreenshot is not supported: this browser has no rendering engine')
1381
+ this.debug('saveElementScreenshot skipped: this browser has no rendering engine')
1382
+ return
1359
1383
  }
1360
1384
  const res = await this._run(this._candidates(locator), 'rect')
1361
1385
  if (!res.found) throw new ElementNotFound(locator)
@@ -72,7 +72,7 @@ const config = {}
72
72
  *
73
73
  * ## Limitations
74
74
  *
75
- * - No screenshots and no screencast: `saveScreenshot` throws.
75
+ * - No screenshots and no screencast: `saveScreenshot` and `saveElementScreenshot` do nothing (a debug message is printed).
76
76
  * - No frames or popups.
77
77
  * - No scrolling: scroll positions always stay at 0.
78
78
  * - Computed styles cover what visibility checks need (`display`, `visibility`, `opacity`,
@@ -76,7 +76,7 @@ export default function installCodeceptClient(xpathNeedsPolyfill) {
76
76
  const hayCmp = opts.ignoreCase ? hay.toLowerCase() : hay
77
77
  const needleCmp = opts.ignoreCase ? needleNorm.toLowerCase() : needleNorm
78
78
  const idx = hayCmp.indexOf(needleCmp)
79
- if (idx === -1) return { found: false, snippet: null }
79
+ if (idx === -1) return { found: false, snippet: null, text: hay }
80
80
  const from = Math.max(0, idx - 60)
81
81
  return { found: true, snippet: hay.slice(from, idx + needleNorm.length + 60) }
82
82
  }
@@ -0,0 +1,12 @@
1
+ export default function layoutProbe() {
2
+ const style = document.createElement('style')
3
+ style.textContent = '.__codecept-layout-probe{display:none}'
4
+ document.documentElement.appendChild(style)
5
+ const probe = document.createElement('div')
6
+ probe.className = '__codecept-layout-probe'
7
+ ;(document.body || document.documentElement).appendChild(probe)
8
+ const display = getComputedStyle(probe).display
9
+ style.remove()
10
+ probe.remove()
11
+ return display
12
+ }
@@ -1,4 +1,7 @@
1
1
  import { WebSocket } from 'ws'
2
+ import debugModule from 'debug'
3
+
4
+ const debug = debugModule('codeceptjs:cdp')
2
5
 
3
6
  class CDPConnection {
4
7
  constructor(endpoint, options = {}) {
@@ -9,6 +12,7 @@ class CDPConnection {
9
12
  this.lastId = 0
10
13
  this.pending = new Map()
11
14
  this.listeners = new Map()
15
+ this.totals = {}
12
16
  }
13
17
 
14
18
  async connect() {
@@ -49,7 +53,7 @@ class CDPConnection {
49
53
  this.pending.delete(id)
50
54
  reject(new Error(`CDP command ${method} timed out after ${this.timeout}ms`))
51
55
  }, this.timeout)
52
- this.pending.set(id, { resolve, reject, timer })
56
+ this.pending.set(id, { resolve, reject, timer, method, started: Date.now() })
53
57
  this.ws.send(JSON.stringify(message))
54
58
  })
55
59
  }
@@ -61,9 +65,12 @@ class CDPConnection {
61
65
 
62
66
  _onMessage(msg) {
63
67
  if (msg.id && this.pending.has(msg.id)) {
64
- const { resolve, reject, timer } = this.pending.get(msg.id)
68
+ const { resolve, reject, timer, method, started } = this.pending.get(msg.id)
65
69
  clearTimeout(timer)
66
70
  this.pending.delete(msg.id)
71
+ const ms = Date.now() - started
72
+ this.totals[method] = (this.totals[method] || 0) + ms
73
+ debug(`${method} ${ms}ms`)
67
74
  if (msg.error) reject(new Error(msg.error.message))
68
75
  else resolve(msg.result)
69
76
  return
@@ -80,6 +87,7 @@ class CDPConnection {
80
87
 
81
88
  async close() {
82
89
  if (!this.ws) return
90
+ debug('total time per method', this.totals)
83
91
  await new Promise(resolve => {
84
92
  if (this.ws.readyState === WebSocket.CLOSED) return resolve()
85
93
  this.ws.once('close', resolve)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "4.2.1-beta.1",
3
+ "version": "4.2.1-beta.2",
4
4
  "type": "module",
5
5
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
6
6
  "keywords": [
@@ -3438,7 +3438,7 @@ declare namespace CodeceptJS {
3438
3438
  *
3439
3439
  * ## Limitations
3440
3440
  *
3441
- * - No screenshots and no screencast: `saveScreenshot` throws.
3441
+ * - No screenshots and no screencast: `saveScreenshot` and `saveElementScreenshot` do nothing (a debug message is printed).
3442
3442
  * - No frames or popups.
3443
3443
  * - No scrolling: scroll positions always stay at 0.
3444
3444
  * - Computed styles cover what visibility checks need (`display`, `visibility`, `opacity`,
@@ -3541,7 +3541,7 @@ declare namespace CodeceptJS {
3541
3541
  *
3542
3542
  * ## Limitations
3543
3543
  *
3544
- * - No screenshots and no screencast: `saveScreenshot` throws.
3544
+ * - No screenshots and no screencast: `saveScreenshot` and `saveElementScreenshot` do nothing (a debug message is printed).
3545
3545
  * - No frames or popups.
3546
3546
  * - No scrolling: scroll positions always stay at 0.
3547
3547
  * - Computed styles cover what visibility checks need (`display`, `visibility`, `opacity`,