diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index f393a4d0d..f849bdb04 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -37,7 +37,7 @@ jobs: env: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true - name: Install deps - run: npx playwright install-deps + run: npm install playwright@1.32.3 & npx playwright install-deps - name: start a server run: "php -S 127.0.0.1:8000 -t test/data/app &" - name: run chromium tests diff --git a/docs/helpers/Appium.md b/docs/helpers/Appium.md index 134cd93f9..4dbc724fd 100644 --- a/docs/helpers/Appium.md +++ b/docs/helpers/Appium.md @@ -25,7 +25,6 @@ Launch the daemon: `appium` This helper should be configured in codecept.conf.ts or codecept.conf.js -- `appiumV2`: set this to true if you want to run with Appiumv2 - `app`: Application path. Local path or remote URL to an .ipa or .apk file, or a .zip containing one of these. Alias to desiredCapabilities.appPackage - `host`: (default: 'localhost') Appium host - `port`: (default: '4723') Appium port diff --git a/docs/helpers/Playwright.md b/docs/helpers/Playwright.md index 20cc6a474..2a6a6bf41 100644 --- a/docs/helpers/Playwright.md +++ b/docs/helpers/Playwright.md @@ -41,40 +41,40 @@ Type: [object][5] - `url` **[string][8]** base url of website to be tested - `browser` **(`"chromium"` | `"firefox"` | `"webkit"` | `"electron"`)?** a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium. -- `show` **[boolean][26]?** show browser window. -- `restart` **([string][8] | [boolean][26])?** restart strategy between tests. Possible values:- 'context' or **false** - restarts [browser context][33] but keeps running browser. Recommended by Playwright team to keep tests isolated. +- `show` **[boolean][30]?** show browser window. +- `restart` **([string][8] | [boolean][30])?** restart strategy between tests. Possible values:- 'context' or **false** - restarts [browser context][37] but keeps running browser. Recommended by Playwright team to keep tests isolated. - 'browser' or **true** - closes browser and opens it again between tests. - 'session' or 'keep' - keeps browser context and session, but cleans up cookies and localStorage between tests. The fastest option when running tests in windowed mode. Works with `keepCookies` and `keepBrowserState` options. This behavior was default before CodeceptJS 3.1 -- `timeout` **[number][12]?** - [timeout][34] in ms of all Playwright actions . -- `disableScreenshots` **[boolean][26]?** don't save screenshot on failure. +- `timeout` **[number][14]?** - [timeout][38] in ms of all Playwright actions . +- `disableScreenshots` **[boolean][30]?** don't save screenshot on failure. - `emulate` **any?** browser in device emulation mode. -- `video` **[boolean][26]?** enables video recording for failed tests; videos are saved into `output/videos` folder -- `keepVideoForPassedTests` **[boolean][26]?** save videos for passed tests; videos are saved into `output/videos` folder -- `trace` **[boolean][26]?** record [tracing information][35] with screenshots and snapshots. -- `keepTraceForPassedTests` **[boolean][26]?** save trace for passed tests. -- `fullPageScreenshots` **[boolean][26]?** make full page screenshots on failure. -- `uniqueScreenshotNames` **[boolean][26]?** option to prevent screenshot override if you have scenarios with the same name in different suites. -- `keepBrowserState` **[boolean][26]?** keep browser state between tests when `restart` is set to 'session'. -- `keepCookies` **[boolean][26]?** keep cookies between tests when `restart` is set to 'session'. -- `waitForAction` **[number][12]?** how long to wait after click, doubleClick or PressKey actions in ms. Default: 100. -- `waitForNavigation` **(`"load"` | `"domcontentloaded"` | `"networkidle"`)?** When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API][36]. -- `pressKeyDelay` **[number][12]?** Delay between key presses in ms. Used when calling Playwrights page.type(...) in fillField/appendField -- `getPageTimeout` **[number][12]?** config option to set maximum navigation time in milliseconds. -- `waitForTimeout` **[number][12]?** default wait* timeout in ms. Default: 1000. +- `video` **[boolean][30]?** enables video recording for failed tests; videos are saved into `output/videos` folder +- `keepVideoForPassedTests` **[boolean][30]?** save videos for passed tests; videos are saved into `output/videos` folder +- `trace` **[boolean][30]?** record [tracing information][39] with screenshots and snapshots. +- `keepTraceForPassedTests` **[boolean][30]?** save trace for passed tests. +- `fullPageScreenshots` **[boolean][30]?** make full page screenshots on failure. +- `uniqueScreenshotNames` **[boolean][30]?** option to prevent screenshot override if you have scenarios with the same name in different suites. +- `keepBrowserState` **[boolean][30]?** keep browser state between tests when `restart` is set to 'session'. +- `keepCookies` **[boolean][30]?** keep cookies between tests when `restart` is set to 'session'. +- `waitForAction` **[number][14]?** how long to wait after click, doubleClick or PressKey actions in ms. Default: 100. +- `waitForNavigation` **(`"load"` | `"domcontentloaded"` | `"networkidle"`)?** When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API][40]. +- `pressKeyDelay` **[number][14]?** Delay between key presses in ms. Used when calling Playwrights page.type(...) in fillField/appendField +- `getPageTimeout` **[number][14]?** config option to set maximum navigation time in milliseconds. +- `waitForTimeout` **[number][14]?** default wait* timeout in ms. Default: 1000. - `basicAuth` **[object][5]?** the basic authentication to pass to base url. Example: {username: 'username', password: 'password'} - `windowSize` **[string][8]?** default window size. Set a dimension like `640x480`. - `colorScheme` **(`"dark"` | `"light"` | `"no-preference"`)?** default color scheme. Possible values: `dark` | `light` | `no-preference`. - `userAgent` **[string][8]?** user-agent string. - `locale` **[string][8]?** locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ... -- `manualStart` **[boolean][26]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`. +- `manualStart` **[boolean][30]?** do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`. - `chromium` **[object][5]?** pass additional chromium options - `firefox` **[object][5]?** pass additional firefox options - `electron` **[object][5]?** (pass additional electron options -- `channel` **any?** (While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge][37]. -- `ignoreLog` **[Array][15]<[string][8]>?** An array with console message types that are not logged to debug log. Default value is `['warning', 'log']`. E.g. you can set `[]` to log all messages. See all possible [values][38]. -- `ignoreHTTPSErrors` **[boolean][26]?** Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false` -- `bypassCSP` **[boolean][26]?** bypass Content Security Policy or CSP -- `highlightElement` **[boolean][26]?** highlight the interacting elements +- `channel` **any?** (While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge][41]. +- `ignoreLog` **[Array][19]<[string][8]>?** An array with console message types that are not logged to debug log. Default value is `['warning', 'log']`. E.g. you can set `[]` to log all messages. See all possible [values][42]. +- `ignoreHTTPSErrors` **[boolean][30]?** Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false` +- `bypassCSP` **[boolean][30]?** bypass Content Security Policy or CSP +- `highlightElement` **[boolean][30]?** highlight the interacting elements @@ -406,6 +406,23 @@ I.attachFile('form input[name=avatar]', 'data/avatar.jpg'); - `pathToFile` **[string][8]** local file path relative to codecept.conf.ts or codecept.conf.js config file. ⚠️ returns a _promise_ which is synchronized internally by recorder +### blur + +Remove focus from a text input, button, etc +Calls [blur][9] on the element. + +#### Parameters + +- `locator` **([string][8] | [object][5])** field located by label|name|CSS|XPath|strict locator. +- `options` **any?** [Additional options][9] for available options object as 2nd argument.Examples:```js + I.blur('.text-area') + ``````js + //element `#product-tile` is focused + I.see('#add-to-cart-btn'); + I.blur('#product-tile') + I.dontSee('#add-to-cart-btn'); + ``` + ### cancelPopup Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt. @@ -427,7 +444,7 @@ I.checkOption('agree', '//form'); - `field` **([string][8] | [object][5])** checkbox located by label | name | CSS | XPath | strict locator. - `context` **([string][8]? | [object][5])** (optional, `null` by default) element located by CSS | XPath | strict locator. - ⚠️ returns a _promise_ which is synchronized internally by recorder[Additional options][9] for check available as 3rd argument.Examples:```js + ⚠️ returns a _promise_ which is synchronized internally by recorder[Additional options][10] for check available as 3rd argument.Examples:```js // click on element at position I.checkOption('Agree', '.signup', { position: { x: 5, y: 5 } }) ```> ⚠️ To avoid flakiness, option `force: true` is set by default @@ -450,19 +467,16 @@ I.clearCookie('test'); ### clearField -Clears a ` +Textarea not focused + + + + + diff --git a/test/helper/Playwright_test.js b/test/helper/Playwright_test.js index 9e274c9d5..b4f0d56ac 100644 --- a/test/helper/Playwright_test.js +++ b/test/helper/Playwright_test.js @@ -184,6 +184,43 @@ describe('Playwright', function () { .then(() => I.dontSee('Hovered', '#show'))); }); + describe('#focus, #blur', () => { + it('should focus a button, field and textarea', async () => { + await I.amOnPage('/form/focus_blur_elements'); + + await I.focus('#button'); + await I.see('Button is focused', '#buttonMessage'); + + await I.focus('#field'); + await I.see('Button not focused', '#buttonMessage'); + await I.see('Input field is focused', '#fieldMessage'); + + await I.focus('#textarea'); + await I.see('Button not focused', '#buttonMessage'); + await I.see('Input field not focused', '#fieldMessage'); + await I.see('Textarea is focused', '#textareaMessage'); + }); + + it('should blur focused button, field and textarea', async () => { + await I.amOnPage('/form/focus_blur_elements'); + + await I.focus('#button'); + await I.see('Button is focused', '#buttonMessage'); + await I.blur('#button'); + await I.see('Button not focused', '#buttonMessage'); + + await I.focus('#field'); + await I.see('Input field is focused', '#fieldMessage'); + await I.blur('#field'); + await I.see('Input field not focused', '#fieldMessage'); + + await I.focus('#textarea'); + await I.see('Textarea is focused', '#textareaMessage'); + await I.blur('#textarea'); + await I.see('Textarea not focused', '#textareaMessage'); + }); + }); + describe('#switchToNextTab, #switchToPreviousTab, #openNewTab, #closeCurrentTab, #closeOtherTabs, #grabNumberOfOpenTabs', () => { it('should only have 1 tab open when the browser starts and navigates to the first page', () => I.amOnPage('/') .then(() => I.wait(1)) @@ -454,6 +491,35 @@ describe('Playwright', function () { }); }); + describe('#clearField', () => { + it('should clear input', async () => { + await I.amOnPage('/form/field'); + await I.fillField('Name', 'value that is cleared using I.clearField()'); + await I.clearField('Name'); + await I.dontSeeInField('Name', 'value that is cleared using I.clearField()'); + }); + + it('should clear textarea', async () => { + await I.amOnPage('/form/textarea'); + await I.fillField('#description', 'value that is cleared using I.clearField()'); + await I.clearField('#description'); + await I.dontSeeInField('#description', 'value that is cleared using I.clearField()'); + }); + + it('should clear contenteditable', async () => { + const isClearMethodPresent = await I.usePlaywrightTo('check if new Playwright .clear() method present', async ({ page }) => { + return typeof page.locator().clear === 'function'; + }); + if (!isClearMethodPresent) { + this.skip(); + } + + await I.amOnPage('/form/contenteditable'); + await I.clearField('#contenteditableDiv'); + await I.dontSee('This is editable. Click here to edit this text.', '#contenteditableDiv'); + }); + }); + describe('#pressKey, #pressKeyDown, #pressKeyUp', () => { it('should be able to send special keys to element', async () => { await I.amOnPage('/form/field'); diff --git a/typings/tests/helpers/Playwright.types.ts b/typings/tests/helpers/Playwright.types.ts index 5cfbb30c3..f1c58de10 100644 --- a/typings/tests/helpers/Playwright.types.ts +++ b/typings/tests/helpers/Playwright.types.ts @@ -58,6 +58,8 @@ playwright.click(str, str); // $ExpectType void playwright.click(str, null, { position }); // $ExpectType void playwright.clickLink(); // $ExpectType void playwright.forceClick(str); // $ExpectType void +playwright.focus(str); // $ExpectType void +playwright.blur(str); // $ExpectType void playwright.doubleClick(str); // $ExpectType void playwright.rightClick(str); // $ExpectType void playwright.checkOption(str); // $ExpectType void diff --git a/typings/tests/helpers/PlaywrightTs.types.ts b/typings/tests/helpers/PlaywrightTs.types.ts index 22a512129..4bc003391 100644 --- a/typings/tests/helpers/PlaywrightTs.types.ts +++ b/typings/tests/helpers/PlaywrightTs.types.ts @@ -54,6 +54,8 @@ playwright.click(str, str); // $ExpectType Promise playwright.click(str, null, { position }); // $ExpectType Promise playwright.clickLink(); // $ExpectType Promise playwright.forceClick(str); // $ExpectType Promise +playwright.focus(str); // $ExpectType Promise +playwright.blur(str); // $ExpectType Promise playwright.doubleClick(str); // $ExpectType Promise playwright.rightClick(str); // $ExpectType Promise playwright.checkOption(str); // $ExpectType Promise