Skip to content

Commit 3f7d2bd

Browse files
DavertMikDavertMikclaude
authored
feat: add context parameter to appendField, clearField, attachFile (#5479)
* feat: add context parameter to appendField, clearField, attachFile Add optional context parameter to remaining form-filling methods (appendField, clearField, attachFile) across Playwright, Puppeteer, and WebDriver helpers for consistency with fillField, selectOption, checkOption, and uncheckOption which already support it. This allows scoping element search to a specific DOM container: I.appendField('Name', 'jon', '.form-container') I.clearField('Name', '.form-container') I.attachFile('Avatar', 'data/avatar.jpg', '.form-container') Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add tests for context parameter on appendField, clearField, attachFile Add shared webapi tests verifying that context scoping works for appendField, clearField, and attachFile. Extended the context.php test page with pre-filled values and file inputs to support the tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: simplify Playwright clearField signature to match other helpers Remove unused `options` parameter from Playwright's clearField. The options were accepted but never passed to the underlying clear() call. Now all helpers have consistent `clearField(locator, context)` signature. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add context parameter to appendField, attachFile, clearField docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: clarify context parameter is optional in all form method docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add context parameter to seeInField and dontSeeInField Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: pass context string (not locateFn) to findFields in WebDriver proceedSeeField proceedSeeField was double-wrapping context through prepareLocateFn before passing to findFields, which already handles context internally. This caused "locator.replace is not a function" errors in 37 WebDriver tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: DavertMik <davert@testomat.io> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c6a63d4 commit 3f7d2bd

File tree

14 files changed

+109
-57
lines changed

14 files changed

+109
-57
lines changed

docs/webapi/appendField.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
Appends text to a input field or textarea.
22
Field is located by name, label, CSS or XPath
33

4+
The third parameter is an optional context (CSS or XPath locator) to narrow the search.
5+
46
```js
57
I.appendField('#myTextField', 'appended');
68
// typing secret
79
I.appendField('password', secret('123456'));
10+
// within a context
11+
I.appendField('name', 'John', '.form-container');
812
```
913
@param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator
1014
@param {string} value text value to append.
15+
@param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
1116
@returns {void} automatically synchronized promise through #recorder

docs/webapi/attachFile.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ Attaches a file to element located by label, name, CSS or XPath
22
Path to file is relative current codecept directory (where codecept.conf.ts or codecept.conf.js is located).
33
File will be uploaded to remote system (if tests are running remotely).
44

5+
The third parameter is an optional context (CSS or XPath locator) to narrow the search.
6+
57
```js
68
I.attachFile('Avatar', 'data/avatar.jpg');
79
I.attachFile('form input[name=avatar]', 'data/avatar.jpg');
10+
// within a context
11+
I.attachFile('Avatar', 'data/avatar.jpg', '.form-container');
812
```
913

1014
@param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
1115
@param {string} pathToFile local file path relative to codecept.conf.ts or codecept.conf.js config file.
16+
@param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
1217
@returns {void} automatically synchronized promise through #recorder

docs/webapi/checkOption.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Selects a checkbox or radio button.
22
Element is located by label or name or CSS or XPath.
33

4-
The second parameter is a context (CSS or XPath locator) to narrow the search.
4+
The second parameter is an optional context (CSS or XPath locator) to narrow the search.
55

66
```js
77
I.checkOption('#agree');

docs/webapi/clearField.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
Clears a `<textarea>` or text `<input>` element's value.
22

3+
The second parameter is an optional context (CSS or XPath locator) to narrow the search.
4+
35
```js
46
I.clearField('Email');
57
I.clearField('user[email]');
68
I.clearField('#email');
9+
// within a context
10+
I.clearField('Email', '.form-container');
711
```
812
@param {LocatorOrString} editable field located by label|name|CSS|XPath|strict locator.
13+
@param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
914
@returns {void} automatically synchronized promise through #recorder.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
Checks that value of input field or textarea doesn't equal to given value
22
Opposite to `seeInField`.
33

4+
The third parameter is an optional context (CSS or XPath locator) to narrow the search.
5+
46
```js
57
I.dontSeeInField('email', 'user@user.com'); // field by name
68
I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS
9+
// within a context
10+
I.dontSeeInField('Name', 'old_value', '.form-container');
711
```
812

913
@param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1014
@param {CodeceptJS.StringOrSecret} value value to check.
15+
@param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
1116
@returns {void} automatically synchronized promise through #recorder

docs/webapi/fillField.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Fills a text field or textarea, after clearing its value, with the given string.
22
Field is located by name, label, CSS, or XPath.
33

4-
The third parameter is a context (CSS or XPath locator) to narrow the search.
4+
The third parameter is an optional context (CSS or XPath locator) to narrow the search.
55

66
```js
77
// by label

docs/webapi/seeInField.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
Checks that the given input field or textarea equals to given value.
22
For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath.
33

4+
The third parameter is an optional context (CSS or XPath locator) to narrow the search.
5+
46
```js
57
I.seeInField('Username', 'davert');
68
I.seeInField({css: 'form textarea'},'Type your comment here');
79
I.seeInField('form input[type=hidden]','hidden_value');
810
I.seeInField('#searchform input','Search');
11+
// within a context
12+
I.seeInField('Name', 'John', '.form-container');
913
```
1014
@param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1115
@param {CodeceptJS.StringOrSecret} value value to check.
16+
@param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
1217
@returns {void} automatically synchronized promise through #recorder

docs/webapi/selectOption.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Selects an option in a drop-down select.
22
Field is searched by label | name | CSS | XPath.
33
Option is selected by visible text or by value.
44

5-
The third parameter is a context (CSS or XPath locator) to narrow the search.
5+
The third parameter is an optional context (CSS or XPath locator) to narrow the search.
66

77
```js
88
I.selectOption('Choose Plan', 'Monthly'); // select by label

docs/webapi/uncheckOption.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Unselects a checkbox or radio button.
22
Element is located by label or name or CSS or XPath.
33

4-
The second parameter is a context (CSS or XPath locator) to narrow the search.
4+
The second parameter is an optional context (CSS or XPath locator) to narrow the search.
55

66
```js
77
I.uncheckOption('#agree');

lib/helper/Playwright.js

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,24 +2278,10 @@ class Playwright extends Helper {
22782278
}
22792279

22802280
/**
2281-
* Clears the text input element: `<input>`, `<textarea>` or `[contenteditable]` .
2282-
*
2283-
*
2284-
* Examples:
2285-
*
2286-
* ```js
2287-
* I.clearField('.text-area')
2288-
*
2289-
* // if this doesn't work use force option
2290-
* I.clearField('#submit', { force: true })
2291-
* ```
2292-
* Use `force` to bypass the [actionability](https://playwright.dev/docs/actionability) checks.
2293-
*
2294-
* @param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
2295-
* @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-locator#locator-clear) for available options object as 2nd argument.
2281+
* {{> clearField }}
22962282
*/
2297-
async clearField(locator, options = {}) {
2298-
const els = await findFields.call(this, locator)
2283+
async clearField(locator, context = null) {
2284+
const els = await findFields.call(this, locator, context)
22992285
assertElementExists(els, locator, 'Field to clear')
23002286
if (this.options.strict) assertOnlyOneElement(els, locator)
23012287

@@ -2311,8 +2297,8 @@ class Playwright extends Helper {
23112297
/**
23122298
* {{> appendField }}
23132299
*/
2314-
async appendField(field, value) {
2315-
const els = await findFields.call(this, field)
2300+
async appendField(field, value, context = null) {
2301+
const els = await findFields.call(this, field, context)
23162302
assertElementExists(els, field, 'Field')
23172303
if (this.options.strict) assertOnlyOneElement(els, field)
23182304
await highlightActiveElement.call(this, els[0])
@@ -2324,30 +2310,30 @@ class Playwright extends Helper {
23242310
/**
23252311
* {{> seeInField }}
23262312
*/
2327-
async seeInField(field, value) {
2313+
async seeInField(field, value, context = null) {
23282314
const _value = typeof value === 'boolean' ? value : value.toString()
2329-
return proceedSeeInField.call(this, 'assert', field, _value)
2315+
return proceedSeeInField.call(this, 'assert', field, _value, context)
23302316
}
23312317

23322318
/**
23332319
* {{> dontSeeInField }}
23342320
*/
2335-
async dontSeeInField(field, value) {
2321+
async dontSeeInField(field, value, context = null) {
23362322
const _value = typeof value === 'boolean' ? value : value.toString()
2337-
return proceedSeeInField.call(this, 'negate', field, _value)
2323+
return proceedSeeInField.call(this, 'negate', field, _value, context)
23382324
}
23392325

23402326
/**
23412327
* {{> attachFile }}
23422328
*
23432329
*/
2344-
async attachFile(locator, pathToFile) {
2330+
async attachFile(locator, pathToFile, context = null) {
23452331
const file = path.join(global.codecept_dir, pathToFile)
23462332

23472333
if (!fileExists(file)) {
23482334
throw new Error(`File at ${file} can not be found on local system`)
23492335
}
2350-
const els = await findFields.call(this, locator)
2336+
const els = await findFields.call(this, locator, context)
23512337
assertElementExists(els, locator, 'Field')
23522338
await els[0].setInputFiles(file)
23532339
return this._waitForAction()
@@ -4493,8 +4479,8 @@ async function proceedSelect(context, el, option) {
44934479
return this._waitForAction()
44944480
}
44954481

4496-
async function proceedSeeInField(assertType, field, value) {
4497-
const els = await findFields.call(this, field)
4482+
async function proceedSeeInField(assertType, field, value, context) {
4483+
const els = await findFields.call(this, field, context)
44984484
assertElementExists(els, field, 'Field')
44994485
const el = els[0]
45004486
const tag = await el.evaluate(e => e.tagName)

0 commit comments

Comments
 (0)