Pourquoi getComputedStyle () dans un test JEST renvoie-t-il différents résultats aux styles calculés dans Chrome / Firefox DevTools


16

J'ai écrit un bouton personnalisé ( MyStyledButton) basé sur 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;

Il est stylisé à l'aide d'un thème, ce qui spécifie qu'il backgroundColordoit être une nuance de jaune (spécialement #fbb900)

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

export const myYellow = "#FBB900";

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

Le composant est instancié dans mon principal index.jset enveloppé dans le theme.

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

Si j'examine le bouton dans Chrome DevTools, il background-colorest "calculé" comme prévu. C'est également le cas dans Firefox DevTools.

Capture d'écran de Chrome

Cependant, lorsque j'écris un test JEST pour vérifier le background-coloret que je recherche le style de nœud DOM du bouton à l'aide du bouton getComputedStyles()Je transparentreviens et le test échoue.

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);

J'ai inclus un CodeSandbox avec le problème exact, le code minimum à reproduire et l'échec du test JEST.

Modifier sans tête-neige-nyofd


La couleur d'arrière-plan .MuiButtonBase-root-33 est transparente tandis que .MuiButton-contenuesPrimary-13 ne l'est pas - donc le problème est que les classes en CSS sont également importantes, donc seul l'ordre de chargement les distingue -> dans les styles de test sont chargés dans le mauvais ordre.
Zydnar

1
@Andreas - Mis à jour comme demandé
Simon Long

@Zyndar - Oui, je le sais. Existe-t-il un moyen de réussir ce test?
Simon Long

Le themebesoin ne serait-il pas utilisé dans le test? Comme dans, enveloppez le <MyStyledButton>dans le <MuiThemeProvider theme={theme}>? Ou utiliser une fonction wrapper pour ajouter le thème à tous les composants?
Brett DeWoody

Non, cela ne fait aucune différence.
Simon Long

Réponses:


1

Je me suis rapproché, mais je n'ai pas encore trouvé de solution.

Le principal problème est que MUIButton injecte une balise à l'élément pour alimenter les styles. Cela ne se produit pas dans votre test unitaire. J'ai pu faire fonctionner cela en utilisant le createMount que les tests de matériaux utilisent.

Après ce correctif, le style s'affiche correctement. Cependant, le style calculé ne fonctionne toujours pas. Il semble que d'autres ont rencontré des problèmes avec la manipulation correcte des enzymes - donc je ne sais pas si c'est possible.

Pour arriver là où j'étais, prenez votre extrait de test, copiez-le en haut, puis changez votre code de test en:

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;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.