Web Testing

Installation

  1. Copy the below line to dependencies section of the project build.gradle file

    Please make sure to use the same version for all VIVIDUS dependencies.
    Example 1. build.gradle
    implementation(group: 'org.vividus', name: 'vividus-plugin-web-app', version: '0.6.3')
  2. If the project was imported to the IDE before adding new dependency, re-generate the configuration files for the used IDE and then refresh the project in the used IDE.

Profiles

Profiles allow to choose or parameterize browser that tests run on. See more details on the profiles and nesting strategy on the configuration page.

Web-application plugin contains significant number of built-in profiles. They can be found after plugin installation by the following path in Eclipse IDE:

Referenced Libraries -> vividus-plugin-web-app-X.Y.Z -> properties -> profile -> web

Let’s go through the structure and review its content.

Desktop

General place for web profiles. Each of the directory contains browser related properties. This is a place for adjustments for your browser. Add there any properties you need: screen resolution, path to driver or to a custom browser.

Configure driver path

While executing tests on the local machine it is allowed to use custom browser driver. This approach first requires manually downloading the driver (See Quick Reference Section for download links). The path to the downloaded binary should be configured using the following property:

web.driver.<browser>.driver-executable-path=/path/to/driver/executable

where <browser> is one of the following values:

  • chrome

  • firefox

  • safari

  • iexplore

  • edge

  • opera

Configure browser path

While executing tests on the local machine it is allowed to configure path to browser executable file. In general cases it’s not required, installed browsers are found automatically (except Opera browser). Also, for example, if browser is not installed, but only downloaded and unpacked into some folder, the path to the downloaded binary should be configured using the following property:

web.driver.<browser>.binary-path=/path/to/custom/browser/executable

where <browser> is one of the following values:

  • chrome

  • firefox

  • edge

  • opera

List of desktop profiles

Profile Example of properties

web/desktop/chrome

selenium.grid.platform-name=Windows
selenium.grid.platform-version=10
web.driver.chrome.command-line-arguments=--disable-auto-reload

web/desktop/edge

selenium.grid.platform-name=macOS
selenium.grid.platform-version=12.5
selenium.grid.capabilities.browserName=MicrosoftEdge

web/desktop/firefox

selenium.grid.platform-name=Windows
selenium.grid.platform-version=10
web.driver.firefox.command-line-arguments=--turbo

web/desktop/iexplore

selenium.grid.capabilities.browserName=internet explorer
web.driver.iexplore.command-line-arguments=-private
selenium.grid.capabilities.iedriverVersion=3.141.0
selenium.grid.platform-name=Windows
selenium.grid.platform-version=7

web/desktop/opera

selenium.grid.screen-resolution=1920x1080
selenium.grid.platform-name=Windows
selenium.grid.platform-version=10
In order to run tests in Opera browser locally, it is required to configure browser path.

web/desktop/safari

selenium.grid.platform-name=macOS
selenium.grid.platform-version=11.00

Mobile emulation

  1. Built-in devices

    Chrome allows to emulate view on mobile devices using Device mode. Such feature is reflected in mobile_emulation subdirectory in Profiles. Use device-name property to mention target device:

    web.driver.chrome.mobile-emulation.device-name=DEVICE_NAME

    Available for emulation devices you can find in the Dimensions list in chrome.

  2. Custom devices

    In case you need to use Responsive Viewport Mode and set up your own device, update the screen resolution in the following properties:

    web.driver.chrome.mobile-emulation.width=1440
    web.driver.chrome.mobile-emulation.height=900

Headless

Headless mode is a functionality that allows the execution of a full version of the browser while controlling it programmatically. It can be used without dedicated graphics or display, meaning that it runs without its “head”, the Graphical User Interface (GUI). The following profiles running browsers in headless mode are available:

  • web/headless/chrome

  • web/headless/firefox

Docker

The profile can be enabled by adding web/docker to configuration.profiles property. The profile should be used together with the browser profile.

Default selenium grid URL is set to selenium.grid.url=http://localhost:4444/wd/hub. Don’t forget to modify it if your grid is running in a different location.
Example 2. Run chrome in docker container
configuraiton.profiles=web/docker,web/desktop/chrome

Phone

