styled-components / jest-styled-components

🔧 💅 Jest utilities for Styled Components
MIT License
1.59k stars 145 forks source link

How do you test createGlobalStyle? #232

Open willbamford opened 5 years ago

willbamford commented 5 years ago

Hi,

Has anyone found a way of testing the styling in createGlobalStyle?

I'm experiencing the same issue as mentioned in this thread i.e. mounting <GlobalStyle /> doesn't result in generated CSS.

mrmckeb commented 4 years ago

This is the best I've come up with... but I don't like it.

render(<GlobalStyle />);
const styleTags = document.head.getElementsByTagName('style');
expect(styleTags)...
gibbok commented 4 years ago

Try to get check on the document.head, this should help 😄

describe('GlobalStyle', () => {
  it('renders properly', () => {
    renderer.create(<GlobalStyle />);
    expect(document.head).toMatchSnapshot();
  });
});

The snapshot will contain the CSS added in the head, an example:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`GlobalStyle renders properly 1`] = `
<head>
  <style
    data-styled="active"
    data-styled-version="5.1.1"
  >
    html{line-height:1.15;-webkit-text-size-adjust:100%;}
    body{margin:0;}
    main{display:block;}
    h1{font-size:2em;margin:0.67em 0;}
    hr{box-sizing:content-box;height:0;overflow:visible;}
    pre{font-family:monospace,monospace;font-size:1em;}
    a{background-color:transparent;}
    abbr[title]{border-bottom:none;-webkit-text-decoration:underline;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;}
    b,strong{font-weight:bolder;}
    code,kbd,samp{font-family:monospace,monospace;font-size:1em;}
    small{font-size:80%;}
    sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline;}
    sub{bottom:-0.25em;}
    sup{top:-0.5em;}
    img{border-style:none;}
    button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0;}
    button,input{overflow:visible;}
    button,select{text-transform:none;}
    button,[type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button;}
    button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0;}
    button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText;}
    fieldset{padding:0.35em 0.75em 0.625em;}
    legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal;}
    progress{vertical-align:baseline;}
    textarea{overflow:auto;}
    [type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0;}
    [type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto;}
    [type="search"]{-webkit-appearance:textfield;outline-offset:-2px;}
    [type="search"]::-webkit-search-decoration{-webkit-appearance:none;}
    ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit;}
    details{display:block;}
    summary{display:list-item;}
    template{display:none;}
    [hidden]{display:none;}
    html{box-sizing:border-box;font-size:62.5%;font-family:'Oleo Script',cursive;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-o-font-feature-settings:'salt' 1;-ms-font-feature-settings:'salt' 1;-webkit-font-smoothing:antialiased;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-moz-osx-font-smoothing:grayscale;-moz-font-feature-settings:'salt' 1;-webkit-font-feature-settings:'salt' 1;font-feature-settings:'salt' 1;text-rendering:optimizeLegibility;}
    *,*:before,*:after{box-sizing:inherit;}
    body{margin:0;padding:0;}
  </style>
</head>
`;
lester-arevalo commented 3 years ago

render(); const styleTags = document.head.getElementsByTagName('style'); throws an error console.error Error: Could not parse CSS stylesheet at exports.createStylesheet

sauldeleon commented 2 years ago

document.head.getElementsByTagName('style')

I tried to do this, but I dont see anything in the Head nor in the body :(

mukundhan94 commented 2 months ago

had to combine a few existing workarounds to arrive here,

The Code is self-explanatory

GlobalStyles.tsx

export const GlobalStyles = createGlobalStyle`
    button,
    fieldset,
    input {
        all: unset;
    }
}

setupTests.ts

export const globalStyleInjector = new GlobalStyleInjector();
globalStyleInjector.init();

GlobalStyles.test.tsx

import renderer from "react-test-renderer";
import { GlobalStyles } from "./GlobalStyles";
import { globalStyleInjector } from "../setupTests";

function formElement(styleTags: string) {
  const template = document.createElement("template");
  template.innerHTML = styleTags;
  const styledComponentsElement = template.content.firstChild;
  return styledComponentsElement;
}

class GlobalStyleInjector {
  private styleTag: string = "";

  public setStyle(style: string[] = []) {
    this.styleTag = `<style>${style.join(" ")}</style>`;
  }

  public getStyleTag() {
    return this.styleTag;
  }

  init() {
    jest.mock("styled-components", () => {
      const originalModule = jest.requireActual("styled-components");
      const createGlobalStyle = (css: any[], ...rest: any[]) => {
        this.setStyle(css);
        return originalModule.createGlobalStyle(css, ...rest);
      };

      return {
        __esModule: true,
        ...originalModule,
        createGlobalStyle: jest.fn(createGlobalStyle)
      };
    });
  }
}

describe("GlobalStyle", () => {
  it("renders properly", () => {
    renderer.create(<GlobalStyles />);
    document.head.appendChild(
      formElement(globalStyleInjector.getStyleTag()) as ChildNode
    );
    expect(document.head).toMatchSnapshot();
  });
});

GlobalStyles.test.tsx.snap

// Jest Snapshot v1

exports[`GlobalStyle renders properly 1`] = `
<head>
  <style>

    button,
    fieldset,
    input {
        all: unset;
    }

  </style>
</head>
`;