Skip to content

Commit 03943c1

Browse files
authored
feat(playwright): wait for disabled (#4412)
1 parent 7769c02 commit 03943c1

File tree

6 files changed

+87
-5
lines changed

6 files changed

+87
-5
lines changed

docs/helpers/Playwright.md

+12
Original file line numberDiff line numberDiff line change
@@ -2444,6 +2444,18 @@ I.waitForDetached('#popup');
24442444

24452445
Returns **void** automatically synchronized promise through #recorder
24462446

2447+
### waitForDisabled
2448+
2449+
Waits for element to become disabled (by default waits for 1sec).
2450+
Element can be located by CSS or XPath.
2451+
2452+
#### Parameters
2453+
2454+
- `locator` **([string][9] | [object][6])** element located by CSS|XPath|strict locator.
2455+
- `sec` **[number][20]** (optional) time in seconds to wait, 1 by default.
2456+
2457+
Returns **void** automatically synchronized promise through #recorder
2458+
24472459
### waitForElement
24482460

24492461
Waits for element to be present on page (by default waits for 1sec).

docs/webapi/waitForDisabled.mustache

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Waits for element to become disabled (by default waits for 1sec).
2+
Element can be located by CSS or XPath.
3+
4+
@param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
5+
@param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
6+
@returns {void} automatically synchronized promise through #recorder

lib/helper/Playwright.js

+29-1
Original file line numberDiff line numberDiff line change
@@ -2476,7 +2476,7 @@ class Playwright extends Helper {
24762476
async waitForEnabled(locator, sec) {
24772477
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
24782478
locator = new Locator(locator, 'css')
2479-
const matcher = await this.context
2479+
24802480
let waiter
24812481
const context = await this._getContext()
24822482
if (!locator.isXPath()) {
@@ -2498,6 +2498,34 @@ class Playwright extends Helper {
24982498
})
24992499
}
25002500

2501+
/**
2502+
* {{> waitForDisabled }}
2503+
*/
2504+
async waitForDisabled(locator, sec) {
2505+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2506+
locator = new Locator(locator, 'css')
2507+
2508+
let waiter
2509+
const context = await this._getContext()
2510+
if (!locator.isXPath()) {
2511+
const valueFn = function ([locator]) {
2512+
return Array.from(document.querySelectorAll(locator)).filter((el) => el.disabled).length > 0
2513+
}
2514+
waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout })
2515+
} else {
2516+
const disabledFn = function ([locator, $XPath]) {
2517+
eval($XPath) // eslint-disable-line no-eval
2518+
return $XPath(null, locator).filter((el) => el.disabled).length > 0
2519+
}
2520+
waiter = context.waitForFunction(disabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout })
2521+
}
2522+
return waiter.catch((err) => {
2523+
throw new Error(
2524+
`element (${locator.toString()}) is still enabled after ${waitTimeout / 1000} sec\n${err.message}`,
2525+
)
2526+
})
2527+
}
2528+
25012529
/**
25022530
* {{> waitForValue }}
25032531
*/

lib/helper/REST.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ class REST extends Helper {
206206
: this.debugSection('Request', JSON.stringify(_debugRequest))
207207

208208
if (this.options.printCurl) {
209-
this.debugSection('CURL Request', curlize(request));
209+
this.debugSection('CURL Request', curlize(request))
210210
}
211211

212212
let response
@@ -393,8 +393,13 @@ class REST extends Helper {
393393
module.exports = REST
394394

395395
function curlize(request) {
396-
if (request.data?.constructor.name.toLowerCase() === 'formdata') return 'cURL is not printed as the request body is not a JSON'
397-
let curl = `curl --location --request ${request.method ? request.method.toUpperCase() : 'GET'} ${request.baseURL} `.replace("'", '')
396+
if (request.data?.constructor.name.toLowerCase() === 'formdata')
397+
return 'cURL is not printed as the request body is not a JSON'
398+
let curl =
399+
`curl --location --request ${request.method ? request.method.toUpperCase() : 'GET'} ${request.baseURL} `.replace(
400+
"'",
401+
'',
402+
)
398403

399404
if (request.headers) {
400405
Object.entries(request.headers).forEach(([key, value]) => {
@@ -411,4 +416,3 @@ function curlize(request) {
411416
}
412417
return curl
413418
}
414-
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<html>
2+
<body>
3+
4+
<input id="text" type="text" name="test" disabled="true" value="some text">
5+
6+
<button id="button" type="button" name="button1" disabled="true" value="first" onclick="updateMessage('button was clicked')">A Button</button>
7+
8+
<div id="message"></div>
9+
10+
<script>
11+
setTimeout(function () {
12+
document.querySelector('#text').disabled = false;
13+
document.querySelector('#button').disabled = false;
14+
}, 2000);
15+
16+
function updateMessage(msg) {
17+
document.querySelector('#message').textContent = msg;
18+
}
19+
</script>
20+
</body>
21+
</html>

test/helper/Playwright_test.js

+11
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,17 @@ describe('Playwright', function () {
731731
.then(() => I.see('button was clicked', '#message')))
732732
})
733733

734+
describe('#waitForDisabled', () => {
735+
it('should wait for input text field to be disabled', () =>
736+
I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1)))
737+
738+
it('should wait for input text field to be enabled by xpath', () =>
739+
I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled("//*[@name = 'test']", 1)))
740+
741+
it('should wait for a button to be disabled', () =>
742+
I.amOnPage('/form/wait_disabled').then(() => I.waitForDisabled('#text', 1)))
743+
})
744+
734745
describe('#waitForValue', () => {
735746
it('should wait for expected value for given locator', () =>
736747
I.amOnPage('/info')

0 commit comments

Comments
 (0)