Skip to content

Commit

Permalink
feat(fuselage-hooks): React 18 compatibility (#1483)
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan authored Nov 14, 2024
1 parent f064014 commit 4910d29
Show file tree
Hide file tree
Showing 62 changed files with 282 additions and 264 deletions.
6 changes: 6 additions & 0 deletions .changeset/witty-dodos-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/fuselage-hooks': minor
'@rocket.chat/fuselage': patch
---

Enables hooks' compatibility with React 18
7 changes: 0 additions & 7 deletions packages/fuselage-hooks/jest.config.js

This file was deleted.

68 changes: 68 additions & 0 deletions packages/fuselage-hooks/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { Config } from 'jest';

export default {
projects: [
{
displayName: 'React 17',
preset: 'ts-jest',
errorOnDeprecated: true,
testMatch: [
'<rootDir>/src/**/*.spec.{ts,tsx}',
'!**/*.server.spec.{ts,tsx}',
],
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['testing-utils/setup/noErrorsLogged'],
moduleNameMapper: {
'^react($|/.+)': 'react$1',
'^react-dom/client$': 'react-dom$1',
'^react-dom($|/.+)': 'react-dom$1',
},
},
{
displayName: 'React 17 SSR',
preset: 'ts-jest',
errorOnDeprecated: true,
testMatch: ['<rootDir>/src/**/*.server.spec.{ts,tsx}'],
testEnvironment: 'node',
setupFilesAfterEnv: ['testing-utils/setup/noErrorsLogged'],
moduleNameMapper: {
'^react($|/.+)': 'react$1',
'^react-dom/client$': 'react-dom$1',
'^react-dom($|/.+)': 'react-dom$1',
},
},
{
displayName: 'React 18',
preset: 'ts-jest',
errorOnDeprecated: true,
testMatch: [
'<rootDir>/src/**/*.spec.{ts,tsx}',
'!**/*.server.spec.{ts,tsx}',
],
testEnvironment: 'jsdom',
setupFilesAfterEnv: [
'testing-utils/setup/noErrorsLogged',
'<rootDir>/src/jest-setup.ts',
],
moduleNameMapper: {
'^react($|/.+)': 'react18$1',
'^react-dom($|/.+)': 'react-dom18$1',
},
},
{
displayName: 'React 18 SSR',
preset: 'ts-jest',
errorOnDeprecated: true,
testMatch: ['<rootDir>/src/**/*.server.spec.{ts,tsx}'],
testEnvironment: 'node',
setupFilesAfterEnv: [
'testing-utils/setup/noErrorsLogged',
'<rootDir>/src/jest-setup.ts',
],
moduleNameMapper: {
'^react($|/.+)': 'react18$1',
'^react-dom($|/.+)': 'react-dom18$1',
},
},
],
} satisfies Config;
5 changes: 4 additions & 1 deletion packages/fuselage-hooks/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"@rollup/plugin-json": "~4.1.0",
"@rollup/plugin-node-resolve": "~13.1.3",
"@rollup/plugin-typescript": "~8.3.4",
"@testing-library/react-hooks": "~8.0.1",
"@testing-library/react": "~16.0.1",
"@testing-library/user-event": "~14.5.2",
"@types/jest": "~29.5.12",
"@types/react": "~17.0.80",
Expand All @@ -63,6 +63,9 @@
"npm-run-all": "^4.1.5",
"prettier": "~3.3.3",
"react": "^17.0.2",
"react-dom": "~17.0.2",
"react-dom18": "npm:react-dom@18",
"react18": "npm:react@18",
"rimraf": "~5.0.0",
"rollup": "~2.79.2",
"rollup-plugin-terser": "~7.0.2",
Expand Down
3 changes: 3 additions & 0 deletions packages/fuselage-hooks/src/jest-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { configure } from '@testing-library/react';

configure({ reactStrictMode: true });
45 changes: 45 additions & 0 deletions packages/fuselage-hooks/src/testing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
queries,
Queries,
RenderHookOptions,
RenderHookResult,
renderHook as _renderHook,
} from '@testing-library/react';
import { createElement } from 'react';
import * as ReactDOMClient from 'react-dom';
import { renderToString } from 'react-dom/server';

type RendererableContainer = Element | Document | DocumentFragment;

