Warum gibt getComputedStyle () in einem JEST-Test unterschiedliche Ergebnisse an berechnete Stile in Chrome / Firefox DevTools zurück?

16

Ich habe eine benutzerdefinierte Schaltfläche ( MyStyledButton) basierend auf Material-UI geschrieben 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;

Es ist mit einem Thema gestaltet und dies gibt backgroundColoran, dass es sich um einen Gelbton handelt (speziell #fbb900)

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

export const myYellow = "#FBB900";

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

Die Komponente wird in meiner Hauptkomponente instanziiert index.jsund in die eingeschlossen theme.

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

Wenn ich die Schaltfläche in Chrome DevTools untersuche, background-colorwird sie wie erwartet "berechnet". Dies ist auch in Firefox DevTools der Fall.

Screenshot von Chrome

Wenn ich jedoch einen JEST-Test schreibe, um den background-colorDOM-Knotenstil zu überprüfen, frage getComputedStyles()ich transparentzurück und der Test schlägt fehl.

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

Ich habe eine CodeSandbox mit dem genauen Problem, dem zu reproduzierenden Mindestcode und dem fehlgeschlagenen JEST-Test beigefügt.

Bearbeiten Sie Headless-Snow-Nyofd

Simon Long
quelle
.MuiButtonBase-root-33 Hintergrundfarbe ist transparent, während .MuiButton-enthaltenes Primär-13 nicht transparent ist - das Problem ist also, dass Klassen in CSS gleich wichtig sind, sodass nur die Reihenfolge der Ladevorgänge sie unterscheiden -> in Teststilen werden sie in falscher Reihenfolge geladen.
Zydnar
1
@ Andreas - Aktualisiert wie gewünscht
Simon Long
@ Zyndar - Ja das weiß ich. Gibt es eine Möglichkeit, diesen Test zu bestehen?
Simon Long
Müsste das nicht themeim Test verwendet werden? Wie in, wickeln Sie die <MyStyledButton>in die <MuiThemeProvider theme={theme}>? Oder verwenden Sie eine Wrapper-Funktion, um das Thema allen Komponenten hinzuzufügen?
Brett DeWoody
Nein, das macht keinen Unterschied.
Simon Long

Antworten:

1

Ich bin näher gekommen, aber noch nicht ganz an einer Lösung.

Das Hauptproblem besteht darin, dass MUIButton dem Element ein Tag hinzufügt, um die Stile zu aktivieren. Dies geschieht in Ihrem Komponententest nicht. Ich konnte dies mithilfe des von den Materialtests verwendeten createMount zum Laufen bringen .

Nach diesem Fix wird der Stil korrekt angezeigt. Der berechnete Stil funktioniert jedoch immer noch nicht. Es sieht so aus, als ob andere auf Probleme mit der korrekten Handhabung von Enzymen gestoßen sind - daher bin ich mir nicht sicher, ob dies möglich ist.

Um dorthin zu gelangen, wo ich war, nehmen Sie Ihr Test-Snippet, kopieren Sie es nach oben und ändern Sie dann Ihren Testcode in:

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
quelle