restyle: Jest failes with "Value does not exist in theme['spacing']" when spacing value is used

I’m using a spacing theme value on a Box component:

import React from 'react';
import { Box, Text } from '../';

function NiceBox() {
  return (
    <Box padding="m">
      <Text>So nice!</Text>
    </Box>
  );
}

export default NiceBox;

Inside a Jest test file, I try to render the component using @testing-library/react-native (see https://github.com/Shopify/restyle/issues/62#issuecomment-712883700)

import React from 'react';
import { render } from '@testing-library/react-native';
import NiceBox from './NiceBox';

test('renders correctly', () => {
  render(<NiceBox />);
});

Which throws this error:

Value 'm' does not exist in theme['spacing']

The spacing value exist in the theme deceleration, and renders correctly (outside Jest).

Any idea why is that? 🥺

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (5 by maintainers)

Most upvoted comments

@guytepper hi, restyle requires the ThemeProvider component to wrap the whole application. You pass the theme object as the ThemeProvider’s prop and it makes the theme available to nested components via React Context. So when you’re rendering <Bod padding="m" />, the Box component tries to get the theme context. But it’s not present in your test.

Usually, a good practice here is to create your custom render wrapper to set up your contexts, e.g.:

// Some global test-utils.js file

import React from 'react';
import { ThemeProvider } from '@shopify/restyle';
import { render as rntlRender } from '@testing-library/react-native';

const theme = {
   // some options here
   spacing: {
     s: 4,
     m: 8,
     l: 10,
   },
}

function render(ui, opts) {
    return rntlRender(ui, {
           wrapper: ({children}) => (
                  <ThemeProvider theme={theme}>
                     {children}
                  </ThemeProvider>
           )
       },
    )
}

export * from '@testing-library/react-native';
export {render};

And then later in your test:

// NiceBox.test.jsx

import React from 'react';
import { render } from './test-utils';
import NiceBox from './NiceBox';

test('renders correctly', () => {
  render(<NiceBox />);
});

You can use Jest’s moduleDirectory option and eslint-import-resolver-jest to allow absolute imports for test-utils, so no matter how deep in your folder structure the component test file is located, you can import it like import { render } from 'test-utils'

This is a very common scenario, I guess having a small note on that in the documentation would be very helpful I’d be happy to open the PR if it aligns with Shopify’s doc vision for this project 🙂

@caelinsutch you create a setup.js file. and in your jest.config.js,

setupFiles: ['<rootDir>/jest/setup.js'],

In that way, you probably would need to mock almost any component using the restyle theme as each of them will use the useDimensions hook. So you can also try to globally mock the useDimensions hook, e.g. in your setupJest file