codeceptjs 4.0.0-rc.1 → 4.0.0-rc.7
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/README.md +39 -27
- package/bin/mcp-server.js +610 -0
- package/docs/webapi/appendField.mustache +5 -0
- package/docs/webapi/attachFile.mustache +12 -0
- package/docs/webapi/checkOption.mustache +1 -1
- package/docs/webapi/clearField.mustache +5 -0
- package/docs/webapi/dontSeeCurrentPathEquals.mustache +10 -0
- package/docs/webapi/dontSeeElement.mustache +4 -0
- package/docs/webapi/dontSeeInField.mustache +5 -0
- package/docs/webapi/fillField.mustache +5 -0
- package/docs/webapi/seeCurrentPathEquals.mustache +10 -0
- package/docs/webapi/seeElement.mustache +4 -0
- package/docs/webapi/seeInField.mustache +5 -0
- package/docs/webapi/selectOption.mustache +5 -0
- package/docs/webapi/uncheckOption.mustache +1 -1
- package/lib/codecept.js +20 -17
- package/lib/command/init.js +0 -3
- package/lib/command/run-workers.js +1 -0
- package/lib/container.js +19 -4
- package/lib/helper/Appium.js +8 -8
- package/lib/helper/Playwright.js +163 -70
- package/lib/helper/Puppeteer.js +165 -59
- package/lib/helper/WebDriver.js +134 -49
- package/lib/listener/globalRetry.js +32 -6
- package/lib/plugin/aiTrace.js +464 -0
- package/lib/plugin/retryFailedStep.js +28 -19
- package/lib/plugin/stepByStepReport.js +5 -1
- package/lib/utils.js +48 -0
- package/lib/workers.js +49 -7
- package/package.json +5 -3
- package/lib/listener/enhancedGlobalRetry.js +0 -110
- package/lib/plugin/enhancedRetryFailedStep.js +0 -99
- package/lib/plugin/htmlReporter.js +0 -3648
- package/lib/retryCoordinator.js +0 -207
- package/typings/promiseBasedTypes.d.ts +0 -9469
- package/typings/types.d.ts +0 -11402
package/lib/helper/Playwright.js
CHANGED
|
@@ -23,7 +23,11 @@ import {
|
|
|
23
23
|
clearString,
|
|
24
24
|
requireWithFallback,
|
|
25
25
|
normalizeSpacesInString,
|
|
26
|
+
normalizePath,
|
|
27
|
+
resolveUrl,
|
|
26
28
|
relativeDir,
|
|
29
|
+
getMimeType,
|
|
30
|
+
base64EncodeFile,
|
|
27
31
|
} from '../utils.js'
|
|
28
32
|
import { isColorProperty, convertColorToRGBA } from '../colorUtils.js'
|
|
29
33
|
import ElementNotFound from './errors/ElementNotFound.js'
|
|
@@ -1944,8 +1948,15 @@ class Playwright extends Helper {
|
|
|
1944
1948
|
* {{> seeElement }}
|
|
1945
1949
|
*
|
|
1946
1950
|
*/
|
|
1947
|
-
async seeElement(locator) {
|
|
1948
|
-
let els
|
|
1951
|
+
async seeElement(locator, context = null) {
|
|
1952
|
+
let els
|
|
1953
|
+
if (context) {
|
|
1954
|
+
const contextEls = await this._locate(context)
|
|
1955
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
1956
|
+
els = await findElements.call(this, contextEls[0], locator)
|
|
1957
|
+
} else {
|
|
1958
|
+
els = await this._locate(locator)
|
|
1959
|
+
}
|
|
1949
1960
|
els = await Promise.all(els.map(el => el.isVisible()))
|
|
1950
1961
|
try {
|
|
1951
1962
|
return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'))
|
|
@@ -1958,8 +1969,15 @@ class Playwright extends Helper {
|
|
|
1958
1969
|
* {{> dontSeeElement }}
|
|
1959
1970
|
*
|
|
1960
1971
|
*/
|
|
1961
|
-
async dontSeeElement(locator) {
|
|
1962
|
-
let els
|
|
1972
|
+
async dontSeeElement(locator, context = null) {
|
|
1973
|
+
let els
|
|
1974
|
+
if (context) {
|
|
1975
|
+
const contextEls = await this._locate(context)
|
|
1976
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
1977
|
+
els = await findElements.call(this, contextEls[0], locator)
|
|
1978
|
+
} else {
|
|
1979
|
+
els = await this._locate(locator)
|
|
1980
|
+
}
|
|
1963
1981
|
els = await Promise.all(els.map(el => el.isVisible()))
|
|
1964
1982
|
try {
|
|
1965
1983
|
return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'))
|
|
@@ -2245,8 +2263,8 @@ class Playwright extends Helper {
|
|
|
2245
2263
|
* {{> fillField }}
|
|
2246
2264
|
*
|
|
2247
2265
|
*/
|
|
2248
|
-
async fillField(field, value) {
|
|
2249
|
-
const els = await findFields.call(this, field)
|
|
2266
|
+
async fillField(field, value, context = null) {
|
|
2267
|
+
const els = await findFields.call(this, field, context)
|
|
2250
2268
|
assertElementExists(els, field, 'Field')
|
|
2251
2269
|
if (this.options.strict) assertOnlyOneElement(els, field)
|
|
2252
2270
|
const el = els[0]
|
|
@@ -2262,24 +2280,10 @@ class Playwright extends Helper {
|
|
|
2262
2280
|
}
|
|
2263
2281
|
|
|
2264
2282
|
/**
|
|
2265
|
-
*
|
|
2266
|
-
*
|
|
2267
|
-
*
|
|
2268
|
-
* Examples:
|
|
2269
|
-
*
|
|
2270
|
-
* ```js
|
|
2271
|
-
* I.clearField('.text-area')
|
|
2272
|
-
*
|
|
2273
|
-
* // if this doesn't work use force option
|
|
2274
|
-
* I.clearField('#submit', { force: true })
|
|
2275
|
-
* ```
|
|
2276
|
-
* Use `force` to bypass the [actionability](https://playwright.dev/docs/actionability) checks.
|
|
2277
|
-
*
|
|
2278
|
-
* @param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
|
|
2279
|
-
* @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-locator#locator-clear) for available options object as 2nd argument.
|
|
2283
|
+
* {{> clearField }}
|
|
2280
2284
|
*/
|
|
2281
|
-
async clearField(locator,
|
|
2282
|
-
const els = await findFields.call(this, locator)
|
|
2285
|
+
async clearField(locator, context = null) {
|
|
2286
|
+
const els = await findFields.call(this, locator, context)
|
|
2283
2287
|
assertElementExists(els, locator, 'Field to clear')
|
|
2284
2288
|
if (this.options.strict) assertOnlyOneElement(els, locator)
|
|
2285
2289
|
|
|
@@ -2295,8 +2299,8 @@ class Playwright extends Helper {
|
|
|
2295
2299
|
/**
|
|
2296
2300
|
* {{> appendField }}
|
|
2297
2301
|
*/
|
|
2298
|
-
async appendField(field, value) {
|
|
2299
|
-
const els = await findFields.call(this, field)
|
|
2302
|
+
async appendField(field, value, context = null) {
|
|
2303
|
+
const els = await findFields.call(this, field, context)
|
|
2300
2304
|
assertElementExists(els, field, 'Field')
|
|
2301
2305
|
if (this.options.strict) assertOnlyOneElement(els, field)
|
|
2302
2306
|
await highlightActiveElement.call(this, els[0])
|
|
@@ -2308,63 +2312,94 @@ class Playwright extends Helper {
|
|
|
2308
2312
|
/**
|
|
2309
2313
|
* {{> seeInField }}
|
|
2310
2314
|
*/
|
|
2311
|
-
async seeInField(field, value) {
|
|
2315
|
+
async seeInField(field, value, context = null) {
|
|
2312
2316
|
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
2313
|
-
return proceedSeeInField.call(this, 'assert', field, _value)
|
|
2317
|
+
return proceedSeeInField.call(this, 'assert', field, _value, context)
|
|
2314
2318
|
}
|
|
2315
2319
|
|
|
2316
2320
|
/**
|
|
2317
2321
|
* {{> dontSeeInField }}
|
|
2318
2322
|
*/
|
|
2319
|
-
async dontSeeInField(field, value) {
|
|
2323
|
+
async dontSeeInField(field, value, context = null) {
|
|
2320
2324
|
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
2321
|
-
return proceedSeeInField.call(this, 'negate', field, _value)
|
|
2325
|
+
return proceedSeeInField.call(this, 'negate', field, _value, context)
|
|
2322
2326
|
}
|
|
2323
2327
|
|
|
2324
2328
|
/**
|
|
2325
2329
|
* {{> attachFile }}
|
|
2326
2330
|
*
|
|
2327
2331
|
*/
|
|
2328
|
-
async attachFile(locator, pathToFile) {
|
|
2332
|
+
async attachFile(locator, pathToFile, context = null) {
|
|
2329
2333
|
const file = path.join(global.codecept_dir, pathToFile)
|
|
2330
2334
|
|
|
2331
2335
|
if (!fileExists(file)) {
|
|
2332
2336
|
throw new Error(`File at ${file} can not be found on local system`)
|
|
2333
2337
|
}
|
|
2334
|
-
const els = await findFields.call(this, locator)
|
|
2335
|
-
|
|
2336
|
-
|
|
2338
|
+
const els = await findFields.call(this, locator, context)
|
|
2339
|
+
if (els.length) {
|
|
2340
|
+
const tag = await els[0].evaluate(el => el.tagName)
|
|
2341
|
+
const type = await els[0].evaluate(el => el.type)
|
|
2342
|
+
if (tag === 'INPUT' && type === 'file') {
|
|
2343
|
+
await els[0].setInputFiles(file)
|
|
2344
|
+
return this._waitForAction()
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
const targetEls = els.length ? els : await this._locate(locator)
|
|
2349
|
+
assertElementExists(targetEls, locator, 'Element')
|
|
2350
|
+
const base64Content = base64EncodeFile(file)
|
|
2351
|
+
const fileName = path.basename(file)
|
|
2352
|
+
const mimeType = getMimeType(fileName)
|
|
2353
|
+
await targetEls[0].evaluate((el, { base64Content, fileName, mimeType }) => {
|
|
2354
|
+
const binaryStr = atob(base64Content)
|
|
2355
|
+
const bytes = new Uint8Array(binaryStr.length)
|
|
2356
|
+
for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i)
|
|
2357
|
+
const fileObj = new File([bytes], fileName, { type: mimeType })
|
|
2358
|
+
const dataTransfer = new DataTransfer()
|
|
2359
|
+
dataTransfer.items.add(fileObj)
|
|
2360
|
+
el.dispatchEvent(new DragEvent('dragenter', { dataTransfer, bubbles: true }))
|
|
2361
|
+
el.dispatchEvent(new DragEvent('dragover', { dataTransfer, bubbles: true }))
|
|
2362
|
+
el.dispatchEvent(new DragEvent('drop', { dataTransfer, bubbles: true }))
|
|
2363
|
+
}, { base64Content, fileName, mimeType })
|
|
2337
2364
|
return this._waitForAction()
|
|
2338
2365
|
}
|
|
2339
2366
|
|
|
2340
2367
|
/**
|
|
2341
2368
|
* {{> selectOption }}
|
|
2342
2369
|
*/
|
|
2343
|
-
async selectOption(select, option) {
|
|
2344
|
-
const
|
|
2370
|
+
async selectOption(select, option, context = null) {
|
|
2371
|
+
const pageContext = await this.context
|
|
2345
2372
|
const matchedLocator = new Locator(select)
|
|
2346
2373
|
|
|
2374
|
+
let contextEl
|
|
2375
|
+
if (context) {
|
|
2376
|
+
const contextEls = await this._locate(context)
|
|
2377
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
2378
|
+
contextEl = contextEls[0]
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2347
2381
|
// Strict locator
|
|
2348
2382
|
if (!matchedLocator.isFuzzy()) {
|
|
2349
2383
|
this.debugSection('SelectOption', `Strict: ${JSON.stringify(select)}`)
|
|
2350
|
-
const els = await this._locate(matchedLocator)
|
|
2384
|
+
const els = contextEl ? await findElements.call(this, contextEl, matchedLocator) : await this._locate(matchedLocator)
|
|
2351
2385
|
assertElementExists(els, select, 'Selectable element')
|
|
2352
|
-
return proceedSelect.call(this,
|
|
2386
|
+
return proceedSelect.call(this, pageContext, els[0], option)
|
|
2353
2387
|
}
|
|
2354
2388
|
|
|
2355
2389
|
// Fuzzy: try combobox
|
|
2356
2390
|
this.debugSection('SelectOption', `Fuzzy: "${matchedLocator.value}"`)
|
|
2357
|
-
|
|
2358
|
-
|
|
2391
|
+
const comboboxSearchCtx = contextEl || pageContext
|
|
2392
|
+
let els = await findByRole(comboboxSearchCtx, { role: 'combobox', name: matchedLocator.value })
|
|
2393
|
+
if (els?.length) return proceedSelect.call(this, pageContext, els[0], option)
|
|
2359
2394
|
|
|
2360
2395
|
// Fuzzy: try listbox
|
|
2361
|
-
els = await findByRole(
|
|
2362
|
-
if (els?.length) return proceedSelect.call(this,
|
|
2396
|
+
els = await findByRole(comboboxSearchCtx, { role: 'listbox', name: matchedLocator.value })
|
|
2397
|
+
if (els?.length) return proceedSelect.call(this, pageContext, els[0], option)
|
|
2363
2398
|
|
|
2364
2399
|
// Fuzzy: try native select
|
|
2365
|
-
els = await findFields.call(this, select)
|
|
2400
|
+
els = await findFields.call(this, select, context)
|
|
2366
2401
|
assertElementExists(els, select, 'Selectable element')
|
|
2367
|
-
return proceedSelect.call(this,
|
|
2402
|
+
return proceedSelect.call(this, pageContext, els[0], option)
|
|
2368
2403
|
}
|
|
2369
2404
|
|
|
2370
2405
|
/**
|
|
@@ -2405,6 +2440,26 @@ class Playwright extends Helper {
|
|
|
2405
2440
|
urlEquals(this.options.url).negate(url, await this._getPageUrl())
|
|
2406
2441
|
}
|
|
2407
2442
|
|
|
2443
|
+
/**
|
|
2444
|
+
* {{> seeCurrentPathEquals }}
|
|
2445
|
+
*/
|
|
2446
|
+
async seeCurrentPathEquals(path) {
|
|
2447
|
+
const currentUrl = await this._getPageUrl()
|
|
2448
|
+
const baseUrl = this.options.url || 'http://localhost'
|
|
2449
|
+
const actualPath = new URL(currentUrl, baseUrl).pathname
|
|
2450
|
+
return equals('url path').assert(normalizePath(path), normalizePath(actualPath))
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
/**
|
|
2454
|
+
* {{> dontSeeCurrentPathEquals }}
|
|
2455
|
+
*/
|
|
2456
|
+
async dontSeeCurrentPathEquals(path) {
|
|
2457
|
+
const currentUrl = await this._getPageUrl()
|
|
2458
|
+
const baseUrl = this.options.url || 'http://localhost'
|
|
2459
|
+
const actualPath = new URL(currentUrl, baseUrl).pathname
|
|
2460
|
+
return equals('url path').negate(normalizePath(path), normalizePath(actualPath))
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2408
2463
|
/**
|
|
2409
2464
|
* {{> see }}
|
|
2410
2465
|
*
|
|
@@ -3362,6 +3417,7 @@ class Playwright extends Helper {
|
|
|
3362
3417
|
*/
|
|
3363
3418
|
async waitInUrl(urlPart, sec = null) {
|
|
3364
3419
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
3420
|
+
const expectedUrl = resolveUrl(urlPart, this.options.url)
|
|
3365
3421
|
|
|
3366
3422
|
return this.page
|
|
3367
3423
|
.waitForFunction(
|
|
@@ -3369,13 +3425,13 @@ class Playwright extends Helper {
|
|
|
3369
3425
|
const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
|
|
3370
3426
|
return currUrl.indexOf(urlPart) > -1
|
|
3371
3427
|
},
|
|
3372
|
-
|
|
3428
|
+
expectedUrl,
|
|
3373
3429
|
{ timeout: waitTimeout },
|
|
3374
3430
|
)
|
|
3375
3431
|
.catch(async e => {
|
|
3376
|
-
const currUrl = await this._getPageUrl()
|
|
3432
|
+
const currUrl = await this._getPageUrl()
|
|
3377
3433
|
if (/Timeout/i.test(e.message)) {
|
|
3378
|
-
throw new Error(`expected url to include ${
|
|
3434
|
+
throw new Error(`expected url to include ${expectedUrl}, but found ${currUrl}`)
|
|
3379
3435
|
} else {
|
|
3380
3436
|
throw e
|
|
3381
3437
|
}
|
|
@@ -3387,26 +3443,46 @@ class Playwright extends Helper {
|
|
|
3387
3443
|
*/
|
|
3388
3444
|
async waitUrlEquals(urlPart, sec = null) {
|
|
3389
3445
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
3390
|
-
|
|
3391
|
-
const baseUrl = this.options.url
|
|
3392
|
-
let expectedUrl = urlPart
|
|
3393
|
-
if (urlPart.indexOf('http') < 0) {
|
|
3394
|
-
expectedUrl = baseUrl + urlPart
|
|
3395
|
-
}
|
|
3446
|
+
const expectedUrl = resolveUrl(urlPart, this.options.url)
|
|
3396
3447
|
|
|
3397
3448
|
try {
|
|
3398
3449
|
await this.page.waitForURL(
|
|
3399
|
-
url => url.href
|
|
3450
|
+
url => url.href === expectedUrl,
|
|
3400
3451
|
{ timeout: waitTimeout },
|
|
3401
3452
|
)
|
|
3402
3453
|
} catch (e) {
|
|
3403
3454
|
const currUrl = await this._getPageUrl()
|
|
3404
3455
|
if (/Timeout/i.test(e.message)) {
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3456
|
+
throw new Error(`expected url to be ${expectedUrl}, but found ${currUrl}`)
|
|
3457
|
+
} else {
|
|
3458
|
+
throw e
|
|
3459
|
+
}
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
/**
|
|
3464
|
+
* {{> waitCurrentPathEquals }}
|
|
3465
|
+
*/
|
|
3466
|
+
async waitCurrentPathEquals(path, sec = null) {
|
|
3467
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
|
|
3468
|
+
const normalizedPath = normalizePath(path)
|
|
3469
|
+
|
|
3470
|
+
try {
|
|
3471
|
+
await this.page.waitForFunction(
|
|
3472
|
+
expectedPath => {
|
|
3473
|
+
const actualPath = window.location.pathname
|
|
3474
|
+
const normalizePath = p => (p === '' || p === '/' ? '/' : p.replace(/\/+/g, '/').replace(/\/$/, '') || '/')
|
|
3475
|
+
return normalizePath(actualPath) === expectedPath
|
|
3476
|
+
},
|
|
3477
|
+
normalizedPath,
|
|
3478
|
+
{ timeout: waitTimeout },
|
|
3479
|
+
)
|
|
3480
|
+
} catch (e) {
|
|
3481
|
+
const currentUrl = await this._getPageUrl()
|
|
3482
|
+
const baseUrl = this.options.url || 'http://localhost'
|
|
3483
|
+
const actualPath = new URL(currentUrl, baseUrl).pathname
|
|
3484
|
+
if (/Timeout/i.test(e.message)) {
|
|
3485
|
+
throw new Error(`expected path to be ${normalizedPath}, but found ${normalizePath(actualPath)}`)
|
|
3410
3486
|
} else {
|
|
3411
3487
|
throw e
|
|
3412
3488
|
}
|
|
@@ -4092,9 +4168,15 @@ class Playwright extends Helper {
|
|
|
4092
4168
|
|
|
4093
4169
|
export default Playwright
|
|
4094
4170
|
|
|
4095
|
-
function buildLocatorString(locator) {
|
|
4171
|
+
export function buildLocatorString(locator) {
|
|
4096
4172
|
if (locator.isXPath()) {
|
|
4097
|
-
|
|
4173
|
+
// Make XPath relative so it works correctly within scoped contexts (e.g. within()).
|
|
4174
|
+
// Playwright's XPath engine auto-converts "//..." to ".//..." when the root is not a Document,
|
|
4175
|
+
// but only when the selector starts with "/". Locator methods like at() wrap XPath in
|
|
4176
|
+
// parentheses (e.g. "(//...)[position()=1]"), bypassing that auto-conversion.
|
|
4177
|
+
// We fix this by prepending "." before the first "//" that follows any leading parentheses.
|
|
4178
|
+
const value = locator.value.replace(/^(\(*)\/\//, '$1.//')
|
|
4179
|
+
return `xpath=${value}`
|
|
4098
4180
|
}
|
|
4099
4181
|
if (locator.isShadow()) {
|
|
4100
4182
|
// Convert shadow locator to CSS with >> chaining operator
|
|
@@ -4335,34 +4417,45 @@ async function proceedIsChecked(assertType, option) {
|
|
|
4335
4417
|
return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
|
|
4336
4418
|
}
|
|
4337
4419
|
|
|
4338
|
-
async function findFields(locator) {
|
|
4420
|
+
async function findFields(locator, context = null) {
|
|
4421
|
+
let contextEl
|
|
4422
|
+
if (context) {
|
|
4423
|
+
const contextEls = await this._locate(context)
|
|
4424
|
+
assertElementExists(contextEls, context, 'Context element')
|
|
4425
|
+
contextEl = contextEls[0]
|
|
4426
|
+
}
|
|
4427
|
+
|
|
4428
|
+
const locateFn = contextEl
|
|
4429
|
+
? loc => findElements.call(this, contextEl, loc)
|
|
4430
|
+
: loc => this._locate(loc)
|
|
4431
|
+
|
|
4339
4432
|
// Handle role locators with text/exact options
|
|
4340
4433
|
if (isRoleLocatorObject(locator)) {
|
|
4341
|
-
const
|
|
4342
|
-
const roleElements = await handleRoleLocator(
|
|
4434
|
+
const matcher = contextEl || (await this.page)
|
|
4435
|
+
const roleElements = await handleRoleLocator(matcher, locator)
|
|
4343
4436
|
if (roleElements) return roleElements
|
|
4344
4437
|
}
|
|
4345
4438
|
|
|
4346
4439
|
const matchedLocator = new Locator(locator)
|
|
4347
4440
|
if (!matchedLocator.isFuzzy()) {
|
|
4348
|
-
return
|
|
4441
|
+
return locateFn(matchedLocator)
|
|
4349
4442
|
}
|
|
4350
4443
|
const literal = xpathLocator.literal(locator)
|
|
4351
4444
|
|
|
4352
|
-
let els = await
|
|
4445
|
+
let els = await locateFn({ xpath: Locator.field.labelEquals(literal) })
|
|
4353
4446
|
if (els.length) {
|
|
4354
4447
|
return els
|
|
4355
4448
|
}
|
|
4356
4449
|
|
|
4357
|
-
els = await
|
|
4450
|
+
els = await locateFn({ xpath: Locator.field.labelContains(literal) })
|
|
4358
4451
|
if (els.length) {
|
|
4359
4452
|
return els
|
|
4360
4453
|
}
|
|
4361
|
-
els = await
|
|
4454
|
+
els = await locateFn({ xpath: Locator.field.byName(literal) })
|
|
4362
4455
|
if (els.length) {
|
|
4363
4456
|
return els
|
|
4364
4457
|
}
|
|
4365
|
-
return
|
|
4458
|
+
return locateFn({ css: locator })
|
|
4366
4459
|
}
|
|
4367
4460
|
|
|
4368
4461
|
async function proceedSelect(context, el, option) {
|
|
@@ -4411,8 +4504,8 @@ async function proceedSelect(context, el, option) {
|
|
|
4411
4504
|
return this._waitForAction()
|
|
4412
4505
|
}
|
|
4413
4506
|
|
|
4414
|
-
async function proceedSeeInField(assertType, field, value) {
|
|
4415
|
-
const els = await findFields.call(this, field)
|
|
4507
|
+
async function proceedSeeInField(assertType, field, value, context) {
|
|
4508
|
+
const els = await findFields.call(this, field, context)
|
|
4416
4509
|
assertElementExists(els, field, 'Field')
|
|
4417
4510
|
const el = els[0]
|
|
4418
4511
|
const tag = await el.evaluate(e => e.tagName)
|