-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4402 from wix/docs/webviews-guide
docs(webviews): add "Testing WebViews" guide.
- Loading branch information
Showing
2 changed files
with
154 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
# Testing WebViews | ||
|
||
In this tutorial, we'll go over how you can test a WebView in React Native applications using Detox. We will cover how to engage with web elements in both single and multi WebView scenarios, apply matchers, and execute actions. | ||
|
||
WebViews are crucial parts in a lot of mobile applications, rendering content like web pages or PDF documents within the native environment. However, because the content inside WebViews is web content and not native, it isn't straightforward to interact with using Detox. But fear not, Detox has got you covered with its suite of Web View methods. | ||
|
||
:::note | ||
|
||
This guide provides an overview of testing web views within React Native apps with Detox. For complete API details, refer to our [WebView API documentation][api]. | ||
|
||
::: | ||
|
||
## Step 0: Setting Up Detox | ||
|
||
The first thing you'll need is to have your Detox environment properly set up. If you need a hand with that, you can follow the set-up guide [here][setup]. | ||
|
||
## Step 1: Locating the WebView | ||
|
||
Detox provides two approaches for locating the host web view and its inner elements, depending on the number of WebViews on the screen. | ||
|
||
### Single WebView Scenario | ||
|
||
The case of a single WebView on the screen is the most common scenario, and it's the simplest to handle. | ||
|
||
Detox will automatically locate the web view for you, so you don't need to do anything special to find it. | ||
In this case, you can use the [`web.element()`][webelementmatcher] function with web element matchers to reference elements inside it, see [next step][finding-inner-elements] in this guide for further details. | ||
|
||
### Multiple Web Views Scenario | ||
|
||
In scenarios where there are multiple WebViews displayed on the screen, you will have to identify a particular WebView first. | ||
Use a [native matcher][native-matcher] to do this, same as you would for native elements. | ||
|
||
```javascript | ||
const myWebView = web(by.id('webview_identifier')); | ||
``` | ||
|
||
After locating the web view, you can then use the `myWebView.element()` method with web view matchers to locate elements within it. See [next step][finding-inner-elements] in this guide for further details. | ||
|
||
#### Using `atIndex` | ||
|
||
It is also possible to locate the web view by applying at-index to the web view matcher in case there are multiple matching web views for the same matcher. | ||
|
||
```javascript | ||
const myWebView = web(by.id('webview_identifier').atIndex(1)); | ||
``` | ||
|
||
:::note | ||
|
||
`atIndex()` API for WebView matching is currently supported for iOS only. Check our [API documentation][at-index-api] for updates. | ||
|
||
::: | ||
|
||
## Step 2: Finding Inner Elements | ||
|
||
Element matchers are used to find elements within a web view. The [Detox WebView APIs][matchers-apis] provide various matchers for locating elements within a web view (e.g. `by.web.id(id)`, `by.web.className(className)`, `by.web.tag(tag)`, `atIndex(index)` etc.). | ||
|
||
Here are examples of using some of the matchers: | ||
|
||
```javascript | ||
// Match by ID attribute | ||
const elementByID = web.element(by.web.id('identifier')); | ||
|
||
// Match by CSS class name attribute | ||
const elementByClassName = web.element(by.web.className('className')); | ||
|
||
// Match by CSS selector | ||
const elementByCSSSelector = web.element(by.web.cssSelector('#cssSelector')); | ||
|
||
// Match with index in case of multiple matching elements | ||
const elementAtIndex = web.element(by.web.id('identifier').atIndex(1)); | ||
``` | ||
|
||
## Step 3: Perform Actions | ||
|
||
Actions allow you to interact with elements within a web view. The [Detox WebView APIs][actions-apis] provide various actions that can be invoked on inner elements. | ||
|
||
For example, here's a simple example for filling a login form and press on login button: | ||
|
||
```javascript | ||
|
||
// Fill username and password | ||
await web.element(by.web.id('username')).typeText('John Doe'); | ||
await web.element(by.web.id('password')).typeText('123456789'); | ||
|
||
// Press the login button | ||
await web.element(by.web.id('login')).tap(); | ||
|
||
``` | ||
|
||
### Perform Custom Actions (`runScript`) | ||
|
||
You can also execute custom JavaScript code on the web view using the `runScript` action (see [API docs][run-script-api]). | ||
This is useful for scenarios where you need to interact with the web view in a way that isn't covered by the built-in actions, for fetching data, or for triggering custom events. | ||
|
||
For example, you can use `runScript` to get the font size of a text element: | ||
|
||
```javascript | ||
// Define the matcher for the inner text element | ||
const textElement = web(by.id('webview_identifier')).element(by.web.id('text_element')); | ||
|
||
// Get the font size of a text element | ||
const fontSize = await textElement.runScript(function get(element) { | ||
return element.style.fontSize; | ||
}); | ||
``` | ||
|
||
## Step 4: Assert on Expected Behaviour | ||
|
||
Expectations are assertions on the state of elements within a WebView. | ||
|
||
For instance, to verify an element has specific text: | ||
|
||
```javascript | ||
await expect(web.element(by.web.id('identifier'))).toHaveText('Hello World!'); | ||
``` | ||
|
||
Or to assert an element does not exist: | ||
|
||
```javascript | ||
await expect(web.element(by.web.id('invalid_identifier'))).not.toExist(); | ||
``` | ||
|
||
## Full Example | ||
|
||
Here's a full example of a test that interacts with a WebView: | ||
|
||
```javascript | ||
it('should login successfully', async () => { | ||
// Assert the welcome message is not visible before login | ||
await expect(web.element(by.web.id('welcome_message'))).not.toExist(); | ||
|
||
// Fill username and password | ||
await web.element(by.web.id('username')).typeText('John Doe'); | ||
await web.element(by.web.id('password')).typeText('123456789'); | ||
|
||
// Press the login button | ||
await web.element(by.web.id('login')).tap(); | ||
|
||
// Assert the login was successful | ||
await expect(web.element(by.web.id('welcome_message'))).toHaveText('Welcome, John Doe!'); | ||
}); | ||
``` | ||
|
||
[setup]: ../introduction/environment-setup.md | ||
[api]: ../api/webviews.md | ||
[native-matcher]: ../api/matchers.md | ||
[content-editable]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/contentEditable | ||
[webelementmatcher]: ../api/webviews.md#webelementmatcher | ||
[matchers-apis]: ../api/webviews.md#matchers | ||
[actions-apis]: ../api/webviews.md#actions | ||
[run-script-api]: ../api/webviews.md#runscriptscript-args | ||
[finding-inner-elements]: #step-2-finding-inner-elements | ||
[at-index-api]: ../api/webviews.md#webnativematcheratindexindexelementmatcher |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters