Files
react-test/test/integration/mui-system/theme-scoping.test.tsx
how2ice 005cf56baf
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
init project
2025-12-12 14:26:25 +09:00

161 lines
4.9 KiB
TypeScript

import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import { createRenderer, screen } from '@mui/internal-test-utils';
import { ThemeContext } from '@mui/styled-engine';
import * as material from '@mui/material';
import * as joy from '@mui/joy';
// simulate 3rd-party library like Theme-UI, Chakra-UI, or Mantine
interface LibTheme {
palette: { brand: string };
vars: { palette: { brand: string } };
}
function LibThemeProvider({ children }: React.PropsWithChildren<{}>) {
const theme = React.useMemo<LibTheme>(
() => ({ palette: { brand: '#ff5252' }, vars: { palette: { brand: 'var(--palette-brand)' } } }),
[],
);
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
}
function LibComponent() {
const theme = React.useContext(ThemeContext as unknown as React.Context<LibTheme>);
return <div style={{ color: theme.palette.brand }} />;
}
const joyTheme = joy.extendTheme({
components: {
JoyButton: {
defaultProps: {
variant: 'outlined',
},
styleOverrides: {
root: ({ theme }) => ({
color: theme.vars.palette.text.primary,
mixBlendMode: 'darken',
}),
},
},
},
});
const CustomJoy = joy.styled('div')(({ theme }) => ({
fontSize: theme.vars.fontSize.md,
}));
const materialTheme = material.createTheme({
components: {
MuiButton: {
defaultProps: {
variant: 'outlined',
},
styleOverrides: {
root: ({ theme }) => ({
color: theme.palette.text.primary,
mixBlendMode: 'darken',
}),
},
},
},
});
const CustomMaterial = material.styled('div')(({ theme }) => ({
borderRadius: theme.shape.borderRadius,
}));
describe('Multiple nested theme providers', () => {
const { render } = createRenderer();
let originalMatchmedia: any;
let storage: Record<string, string> = {};
const createMatchMedia = (matches: boolean) => () => ({
matches,
// Keep mocking legacy methods because @mui/material v5 still uses them
addListener: () => {},
addEventListener: () => {},
removeListener: () => {},
removeEventListener: () => {},
});
beforeEach(() => {
originalMatchmedia = window.matchMedia;
// Create mocks of localStorage getItem and setItem functions
Object.defineProperty(globalThis, 'localStorage', {
value: {
getItem: spy((key) => storage[key]),
setItem: spy((key, value) => {
storage[key] = value;
}),
},
configurable: true,
});
// clear the localstorage
storage = {};
window.matchMedia = createMatchMedia(false) as unknown as typeof window.matchMedia;
});
afterEach(() => {
window.matchMedia = originalMatchmedia;
});
it('[docs] Material UI + Joy UI', () => {
render(
<joy.CssVarsProvider theme={{ [joy.THEME_ID]: joyTheme }}>
<material.ThemeProvider theme={materialTheme}>
<joy.Button
sx={(theme) => ({
// test `sx`
bgcolor: theme.vars.palette.neutral[100],
})}
>
Joy
</joy.Button>
<material.Button
sx={(theme) => ({
bgcolor: theme.palette.secondary.light,
})}
>
Material
</material.Button>
</material.ThemeProvider>
</joy.CssVarsProvider>,
);
// these test if `useThemeProps` works with theme scoping
expect(screen.getByText('Joy')).to.have.class(joy.buttonClasses.variantOutlined);
expect(screen.getByText('Joy')).toHaveComputedStyle({ mixBlendMode: 'darken' });
expect(screen.getByText('Material')).to.have.class(material.buttonClasses.outlinedPrimary);
expect(screen.getByText('Material')).toHaveComputedStyle({ mixBlendMode: 'darken' });
});
it('Material UI works with 3rd-party lib', () => {
render(
<LibThemeProvider>
<material.ThemeProvider theme={{ [material.THEME_ID]: materialTheme }}>
<material.Button>Material</material.Button>
<CustomMaterial /> {/* styled() should work with theme scoping */}
<LibComponent />{' '}
{/* still able to render even though it is wrapped in Material UI ThemeProvider */}
</material.ThemeProvider>
</LibThemeProvider>,
);
expect(screen.getByText('Material')).to.have.class(material.buttonClasses.outlinedPrimary);
});
it('Joy UI works with 3rd-party lib', () => {
render(
<LibThemeProvider>
<joy.ThemeProvider theme={{ [joy.THEME_ID]: joyTheme }}>
<joy.Button>Joy</joy.Button>
<CustomJoy /> {/* styled() should work with theme scoping */}
<LibComponent />{' '}
{/* still able to render even though it is wrapped in Material UI ThemeProvider */}
</joy.ThemeProvider>
</LibThemeProvider>,
);
expect(screen.getByText('Joy')).to.have.class(joy.buttonClasses.variantOutlined);
});
});