Contains phone related properties, for android and iOS devices.

Profile Example of properties

web/phone/android

selenium.grid.capabilities.platformName=Android
selenium.grid.capabilities.platformVersion=12.0
selenium.grid.capabilities.deviceOrientation=portrait
selenium.grid.capabilities.appiumVersion=2.0.0

web/phone/ios

selenium.grid.capabilities.platformName=iOS
selenium.grid.capabilities.platformVersion=16.2
selenium.grid.capabilities.deviceOrientation=portrait
selenium.grid.capabilities.appiumVersion=2.0.0

Tablet

Similar to the Phone directory, but is designed for tablets properties.

Profile Example of properties

web/tablet

selenium.grid.capabilities.platformName=iOS
selenium.grid.capabilities.platformVersion=14.0
selenium.grid.capabilities.deviceName=iPad
selenium.grid.capabilities.deviceOrientation=landscape
selenium.grid.capabilities.appiumVersion=1.21.1

Locator

Locator Types

Type Description Example

id

id attribute of an element

id(submitForm)

cssSelector

CSS selector to an element

cssSelector(.menu-item)

xPath

xPath to locate an element

xpath(//a)

unnormalizedXPath

xPath to locate an element. Unlike xPath locator this one doesn’t add space normalization and moves handling of spaces up to user

unnormalizedXPath(//li[text()='ID:    testId'])

tagName

name of an element tagName

tagName(a)

className

CSS class name

className(bold)

linkText

text of the link

linkText(Google)

linkUrl

href attribute of the link element

linkUrl(/faq)

linkUrlPart

part of a href attribute of the link element

linkUrlPart(faq)

caseSensitiveText

case sensitive text of an element

caseSensitiveText(Description)

caseInsensitiveText

case insensitive text of an element

caseInsensitiveText(description)

imageSrc

shortcut to a .//img[@src='<value>>']

imgSrc(/images/kote.png)

imageSrcPart

shortcut to a .//img[contains(@src,'<value>>')]']

imgSrcPart(kote.png)

buttonName

elements of type button or input with text or any attribute value

buttonName(submit)

fieldName

input or textarea with text or any attribute value

fieldName(editor)

radioButton

input element with @type="radio" and label text value

radioButton(One)

checkboxName

input element with @type="checkbox" and text value

checkboxName(allow)

elementName

any attribute or text value

elementName(OK)

shadowCssSelector

chain of css selectors, separated by ;, where first value - selector for upper shadow host, last value - target element selector

shadowCssSelector(.upperHost; #innerHost1; #innerHost2; .targetValue)

Visibility types

Visibility type Usage example Description

VISIBLE

xpath(//a)

Default visibility option. Only visible elements will be found

INVISIBLE

xpath(//a):i

Only invisible elements will be found

all

xpath(//a):a

Either visible and invisible elements will be found

Filter types

The filters are applied after elements search using one of the locators specified above. The elements not matching the filter condition are sorted out without any notice.

Filter type Description Example

index

Get an element by the specified index from a collection of elements found by a locator. Indexes start from 1.

tagName(div)→filter.index(2)

textPart

Filter elements by their text parts.

tagName(h3)→filter.textPart(Welcome)

attribute

Filter elements by their attribute values

tagName(div)→filter.attribute(class=burger-menu) - div element has the class attribute with burger-menu value tagName(div)→filter.attribute(class) - div element has the class attribute with any value tagName(div)→filter.attribute(class=) - div element has the class attribute with an empty value

state

element State

id(v1)→filter.state(VISIBLE)

caseSensitiveText

element text should match case sensitively

id(v1)→filter.caseSensitiveText(text)

classAttributePart

class attribute should contain part

id(v1)→filter.classAttributePart(clazz)

linkUrl

href attribute of the link element

id(v1)→filter.linkUrl(/url)

linkUrlPart

part of href attribute of the link element

id(v1)→filter.linkUrlPart(/url)

tooltip

title attribute value

id(v1)→filter.tooltip(title)

imageSrcPart

src attribute should contain value

id(v1)→filter.imageSrcPart(part)

placeholder

Placeholder attribute should be equal to a value

id(v1)→filter.placeholder(placeholder-value)

validationIconSource

CSS property background-image should match

id(v1)→filter.validationIconSource(src)

fieldText

field text should match expected value

id(v1)→filter.fieldText(value)

fieldTextPart

field text should contain expected value

id(v1)→filter.fieldTextPart(value)

dropDownText

any of select options should be equal to a value

id(v1)→filter.dropDownText(value)

Steps

For the full list of web-related steps, please see Web Application plugin documentation.

Page steps

Open main application page

Loading the page which was associated with the main application page.

Main page can be set by the property web-application.main-page-url in the property file.

Given I am on main application page
Example 3. Open page defined in the web-application.main-page-url variable
Given I am on main application page

Open a page with defined URL

Loading the page with a given absolute URL, e.g. https://example.com/.

Given I am on page with URL `$pageURL`
Example 4. Open 'https://docs.vividus.dev/' page
Given I am on page with URL `https://docs.vividus.dev/`

Open page with relative URL

Navigates the browser to the specific path in the current host defined in the relative URL step parameter.

A relative URL can point to a file within a web site (like about.html or /products).

  • If the parameter starts with '/' char, navigation will be performed from the root of the host, see examples below.

  • If the parameter starts without '/' char or with './', navigation will be performed from the current path directory.

Table 1. Examples
Current page Relative URL parameter Opened page

https://mysite.com

about.html

https://mysite.com/about.html

https://mysite.com

/products/new

https://mysite.com/products/new

https://mysite.com/path/foo

stats

https://mysite.com/path/foo/stats

https://mysite.com/path/foo

./docs/info.html

https://mysite.com/path/foo/docs/info.html

https://mysite.com/path/foo

/documents

https://mysite.com/documents

When I go to relative URL `$relativeURL`
  • relativeURL - A string value of the relative URL.

    1. Open main application page and then navigate to '/products/new' page on the application host

Given I am on main application page
When I go to relative URL `/products/new`

Refresh the page

Refreshes the page: the step does the same as the reload button in the browser.

When I refresh page

Validate the page title

Checks the page title matches to the text according to the provided string validation rule

Then page title $comparisonRule `$text`
  • $comparisonRule - string validation rule. One of:

    • is equal to - title should be equal to text

    • contains - title should contain text

    • does not contain - title should not contain text

  • text - the text of the title to compare

Example 5. Validate 'https://docs.vividus.dev/' page title
Then page title is equal to `What is VIVIDUS :: VIVIDUS`
Example 6. Validate the part of 'https://docs.vividus.dev/' page title
Then page title contains `VIVIDUS`

Click on element

Clicks on the element found by the specified locator.

The atomic actions performed are:

  • find the element by the locator;

  • click on the element if it is found, otherwise the whole step is failed and its execution stops;

  • the first two actions are retried once if the field becomes stale during actions execution in other words if StaleElementReferenceException is occurred at any atomic action.

If element by the specified locator is not clickable (overlapped by another element, problems with page/context loading or the element is disabled) the step will fail with corresponding error:

Could not click on the element: org.openqa.selenium.ElementClickInterceptedException: element click intercepted:
Element <a href="#where-to-buy" data-tab-name="..." role="button">Where to Buy</a> is not clickable at point (1619, 275).
Other element would receive the click: <div class="content">...</div>
When I click on element located by `$locator`
  • $locator - The locator used to find element.

Example 7. Click on element
When I click on element located by `name(Submit)`

Scrolling steps

Scroll context

Scrolls the context to an edge

When I scroll context to $scrollDirection edge
  • $scrollDirection - the direction of the scroll. One of:

    • LEFT - start of a page/element horizontally

    • RIGHT - end of a page/element horizontally

    • TOP - start of a page/element vertically

    • BOTTOM - end of a page/element vertically

If the context is not set, the whole page will be scrolled
Example 8. Scroll login to a bottom
When I change context to element located by `id(login)`
When I scroll context to BOTTOM edge

Scroll element into view

Scrolls an element into the view.

When I scroll element located by `$locator` into view
  • $locator - The locator used to find element.

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I scroll element located `$locator` into view
  • $locator - The locator used to find element.

Example 9. Scroll button into view
When I scroll element located by `id(way_down_button)` into view

Validate the page is scrolled to element

Checks if the page is scrolled to the specific element

Then page is scrolled to element located by `$locator`
  • $locator - The locator used to find element.

Example 10. Validate Contact link is scrolled into view
Then page is scrolled to element located by `xpath(//a[text()="Contact"])`

Text validation steps

Validate the text exists

Validates that the text is presented in the current context. Expected text is case sensitive.

The context can be set by the corresponding steps. If no context is set, the text will be searched on the whole page.

Then text `$text` exists
  • $text - Expected text.

Example 11. Check the text 'Contract Us' is presented on the page
Given I am on page with URL `https://docs.vividus.dev/`
Then text `Contract Us` exists

Validate the text does not exists

Validates that the text is not presented in the current context.

The context can be set by the corresponding steps. If no context is set, the text will be searched on the whole page.

Then text `$text` does not exist
  • $text - Text that should not exist.

Example 12. Check the text 'Deprecated' is not presented in the element
When I change context to element located by `id(code)`
Then text `Deprecated` does not exist

Validate the text matches regex

Validates that the text from current context matches the specified regular expression.

The context can be set by the corresponding steps. If no context is set, the text will be searched on the whole page.

Then text matches `$regex`

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

Then the text matches '$regex'
Example 13. Check the text with pattern 'User ".*" successfully logged in' is presented in the current context
When I change context to element located by `id(code)`
Then text matches `User ".*" successfully logged in`

Tab steps

Open a new tab

Opens a new browser tab and switches the focus for future commands to this tab.

When I open new tab
Example 14. Open page in a new tab
When I open new tab
Given I am on page with URL `https://docs.vividus.dev/`

Open URL in a new tab

Opens a new tab, switches the focus to this tab and loads the given URL.

The key difference of this step from the previous one opening a new tab is that this step inherits the state of the previous page, i.e.:

When I open URL `$URL` in new tab

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I open URL `$URL` in new window
  • $URL - The URL to open.

Example 15. Open docs in a new tab
When I open URL `https://docs.vividus.dev` in new tab

Close current tab

Closes the current tab and switches to the previous tab.

When I close current tab

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I close the current window
Handling alerts displayed with 'onbeforeunload' events is not implied by the WebDriver specification to close window. For handling alerts use step based on JavaScript 'Close current tab with possibility to handle alert'.
This step can only be applied to a session with multiple tabs open.
Example 16. Open URL in new tab, close it and switch to the previous page
Given I am on page with URL `https://example.com/`
When I open URL `https://example.com/contact-us` in new tab
When I close current tab

Close current tab with possibility to handle alert

Trying to close the current tab with 'onbeforeunload' events handling.

  • If an alert window is opened via 'onbeforeunload' event, it must be checked and handled in the subsequent steps.

  • If an alert window is not opened, the step closes the current window and switches to the previous window.

When I attempt to close current tab with possibility to handle alert

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I attempt to close current window with possibility to handle alert
This step can only be used if the current tab was opened via the step When I open URL `$pageUrl` in new tab.
If you confirm window close in alert, the tab will be closed, and you will need to switch to current tab using the following step: When I switch to tab with title that $stringComparisonRule `$windowName`.
Example 17. Checking for an alert when trying to close a window with form
Given I am on page with URL `https://example.com/`
When I open URL `https://example.com/form` in new tab
When I click on element located by `xpath(//*[@id='form-edit'])`
When I execute sequence of actions:
|type      |argument    |
|ENTER_TEXT|changed text|
When I attempt to close current tab with possibility to handle alert
Then an alert is present
When I accept alert with message which matches `.*`

Execute sequence of actions

Executes the sequence of web actions

When I execute sequence of actions: $actions
  • $actions - table of actions to execute

    Table 2. Possible actions
    type argument Argument example

    DOUBLE_CLICK

    Element locator or empty.

    By.linkUrl(http://httpbin.org)

    CLICK_AND_HOLD

    Element locator or empty.

    By.linkText(Click me)

    MOVE_BY_OFFSET

    Point.

    (10, 15) where x is 10 and y is 15

    RELEASE

    Element locator or empty.

    By.tagName(div)

    ENTER_TEXT

    Text to type.

    Minsk City

    CLICK

    Element locator or empty.

    By.caseSensitiveText(Done)

    PRESS_KEYS

    Comma-separated keys to press and release.

    BACK_SPACE

    KEY_DOWN

    Comma-separated keys to press one by one.

    CONTROL,SHIFT,ALT

    KEY_UP

    Comma-separated keys to release one by one.

    CONTROL,SHIFT,ALT

    MOVE_TO

    Element locator.

    By.id(username)

Windows/Unix and macOS platforms have different keyboards. For example, Ctrl+C combination is used to copy text on Windows and Unix, but ⌘ Command+C should be used on macOS with default preferences.

In order to close this gap VIVIDUS offers unique key OS_INDEPENDENT_CONTROL: it is mapped to CONTROL key on Windows/Unix and to COMMAND key on macOS. Using this key it is possible to make tests fully platform independent.

Example 18. Execute various web-actions
When I execute sequence of actions:
|type          |argument                                |
|DOUBLE_CLICK  |By.fieldText(Hello World)               |
|DOUBLE_CLICK  |                                        |
|CLICK_AND_HOLD|By.xpath(//signature-pad-control/canvas)|
|CLICK_AND_HOLD|                                        |
|MOVE_BY_OFFSET|(-300, 0)                               |
|RELEASE       |By.xpath(//signature-pad-control/canvas)|
|RELEASE       |                                        |
|ENTER_TEXT    |Text                                    |
|CLICK         |By.placeholder(Enter your password)     |
|CLICK         |                                        |
|PRESS_KEYS    |BACK_SPACE                              |
|KEY_DOWN      |CONTROL,SHIFT                           |
|KEY_UP        |CONTROL,SHIFT                           |
|MOVE_TO       |By.id(name)                             |

This step can be used to perform clipboard interactions.

Example 19. Select all text in the focused field and copy it to the clipboard on Windows
When I execute sequence of actions:
|type      |argument  |
|KEY_DOWN  |CONTROL, a|
|KEY_UP    |a, CONTROL|
|KEY_DOWN  |CONTROL, c|
|KEY_UP    |c, CONTROL|
Example 20. Paste text from the clipboard to the focused field on MacOS
When I execute sequence of actions:
|type      |argument  |
|KEY_DOWN  |COMMAND, v|
|KEY_UP    |v, COMMAND|
Example 21. Select all text in the focused field and copy it to the clipboard on any OS
When I execute sequence of actions:
|type      |argument                 |
|KEY_DOWN  |OS_INDEPENDENT_CONTROL, a|
|KEY_UP    |a, OS_INDEPENDENT_CONTROL|
|KEY_DOWN  |OS_INDEPENDENT_CONTROL, c|
|KEY_UP    |c, OS_INDEPENDENT_CONTROL|

Browser logs steps

This set of steps allows to validate the browser console logging messages.

In order to configure availability of the INFO level messages use following properties:

Browser

Property to enable INFO logs

Google Chrome

selenium.capabilities.goog\:loggingPrefs.browser=INFO

Microsoft Edge Chromium

selenium.capabilities.ms\:loggingPrefs.browser=INFO

Validate log entries absence

Validates the absence of log entries of the desired level in the browser console.

Then there are no browser console $logLevels
  • $logLevels - List of the comma-separated messages levels. The supported levels are: ERRORS, WARNINGS, INFOS.

Example 22. Validate absence of JS errors
Given I am on page with URL `https://vividus-test-site-a92k.onrender.com/`
Then there are no browser console ERRORS

Validate specific log entries absence

Validates the absence of specific log entries of the desired level in the browser console.

Then there are no browser console $logLevels by regex `$regex`

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

Then there are no browser console $logLevels by regex '$regex'
  • $logLevels - List of the comma-separated messages levels. The supported levels are: ERRORS, WARNINGS, INFOS.

  • $regex - The regular expression to match log entry messages.

Example 23. Validate absence of JS error referencing user
Given I am on page with URL `https://vividus-test-site-a92k.onrender.com/`
Then there are no browser console ERRORS by regex `.*user.*`

Validate specific log entries presence

Validates the presence of specific log entries of the desired level in the browser console.

Then there are browser console $logLevels by regex `$regex`
  • $logLevels - List of the comma-separated messages levels. The supported levels are: ERRORS, WARNINGS, INFOS.

  • $regex - The regular expression to match log entry messages.

Example 24. Validate presence of JS errors referencing user
Given I am on page with URL `https://vividus-test-site-a92k.onrender.com/`
Then there are browser console ERRORS by regex `.*user.*`

Wait for console log entries and save them

Waits for the appearance of the console log entries with the expected level and which match regular expression and saves all the entries (including awaited ones) of the expected level gathered during the wait to the scoped variable.

Wait uses generic UI timeouts specified by the properties ui.wait.timeout and ui.wait.polling-period. See [_properties] section for more details.
When I wait until browser console $logEntries by regex `$regex` appear and save all entries into $scopes variable `$variableName`
  • $logLevels - List of the comma-separated messages levels. The supported levels are: ERRORS, WARNINGS, INFOS.

  • $regex - The regular expression to match log entry messages.

  • $scopes - The comma-separated set of the variables scopes.

  • $variableName - The name of the variable to save the value of the barcode.

Example 25. Wait for application readiness
Given I am on page with URL `https://vividus-test-site-a92k.onrender.com/`
When I wait until browser console infos by regex `.*Application ready.*` appear and save all entries into scenario variable `logs`
Then `${logs}` matches `.*Application ready in \d+ seconds.*`

Perform steps for each found element

Executes the steps against all elements found by locator. After a required number of elements is found, search context switches in order for each found element and performs all steps on it.

If comparison rule mismatch steps will not be performed even if elements are found.
When I find $comparisonRule `$number` elements by `$locator` and for each element do$stepsToExecute

Alias:

When I find $comparisonRule '$number' elements by $locator and for each element do$stepsToExecute
  • $comparisonRule - The comparison rule.

  • $number - The number of elements to find.

  • $locator - The locator used to find elements.

  • $stepsToExecute - The ExamplesTable with a single column containing the steps to execute.

Example 26. Script type check
When I find = `5` elements by `xpath(//script):a` and for each element do
|step                                                                                      |
|When I set 'type' attribute value of the context element to the 'scenario' variable 'type'|
|Then `${type}` is equal to `text/javascript`                                              |

Context steps

Switch to the default context of page

Switches context to the root <html> element of the current page.

When I switch back to page

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I switch back to the page
Example 27. Switch to user context and back to the default context of page
Given I am on page with URL `https://vividus-test-site-a92k.onrender.com/elementState.html`
When I change context to element located by `id(button-hide)`
Then text `Element to hide` does not exist
When I switch back to page
Then text `Element to hide` exists

Switch context to a frame

Switches to <iframe> or <frame> element using one of the supported locators.

When I switch to frame located by `$locator`

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I switch to frame located `$locator`
  • $locator - Locator of frame element.

Example 28. Switch to frame
Given I am on page with URL `https://vividus-test-site-a92k.onrender.com/nestedFrames.html`
Then text `Modal Frame Example` does not exist
When I switch to frame located by `id(parent)`
Then text `Modal Frame Example` exists

Switch context to new tab

Switch the focus of future browser commands to new tab.

This step gets the identifier of the currently active tab and then switches focus to the first available tab with a different identifier. For example, if tabs #1, #2, #3 are open and tab #2 is active, this step will switch focus to tab #3.

A new tab should already be open for this step to function. After executing this step, the new tab will become the active tab.
When I switch to new tab

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I switch to a new window
Example 29. Open the new tab by link and switch to it
Given I am on page with URL `https://the-internet.herokuapp.com/windows`
When I click on element located by `linkUrlPart(/windows/new)`
Then text `New Window` does not exist
When I switch to new tab
Then text `New Window` exists

Switch context to new tab with specified title

Switch the focus of future browser commands to new tab with specified title.

When I switch to tab with title that $stringComparisonRule `$tabName`

Deprecated syntax (will be removed in VIVIDUS 0.7.0):

When I switch to window with title that $stringComparisonRule `$windowName`
Example 30. Open the new tab by link and switch to it using regex title pattern
Given I am on page with URL `https://the-internet.herokuapp.com/windows`
When I click on element located by `linkUrlPart(/windows/new)`
Then text `New Window` does not exist
When I switch to tab with title that matches `.*[wW]indow.*`
Then text `New Window` exists