codeceptjs 4.0.0-rc.10 → 4.0.0-rc.11

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.
package/bin/mcp-server.js CHANGED
@@ -12,7 +12,8 @@ import path from 'path'
12
12
  import crypto from 'crypto'
13
13
  import { spawn } from 'child_process'
14
14
  import { createRequire } from 'module'
15
- import { existsSync, readdirSync } from 'fs'
15
+ import { existsSync, readdirSync, writeFileSync } from 'fs'
16
+ import { mkdirp } from 'mkdirp'
16
17
 
17
18
  const require = createRequire(import.meta.url)
18
19
 
@@ -439,12 +440,38 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
439
440
  const helper = Object.values(helpers)[0]
440
441
  if (helper) {
441
442
  try {
442
- if (helper.grabAriaSnapshot) result.artifacts.aria = await helper.grabAriaSnapshot()
443
- if (helper.grabCurrentUrl) result.artifacts.url = await helper.grabCurrentUrl()
444
- if (helper.grabBrowserLogs) result.artifacts.consoleLogs = (await helper.grabBrowserLogs()) || []
443
+ const traceDir = getTraceDir('mcp', 'run_code')
444
+ mkdirp.sync(traceDir)
445
+
446
+ if (helper.grabAriaSnapshot) {
447
+ const aria = await helper.grabAriaSnapshot()
448
+ const ariaFile = path.join(traceDir, 'aria.txt')
449
+ writeFileSync(ariaFile, aria)
450
+ result.artifacts.aria = `file://${ariaFile}`
451
+ }
452
+
453
+ if (helper.grabCurrentUrl) {
454
+ result.artifacts.url = await helper.grabCurrentUrl()
455
+ }
456
+
457
+ if (helper.grabBrowserLogs) {
458
+ const logs = (await helper.grabBrowserLogs()) || []
459
+ const logsFile = path.join(traceDir, 'console.json')
460
+ writeFileSync(logsFile, JSON.stringify(logs, null, 2))
461
+ result.artifacts.consoleLogs = `file://${logsFile}`
462
+ }
463
+
445
464
  if (helper.grabSource) {
446
465
  const html = await helper.grabSource()
447
- result.artifacts.html = html.substring(0, 10000) + '...'
466
+ const htmlFile = path.join(traceDir, 'page.html')
467
+ writeFileSync(htmlFile, html)
468
+ result.artifacts.html = `file://${htmlFile}`
469
+ }
470
+
471
+ if (helper.saveScreenshot) {
472
+ const screenshotFile = path.join(traceDir, 'screenshot.png')
473
+ await helper.saveScreenshot(screenshotFile)
474
+ result.artifacts.screenshot = `file://${screenshotFile}`
448
475
  }
449
476
  } catch (e) {
450
477
  result.output += ` (Warning: ${e.message})`
@@ -7,6 +7,7 @@ import promiseRetry from 'promise-retry'
7
7
  import Locator from '../locator.js'
8
8
  import recorder from '../recorder.js'
9
9
  import store from '../store.js'
10
+ import { checkFocusBeforeType, checkFocusBeforePressKey } from './extras/focusCheck.js'
10
11
  import { includes as stringIncludes } from '../assert/include.js'
11
12
  import { urlEquals, equals } from '../assert/equal.js'
12
13
  import { empty } from '../assert/empty.js'
@@ -2231,6 +2232,7 @@ class Playwright extends Helper {
2231
2232
  * {{> pressKeyWithKeyNormalization }}
2232
2233
  */
2233
2234
  async pressKey(key) {
2235
+ await checkFocusBeforePressKey(this, key)
2234
2236
  const modifiers = []
2235
2237
  if (Array.isArray(key)) {
2236
2238
  for (let k of key) {
@@ -2259,6 +2261,8 @@ class Playwright extends Helper {
2259
2261
  * {{> type }}
2260
2262
  */
2261
2263
  async type(keys, delay = null) {
2264
+ await checkFocusBeforeType(this)
2265
+
2262
2266
  // Always use page.keyboard.type for any string (including single character and national characters).
2263
2267
  if (!Array.isArray(keys)) {
2264
2268
  keys = keys.toString()
@@ -2933,7 +2937,7 @@ class Playwright extends Helper {
2933
2937
  const els = await this._locate(matchedLocator)
2934
2938
  assertElementExists(els, locator)
2935
2939
  const snapshot = await els[0].ariaSnapshot()
2936
- this.debugSection('Aria Snapshot', snapshot)
2940
+ this.debugSection('Aria Snapshot', `${snapshot.split('\n').length} lines`)
2937
2941
  return snapshot
2938
2942
  }
2939
2943
 
@@ -8,6 +8,7 @@ import promiseRetry from 'promise-retry'
8
8
  import Locator from '../locator.js'
9
9
  import recorder from '../recorder.js'
10
10
  import store from '../store.js'
11
+ import { checkFocusBeforeType, checkFocusBeforePressKey } from './extras/focusCheck.js'
11
12
  import { includes as stringIncludes } from '../assert/include.js'
12
13
  import { urlEquals, equals } from '../assert/equal.js'
13
14
  import { empty } from '../assert/empty.js'
@@ -1547,6 +1548,7 @@ class Puppeteer extends Helper {
1547
1548
  * {{> pressKeyWithKeyNormalization }}
1548
1549
  */
1549
1550
  async pressKey(key) {
1551
+ await checkFocusBeforePressKey(this, key)
1550
1552
  const modifiers = []
1551
1553
  if (Array.isArray(key)) {
1552
1554
  for (let k of key) {
@@ -1575,6 +1577,8 @@ class Puppeteer extends Helper {
1575
1577
  * {{> type }}
1576
1578
  */
1577
1579
  async type(keys, delay = null) {
1580
+ await checkFocusBeforeType(this)
1581
+
1578
1582
  if (!Array.isArray(keys)) {
1579
1583
  keys = keys.toString()
1580
1584
  keys = keys.split('')
@@ -10,6 +10,7 @@ import promiseRetry from 'promise-retry'
10
10
  import { includes as stringIncludes } from '../assert/include.js'
11
11
  import { urlEquals, equals } from '../assert/equal.js'
12
12
  import store from '../store.js'
13
+ import { checkFocusBeforeType, checkFocusBeforePressKey } from './extras/focusCheck.js'
13
14
  import output from '../output.js'
14
15
  const { debug } = output
15
16
  import { empty } from '../assert/empty.js'
@@ -2237,6 +2238,7 @@ class WebDriver extends Helper {
2237
2238
  * {{> pressKeyWithKeyNormalization }}
2238
2239
  */
2239
2240
  async pressKey(key) {
2241
+ await checkFocusBeforePressKey(this, key)
2240
2242
  const modifiers = []
2241
2243
  if (Array.isArray(key)) {
2242
2244
  for (let k of key) {
@@ -2283,6 +2285,8 @@ class WebDriver extends Helper {
2283
2285
  * {{> type }}
2284
2286
  */
2285
2287
  async type(keys, delay = null) {
2288
+ await checkFocusBeforeType(this)
2289
+
2286
2290
  if (!Array.isArray(keys)) {
2287
2291
  keys = keys.toString()
2288
2292
  keys = keys.split('')
@@ -0,0 +1,8 @@
1
+ class NonFocusedType extends Error {
2
+ constructor(message) {
3
+ super(message)
4
+ this.name = 'NonFocusedType'
5
+ }
6
+ }
7
+
8
+ export default NonFocusedType
@@ -0,0 +1,43 @@
1
+ import store from '../../store.js'
2
+ import NonFocusedType from '../errors/NonFocusedType.js'
3
+
4
+ const MODIFIER_PATTERN = /^(control|ctrl|meta|cmd|command|commandorcontrol|ctrlorcommand)/i
5
+ const EDITING_KEYS = new Set(['a', 'c', 'x', 'v', 'z', 'y'])
6
+
7
+ async function isNoElementFocused(helper) {
8
+ return helper.executeScript(() => {
9
+ const ae = document.activeElement
10
+ return !ae || ae === document.documentElement || (ae === document.body && !ae.isContentEditable)
11
+ })
12
+ }
13
+
14
+ export async function checkFocusBeforeType(helper) {
15
+ if (!helper.options.strict && !store.debugMode) return
16
+ if (!await isNoElementFocused(helper)) return
17
+
18
+ const message = 'No element is in focus. Use I.click() or I.focus() to activate an element before typing.'
19
+ if (helper.options.strict) throw new NonFocusedType(message)
20
+ helper.debugSection('Warning', message)
21
+ }
22
+
23
+ export async function checkFocusBeforePressKey(helper, originalKey) {
24
+ if (!helper.options.strict && !store.debugMode) return
25
+ if (!Array.isArray(originalKey)) return
26
+
27
+ let hasCtrlOrMeta = false
28
+ let actionKey = null
29
+ for (const k of originalKey) {
30
+ if (MODIFIER_PATTERN.test(k)) {
31
+ hasCtrlOrMeta = true
32
+ } else {
33
+ actionKey = k
34
+ }
35
+ }
36
+ if (!hasCtrlOrMeta || !actionKey || !EDITING_KEYS.has(actionKey.toLowerCase())) return
37
+
38
+ if (!await isNoElementFocused(helper)) return
39
+
40
+ const message = `No element is in focus. Key combination with "${originalKey.join('+')}" may not work as expected. Use I.click() or I.focus() first.`
41
+ if (helper.options.strict) throw new NonFocusedType(message)
42
+ helper.debugSection('Warning', message)
43
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "4.0.0-rc.10",
3
+ "version": "4.0.0-rc.11",
4
4
  "type": "module",
5
5
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
6
6
  "keywords": [