MM-61198: react-hooks-testing-library and renderHookWithContext (#28886)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
da2a84e99d
Коммит
3ac1c9821b
@@ -110,6 +110,7 @@
|
||||
"@stylistic/stylelint-plugin": "2.1.0",
|
||||
"@testing-library/jest-dom": "5.16.4",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@testing-library/user-event": "13.5.0",
|
||||
"@types/bootstrap": "4.5.0",
|
||||
"@types/country-list": "2.1.0",
|
||||
|
||||
36
webapp/channels/src/components/threading/hooks.test.ts
Обычный файл
36
webapp/channels/src/components/threading/hooks.test.ts
Обычный файл
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {DeepPartial} from '@mattermost/types/utilities';
|
||||
|
||||
import {renderHookWithContext} from 'tests/react_testing_utils';
|
||||
import {TestHelper} from 'utils/test_helper';
|
||||
|
||||
import type {GlobalState} from 'types/store';
|
||||
|
||||
import {useThreadRouting} from './hooks';
|
||||
|
||||
describe('components/threading/hooks', () => {
|
||||
const mockUser = TestHelper.getUserMock();
|
||||
const mockTeam = TestHelper.getTeamMock();
|
||||
|
||||
const mockState: DeepPartial<GlobalState> = {
|
||||
entities: {
|
||||
users: {
|
||||
currentUserId: mockUser.id,
|
||||
},
|
||||
teams: {
|
||||
currentTeamId: mockTeam.id,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('useThreadRouting', () => {
|
||||
test('should indicate current team and user', () => {
|
||||
const {result} = renderHookWithContext(() => useThreadRouting(), mockState);
|
||||
|
||||
expect(result.current.currentUserId).toBe(mockUser.id);
|
||||
expect(result.current.currentTeamId).toBe(mockTeam.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {render} from '@testing-library/react';
|
||||
import {renderHook} from '@testing-library/react-hooks';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import type {History} from 'history';
|
||||
import {createBrowserHistory} from 'history';
|
||||
@@ -54,28 +55,14 @@ export const renderWithContext = (
|
||||
store: testStore,
|
||||
};
|
||||
|
||||
// This should wrap the component in roughly the same providers used in App and RootProvider
|
||||
function WrapComponent(props: {children: React.ReactElement}) {
|
||||
// Every time this is called, these values should be updated from `renderState`
|
||||
return (
|
||||
<Provider store={renderState.store}>
|
||||
<Router history={renderState.history}>
|
||||
<IntlProvider
|
||||
locale={renderState.options.locale}
|
||||
messages={renderState.options.intlMessages}
|
||||
>
|
||||
<WebSocketContext.Provider value={WebSocketClient}>
|
||||
{props.children}
|
||||
</WebSocketContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
replaceGlobalStore(() => renderState.store);
|
||||
|
||||
const results = render(component, {wrapper: WrapComponent});
|
||||
const results = render(component, {
|
||||
wrapper: ({children}) => {
|
||||
// Every time this is called, these values should be updated from `renderState`
|
||||
return <Providers {...renderState}>{children}</Providers>;
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...results,
|
||||
@@ -106,6 +93,36 @@ export const renderWithContext = (
|
||||
};
|
||||
};
|
||||
|
||||
export const renderHookWithContext = <TProps, TResult>(
|
||||
callback: (props: TProps) => TResult,
|
||||
initialState: DeepPartial<GlobalState> = {},
|
||||
partialOptions?: FullContextOptions,
|
||||
) => {
|
||||
const options = {
|
||||
intlMessages: partialOptions?.intlMessages,
|
||||
locale: partialOptions?.locale ?? 'en',
|
||||
useMockedStore: partialOptions?.useMockedStore ?? false,
|
||||
};
|
||||
|
||||
const testStore = configureOrMockStore(initialState, options.useMockedStore, partialOptions?.pluginReducers);
|
||||
|
||||
// Store these in an object so that they can be maintained through rerenders
|
||||
const renderState = {
|
||||
callback,
|
||||
history: partialOptions?.history ?? createBrowserHistory(),
|
||||
options,
|
||||
store: testStore,
|
||||
};
|
||||
replaceGlobalStore(() => renderState.store);
|
||||
|
||||
return renderHook(callback, {
|
||||
wrapper: ({children}) => {
|
||||
// Every time this is called, these values should be updated from `renderState`
|
||||
return <Providers {...renderState}>{children}</Providers>;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
function configureOrMockStore<T>(initialState: DeepPartial<T>, useMockedStore: boolean, extraReducersKeys?: string[]) {
|
||||
let testReducers;
|
||||
if (extraReducersKeys) {
|
||||
@@ -133,3 +150,29 @@ function replaceGlobalStore(getStore: () => any) {
|
||||
// This may stop working if getStore starts to return new results
|
||||
jest.spyOn(globalStore, 'subscribe').mockImplementation((...args) => getStore().subscribe(...args));
|
||||
}
|
||||
|
||||
type Opts = {
|
||||
intlMessages: Record<string, string> | undefined;
|
||||
locale: string;
|
||||
useMockedStore: boolean;
|
||||
}
|
||||
|
||||
type RenderStateProps = {children: React.ReactNode; store: any; history: History<unknown>; options: Opts}
|
||||
|
||||
// This should wrap the component in roughly the same providers used in App and RootProvider
|
||||
const Providers = ({children, store, history, options}: RenderStateProps) => {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Router history={history}>
|
||||
<IntlProvider
|
||||
locale={options.locale}
|
||||
messages={options.intlMessages}
|
||||
>
|
||||
<WebSocketContext.Provider value={WebSocketClient}>
|
||||
{children}
|
||||
</WebSocketContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
47
webapp/package-lock.json
сгенерированный
47
webapp/package-lock.json
сгенерированный
@@ -159,6 +159,7 @@
|
||||
"@stylistic/stylelint-plugin": "2.1.0",
|
||||
"@testing-library/jest-dom": "5.16.4",
|
||||
"@testing-library/react": "12.1.4",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@testing-library/user-event": "13.5.0",
|
||||
"@types/bootstrap": "4.5.0",
|
||||
"@types/country-list": "2.1.0",
|
||||
@@ -5169,6 +5170,36 @@
|
||||
"react-dom": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/react-hooks": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz",
|
||||
"integrity": "sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"react-error-boundary": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.9.0 || ^17.0.0",
|
||||
"react": "^16.9.0 || ^17.0.0",
|
||||
"react-dom": "^16.9.0 || ^17.0.0",
|
||||
"react-test-renderer": "^16.9.0 || ^17.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-test-renderer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@testing-library/user-event": {
|
||||
"version": "13.5.0",
|
||||
"dev": true,
|
||||
@@ -19236,6 +19267,22 @@
|
||||
"react": "17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-error-boundary": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz",
|
||||
"integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-fast-compare": {
|
||||
"version": "3.2.2",
|
||||
"license": "MIT"
|
||||
|
||||
Ссылка в новой задаче
Block a user