¿Por qué getComputedStyle () en una prueba JEST devuelve resultados diferentes a los estilos calculados en Chrome / Firefox DevTools

16

He escrito un botón personalizado ( MyStyledButton) basado en material-ui Button .

import React from "react";
import { Button } from "@material-ui/core";
import { makeStyles } from "@material-ui/styles";

const useStyles = makeStyles({
  root: {
    minWidth: 100
  }
});

function MyStyledButton(props) {
  const buttonStyle = useStyles(props);
  const { children, width, ...others } = props;

  return (

      <Button classes={{ root: buttonStyle.root }} {...others}>
        {children}
      </Button>
     );
}

export default MyStyledButton;

Está diseñado con un tema y esto especifica backgroundColorque debe ser un tono de amarillo (Específicamente #fbb900)

import { createMuiTheme } from "@material-ui/core/styles";

export const myYellow = "#FBB900";

export const theme = createMuiTheme({
  overrides: {
    MuiButton: {
      containedPrimary: {
        color: "black",
        backgroundColor: myYellow
      }
    }
  }
});

El componente se instancia en mi main index.jsy se envuelve en el theme.

  <MuiThemeProvider theme={theme}>
     <MyStyledButton variant="contained" color="primary">
       Primary Click Me
     </MyStyledButton>
  </MuiThemeProvider>

Si examino el botón en Chrome DevTools, background-colorse "calcula" como se esperaba. Este es también el caso en Firefox DevTools.

Captura de pantalla de Chrome

Sin embargo, cuando escribo una prueba JEST para verificar background-colory consulto el estilo del nodo DOM, si uso el botón getComputedStyles(), transparentregreso y la prueba falla.

const wrapper = mount(
    <MyStyledButton variant="contained" color="primary">
      Primary
    </MyStyledButton>
  );
  const foundButton = wrapper.find("button");
  expect(foundButton).toHaveLength(1);
  //I want to check the background colour of the button here
  //I've tried getComputedStyle() but it returns 'transparent' instead of #FBB900
  expect(
    window
      .getComputedStyle(foundButton.getDOMNode())
      .getPropertyValue("background-color")
  ).toEqual(myYellow);

He incluido un CodeSandbox con el problema exacto, el código mínimo para reproducir y la prueba JEST que falla.

Editar sin cabeza-nieve-nyofd

Simon Long
fuente
.MuiButtonBase-root-33 background-color es transparente, mientras que .MuiButton-contenidoPrimary-13 no lo es, por lo que el problema es que las clases en CSS son igualmente importantes, por lo que solo el orden de carga los distingue -> en los estilos de prueba se cargan en orden incorrecto.
Zydnar
1
@Andreas - Actualizado según lo solicitado
Simon Long
@Zyndar: Sí, lo sé. ¿Hay alguna forma de hacer pasar esta prueba?
Simon Long
¿No sería themenecesario utilizarlo en la prueba? Como en, envolver el <MyStyledButton>en el <MuiThemeProvider theme={theme}>? ¿O utiliza alguna función de contenedor para agregar el tema a todos los componentes?
Brett DeWoody
No, eso no hace ninguna diferencia.
Simon Long

Respuestas:

1

Me he acercado, pero todavía no estoy en una solución.

El problema principal es que MUIButton inyecta una etiqueta al elemento para potenciar los estilos. Esto no está sucediendo en su prueba de unidad. Pude hacer que esto funcionara usando createMount que usan las pruebas de material.

Después de esta corrección, el estilo se muestra correctamente. Sin embargo, el estilo calculado aún no funciona. Parece que otros han tenido problemas con el manejo correcto de las enzimas, por lo que no estoy seguro de si es posible.

Para llegar a donde estaba, tome su fragmento de prueba, cópielo en la parte superior y luego cambie su código de prueba a:

const myMount = createMount({ strict: true });
  const wrapper = myMount(
    <MuiThemeProvider theme={theme}>
      <MyStyledButton variant="contained" color="primary">
        Primary
      </MyStyledButton>
    </MuiThemeProvider>
  );
class Mode extends React.Component {
  static propTypes = {
    /**
     * this is essentially children. However we can't use children because then
     * using `wrapper.setProps({ children })` would work differently if this component
     * would be the root.
     */
    __element: PropTypes.element.isRequired,
    __strict: PropTypes.bool.isRequired,
  };

  render() {
    // Excess props will come from e.g. enzyme setProps
    const { __element, __strict, ...other } = this.props;
    const Component = __strict ? React.StrictMode : React.Fragment;

    return <Component>{React.cloneElement(__element, other)}</Component>;
  }
}

// Generate an enhanced mount function.
function createMount(options = {}) {

  const attachTo = document.createElement('div');
  attachTo.className = 'app';
  attachTo.setAttribute('id', 'app');
  document.body.insertBefore(attachTo, document.body.firstChild);

  const mountWithContext = function mountWithContext(node, localOptions = {}) {
    const strict = true;
    const disableUnnmount = false;
    const localEnzymeOptions = {};
    const globalEnzymeOptions = {};

    if (!disableUnnmount) {
      ReactDOM.unmountComponentAtNode(attachTo);
    }

    // some tests require that no other components are in the tree
    // e.g. when doing .instance(), .state() etc.
    return mount(strict == null ? node : <Mode __element={node} __strict={Boolean(strict)} />, {
      attachTo,
      ...globalEnzymeOptions,
      ...localEnzymeOptions,
    });
  };

  mountWithContext.attachTo = attachTo;
  mountWithContext.cleanUp = () => {
    ReactDOM.unmountComponentAtNode(attachTo);
    attachTo.parentElement.removeChild(attachTo);
  };

  return mountWithContext;
}
AnilRedshift
fuente