Burlarse de framer-motion v4

Testing Library ha cambiado el juego de pruebas de interfaz de usuario para mejor. Si aún no lo has probado, échale un vistazo.

En el trabajo, nuestros nuevos esfuerzos de interfaz de usuario están impulsados ​​por la interfaz de usuario de Chakra, que utiliza Framer Motion debajo del capó para las animaciones. Con todo este trabajo, lo estamos probando usando Jest y React Testing Library (RTL).

Una excelente manera de defenderse de las regresiones de la interfaz de usuario (copia, estilos, etc.) es la prueba de instantáneas. A medida que nos adentramos cada vez más en las funciones y mejores pruebas de Chakra, nos encontramos con problemas en los que el style animado las propiedades tienen diferencias mínimas entre las instantáneas.

RTL recomienda burlarse de las bibliotecas de animación para resolver este problema. Hay algunas soluciones para hacer esto con framer-motion en la web, pero no creo que estén a la altura de la versión actual de la biblioteca (4._ ).

Después de investigar la fuente de movimiento del enmarcador, me di cuenta de nuestro intento de burlarnos del motion exportar como un objeto (ver aquí) no funcionaba porque motion se construye utilizando Proxy.

Basta de palabras, ¿cómo estabilizo mis pruebas instantáneas?

// __mocks__/framer-motion.ts

import { CustomDomComponent, CustomMotionComponentConfig } from 'framer-motion/types/render/dom/motion-proxy';
import * as React from 'react';

const actual = jest.requireActual('framer-motion');

// https://github.com/framer/motion/blob/main/src/render/dom/motion.ts
function custom<Props>(
  Component: string | React.ComponentType<Props>,
  _customMotionComponentConfig: CustomMotionComponentConfig = {},
): CustomDomComponent<Props> {
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  return React.forwardRef((props, ref) => {
    const regularProps = Object.fromEntries(
      // do not pass framer props to DOM element
      Object.entries(props).filter(([key]) => !actual.isValidMotionProp(key)),
    );
    return typeof Component === 'string' ? (
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      <div ref={ref} {...regularProps} />
    ) : (
      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
      // @ts-ignore
      <Component ref={ref} {...regularProps} />
    );
  });
}

const componentCache = new Map<string, unknown>();
const motion = new Proxy(custom, {
  get: (_target, key: string) => {
    if (!componentCache.has(key)) {
      componentCache.set(key, custom(key));
    }

    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    return componentCache.get(key)!;
  },
});

module.exports = {
  __esModule: true,
  ...actual,
  AnimatePresence: ({ children }: { children: React.ReactChildren }) => <>{children}</>,
  motion,
};

Ahora en su archivo de configuración de prueba puede llamar a jest.mock('framer-motion') y todas las propiedades relacionadas con la animación se filtrarán.

¡Feliz prueba!