-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
e2e tests: framer-motion
animations are not disabled by plugin disabling CSS animations
#43282
Comments
Puppeteer does have a way to emulate reduced motion, but prior attempts to use it didn't work - #18453. There have been quite a few updates of puppeteer since, so things may be different. |
Should we be try to emulate reduced motion in addition to "force-disabling" all CSS animations, or as an alternative? The original intention of the e2e tests plugin was to disable all animations in order to make e2e tests "more stable" — if that intention still holds true today, simulating reduced motion likely won't give the same results (some animations may still be happening) and we may need to find alternative options. I also wonder if this plugin is necessary — as state before, by disabling all CSS animations we're making our e2e tests less realistic (compared to what the final user will interact with) |
Possibly both? My main concern is test reliability, which is what makes me think both.
I think I've seen this discussion before somewhere (but I wasn't participating). For Puppeteer, the tests are already regularly flakey, and historically written in a way where they expect elements to be visible instantly. It may not be realistic to turn all animations on, a lot of tests would need to be updated to use For Playwright, the argument is a bit simpler. Animations being active does make tests run more slowly, but given Playwright does auto-waiting there should really be no difference between having animations on and off in terms of whether tests pass. I think the best thing for the long term is to continue facilitating the migration to Playwright so that this is a simpler choice. |
Unfortunately, some components still seem to fail with Playwright, even when the reduced motion is set and animations are disabled (natively). I recorded those components during the tests and noticed that they are animating into their default/initial state. I've checked if the
Hope it helps! 🙌 |
Thank you @WunderBart ! We can look into removing initial animation from these components:
During your tests, were the rest of the |
Sorry, I was under the impression that ToggleGroupControl was migrated to framer-motion but I guess it's not? It does its own |
I had started working on it — I opened a first attempt, which was then superseded by a second attempt using shared layout animations, which couldn't be merged because of a bug in |
I also had another thought — if we wanted to disable framer-motion animations, what if we mocked |
@ciampo I haven't tested any user interactions yet - just the initial part. Which components do you think could be problematic? I'd be happy to do some more testing to learn more about FM behavior 👍 edit: I guess I can start from the |
You could test Of the ones you listed, |
Huh, I should have checked myself, but I assumed that |
OK, so I've been testing the // font-size-picker.test.ts
test( 'Can change size to "Small"', async ( { page } ) => {
const button = await page.locator( 'button[aria-label="Small"]' );
await button.click();
const buttonHighlight = await page.waitForSelector(
'[aria-label="Font size"] > div[role=presentation]'
);
await buttonHighlight?.waitForElementState( 'stable' );
expect( button ).toHaveAttribute( 'aria-checked', 'true' );
expect( await page.screenshot() ).toMatchSnapshot();
} ); ...and for the Popover component: // popover.test.ts
test( 'Should pop over', async ( { page } ) => {
await page.click( 'role=button' );
const popover = await page.waitForSelector( '.components-popover' );
await popover.waitForElementState( 'stable' );
expect( await page.screenshot() ).toMatchSnapshot();
} ); I'm still not sure why turning animation off doesn't work, but I don't think it's that important right now. If we can reliably test with animations on, I think we should do it as it has way more value than the other way around. It shows the intent behind those animations because we explicitly need to account for them in the tests. For example, those initial animations that I mentioned above - if we were able to just turn them off in the first place, the tests would just pass ignoring the fact that they might be an unwanted side-effect! 💪 Let me know what you think, @ciampo! |
I was reading about Out of curiosity, would the Would there ever be the option to remove the Specifically to screenshots, it looks like the |
If the only thing we need to wait for is the element's opacity (its bounding box is static), then for the screenshot to be done at the right moment, I suppose we'd need a custom waiter. This should be doable as we can wait for the opacity via
Yes, as long as the bounding box of the element is moving, the stability check should keep working.
It doesn't look to be working ATM reliably, true. In my testing, it didn't even work reliably for the |
Definitely for Playwright, which I think should be done by default. Are we disabling animations for Playwright as we did for Puppeteer? cc @kevin940726 |
Nope. We are not activating that plugin in Playwright tests. If somehow something breaks while screenshotting, friendly reminder that we can always use await expect.poll(
() => locator.evaluate( ( node ) => getComputedStyle( node ).opacity )
).toBe( '1' ) |
What
The
disable-animation
plugin runs during e2e tests in order to make them "more stable" (see original PR).But this set of styles don't have an impact on animations happening via the
framer-motion
library (as noted by @talldan in #43186 (review)) — this is becauseframer-motion
"manually" sets the animated values as inline styles for each frame (instead of relying on native CSS animations and transforms).Proposed next steps
The best solution that comes to my mind is:
disable-animation
plugin, setting a global variable that can be read in app codeMotionConfig
component (see docs): when the global variable from the point before is defined, thereducedMotion
option can be set toalways
, while normally it would be set touser
It should be noted that this is only a suboptimal solution:
An alternative approach could be to manually check for that global "e2e_disable_css_animations" variable in the React code, and conditionally render an alternative to
framer-motion
components that doesn't animate (i.e. a normaldiv
instead of amotion.div
) — although this approach would also mean that our e2e tests would not actually test the same exact components that are rendered in our user's browsersThe text was updated successfully, but these errors were encountered: