Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cibernox/ember-native-dom-helpers
Test helpers for your integration tests that fire native events
https://github.com/cibernox/ember-native-dom-helpers
ember events helpers native tests
Last synced: 2 days ago
JSON representation
Test helpers for your integration tests that fire native events
- Host: GitHub
- URL: https://github.com/cibernox/ember-native-dom-helpers
- Owner: cibernox
- License: mit
- Created: 2017-02-16T18:00:24.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2022-12-07T04:13:12.000Z (about 2 years ago)
- Last Synced: 2025-01-15T10:52:21.193Z (9 days ago)
- Topics: ember, events, helpers, native, tests
- Language: JavaScript
- Size: 1.15 MB
- Stars: 186
- Watchers: 10
- Forks: 37
- Open Issues: 47
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
README
![Build Status](https://travis-ci.org/cibernox/ember-native-dom-helpers.svg?branch=master)
# IMPORTANT: You probably don't need this addon.
In Ember, since `ember-(cli-)qunit` 3.X (around late 2017) there is a new testing API that already
provides almost identical test helpers from the ones in this addon.This addon was used as an experiment that helped bikeshed the API of the helpers that are now part
of default testing API, like `click`, `tap`, `fillIn` and others.The only two helpers in this addon that are not part of the default set of helpers that ship with Ember's
test harness are `scrollTo(selectorOrHTMLElement, x, y)` and `selectFiles(selectorOrHTMLElement, files = [])`.Unless you want to use those, you are better served using the helpers provided by `@ember/test-helpers`.
# ember-native-dom-helpers
Test helpers for integration tests that mimic the behaviour of the acceptance
test helpers provided by Ember.Use this addon as a way to start the gradual migration towards the future
["testing unification" RFC][emberjs/rfcs/pull/119], which proposes only native DOM.See the [Grand Testing Unification RFC][emberjs/rfcs/pull/119]
- [shared-test-helpers]
- [example-migration-of-component-integration-test][emberjs/rfcs/pull/119]: https://github.com/emberjs/rfcs/pull/119
[shared-test-helpers]: https://github.com/rwjblue/rfcs/blob/42/text/0000-grand-testing-unification.md#shared-test-helpers
[example-migration-of-component-integration-test]: https://github.com/rwjblue/rfcs/blob/42/text/0000-grand-testing-unification.md#example-migration-of-component-integration-test**Status**: (Pre) 1.0, although we have a good idea about what the needs are for
test helpers, we are working through a few points on what changes are needed
when using only standard DOM APIs (i.e. without jQuery).## Usage
### Integration tests
```js
import { click, fillIn, find, findAll, keyEvent, triggerEvent } from 'ember-native-dom-helpers';moduleForComponent('my-component', 'Integration | Component | my-component', {
integration: true
});test('I can interact with my component', async function(assert) {
this.render(hbs```
{{my-component}}
```);await fillIn('.some-input', 'some text');
await click('.main-button');
await keyEvent('.other-input', 'keyup', 40); // down arrow
await triggerEvent('.some-drop-area', 'mouseenter');assert.ok(find('.result-of-event-happened'));
assert.equal(findAll('.result-list-item').length, 3);
})
```### Acceptance tests
You can use the exact same helpers for your acceptance tests. All interaction helpers like
`click`, `fillIn`, et al., return a promise that fullfils when "the world has settled"
(that is, there are no pending requests or promises, and the runloop has been drained), which
is what the `andThen` acceptance helper used to do. However, this helper can now be replaced
by the `async`/`await` syntax in ES2017, yielding easier-to-read tests:```js
import { visit, click, find, fillIn } from 'ember-native-dom-helpers';moduleForAcceptance('Acceptance | Sign up');
test('Usage awaiting the world to settle', async function(assert) {
await visit('/sign-up');await fillIn('.first-name', 'Chuck');
await fillIn('.last-name', 'Berry');
await click('.submit-btn');assert.ok(find('.welcome-msg'), 'There is a welcome banner');
assert.equal(find('.welcome-msg-name'), 'Chuck');
});
```## Advantages compared with `this.$(selector).click()`
The main advantages are:
- Fires native events: In Ember, when adding events with the `onclick={{action "foo"}}` syntax,
dispatching jQuery events leads to the action being called twice. Additionally, there are subtle
differences between jQuery and Native events that can bite you. Firing native events fixes that
problem, but they are very verbose and there are browser incompatibilities. This addon makes
firing native events a no-brainer.- Runloop aware: These helpers automatically spawn a runloop, so you don't need to wrap
every interaction with `Ember.run(() => /* interact with element */ );`.- `wait` by default: All the helpers return the `wait()` promise, making it possible to
wait for asynchronous side-effects with `async/await`. (Note that for using async/await
in browsers without native support you must install [ember-maybe-import-regenerator](https://github.com/machty/ember-maybe-import-regenerator)).```js
test('some test', async function(assert) {
this.render(hbs```{{my-component}}```);await click('.my-button');
assert.ok('something happened');
});
```- More realistic behaviour: When a user clicks on an element, `click` is not the only event fired.
In a real click, the sequence of events is `mousedown`, `focus`, `mouseup`, `click`. When a user
fills in an input the sequence of events is `focus`, ``, `input`, and `change`.
The helpers provided by this addon fire those events in the right order, simulating more
closely how a real user would interact with the page.## Standard DOM elements returned using a `find`/`findAll` helpers
- The `find` helper uses `document.querySelector` and will return a single `HTMLElement` or `null`.
- The `findAll` helper uses `document.querySelectorAll` and returns an `Array` with zero or more elements.
- Both `find` and `findAll` helpers query the DOM within `#ember-testing`.
- To use a different value from your `config/environment.js` settings, add to `tests/test-helper.js`…```js
import { settings } from 'ember-native-dom-helpers';
import config from '../config/environment';
const { APP: { rootElement } } = config;settings.rootElement = rootElement || settings.rootElement;
```### What if I prefer jQuery collections over native DOM?
Fear not. If you prefer to use jQuery, just wrap the result and do your thing:
```js
assert.equal($(find('.my-class')).attr('aria-owns'), '#id123')
```## Testing an unsettled world
There is one new helper in this addon that enables some testing patterns that weren't
previously easy to perform using traditional methods.Since the `andThen` helper waits for the app to settle (no pending requests or promises),
and every integration test interaction is wrapped in `Ember.run`, there is no easy way
to test transient state, like loading substates or the state of a component, while some
promise is pending, without an awkward setup of timeouts.Now, however, thanks to explicit usage of promises and the `waitUntil` helper, you can
perform assertions on unsettled states:```js
import { visit, click, find, fillIn, waitUntil, currentURL } from 'ember-native-dom-helpers';moduleForAcceptance('Acceptance | Sign up');
test('Usage awaiting the world to settle', async function(assert) {
await visit('/login');await fillIn('.email', '[email protected]');
await fillIn('.password', 'goldeneye');
let promise = click('.submit-btn');// We wait until the loading substate, that takes 200ms to appear, is displayed
await waitUntil(() => find('.substate-spinner'));
assert.equal(find('.loading-substate-header').textContent.trim(), 'Loading mission. Please wait, Mr. Bond');await promise; // now we wait until the dashboard is fully loaded
assert.equal(currentURL(), '/dashboard');
assert.equal(find('.section-header').textContent, 'Main dashboard');
});
```## I WANT IT NOW, IS THERE A SHORTCUT?
Yes, there is a codemod that will help you transform your test suite to this new style "automatically".
Check https://github.com/simonihmig/ember-native-dom-helpers-codemod.The codemod can't make a *perfect* conversion, but it will do most of the work for you.
## Helpers
- `click(selectorOrHTMLElement, contextHTMLElement, eventOptions)`
- `tap(selectorOrHTMLElement, eventOptions)`
- `fillIn(selectorOrHTMLElement, text)`
- `find(selector, contextHTMLElement)` (query for an element in test DOM, `#ember-testing`)
- `findAll(selector, contextHTMLElement)` (query for elements in test DOM, `#ember-testing`)
- `findWithAssert(selector, contextHTMLElement)` (same as `find`, but raises an Error if no result)
- `keyEvent(selectorOrHTMLElement, type, keyCode, modifiers)` (type being `keydown`, `keyup` or `keypress`, modifiers being object with `{ ctrlKey: false, altKey: false, shiftKey: false, metaKey: false }`)
- `triggerEvent(selectorOrHTMLElement, type, options)`
- `focus(selectorOrHTMLElement)`
- `blur(selectorOrHTMLElement)`
- `scrollTo(selectorOrHTMLElement, x, y)`
- `selectFiles(selectorOrHTMLElement, files = [])` (selects the file(s)/Blob(s) to the given `input[type=file]`. [Example](https://github.com/cibernox/ember-native-dom-helpers/blob/2f5f4d1df29d0d546505b515ca3e11721a86274b/tests/integration/select-files-test.js#L32-L35)
- `visit(url)` (only available in acceptance. Raises an error in integration.)
- `waitUntil(function, options)` (Polls the page until the given callback returns a truthy value, or timesout after 1s)
- `waitFor(selector, options)` (Convenience for the most common use-case of `waitUntil`. It polls the page until the element with the given selector is on the page, or timesout after 1s. It accepts a `count: 3` option to await a specific number of matches.)
- `currentURL()` Identical to the one provided by Ember.
- `currentPath()` Identical to the one provided by Ember.
- `currentRouteName()` Identical to the one provided by Ember.## Notes of `tap`
In order for `tap` to work, your browser has to support touch events. Desktop Chrome and Firefox
have touch events disabled unless the device emulation mode is on. To enable touch events in your
CI, you need to configure testem like the `testem.js` file on this repo.