reactjs - Jest / RTL Failure -- MUI V5 + Emotion Theme 问题
问题描述
我目前正在使用 MUI V5 和 Emotion 进行造型。下面的代码在 Storybook 中没有问题,所以我有点困惑为什么主题没有被注入到 Emotion 样式中。我认为 ThemeProvider 会处理注入,但它似乎不起作用。有什么想法吗?蒂亚!
Badge.tsx
import React, { ReactElement } from 'react';
import * as S from './styles';
export type TBadgeEmphasis = 'subtle' | 'high';
export type TBadgeType = 'default' | 'success' | 'warning' | 'error';
export interface BadgeProps {
/**
* Text for the badge.
*/
children: ReactElement | string;
/**
* Option here between `subtle` and `high` depending on the desired intensity.
*/
emphasis: TBadgeEmphasis;
/**
* Option here between `default`, `success`, `warning` and `error`.
*/
type: string;
}
export const Badge = (props: BadgeProps): ReactElement => {
return (
<S.StyledBadge
data-testid={`${props.type}-${props.emphasis}-badge`}
emphasis={props.emphasis}
label={props.children}
type={props.type}
/>
);
};
Badge.styles.tsx
import { css } from '@emotion/react';
import { styled } from '@mui/material/styles';
import { Chip as MuiChip, ChipProps as MuiChipProps } from '@mui/material';
interface BadgeStyleProps extends MuiChipProps {
emphasis: string;
type: string;
}
const buildStyles = (props: BadgeStyleProps) => {
let styles;
const { emphasis, theme, type } = props;
const baseStyle = css`
font-size: 13px;
font-weight: 700;
border-radius: 4px;
min-width: 90px;
max-width: 180px;
padding-left: 10px;
padding-right: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
if (emphasis === 'subtle') {
switch (type) {
case 'default':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.coolGrey2};
color: ${theme.palette.expanded.slate};
`;
break;
case 'error':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.red4};
color: ${theme.palette.expanded.red2};
`;
break;
case 'success':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.green4};
color: ${theme.palette.expanded.green1};
`;
break;
case 'warning':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.orange3};
color: ${theme.palette.expanded.orange1};
`;
break;
}
} else if (emphasis === 'high') {
switch (type) {
case 'default':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.lightSlate};
color: ${theme.palette.common.white};
`;
break;
case 'error':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.coral};
color: ${theme.palette.common.white};
`;
break;
case 'success':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.green1};
color: ${theme.palette.common.white};
`;
break;
case 'warning':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.orange1};
color: ${theme.palette.common.white};
`;
break;
}
}
return styles;
};
export const StyledBadge = styled(MuiChip)`
${buildStyles};
`;
Badge.test.tsx
import { ThemeProvider } from '@mui/material/styles';
import { render, screen } from '@testing-library/react';
import React, { ReactNode } from 'react';
import { Badge, BadgeProps } from '../';
import { theme } from '../../../packages/core/src/theme';
const DefaultSubtleArgs: BadgeProps = {
children: 'Default',
emphasis: 'subtle',
type: 'default',
};
const ThemeWrapper = ({ children }: { children: any }) => {
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
};
test('renders the badge in the subtle default state', () => {
render(
<ThemeWrapper>
<Badge {...DefaultSubtleArgs} />
</ThemeWrapper>
);
expect(screen.getByTestId('default-subtle-badge')).toHaveTextContent(
'Default'
);
});
const SuccessSubtleArgs: BadgeProps = {
children: 'Success',
emphasis: 'subtle',
type: 'success',
};
test('renders the badge in the subtle success state', () => {
render(
<ThemeWrapper>
<Badge {...SuccessSubtleArgs} />
</ThemeWrapper>
);
expect(screen.getByTestId('success-subtle-badge')).toHaveTextContent(
'Success'
);
});
const WarningSubtleArgs: BadgeProps = {
children: 'Warning',
emphasis: 'subtle',
type: 'warning',
};
test('renders the badge in the subtle warning state', () => {
render(
<ThemeWrapper>
<Badge {...WarningSubtleArgs} />
</ThemeWrapper>
);
expect(screen.getByTestId('warning-subtle-badge')).toHaveTextContent(
'Warning'
);
});
const ErrorSubtleArgs: BadgeProps = {
children: 'Error',
emphasis: 'subtle',
type: 'error',
};
test('renders the badge in the subtle error state', () => {
render(
<ThemeWrapper>
<Badge {...ErrorSubtleArgs} />
</ThemeWrapper>
);
expect(screen.getByTestId('error-subtle-badge')).toHaveTextContent('Error');
});
解决方案
MUI V5 与 Theme Providers 一起工作的方式肯定会发生一些事情。
我找到了一种解决方法,但它并不优雅。请让我知道其他人有另一种方式。
通过您的测试,您只需坚持使用 包装每个组件ThemeProvider
并注入您的主题。
在实际的组件文件中,您将需要使用useTheme
钩子来获取正确的主题对象,然后您需要将其作为唯一的道具传递给样式化的组件。
import { css } from '@emotion/react';
import { Chip as MuiChip, ChipProps as MuiChipProps } from '@mui/material';
import { styled, useTheme, Theme } from '@mui/material/styles';
import React, { ReactElement } from 'react';
export type TBadgeEmphasis = 'subtle' | 'high';
export type TBadgeType = 'default' | 'success' | 'warning' | 'error';
export interface BadgeProps {
/**
* Text for the badge.
*/
children: ReactElement | string;
/**
* Option here between `subtle` and `high` depending on the desired intensity.
*/
emphasis: TBadgeEmphasis;
/**
* Option here between `default`, `success`, `warning` and `error`.
*/
type: string;
}
interface BadgeStyleProps extends MuiChipProps {
emphasis: string;
theme: Theme;
type: string;
}
const StyledBadge = styled(MuiChip)<BadgeStyleProps>(
({ emphasis, theme, type }) => {
let styles;
const baseStyle = css`
font-size: 13px;
font-weight: 700;
border-radius: 4px;
min-width: 90px;
max-width: 180px;
padding-left: 10px;
padding-right: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
if (emphasis === 'subtle') {
switch (type) {
case 'default':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.coolGrey2};
color: ${theme.palette.expanded.slate};
`;
break;
case 'error':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.red4};
color: ${theme.palette.expanded.red2};
`;
break;
case 'success':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.green4};
color: ${theme.palette.expanded.green1};
`;
break;
case 'warning':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.orange3};
color: ${theme.palette.expanded.orange1};
`;
break;
}
} else if (emphasis === 'high') {
switch (type) {
case 'default':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.lightSlate};
color: ${theme.palette.common.white};
`;
break;
case 'error':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.coral};
color: ${theme.palette.common.white};
`;
break;
case 'success':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.green1};
color: ${theme.palette.common.white};
`;
break;
case 'warning':
styles = css`
${baseStyle};
background: ${theme.palette.expanded.orange1};
color: ${theme.palette.common.white};
`;
break;
}
}
return styles;
}
);
export const Badge = (props: BadgeProps): ReactElement => {
const themeOverride = useTheme();
return (
<StyledBadge
data-testid={`${props.type}-${props.emphasis}-badge`}
emphasis={props.emphasis}
label={props.children}
theme={themeOverride}
type={props.type}
/>
);
};
推荐阅读
- excel - Excel:显示单元格中的值并在填充另一个单元格时覆盖
- sql - 如何通过基于平均数据“AVG”的排序进行排序来在 SQL 中排序
- vb.net - 如何在 roslyn 分析器中生成 VB.Net 代码修复
- typescript - TS 从对象参数的回调属性的返回类型推断
- javascript - 从点击更改为显示键(如果我可以指定特定键,则奖励)
- php - Prestashop 1.7.7.8 - ProductListingPresenter::present() 中的 FatalThrowableError
- axios - 如何禁用 Nuxt 中的进度条?
- javascript - 在 React useEffect hook 中处理响应状态 - 生命周期问题?
- python - Qpid Proton Python 在 on_message 中检测到一个空队列
- selenium - Selenium - 向下箭头并输入不可能?