diff --git a/packages/react-components/react-motion-components-preview/library/src/components/Fade/Fade.test.ts b/packages/react-components/react-motion-components-preview/library/src/components/Fade/Fade.test.ts deleted file mode 100644 index 7c3f60b9a2841..0000000000000 --- a/packages/react-components/react-motion-components-preview/library/src/components/Fade/Fade.test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { expectPresenceMotionFunction, expectPresenceMotionObject } from '../../testing/testUtils'; -import { Fade } from './Fade'; - -describe('Fade', () => { - it('stores its motion definition as a static function', () => { - expectPresenceMotionFunction(Fade); - }); - - it('generates a motion definition from the static function', () => { - expectPresenceMotionObject(Fade); - }); -}); diff --git a/packages/react-components/react-motion-components-preview/library/src/components/Fade/Fade.test.tsx b/packages/react-components/react-motion-components-preview/library/src/components/Fade/Fade.test.tsx new file mode 100644 index 0000000000000..3070be848acb2 --- /dev/null +++ b/packages/react-components/react-motion-components-preview/library/src/components/Fade/Fade.test.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { Fade, FadeExaggerated, FadeSnappy } from './Fade'; +import { render } from '@testing-library/react'; +import { motionTokens } from '@fluentui/react-motion'; +import { mockAnimation } from '../../testing/testUtils'; + +describe('Fade motion component', () => { + let originalAnimate: typeof HTMLElement.prototype.animate; + let animateSpy: jest.SpyInstance; + const testElement =
Test
; + + // JSDOM does not support the Web Animations API, so create a mock animate() before spying on it + beforeAll(() => { + originalAnimate = HTMLElement.prototype.animate; + HTMLElement.prototype.animate = () => mockAnimation(); + }); + + beforeEach(() => { + animateSpy = jest.spyOn(HTMLElement.prototype, 'animate'); + }); + + afterEach(() => { + animateSpy.mockRestore(); + }); + + afterAll(() => { + HTMLElement.prototype.animate = originalAnimate; + }); + + it('should render Fade with correct opacity keyframes, duration and easing (visible=false -> true -> false)', () => { + const { rerender } = render({testElement}); + + // Testing fade in motion + rerender({testElement}); + expect(animateSpy).toHaveBeenCalledWith( + [{ opacity: 0 }, { opacity: 1 }], + expect.objectContaining({ duration: motionTokens.durationNormal, easing: motionTokens.curveEasyEase }), + ); + + // Testing fade out motion + rerender({testElement}); + expect(animateSpy).toHaveBeenCalledWith( + [{ opacity: 1 }, { opacity: 0 }], + expect.objectContaining({ duration: motionTokens.durationNormal, easing: motionTokens.curveEasyEase }), + ); + }); + + it('should render Snappy variant of Fade component with correct opacity keyframes, duration and easing', () => { + const { rerender } = render({testElement}); + + rerender({testElement}); + + expect(animateSpy).toHaveBeenCalledWith( + [{ opacity: 0 }, { opacity: 1 }], + expect.objectContaining({ duration: motionTokens.durationFast, easing: motionTokens.curveEasyEase }), + ); + }); + + it('should render Exaggerated variant of Fade component with correct opacity keyframes, duration and easing', () => { + const { rerender } = render({testElement}); + + rerender({testElement}); + + expect(animateSpy).toHaveBeenCalledWith( + [{ opacity: 0 }, { opacity: 1 }], + expect.objectContaining({ duration: motionTokens.durationGentle, easing: motionTokens.curveEasyEase }), + ); + }); +}); diff --git a/packages/react-components/react-motion-components-preview/library/src/testing/testUtils.ts b/packages/react-components/react-motion-components-preview/library/src/testing/testUtils.ts index e80006cd176b2..27c00673f66f4 100644 --- a/packages/react-components/react-motion-components-preview/library/src/testing/testUtils.ts +++ b/packages/react-components/react-motion-components-preview/library/src/testing/testUtils.ts @@ -63,3 +63,31 @@ export function expectPresenceMotionFunction(PresenceComponent: PresenceComponen expect(presenceMotionFn).toBeInstanceOf(Function); } + +export const mockAnimation: () => Animation = () => ({ + finish: jest.fn(), + cancel: jest.fn(), + persist: jest.fn(), + currentTime: null, + effect: null, + finished: Promise.resolve({} as Animation), + id: '', + play: jest.fn(), + pause: jest.fn(), + updatePlaybackRate: jest.fn(), + reverse: jest.fn(), + playState: 'running', + playbackRate: 1, + startTime: null, + timeline: null, + oncancel: null, + onfinish: null, + ready: Promise.resolve({} as Animation), + removeEventListener: jest.fn(), + addEventListener: jest.fn(), + dispatchEvent: jest.fn(), + onremove: null, + pending: false, + replaceState: 'active', + commitStyles: jest.fn(), +});