This is prompted by this question on Twitter:
does
toBeVisibleinjest-domtake styles from CSS files into account? I'm checking a component that has a class that addsdisplay: none;butexpect(component).not.toBeVisible()is failing because it thinks the component is visible.
The problem, as I pointed out responding that tweet, is that when testing isolated components, css stylesheets that would normally be attached to the document via a <link /> element in the head area, are not attached to the virtual jsdom document in which the tests are being run.
I'm not sure how this would be. Especially with css-in-js and css-modules in the picture, I'm not even sure if there's still a framework-agnostic way to automatically handle what these better css systems do with the css to dynamically generate a stylesheet.
Keeping it concrete, only considering stylesheets in general, I'm not even sure if we can make a helper load a css file. All I know is that we can attach css to the document having the actual css code as a string, as we already do here.
We can simplify the above providing some kind of helper to attach styles and run assertions with those styles on. It has to be some kind of wrapper that gives us the opportunity to clean up, because as you see in that test I linked to, the style element has to be detached and cleaned up after the test (something we're not even doing consistently in all those test cases 馃槺).
So at the very least I can come up with something like this:
const stylesheet = `
.hidden { display: none }
`
// ...
test('...', () => {
withStyles(stylesheet, () => {
// ...
expect(element).not.toBeVisible();
});
});
We can keep things as they are, but at the very least we need to document this better in the README.
If we keep things as they are, we can tell people to assert against the element having the css class name or not, but that kinda goes against the guiding principle. Because end users of web apps do not really care about the element having the class or not, but wether it is visible or not. Furthermore, with the popularity of css-in-js or even css-modules, people cannot rely on static css class names anymore.
TODO
I don't think this is a good idea for this library. I think it's the responsibility of the application developer to figure out how to load they're styles into the document. This feels pretty out of scope IMO
Ok, fair enough. As I said, we can keep things as they are, that was my go to solution anyway. But at the very least we should document it. I'll do that. Thanks for your input and for validating what I was thinking.
@gnapse @kentcdodds I ran into the same issue and can't find how to get the stylesheet from CSS module files like the example above. Here's an example of my test and what i'm trying to do:
// App.js
import React from 'react'
import styles from './Vis.module.scss';
export const App = () => (
<div data-testid="app" className={styles.app}>Something here</div>
);
// styles.module.scss
.app {
display: none;
}
// App.test.js
import React from 'react';
import { render } from 'react-testing-library';
import { App } from './App';
import styles from './App.module.scss';
test('App is invisible', () => {
const { getByTestId, container } = render(<App />);
// trying to inject css into test document
const style = document.createElement('style');
// Not sure what to put here. "styles" is an object
// and "styles.app" is just a class name, not the real style attributes.
style.innerHTML = ???;
document.body.appendChild(style);
document.body.appendChild(container);
expect(getByTestId('app')).not.toBeVisible();
document.body.removeChild(style);
document.body.removeChild(container);
});
Any suggestions?
I really don't know of any tool to enable this and believe this would be pretty nontrivial to build. Definitely possible and very useful! But there's no way to do this today...
I'm closing this for now. Feel free to reopen if something actionable arises from all this.
I created a simple utility function for my usecase. might come in handy for those coming here looking for a solution:
import _ from 'lodash'
import { render as rtlRender } from '@testing-library/react'
import sass from 'node-sass'
import { FunctionComponent, ReactElement } from 'react'
type RenderOptions = {
wrapper?: FunctionComponent | undefined
stylesheet?: string
}
function render(ui: ReactElement, options: RenderOptions = {}) {
const view = rtlRender(ui, {
..._.omit(options, 'stylesheet'),
})
if (options.stylesheet) {
const styles = sass.renderSync({ file: options.stylesheet })
const styleElement = document.createElement('style')
styleElement.innerHTML = styles.css.toString()
document.body.appendChild(styleElement)
document.body.appendChild(view.container)
}
return view
}
export * from '@testing-library/react'
// override React Testing Library's render with our own
export { render }
Most helpful comment
Ok, fair enough. As I said, we can keep things as they are, that was my go to solution anyway. But at the very least we should document it. I'll do that. Thanks for your input and for validating what I was thinking.