export function renderHook<
Result,
Props,
Q extends Queries = typeof queries,
Container extends RendererableContainer = HTMLElement,
BaseElement extends RendererableContainer = Container,
>(
render: (initialProps: Props) => Result,
options?: RenderHookOptions<Props, Q, Container, BaseElement> | undefined,
): RenderHookResult<Result, Props> {
if (typeof document === 'undefined') {
let current: Result;
const TestComponent = () => {
current = render(options?.initialProps as any);
return null;
};

renderToString(createElement(TestComponent));

return {
result: { current: current! },
rerender: () => undefined,
unmount: () => undefined,
};
}

if ('createRoot' in ReactDOMClient) return _renderHook(render, options);

return _renderHook(render, { ...options, legacyRoot: true });
}

export { act } from '@testing-library/react';
10 changes: 5 additions & 5 deletions packages/fuselage-hooks/src/useAutoFocus.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { useImperativeHandle, useState } from 'react';

import { renderHook, act } from './testing';
import { useAutoFocus } from './useAutoFocus';

const focus = jest.fn();
Expand All @@ -17,7 +17,7 @@ it('invokes focus', async () => {

act(() => undefined);

expect(focus).toHaveBeenCalledTimes(1);
expect(focus).toHaveBeenCalled();
});

it('does not invoke focus if isFocused is false', () => {
Expand All @@ -28,7 +28,7 @@ it('does not invoke focus if isFocused is false', () => {

act(() => undefined);

expect(focus).toHaveBeenCalledTimes(0);
expect(focus).not.toHaveBeenCalled();
});

it('invokes focus if isFocused is toggled', () => {
Expand All @@ -41,11 +41,11 @@ it('invokes focus if isFocused is toggled', () => {

act(() => undefined);

expect(focus).toHaveBeenCalledTimes(0);
expect(focus).not.toHaveBeenCalled();

act(() => {
result.current.setIsFocused(true);
});

expect(focus).toHaveBeenCalledTimes(1);
expect(focus).toHaveBeenCalled();
});
12 changes: 5 additions & 7 deletions packages/fuselage-hooks/src/useAutoFocus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useEffect, useRef } from 'react';
* @param options - options of the focus request
* @returns the ref which holds the element
* @public
* @deprecated in favor of focus provided by react-hook-form
* @deprecated in favor of focus provided by react-hook-form or the `autoFocus` attribute
*/
export const useAutoFocus = <
T extends { focus: (options?: FocusOptions) => void },
Expand All @@ -17,16 +17,14 @@ export const useAutoFocus = <
options?: FocusOptions,
): Ref<T> => {
const elementRef = useRef<T>(null);

const { preventScroll } = options || {};
const optionsRef = useRef(options);
optionsRef.current = options;

useEffect(() => {
if (isFocused && elementRef.current) {
elementRef.current.focus({
preventScroll,
});
elementRef.current.focus(optionsRef.current);
}
}, [elementRef, isFocused, preventScroll]);
}, [elementRef, isFocused]);

return elementRef;
};
6 changes: 1 addition & 5 deletions packages/fuselage-hooks/src/useBorderBoxSize.server.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
/**
* @jest-environment node
*/

import { renderHook } from '@testing-library/react-hooks/server';
import { useRef } from 'react';

import { renderHook } from './testing';
import { useBorderBoxSize } from './useBorderBoxSize';

