reactjs - Apollo Graphql-ის ერთეული ტესტირება React-ში Hooks-ის გამოყენებით
ვცდილობ შევქმნა ერთეული ტესტი React და Apollo Graphql გამოყენებით, თუმცა მუდმივად ვღებულობ ამ შეცდომას:
Watch Usage: Press w to show more. console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:104
Warning: An update to ThemeHandler inside a test was not wrapped in act(...).
When testing, code that causes React state updates should be wrapped into act(...):
act(() => {
/* fire events that update state */
});
/* assert on the output */
This ensures that you're testing the behavior the user would see in the browser.
in ThemeHandler (at theme-handler.spec.tsx:51)
in ApolloProvider (created by MockedProvider)
in MockedProvider (at theme-handler.spec.tsx:50)
აქ არის ჩემი კოდი:
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core';
import * as Sentry from '@sentry/browser';
import React, { useState } from 'react';
import { BrandTheme, useGetBrandThemeQuery } from '../../generated/graphql';
/**
* Handles the app theme. Will set the default theme or the brand theme taken from the backend.
*/
export default function ThemeHandler(props: React.PropsWithChildren<any>): React.ReactElement {
const brandId = Number(process.env.REACT_APP_BRAND);
// Default Onyo theme
const [theme, setTheme] = useState({
palette: {
primary: { main: '#f65a02' },
secondary: { main: '#520075' },
},
typography: {
fontFamily: 'Quicksand, sans-serif',
},
});
useGetBrandThemeQuery({
variables: { brandId },
skip: brandId <= 0,
onCompleted: data => {
if (
!data.brandTheme ||
!data.brandTheme.brandThemeColor ||
data.brandTheme.brandThemeColor.length === 0
) {
console.warn('Empty brand theme returned, using default');
Sentry.captureMessage(`Empty brand theme for brandId: ${brandId}`, Sentry.Severity.Warning);
} else {
const palette = parseBrandPalette(data.brandTheme as BrandTheme);
setTheme({ ...theme, palette });
console.log('Theme', theme, data.brandTheme);
}
},
});
return <MuiThemeProvider theme={createMuiTheme(theme)}>{props.children}</MuiThemeProvider>;
}
function parseBrandPalette(brandTheme: BrandTheme) {
const pallete: any = {};
for (const color of brandTheme.brandThemeColor!) {
if (color && color.key === 'primaryColor') {
pallete.primary = { main: color.value };
} else if (color && color.key === 'darkPrimaryColor') {
pallete.secondary = { main: color.value };
}
}
return pallete;
}
და ჩემი ტესტი:
import renderer from 'react-test-renderer';
import React from 'react';
import ThemeHandler from './theme-handler';
import { MockedProvider, wait } from '@apollo/react-testing';
import { GetBrandThemeDocument } from '../../generated/graphql';
import { Button } from '@material-ui/core';
const { act } = renderer;
describe('Theme Handler', () => {
const originalEnv = process.env;
beforeEach(() => {
// https://stackoverflow.com/questions/48033841/test-process-env-with-jest/48042799
jest.resetModules();
process.env = { ...originalEnv };
delete process.env.REACT_APP_BRAND;
});
afterEach(() => {
process.env = originalEnv;
});
it('should use a theme retrieved from the backend', async () => {
process.env.REACT_APP_BRAND = '39';
const mocks = [
{
request: {
query: GetBrandThemeDocument,
variables: { brandId: 39 },
},
result: {
data: {
brandTheme: {
brandThemeColor: [
{ key: 'primaryColor', value: '#182335' },
{ key: 'darkPrimaryColor', value: '#161F2F' },
],
},
},
},
},
];
let wrapper;
act(() => {
wrapper = renderer.create(
<MockedProvider mocks={mocks} addTypename={false}>
<ThemeHandler>
<Button color='primary' id='test-obj'>
Hello world!
</Button>
</ThemeHandler>
</MockedProvider>
);
});
await wait(0);
expect(wrapper).toBeTruthy();
});
});
მეც ვცადე Enzyme-ის mount გამოყენება React ტესტ რენდერის ნაცვლად, მაგრამ შედეგი იგივეა.
ჩემი დასკვნით, ეს შეცდომა გამოწვეულია იმით, რომ ვცვლი მიმდინარე სტატუსს ასინქრონული ფუნქციისა და Hooks-ის გამოყენებით. მაგრამ დარწმუნებული არ ვარ, რა შემიძლია განსხვავებულად გავაკეთო, რომ ეს მუშაობდეს.
პასუხი #1
მე მივუშველე ჩემი პრობლემა ისე, რომ დავაფარე ყველაფერი ჩემს ტესტზე act-ით. მე მჯერა, რომ ეს შეცდომა იმის გამო მომხდარა, რომ ტესტის ნაწილი იყო დაფარული act-ით, მაგრამ ასინქრონული ნაწილი არა, ამიტომ ცვლილება ხდებოდა ამ ფუნქციის ფარგლებს გარეთ.
აქ არის განახლებული ტესტი, რომელიც გაივლის:
import React from 'react';
import ThemeHandler from './theme-handler';
import { MockedProvider, wait } from '@apollo/react-testing';
import { GetBrandThemeDocument } from '../../generated/graphql';
import { Button } from '@material-ui/core';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
describe('Theme Handler', () => {
const originalEnv = process.env;
beforeEach(() => {
// https://stackoverflow.com/questions/48033841/test-process-env-with-jest/48042799
jest.resetModules();
process.env = { ...originalEnv };
delete process.env.REACT_APP_BRAND;
});
afterEach(() => {
process.env = originalEnv;
});
it('should use a theme retrieved from the backend', async () => {
process.env.REACT_APP_BRAND = '39';
await act(async () => {
const mocks = [
{
request: {
query: GetBrandThemeDocument,
variables: { brandId: 39 },
},
result: {
data: {
brandTheme: {
brandThemeColor: [
{ key: 'primaryColor', value: '#182335' },
{ key: 'darkPrimaryColor', value: '#161F2F' },
],
},
},
},
},
];
const wrapper = mount(
<MockedProvider mocks={mocks} addTypename={false}>
<ThemeHandler>
<Button color='primary' id='test-obj'>
Hello world!
</Button>
</ThemeHandler>
</MockedProvider>
);
expect(wrapper).toBeTruthy();
await wait(0);
wrapper.update();
expect(wrapper.find('#test-obj')).toBeTruthy();
});
});
});
