styled-components / styled-components

Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress πŸ’…
https://styled-components.com
MIT License
40.47k stars 2.5k forks source link

v6 not injecting any style tag in test environment #4081

Open domarmstrong opened 1 year ago

domarmstrong commented 1 year ago

Environment

## System:
 - OS: macOS 13.4
 - CPU: (10) arm64 Apple M1 Max
 - Memory: 487.28 MB / 64.00 GB
 - Shell: 5.9 - /bin/zsh
## Binaries:
 - Node: 18.16.0 - /private/var/folders/.../node
 - Yarn: 3.6.0 - /private/var/folders/.../yarn
 - npm: 9.5.1 - ~/n/bin/npm
 - pnpm: 8.6.5 - ~/n/bin/pnpm

Reproduction

Repo https://github.com/domarmstrong/styled-components-v6-repro Sandbox https://codesandbox.io/p/sandbox/styled-components-6-cloud-forked-q2m4pm

Steps to reproduce

See reproduction.

It works fine in a non-cloud version of the same sandbox https://codesandbox.io/s/styled-components-6-kqszxg. But fails when run in the cloud version linked above.

Note: the reproduction env is abstracted by react-scripts. However our application uses jest/jsdom env directly with the same behavior, so this issue should not be related to that setup.

Expected Behavior

When running in jest with jsdom a <style> tag is added to the document head.

Actual Behavior

When running in jest with jsdom no style tag is inserted.

domarmstrong commented 1 year ago

I've had a further dig in to this and it appears to be because when running in Jest the dist/styled-components.cjs.js is used, and when built with webpack the ./dist/styled-components.browser.esm.js (or cjs) files are used. The styled-components.cjs.js is compiled to have a hardcoded value that isServer is true. Presumably, this should still be a runtime check, not a static value.

https://github.com/styled-components/styled-components/blob/8e4b064a9001dc32495f9c77f0334a9b527a0bf7/packages/styled-components/src/sheet/Sheet.ts#L23

styled-components.cjs.js

  ve = { isServer: !0, useCSSOMInjection: !f },

styled-components.browser.esm.js

  f = 'undefined' != typeof window && 'HTMLElement' in window,
  Ee = { isServer: !f, useCSSOMInjection: !y },

I've managed to get this working by adding a manual mapping in our jest config file. This wasn't previously required and I'm not sure it's very intuitive.

jest.config.js

  ...
  moduleNameMapper: {
    'styled-components': 'styled-components/dist/styled-components.browser.cjs.js',
  },
  ...
dejanvasic85 commented 1 year ago

Thanks @domarmstrong

Replicated the issue in a fairly clean repository using the testing library which is using jsdom: https://github.com/dejanvasic85/jest-styled-components

Your jest config fixes the problem for the moment. Great find πŸ‘ πŸ”₯

leonluna commented 1 year ago

apparently this issue also happened on v5.2.0 https://github.com/styled-components/styled-components/issues/3262

dejanvasic85 commented 1 year ago

The solution of jest config override negates the use of Jest Styled Components which helps with snapshot testing. Class names are always changing in the snapshots, but we're expecting the styles to be rendered at the top which is the responsibility of this tool. 😒