Skip to content

Commit 39ed5ce

Browse files
docs: add core documentation (#35)
1 parent 5d9bb0b commit 39ed5ce

12 files changed

Lines changed: 321 additions & 42 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ Rust port of [Testing Library](https://testing-library.com/).
1414

1515
Rust Testing Library is available for these Rust frameworks:
1616

17-
- [DOM](./packages/dom) ([`web-sys`](https://rustwasm.github.io/wasm-bindgen/web-sys/index.html))
17+
- [DOM](./packages/dom) ([`web-sys`](https://rustwasm.github.io/wasm-bindgen/web-sys/index.html))
1818

1919
The following frameworks are under consideration:
2020

21-
- [Dioxus](https://dioxuslabs.com/)
22-
- [Leptos](https://leptos.dev/)
23-
- [Yew](https://yew.rs/)
21+
- [Dioxus](https://dioxuslabs.com/)
22+
- [Leptos](https://leptos.dev/)
23+
- [Yew](https://yew.rs/)
2424

2525
See [the Rust Testing Library book](https://testing-library.rustforweb.org/introduction.html#frameworks) for more information.
2626

book/src/SUMMARY.md

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
# Summary
22

3-
- [Introduction](./introduction.md)
4-
- [Core API](./core/README.md)
5-
- [Queries]()
6-
- [About Queries]()
7-
- [By Role]()
8-
- [By Label Text]()
9-
- [By Placeholder Text]()
10-
- [By Text]()
11-
- [By Display Value]()
12-
- [By Alt Text]()
13-
- [By Title]()
14-
- [By Test ID]()
15-
- [User Actions]()
16-
- [Firing Events]()
17-
- [Async Methods]()
18-
- [Appearance and Disappearance]()
19-
- [Considerations]()
20-
- [Advanced]()
21-
- [Accessibility]()
22-
- [Custom Queries]()
23-
- [Debugging]()
24-
- [Querying Within Elements]()
25-
- [Configuration Options]()
26-
- [Frameworks](./frameworks/README.md)
27-
- [DOM Testing Library](./frameworks/dom.md)
28-
- [Introduction]()
29-
- [Install]()
30-
- [Example]()
31-
- [Setup]()
32-
- [API]()
33-
- [Cheatsheet]()
34-
- [Contributing]()
3+
- [Introduction](./introduction.md)
4+
- [Core API](./core/README.md)
5+
- [Queries](./core/queries/README.md)
6+
- [About Queries](./core/queries/about-queries.md)
7+
- [By Role](./core/queries/by-role.md)
8+
- [By Label Text](./core/queries/by-label-text.md)
9+
- [By Placeholder Text]()
10+
- [By Text]()
11+
- [By Display Value]()
12+
- [By Alt Text]()
13+
- [By Title]()
14+
- [By Test ID]()
15+
- [User Actions](./core/user-actions/README.md)
16+
- [Firing Events](./core/user-actions/firing-events.md)
17+
- [Async Methods]()
18+
- [Appearance and Disappearance]()
19+
- [Considerations]()
20+
- [Advanced](./core/advanced/README.md)
21+
- [Accessibility]()
22+
- [Custom Queries]()
23+
- [Debugging]()
24+
- [Querying Within Elements]()
25+
- [Configuration Options]()
26+
- [Frameworks](./frameworks/README.md)
27+
- [DOM Testing Library](./frameworks/dom.md)
28+
- [Introduction]()
29+
- [Install]()
30+
- [Example]()
31+
- [Setup]()
32+
- [API]()
33+
- [Cheatsheet]()
34+
- [Contributing]()

book/src/core/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
# Core API
22

3-
TODO
3+
- [Queries](./queries/README.md)
4+
- [User Actions](./user-actions/README.md)
5+
- [Advanced](./advanced/README.md)

book/src/core/advanced/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Advanced
2+
3+
TODO

book/src/core/queries/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Queries
2+
3+
- [About Queries](./about-queries.md)
4+
- [By Role](./by-role.md)
5+
<!-- - [By Label Text]()
6+
- [By Placeholder Text]()
7+
- [By Text]()
8+
- [By Display Value]()
9+
- [By Alt Text]()
10+
- [By Title]()
11+
- [By Test ID]() -->
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# About Queries
2+
3+
TODO
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# By Label Text
2+
3+
TODO

book/src/core/queries/by-role.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# By Role
2+
3+
> `get_by_role`, `query_by_role`, `get_all_by_role`, `query_all_by_role`, `find_by_role`, `find_all_by_role`
4+
5+
## API
6+
7+
```rust,ignore
8+
use aria_query::AriaRole;
9+
use testing_library_dom::{Matcher, QueryError};
10+
use web_sys::HtmlElement;
11+
12+
fn get_by_role(
13+
// If you're using `screen`, then skip the container argument:
14+
container: &HtmlElement,
15+
role: AriaRole,
16+
options: ByRoleOptions
17+
) -> Result<Option<HtmlElement>, QueryError>;
18+
19+
struct ByRoleOptions {
20+
hidden: Option<bool>,
21+
name: Option<Matcher>,
22+
description: Option<Matcher>,
23+
selected: Option<bool>,
24+
busy: Option<bool>,
25+
checked: Option<bool>,
26+
pressed: Option<bool>,
27+
suggest: Option<bool>,
28+
current: Option<ByRoleOptionsCurrent>,
29+
expanded: Option<bool>,
30+
query_fallbacks: Option<bool>,
31+
level: Option<usize>,
32+
value: Option<ByRoleOptionsValue>,
33+
}
34+
35+
enum ByRoleOptionsCurrent {
36+
Bool(bool),
37+
String(String),
38+
}
39+
40+
struct ByRoleOptionsValue {
41+
now: Option<f64>,
42+
min: Option<f64>,
43+
max: Option<f64>,
44+
text: Option<Matcher>,
45+
}
46+
```
47+
48+
Queries for elements with the given role <!-- (and it also accepts a TextMatch) -->. Default roles are taken into consideration e.g. `<button />` has the `button` role without explicitly setting the `role` attribute. Here you can see [a table of HTML elements with their default and desired roles](https://www.w3.org/TR/html-aria/#docconformance).
49+
50+
Please note that setting a `role` and/or `aria-*` attribute that matches the implicit ARIA semantics is unnecessary and is **not recommended** as these properties are already set by the browser, and we must not use the `role` and `aria-*` attributes in a manner that conflicts with the semantics described. For example, a `button` element can't have the `role` attribute of `heading`, because the `button` element has default characteristics that conflict with the `heading` role.
51+
52+
<!-- TODO: Ensure text still applies to `AriaRole`. -->
53+
54+
> Roles are matched literally by string equality, without inheriting from the ARIA role hierarchy. As a result, querying a superclass role like `checkbox` will not include elements with a subclass role like `switch`.
55+
56+
You can query the returned element(s) by their [accessible name or description](https://www.w3.org/TR/accname-1.1/). The accessible name is for simple cases equal to e.g. the label of a form element, or the text content of a button, or the value of the `aria-label` attribute. It can be used to query a specific element if multiple elements with the same role are present on the rendered content. For an in-depth guide check out ["What is an accessible name?" from TPGi](https://www.tpgi.com/what-is-an-accessible-name/). If you only query for a single element with `get_by_text("The name")` it's oftentimes better to use `get_by_role(expected_role, { name: "The name" })`. The accessible name query does not replace other queries such as `*_by_alt` or `*_by_title`. While the accessible name can be equal to these attributes, it does not replace the functionality of these attributes. For example `<img aria-label="fancy image" src="fancy.jpg" />` will be returned for `get_by_role("img", { name: "fancy image" })`. However, the image will not display its description if `fancy.jpg` could not be loaded. Whether you want to assert this functionality in your test or not is up to you.
57+
58+
<div class="warning">
59+
60+
**Input type password**
61+
62+
Unfortunately, the spec defines that `<input type="password" />` has no implicit role. This means that in order to query this type of element we must fallback to a less powerful query such as [By Label Text](./by-label-text.md).
63+
64+
</div>
65+
66+
## Options
67+
68+
### `hidden`
69+
70+
TODO
71+
72+
### `selected`
73+
74+
TODO
75+
76+
### `busy`
77+
78+
TODO
79+
80+
### `checked`
81+
82+
TODO
83+
84+
### `current`
85+
86+
TODO
87+
88+
### `pressed`
89+
90+
TODO
91+
92+
### `suggest`
93+
94+
TODO
95+
96+
### `expanded`
97+
98+
TODO
99+
100+
### `query_fallbacks`
101+
102+
TODO
103+
104+
### `level`
105+
106+
TODO
107+
108+
### `value`
109+
110+
TODO
111+
112+
### `description`
113+
114+
TODO
115+
116+
## Performance
117+
118+
`get_by_role` is the most preferred query to use as it most closely resembles the user experience, however the calculations it must perform to provide this confidence can be expensive (particularly with large DOM trees).
119+
120+
Where test performance is a concern it may be desirable to trade some of this confidence for improved performance.
121+
122+
`get_by_role` performance can be improved by setting the option [`hidden`](#hidden) to `true` and thereby avoid expensive visibility checks. Note that in doing so inaccessible elements will now be included in the result.
123+
124+
Another option may be to substitute `get_by_role` for simpler `get_by_label_text` and `get_by_text` queries which can be significantly faster though less robust alternatives.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# User Actions
2+
3+
- [Firing Events](./firing-events.md)
4+
- Async Methods
5+
- Appearance and Disappearance
6+
- Considerations
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Firing Events
2+
3+
<!-- > **Note**
4+
>
5+
> Most projects have a few use cases for `fire_event`, but the majority of the time you should probably use `testing-library-user-event`. -->
6+
7+
## `fire_event`
8+
9+
```rust,ignore
10+
use testing_library_dom::{EventType, FireEventError};
11+
use web_sys::EventTarget;
12+
13+
fn fire_event<E: EventType>(node: &EventTarget, event: &E) -> Result<bool, FireEventError>;
14+
```
15+
16+
Fire DOM events.
17+
18+
```rust,ignore
19+
// HTML: <button>Submit</button>
20+
21+
use testing_library_dom::{get_by_text, fire_event};
22+
use web_sys::MouseEvent;
23+
24+
let event = MouseEvent::new("click");
25+
event.set_bubbles(true);
26+
event.set_cancelable(true);
27+
28+
fire_event(
29+
get_by_text(&container, "Submit")
30+
.expect("Get should succeed.")
31+
.expect("Get should return an element."),
32+
&event,
33+
).expect("Event should be fired.");
34+
```
35+
36+
## `FireEvent::[<event_name>]`
37+
38+
```rust,ignore
39+
fn [<event_name>](node: &EventTarget, event_properties: [<EventInit>]) -> Result<bool, CreateOrFireEventError>;
40+
```
41+
42+
Convenience methods for firing DOM events. Check out `src/events.rs` for a full list as well as default event proprties.
43+
44+
<!-- TODO: target, data transfer -->
45+
46+
### Keyboard events
47+
48+
There are three event types related to keyboard input - `keyPress`, `keyDown`, and `keyUp`. When firing these you need to reference an element in the DOM and the key you want to fire.
49+
50+
```rust,ignore
51+
use testing_library_dom::FireEvent;
52+
use web_sys::KeyboardEventInit;
53+
54+
let init = KeyboardEventInit::new();
55+
init.set_key("Enter");
56+
init.set_code("Enter");
57+
init.set_char_code(13);
58+
FireEvent::key_down(&dom_node, &init).expect("Event should be fired.");
59+
60+
61+
let init = KeyboardEventInit::new();
62+
init.set_key("A");
63+
init.set_code("KeyA");
64+
FireEvent::key_down(&dom_node, &init).expect("Event should be fired.");
65+
```
66+
67+
You can find out which key code to use at https://www.toptal.com/developers/keycode.
68+
69+
## `CreateEvent::[<event_name>]`
70+
71+
```rust,ignore
72+
fn [<event_name>](node: &EventTarget, event_properties: [<EventInit>]) -> Result<[<Event>], CreateOrFireEventError>;
73+
```
74+
75+
Convenience methods for creating DOM events that can then be fired by `fire_event`, allowing you to have a reference to the event created: this might be useful if you need to access event properties that cannot be initiated programmatically (such as [`time_stamp`](https://docs.rs/web-sys/latest/web_sys/struct.Event.html#method.time_stamp)).
76+
77+
```rust,ignore
78+
use testing_library_dom::{CreateEvent, fire_event};
79+
use web_sys::MouseEventInit;
80+
81+
let init = MouseEventInit::new();
82+
init.set_button(2);
83+
let my_event = CreateEvent::click(&node, &init).expect("Event should be created.");
84+
85+
fire_event(&node, &my_event).expect("Event should be fired.");
86+
87+
// `my_event.time_stamp()` can be accessed just like any other properties from `my_event`.
88+
// Note: The access to the events created by `create_event` is based on the native event API.
89+
// Therefore, native properties of HTML Event object (e.g. `timeStamp`, `cancelable`, `type`) should be set using `Object.defineProperty`.
90+
// For more info see: https://developer.mozilla.org/en-US/docs/Web/API/Event.
91+
```
92+
93+
## `create_event`
94+
95+
```rust,ignore
96+
use testing_library_dom::{CreateEventError, EventType};
97+
use web_sys::EventTarget;
98+
99+
fn create_event<E: EventType>(
100+
event_name: &str,
101+
node: &EventTarget,
102+
init: Option<E::Init>,
103+
options: CreateEventOptions<E>,
104+
) -> Result<E, CreateEventError>;
105+
106+
struct CreateEventOptions<'a, E: EventType> {
107+
default_init: Option<&'a DefaultInitFn<E>>,
108+
}
109+
110+
type DefaultInitFn<E> = dyn Fn(&<E as EventType>::Init);
111+
```
112+
113+
Create DOM events.
114+
115+
```rust,ignore
116+
use testing_library_dom::{CreateEventOptions, create_event};
117+
use web_sys::{InputEvent, InputEventInit};
118+
119+
let init = InputEventInit::new();
120+
init.set_data(Some("a"));
121+
let event = create_event::<InputEvent>(
122+
"input",
123+
&input,
124+
Some(&init),
125+
CreateEventOptions::default()
126+
).expect("Event should be created.");
127+
```

0 commit comments

Comments
 (0)