You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+69-3Lines changed: 69 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,7 @@ Test Mule is driven by these goals:
19
19
-[Making Assertions](#making-assertions)
20
20
-[Performing Actions](#performing-actions)
21
21
-[Troubleshooting/Debugging a Failing Test](#troubleshootingdebugging-a-failing-test)
22
+
-[Actionability](#actionability)
22
23
-[Full Example](#full-example)
23
24
-[API](#api)
24
25
-[`withBrowser`](#withbrowser)
@@ -261,6 +262,29 @@ test(
261
262
);
262
263
```
263
264
265
+
### Actionability
266
+
267
+
Test Mule performs actionability checks when interacting with the page using the [User API](#user-api-testmuleuser). This concept is closely modeled after [Cypress](https://docs.cypress.io/guides/core-concepts/interacting-with-elements.html#Actionability) and [Playwright's](https://playwright.dev/docs/actionability) implementations of actionability.
268
+
269
+
The core concept behind actionability is that if a real user would not be able to perform an action in your page, you should not be able to perform the actions in your test either. For example, since a user cannot click on an invisible element, your test should not allow you to click on invisible elements.
270
+
271
+
We are working on adding more actionability checks.
272
+
273
+
Here are the actionability checks that are currently implemented. Different methods in the User API perform different actionability checks based on what makes sense. In the API documentation for the [User API](#user-api-testmuleuser), the actionability checks that each method performs are listed.
274
+
275
+
#### Attached
276
+
277
+
Ensures that the element is attached to the DOM, using [`Node.isConnected`](https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected). For example, if you use `document.createElement()`, the created element is not attached to the DOM until you use `ParentNode.append()` or similar.
278
+
279
+
#### Visible
280
+
281
+
Ensures that the element is visible to a user. Currently, the following checks are performed (more will likely be added):
282
+
283
+
- Element is [Attached](#attached) to the DOM
284
+
- Element does not have `display: none` or `visibility: hidden`
285
+
- Element has a size (its [bounding box](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) has a non-zero width and height)
286
+
- Element's opacity is greater than 0.05 (opacity of parent elements are considered)
287
+
264
288
## Full Example
265
289
266
290
There is a menu example in the [examples folder](./examples/menu/index.test.ts)
@@ -399,22 +423,64 @@ The user API allows you to perform actions on behalf of the user. If you have us
399
423
400
424
> **Warning**: The User API is in progress. It should be safe to use the existing methods, but keep in mind that more methods will be added in the future, and more checks will be performed for existing methods as well.
Clicks an element, if the element is visible and the center of it is not covered by another element. If the center of the element is covered by another element, an error is thrown. This is a thin wrapper around Puppeteer's [`ElementHandle.click` method](https://pptr.dev/#?product=Puppeteer&version=v7.0.1&show=api-elementhandleclickoptions). The difference is that `TestMuleUser.click` checks that the target element is an element that actually can be clicked before clicking it!
403
429
404
-
Clicks an element, if the element is visible and the center of it is not covered by another element. If the center of the element is covered by another element, an error is thrown. This is a thin wrapper around Puppeteer's [`ElementHandle.click` method](https://pptr.dev/#?product=Puppeteer&version=v7.0.1&show=api-elementhandleclickoptions). The difference is that `TestMuleUser.click` checks that the target element is not covered before performing the click. Don't forget to `await`, since this returns a Promise!
430
+
**Actionability checks**: It refuses to click elements that are not [**attached**](#attached) or not [**visible**](#visible). You can override the visibility check by passing `{ force: true }`.
431
+
432
+
Additionally, it refuses to click an element if there is another element covering it. `{ force: true }` overrides this behavior.
Types text into an element, if the element is visible. The element must be an `<input>` or `<textarea>` or have `[contenteditable]`.
450
+
451
+
If the element already has text in it, the additional text is appended to the existing text. **This is different from Puppeteer and Playwright's default .type behavior**.
452
+
453
+
**Actionability checks**: It refuses to type into elements that are not [**attached**](#attached) or not [**visible**](#visible). You can override the visibility check by passing `{ force: true }`.
454
+
455
+
In the text, you can pass special commands using curly brackets to trigger special keypresses, similar to [user-event](https://github.com/testing-library/user-event#special-characters) and [Cypress](https://docs.cypress.io/api/commands/type.html#Arguments). Open an issue if you want more commands available here! Note: If you want to simulate individual keypresses independent from a text field, you can use Puppeteer's [page.keyboard API](https://pptr.dev/#?product=Puppeteer&version=v7.1.0&show=api-pagekeyboard)
|`{selectall}`| N/A | Selects all the text of the element. Does not work for elements using `contenteditable`|
464
+
|`{arrowleft}`| ArrowLeft ||
465
+
|`{arrowright}`| ArrowRight ||
466
+
|`{arrowup}`| ArrowUp ||
467
+
|`{arrowdown}`| ArrowDown ||
468
+
469
+
```js
470
+
import { withBrowser } from'test-mule';
471
+
472
+
test(
473
+
'type example',
474
+
withBrowser(async ({ utils, user, screen }) => {
475
+
awaitutils.injectHTML('<input />');
476
+
constbutton=awaituser.type(
477
+
button,
478
+
'this is some text..{backspace}{arrowleft} asdf',
479
+
);
480
+
}),
481
+
);
482
+
```
483
+
418
484
### Utilities API: `TestMuleUtils`
419
485
420
486
The utilities API provides shortcuts for loading and running code in the browser. The methods are wrappers around behavior that can be performed more verbosely with the [Puppeteer `Page` object](#testmulecontextpage). This API is exposed via the [`utils` property in `TestMuleContext`](#testmulecontextutils-testmuleutils)
0 commit comments