Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rust Testing Library Logo

Introduction

Rust Testing Library is a Rust port of Testing Library.

Testing Library is a library of simple and complete testing utilities that encourage good testing practices.

Frameworks

Rust Testing Library is available for these Rust frameworks:

The following frameworks are under consideration:

Support

TODO

License

This project is available under the MIT license.

Rust for Web

The Rust Testing Library project is part of Rust for Web.

Rust for Web creates and ports web libraries for Rust. All projects are free and open source.

Core API

Queries

About Queries

TODO

By Role

get_by_role, query_by_role, get_all_by_role, query_all_by_role, find_by_role, find_all_by_role

API

use aria_query::AriaRole;
use testing_library_dom::{Matcher, QueryError};
use web_sys::HtmlElement;

fn get_by_role(
    // If you're using `screen`, then skip the container argument:
    container: &HtmlElement,
    role: AriaRole,
    options: ByRoleOptions
) -> Result<Option<HtmlElement>, QueryError>;

struct ByRoleOptions {
    hidden: Option<bool>,
    name: Option<Matcher>,
    description: Option<Matcher>,
    selected: Option<bool>,
    busy: Option<bool>,
    checked: Option<bool>,
    pressed: Option<bool>,
    suggest: Option<bool>,
    current: Option<ByRoleOptionsCurrent>,
    expanded: Option<bool>,
    query_fallbacks: Option<bool>,
    level: Option<usize>,
    value: Option<ByRoleOptionsValue>,
}

enum ByRoleOptionsCurrent {
    Bool(bool),
    String(String),
}

struct ByRoleOptionsValue {
    now: Option<f64>,
    min: Option<f64>,
    max: Option<f64>,
    text: Option<Matcher>,
}

Queries for elements with the given role . 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.

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.

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.

You can query the returned element(s) by their accessible name or description. 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. 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.

Input type password

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.

Options

hidden

TODO

selected

TODO

busy

TODO

checked

TODO

current

TODO

pressed

TODO

suggest

TODO

expanded

TODO

query_fallbacks

TODO

level

TODO

value

TODO

description

TODO

Performance

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).

Where test performance is a concern it may be desirable to trade some of this confidence for improved performance.

get_by_role performance can be improved by setting the option hidden to true and thereby avoid expensive visibility checks. Note that in doing so inaccessible elements will now be included in the result.

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.

By Label Text

TODO

User Actions

  • Firing Events
  • Async Methods
  • Appearance and Disappearance
  • Considerations

Firing Events

fire_event

use testing_library_dom::{EventType, FireEventError};
use web_sys::EventTarget;

fn fire_event<E: EventType>(node: &EventTarget, event: &E) -> Result<bool, FireEventError>;

Fire DOM events.

// HTML: <button>Submit</button>

use testing_library_dom::{get_by_text, fire_event};
use web_sys::MouseEvent;

let event = MouseEvent::new("click");
event.set_bubbles(true);
event.set_cancelable(true);

fire_event(
    get_by_text(&container, "Submit").expect("Get should succeed."),
    &event,
).expect("Event should be fired.");

FireEvent::[<event_name>]

fn [<event_name>](node: &EventTarget, event_properties: &[<EventInit>]) -> Result<bool, CreateOrFireEventError>;

Convenience methods for firing DOM events. Check out src/events.rs for a full list as well as default event proprties.

Keyboard events

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.

use testing_library_dom::FireEvent;
use web_sys::KeyboardEventInit;

let init = KeyboardEventInit::new();
init.set_key("Enter");
init.set_code("Enter");
init.set_char_code(13);
FireEvent::key_down(&dom_node, &init).expect("Event should be fired.");

let init = KeyboardEventInit::new();
init.set_key("A");
init.set_code("KeyA");
FireEvent::key_down(&dom_node, &init).expect("Event should be fired.");

You can find out which key code to use at https://www.toptal.com/developers/keycode.

CreateEvent::[<event_name>]

fn [<event_name>](node: &EventTarget, event_properties: &[<EventInit>]) -> Result<[<Event>], CreateOrFireEventError>;

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).

use testing_library_dom::{CreateEvent, fire_event};
use web_sys::MouseEventInit;

let init = MouseEventInit::new();
init.set_button(2);
let my_event = CreateEvent::click(&node, &init).expect("Event should be created.");

fire_event(&node, &my_event).expect("Event should be fired.");

// `my_event.time_stamp()` can be accessed just like any other properties from `my_event`.
// Note: The access to the events created by `create_event` is based on the native event API.
// Therefore, native properties of HTML Event object (e.g. `timeStamp`, `cancelable`, `type`) should be set using `Object.defineProperty`.
// For more info see: https://developer.mozilla.org/en-US/docs/Web/API/Event.

create_event

use testing_library_dom::{CreateEventError, EventType};
use web_sys::EventTarget;

fn create_event<E: EventType>(
    event_name: &str,
    node: &EventTarget,
    init: Option<&E::Init>,
    options: CreateEventOptions<E>,
) -> Result<E, CreateEventError>;

struct CreateEventOptions<'a, E: EventType> {
    default_init: Option<&'a DefaultInitFn<E>>,
}

type DefaultInitFn<E> = dyn Fn(&<E as EventType>::Init);

Create DOM events.

use testing_library_dom::{CreateEventOptions, create_event};
use web_sys::{InputEvent, InputEventInit};

let init = InputEventInit::new();
init.set_data(Some("a"));
let event = create_event::<InputEvent>(
    "input",
    &input,
    Some(&init),
    CreateEventOptions::default()
).expect("Event should be created.");

Advanced

TODO

Frameworks

DOM Testing Library

TODO