Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/react/src/contexts/theme.ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @jest-environment node
*/
import React from 'react';
import { renderToString } from 'react-dom/server';
import { ThemeProvider, useThemeContext } from './theme';

const ThemeTester = () => {
useThemeContext();
return <div />;
};

// This suite runs under the `node` environment (see the docblock above), where
// `document` is not a declared global — the same condition as an SSR framework
// prerendering a client component (e.g. Next.js App Router). A bare
// `document?.body` default would throw `ReferenceError: document is not
// defined` here, because optional chaining only guards against null/undefined
// values, not undeclared globals.
test('ThemeProvider renders without error when document is undefined (SSR)', () => {
expect(typeof document).toBe('undefined');
let html = '';
expect(() => {
html = renderToString(
<ThemeProvider initialTheme="dark">
<ThemeTester />
</ThemeProvider>
);
}).not.toThrow();
expect(html).toBe('<div></div>');
});
2 changes: 1 addition & 1 deletion packages/react/src/contexts/theme.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const ThemeContext = createContext<State & Methods>({
const ThemeProvider = ({
children,
// eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
context = document?.body,
context = typeof document !== 'undefined' ? document.body : undefined,
initialTheme = 'light'
}: ProviderProps) => {
const [theme, setTheme] = useState<Theme>(initialTheme);
Expand Down
13 changes: 11 additions & 2 deletions packages/react/src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ configureAxe({
}
});

if (!('clipboard' in global.navigator)) {
// Guard the DOM-dependent shims so this setup can also run under the `node`
// test environment (used by SSR test suites), where `navigator`/`document` are
// not declared globals.
if (
typeof global.navigator !== 'undefined' &&
!('clipboard' in global.navigator)
) {
Object.defineProperty(global.navigator, 'clipboard', {
value: {
writeText: async () => null
Expand All @@ -19,7 +25,10 @@ if (!('clipboard' in global.navigator)) {
});
}

if (!('execCommand' in global.document)) {
if (
typeof global.document !== 'undefined' &&
!('execCommand' in global.document)
) {
Object.defineProperty(global.document, 'execCommand', {
value: () => null,
configurable: true,
Expand Down
Loading