it('immediately returns zero size', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage-hooks/src/useBorderBoxSize.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { renderHook, act } from '@testing-library/react-hooks';
import type { RefObject } from 'react';
import { useRef } from 'react';
import { withResizeObserverMock } from 'testing-utils/mocks/withResizeObserverMock';

import { renderHook, act } from './testing';
import { useBorderBoxSize } from './useBorderBoxSize';

withResizeObserverMock();
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage-hooks/src/useBreakpoints.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import breakpoints from '@rocket.chat/fuselage-tokens/breakpoints.json';
import { renderHook, act } from '@testing-library/react-hooks';
import { withMatchMediaMock } from 'testing-utils/mocks/withMatchMediaMock';

import { renderHook, act } from './testing';
import { useBreakpoints } from './useBreakpoints';

const setViewport = withMatchMediaMock();
Expand Down
7 changes: 1 addition & 6 deletions packages/fuselage-hooks/src/useClipboard.server.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
/**
* @jest-environment node
*/

import { renderHook } from '@testing-library/react-hooks/server';

import { renderHook } from './testing';
import { useClipboard } from './useClipboard';

it('has hasCopied and copy properties', () => {
Expand Down
10 changes: 5 additions & 5 deletions packages/fuselage-hooks/src/useClipboard.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { withClipboardMock } from 'testing-utils/mocks/withClipboardMock';

import { renderHook, act } from './testing';
import { useClipboard } from './useClipboard';

let container: Element | undefined;
Expand Down Expand Up @@ -87,8 +87,8 @@ it('runs only success function receiving event object', async () => {
await copy(event);
});

expect(onCopySuccess).toBeCalledWith(event);
expect(onCopyError).toBeCalledTimes(0);
expect(onCopySuccess).toHaveBeenCalledWith(event);
expect(onCopyError).toHaveBeenCalledTimes(0);
});

it('runs only error function receiving error object', async () => {
Expand All @@ -112,6 +112,6 @@ it('runs only error function receiving error object', async () => {
await copy(event);
});

expect(onCopySuccess).toBeCalledTimes(0);
expect(onCopyError).toBeCalledWith(rejection);
expect(onCopySuccess).toHaveBeenCalledTimes(0);
expect(onCopyError).toHaveBeenCalledWith(rejection);
});
6 changes: 1 addition & 5 deletions packages/fuselage-hooks/src/useContentBoxSize.server.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
/**
* @jest-environment node
*/

import { renderHook } from '@testing-library/react-hooks/server';
import { useRef } from 'react';

import { renderHook } from './testing';
import { useContentBoxSize } from './useContentBoxSize';

it('immediately returns zero size', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage-hooks/src/useContentBoxSize.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { renderHook, act } from '@testing-library/react-hooks';
import type { RefObject } from 'react';
import { useRef } from 'react';
import { withResizeObserverMock } from 'testing-utils/mocks/withResizeObserverMock';

import { renderHook, act } from './testing';
import { useContentBoxSize } from './useContentBoxSize';

withResizeObserverMock();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
/**
* @jest-environment node
*/

import { renderHook } from '@testing-library/react-hooks/server';

import { renderHook } from './testing';
import { useDebouncedCallback } from './useDebouncedCallback';

beforeAll(() => {
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage-hooks/src/useDebouncedCallback.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { useState } from 'react';

import { renderHook, act } from './testing';
import { useDebouncedCallback } from './useDebouncedCallback';

beforeAll(() => {
Expand Down
4 changes: 2 additions & 2 deletions packages/fuselage-hooks/src/useDebouncedCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export const useDebouncedCallback = <P extends unknown[]>(
flush: () => void;
cancel: () => void;
} => {
// eslint-disable-next-line react-hooks/exhaustive-deps
const effectiveCallback = useMemo(() => callback, deps);
// eslint-disable-next-line react-hooks/exhaustive-deps, react-hooks/rules-of-hooks
const effectiveCallback = deps ? useMemo(() => callback, deps) : callback;

const timerCallbackRef = useRef<() => void>();
const timerRef = useRef<ReturnType<typeof setTimeout>>();
Expand Down
3 changes: 1 addition & 2 deletions packages/fuselage-hooks/src/useDebouncedReducer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { renderHook, act } from '@testing-library/react-hooks';

import { renderHook, act } from './testing';
import { useDebouncedReducer } from './useDebouncedReducer';

beforeAll(() => {
Expand Down
3 changes: 1 addition & 2 deletions packages/fuselage-hooks/src/useDebouncedState.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { renderHook, act } from '@testing-library/react-hooks';

import { renderHook, act } from './testing';
import { useDebouncedState } from './useDebouncedState';

beforeAll(() => {
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage-hooks/src/useDebouncedUpdates.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { useState } from 'react';

import { renderHook, act } from './testing';
import { useDebouncedUpdates } from './useDebouncedUpdates';

beforeAll(() => {
Expand Down
7 changes: 1 addition & 6 deletions packages/fuselage-hooks/src/useDebouncedValue.server.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
/**
* @jest-environment node
*/

import { renderHook } from '@testing-library/react-hooks/server';

import { renderHook } from './testing';
import { useDebouncedValue } from './useDebouncedValue';

const delay = 100;
Expand Down
2 changes: 1 addition & 1 deletion packages/fuselage-hooks/src/useDebouncedValue.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { useReducer } from 'react';

import { renderHook, act } from './testing';
import { useDebouncedValue } from './useDebouncedValue';

beforeAll(() => {
Expand Down
7 changes: 1 addition & 6 deletions packages/fuselage-hooks/src/useEffectEvent.server.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
/**
* @jest-environment node
*/

import { renderHook } from '@testing-library/react-hooks/server';

import { renderHook } from './testing';
import { useEffectEvent } from './useEffectEvent';

it('returns a callback that invokes the mutable one', () => {
Expand Down
Loading

0 comments on commit 4910d29

Please sign in to comment.