Perché getComputedStyle () in un test JEST restituisce risultati diversi agli stili calcolati in Chrome / Firefox DevTools


16

Ho scritto un pulsante personalizzato ( MyStyledButton) basato su 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;

È disegnato con un tema e questo specifica che backgroundColordeve essere una sfumatura di giallo (in particolare #fbb900)

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

export const myYellow = "#FBB900";

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

Il componente è istanziato nel mio principale index.jse racchiuso nel theme.

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

Se esamino il pulsante in Chrome DevTools, background-colorviene "calcolato" come previsto. Questo è anche il caso di Firefox DevTools.

Schermata di Chrome

Tuttavia, quando scrivo un test JEST per controllare background-colore faccio una query sullo stile del nodo DOM del pulsante usando getComputedStyles()torno transparentindietro e il test fallisce.

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

Ho incluso un CodeSandbox con il problema esatto, il codice minimo da riprodurre e il test JEST fallito.

Modifica headless-snow-nyofd


.MuiButtonBase-root-33 background-color è trasparente mentre .MuiButton-contenutePrimary-13 non lo è - quindi il problema è che le classi in CSS sono ugualmente importanti, quindi solo l'ordine di caricamento li distingue -> negli stili di test sono caricati nell'ordine sbagliato.
Zydnar,

1
@Andreas - Aggiornato come richiesto
Simon Long

@Zyndar - Sì, lo so. Esiste un modo per superare questo test?
Simon Long,

Non sarebbe themenecessario utilizzare nel test? Come in, avvolgi il <MyStyledButton>in <MuiThemeProvider theme={theme}>? O utilizzare una funzione wrapper per aggiungere il tema a tutti i componenti?
Brett DeWoody,

No, questo non fa alcuna differenza.
Simon Long,

Risposte:


1

Mi sono avvicinato, ma non ho ancora trovato una soluzione.

Il problema principale è che MUIButton inserisce un tag nell'elemento per alimentare gli stili. Questo non accade nel test unitario. Sono stato in grado di farlo funzionare utilizzando createMount utilizzato dai test sui materiali.

Dopo questa correzione, lo stile viene visualizzato correttamente. Tuttavia, lo stile calcolato non funziona ancora. Sembra che altri abbiano riscontrato problemi con la corretta gestione degli enzimi, quindi non sono sicuro che sia possibile.

Per arrivare a dove mi trovavo, prendi lo snippet di prova, copialo in alto, quindi modifica il codice di prova 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.