@closeio/backbone-testing-library
v1.0.0
Published
DOM testing utilities with API that mirrors React Testing Library
Downloads
18,381
Readme
Backbone Testing Library
DOM testing utilities for Backbone
with an API that mirrors React Testing Library
.
Interested in working on projects like this? Close is looking for great engineers to join our team!
Why would you want this... It's nearly 2021!?
At Close a large portion of our app is still written in Backbone
and we're carefully
transitioning this to React
. We created this library as a way to write tests on our
Backbone
components in the style of React Testing Library
. This means, as we port
components over, we are able to use the same tests with very minimal changes and so
minimize regressions in our app. While we wouldn't recommend building a brand new FE app
with Backbone
, we're open sourcing this to help anyone else looking to transition a
legacy codebase.
Installation
This module is distributed via npm which is bundled with node and
should be installed as one of your project's devDependencies
.
This library also has peerDependencies
listings for @testing-library/dom
:
npm install --save-dev @closeio/backbone-testing-library @testing-library/dom
or
for installation via yarn
yarn add --dev @closeio/backbone-testing-library @testing-library/dom
You may also be interested in installing @testing-library/jest-dom
so you can
use the custom jest matchers.
Example
// models/HiddenMessageModel.js
import Backbone from 'backbone';
const HiddenMessageModel = Backbone.Model.extend({
defaults: {
message: '',
showMessage: false,
},
});
export default HiddenMessageModel;
// views/HiddenMessageView.js
import Backbone from 'backbone';
const HiddenMessageView = Backbone.View.extend({
events: {
'change #toggle': 'setShowMessage',
},
initialize({ model }) {
this.model = model;
this.model.on('change', this.render.bind(this));
},
setShowMessage(e) {
this.model.set('showMessage', e.target.checked);
},
template({ showMessage, message }) {
return `<div>
<label for="toggle">Show Message</label>
<input
id="toggle"
type="checkbox"
${showMessage ? 'checked' : ''}
/>
${showMessage ? message : ''}
</div>`;
},
render() {
this.$el.html(this.template(this.model.attributes));
},
});
export default HiddenMessageView;
// views/HiddenMessageView.test.js
// these imports are something you'd normally configure Jest to import for you
// automatically. Learn more in the setup docs: https://testing-library.com/docs/react-testing-library/setup#cleanup
import '@testing-library/jest-dom';
// NOTE: jest-dom adds handy assertions to Jest and is recommended, but not required
import { render, fireEvent } from '@closeio/backbone-testing-library';
import HiddenMessageModel from '../models/HiddenMessageModel';
import HiddenMessageView from './HiddenMessageView';
test('shows the children when the checkbox is checked', () => {
const testMessage = 'Test Message';
const testModel = new HiddenMessageModel({
message: testMessage,
});
// The queries you'd expect from React Testing Library are returned from render, as are
// `view`, `container`, `baseElement`, `debug` and `unmount`. We also hook into React
// Testing Library's `RTL_SKIP_AUTO_CLEANUP` const to auto unmount views in `afterEach`
const { queryByText, getByLabelText, getByText } = render(HiddenMessageView, {
model: testModel,
});
// query* functions will return the element or null if it cannot be found
// get* functions will return the element or throw an error if it cannot be found
expect(queryByText(testMessage)).toBeNull();
// the queries can accept a regex to make your selectors more resilient to content tweaks and changes.
fireEvent.click(getByLabelText(/show/i));
// .toBeInTheDocument() is an assertion that comes from jest-dom
// otherwise you could use .toBeDefined()
expect(getByText(testMessage)).toBeInTheDocument();
});
render
Parameters
View
- the first argument is theBackbone.View
Class to test, it will be instantiated by the render functionoptions
- optional - the second argument is an options object with the following parameters:container
- optional - behaves like RTL'scontainer
by default creates adiv
and appends it todocument.body
baseElement
- optional - behaves like RTL'sbaseElement
ifcontainer
is specified, then it defaults to that, otherwise this defaults todocument.body
autoRender
- optional - this defaults totrue
. Sometimes you may want to assert on something in between yourBackbone.View
'sinitialize
andrender
methods, if so you can passfalse
here and callrender
manually on the returnedview
instance....options
- any other properties will be passed through asoptions
to theBackbone.View
's constructor. For example, you could addel
if you wanted to manually provide this to the view rather than haveBackbone
auto create it. You'll also likely often want to pass amodel
.
render
Result
The render method returns an object that has a few properties:
...queries
- The most important feature of render is that the queries fromDOM Testing Library
are automatically returned with their first argument bound to thebaseElement
, which defaults todocument.body
view
- TheBackbone
view instance itself.container
- behaves like RTL'scontainer
returns either adiv
autocreated for you, or thecontainer
passed torender
. To get the root element of your rendered element, usecontainer.firstChild
orview.el
.baseElement
- behaves like RTL'sbaseElement
returns eitherdocument.body
or thebaseElement
passed to `render.debug
- behaves like RTL'sdebug
this function is a shortcut forconsole.log(prettyDOM(baseElement))
.unmount
- callsremove
on theBackbone.View
instance and cleans up thecontainer
element. Useful for testing what happens when your view is removed from the page. By default, whenRTL_SKIP_AUTO_CLEANUP
isfalse
,cleanup
is called in everyafterEach
block which runsrender
, which means you don't need to manually unmount your views if you're not testingremove
. While it might seem odd to rely on a ENV var from another library, our intention here is that this library is run in tandem with RTL and behaves identically for porting components.
License
MIT © Close