react-testing-library version: 9.1.1react version: 16.9.0node version:npm (or yarn) version:Code Sandbox: https://codesandbox.io/embed/agitated-snyder-mvvgi
Component:
import React from "react";
const App = () => {
return (
<div className="App">
<h1>Hello Scout</h1>
<h2>Start editing to see some magic happen!</h2>
<video muted />
</div>
);
};
export default App;
Test:
import React from "react";
import { render, wait } from "@testing-library/react";
import App from "./App";
describe("App", () => {
it("renders", async () => {
const { container } = render(<App />);
await wait(() => expect(container.textContent).toContain("Scout"));
});
});
I noticed a waring in my logs when rendering a video element with the muted attribute:
Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.
in video (at App.js:15)
in div (at App.js:12)
in App (at App.test.js:7)
Verified. I'm not sure what this could be! Would you mind digging a little deeper and see if you can figure out what's causing this warning and whether there's anything we can do within React Testing Library? Perhaps you could ask on https://spectrum.chat/testing-library/help-react
@kentcdodds Of course, I'd love to take a look around and see what I can see, though it might not be until after the long weekend here in the US that I am able to dive in.
I've run into the same issue. The problem is that setting the muted property on a HTMLMediaElement leads to an event being fired, which in turn leads to flushDiscreteUpdatesIfNeeded being called.
At first, I thought we should be setting <videoRef>.defaultMuted = true instead, but while that sets the muted attribute on the video element in the DOM, it doesn't actually mute sound. On the other hand, setting muted in react doesn't set the muted attribute in the DOM.
Unfortunately, I haven't found a simple fix (and there are other issues open about this, e.g. this). In case you're interested, my workaround is to use my own wrapper for the render function:
const renderIgnoringUnstableFlushDiscreteUpdates = (component: React.ReactElement) => {
// tslint:disable: no-console
const originalError = console.error;
const error = jest.fn();
console.error = error;
const result = render(component);
expect(error).toHaveBeenCalledTimes(1);
expect(error).toHaveBeenCalledWith("Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.%s", expect.any(String));
console.error = originalError;
// tslint:enable: no-console
return result;
};
Interesting. I think this is out of scope for React Testing Library as it appears to be something with React specifically. If anyone can come up with something we can do to improve things, then please feel free to comment further, but from what I can tell, there's not much we can do.
@chriszwickerocteris thanks! Here's the same code in eslint:
const renderIgnoringUnstableFlushDiscreteUpdates = component => {
/* eslint-disable no-console */
const originalError = console.error
const error = jest.fn()
console.error = error
const result = render( component )
expect( error ).toHaveBeenCalledTimes( 1 )
expect( error ).toHaveBeenCalledWith( 'Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.%s', expect.any( String ) )
console.error = originalError
/* eslint-enable no-console */
return result
}
Just to confirm that this is a react issue with muted event on videos.
I was facing this warning in react-testing-library. I had been looking for the solution for around 4-5 hours. This works for me.
I would like to add steps in the solution because I was facing how to wrap the render component.
Step 1: add this function at the top of the test file.
const renderIgnoringUnstableFlushDiscreteUpdates = (component) => {
// tslint:disable: no-console
const originalError = console.error;
const error = jest.fn();
console.error = error;
const result = render(component);
expect(error).toHaveBeenCalledTimes(1);
expect(error).toHaveBeenCalledWith(
'Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.%s',
expect.any(String),
);
console.error = originalError;
// tslint:enable: no-console
return result;
};
Step 2: Wrap the render component from the step 1 function:
EX: renderIgnoringUnstableFlushDiscreteUpdates(
Step 3: Add this code in setupTest.js file for run video correctly.
window.HTMLMediaElement.prototype.load = () => {
/* do nothing /
};
window.HTMLMediaElement.prototype.play = () => {
/ do nothing /
};
window.HTMLMediaElement.prototype.pause = () => {
/ do nothing /
};
window.HTMLMediaElement.prototype.addTextTrack = () => {
/ do nothing */
};
For me the following snippet in jest setup is helped:
Object.defineProperty(HTMLMediaElement.prototype, 'muted', {
set: () => {},
});
My video element usage is:
<video src={src} autoPlay={true} loop={true} muted={true} playsInline={true} />
this should be fixed along with:
https://github.com/facebook/react/pull/20087
Most helpful comment
I've run into the same issue. The problem is that setting the
mutedproperty on aHTMLMediaElementleads to an event being fired, which in turn leads toflushDiscreteUpdatesIfNeededbeing called.At first, I thought we should be setting
<videoRef>.defaultMuted = trueinstead, but while that sets themutedattribute on thevideoelement in the DOM, it doesn't actually mute sound. On the other hand, settingmutedin react doesn't set themutedattribute in the DOM.Unfortunately, I haven't found a simple fix (and there are other issues open about this, e.g. this). In case you're interested, my workaround is to use my own wrapper for the
renderfunction: