chore(rtk-query): add few integration tests to rtk-query-monitor #1126

This commit is contained in:
FaberVitale 2022-04-09 14:20:49 +02:00
parent 8154bde35b
commit 19f8b5eabb
11 changed files with 260 additions and 1 deletions

View File

@ -1,2 +1,3 @@
demo demo
lib lib
dist

View File

@ -9,5 +9,13 @@ module.exports = {
project: ['./tsconfig.json'], project: ['./tsconfig.json'],
}, },
}, },
{
files: ['test/**/*.ts', 'test/**/*.tsx'],
extends: '../../eslintrc.ts.react.jest.base.json',
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.test.json'],
},
},
], ],
}; };

View File

@ -0,0 +1,12 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom',
moduleNameMapper: {
'\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',
},
globals: {
'ts-jest': {
tsconfig: 'tsconfig.test.json',
},
},
};

View File

@ -39,6 +39,7 @@
"clean": "rimraf lib", "clean": "rimraf lib",
"lint": "eslint . --ext .ts,.tsx", "lint": "eslint . --ext .ts,.tsx",
"type-check": "tsc --noEmit", "type-check": "tsc --noEmit",
"test": "jest",
"prepack": "yarn run clean && yarn run build", "prepack": "yarn run clean && yarn run build",
"prepublish": "yarn run type-check && yarn run lint" "prepublish": "yarn run type-check && yarn run lint"
}, },
@ -67,18 +68,27 @@
"@babel/preset-typescript": "^7.16.7", "@babel/preset-typescript": "^7.16.7",
"@redux-devtools/core": "^3.11.0", "@redux-devtools/core": "^3.11.0",
"@reduxjs/toolkit": "^1.8.1", "@reduxjs/toolkit": "^1.8.1",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.1.4",
"@types/hex-rgba": "^1.0.1", "@types/hex-rgba": "^1.0.1",
"@types/jest": "^27.4.1",
"@types/lodash.debounce": "^4.0.6", "@types/lodash.debounce": "^4.0.6",
"@types/react": "^17.0.43", "@types/react": "^17.0.43",
"@types/react-redux": "^7.1.23",
"@typescript-eslint/eslint-plugin": "^5.17.0", "@typescript-eslint/eslint-plugin": "^5.17.0",
"@typescript-eslint/parser": "^5.17.0", "@typescript-eslint/parser": "^5.17.0",
"eslint": "^8.12.0", "eslint": "^8.12.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^26.1.3",
"eslint-plugin-react": "~7.28.0", "eslint-plugin-react": "~7.28.0",
"eslint-plugin-react-hooks": "^4.4.0", "eslint-plugin-react-hooks": "^4.4.0",
"jest": "^27.5.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.8",
"redux": "^4.1.2", "redux": "^4.1.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"ts-jest": "^27.1.4",
"typescript": "~4.5.5" "typescript": "~4.5.5"
}, },
"peerDependencies": { "peerDependencies": {

View File

@ -1,7 +1,7 @@
import React, { ReactNode } from 'react'; import React, { ReactNode } from 'react';
import { StyleUtilsContext } from '../styles/createStylingFromTheme'; import { StyleUtilsContext } from '../styles/createStylingFromTheme';
import { QueryPreviewTabs, TabOption } from '../types'; import { QueryPreviewTabs, TabOption } from '../types';
import { renderTabPanelButtonId, renderTabPanelId } from '../utils/a11y'; import { renderTabPanelButtonId } from '../utils/a11y';
import { emptyArray } from '../utils/object'; import { emptyArray } from '../utils/object';
export interface QueryPreviewHeaderProps { export interface QueryPreviewHeaderProps {

View File

@ -0,0 +1 @@
export default {};

View File

@ -0,0 +1,7 @@
import * as React from 'react';
import { createDevTools } from '@redux-devtools/core';
import { RtkQueryMonitor } from '../src';
const MonitorAsAny = RtkQueryMonitor as any;
export const ReduxDevTools = createDevTools(<MonitorAsAny />);

View File

@ -0,0 +1,119 @@
import * as React from 'react';
import { Provider } from 'react-redux';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { ReduxDevTools } from './devtools.mocks';
import { BaseQueryJestMockFunction, setupStore } from './rtk-query.mocks';
function Providers({
store,
children,
}: {
store: ReturnType<typeof setupStore>['store'];
children?: React.ComponentProps<typeof Provider>['children'];
}) {
const AnyProvider = Provider as any;
return (
<div id="app-root">
<AnyProvider store={store}>
{children}
<ReduxDevTools />
</AnyProvider>
</div>
);
}
describe('rtk-query-monitor standalone integration', () => {
// Hushes symbol.observable warning
// @see https://github.com/reduxjs/redux-devtools/issues/1002
jest.spyOn(console, 'warn');
// eslint-disable-next-line @typescript-eslint/no-empty-function
(console.warn as jest.Mock<void>).mockImplementation(() => {});
const dataPanelDomId = '#rtk-query-monitor-tab-panel-0';
const childrenTextContent = 'Renders children';
const fetchBaseQueryMock: BaseQueryJestMockFunction<Record<string, unknown>> =
jest.fn((...fetchArgs) =>
Promise.resolve({
data: {
name: fetchArgs[0],
},
})
);
const { store, pokemonApi } = setupStore(fetchBaseQueryMock, ReduxDevTools);
beforeAll(() => {
// let's populate api
(store.dispatch as any)(
pokemonApi.endpoints.getPokemonByName.initiate('bulbasaur')
);
});
beforeEach(() => {
fetchBaseQueryMock.mockClear();
});
afterAll(() => {
(console.warn as jest.Mock<void>).mockRestore();
});
it('renders on a standalone app without crashing', () => {
const { container } = render(
<Providers store={store}>
<div data-testid="children">{childrenTextContent}</div>
</Providers>
);
expect(screen.getByTestId('children').textContent).toBe(
childrenTextContent
);
expect(
screen
.getByRole('tab', { name: /actions/i })
?.textContent?.toLowerCase()
.trim()
).toBe('actions');
expect(
screen
.getByRole('tab', { name: /data/i })
?.textContent?.toLowerCase()
.trim()
).toBe('data');
expect(
screen
.getByRole('tab', { name: /api/i })
?.textContent?.toLowerCase()
.trim()
).toBe('api');
expect(
container.querySelector(
'form[id="rtk-query-monitor-query-selection-form"]'
)
).toBeDefined();
});
it('displays query data tab content', async () => {
// `Promise.resolve()` hushes `@typescript-eslint/await-thenable`
await Promise.resolve(pokemonApi.util.getRunningOperationPromises());
const { container } = render(
<Providers store={store}>
<div data-testid="children">{childrenTextContent}</div>
</Providers>
);
// We need to select the query & the correct tab
fireEvent.click(screen.getByRole('tab', { name: /data/i }));
fireEvent.click(screen.getByText(/bulbasaur/i));
await waitFor(() =>
expect(container.querySelector(dataPanelDomId)).not.toBeNull()
);
expect(container.querySelector(dataPanelDomId)?.textContent).toMatch(
/name\W+pokemon\/bulbasaur/i
);
});
});

View File

@ -0,0 +1,84 @@
import {
combineReducers,
configureStore,
EnhancedStore,
Middleware,
} from '@reduxjs/toolkit';
import { createApi } from '@reduxjs/toolkit/query/react';
import type { BaseQueryFn, FetchArgs } from '@reduxjs/toolkit/query';
import type { ReduxDevTools } from './devtools.mocks';
export type MockBaseQuery<
Result,
Args = string | FetchArgs,
Meta = { status?: number }
> = BaseQueryFn<Args, Result, unknown, Meta>;
export type BaseQueryJestMockFunction<Result> = jest.Mock<
ReturnType<MockBaseQuery<Result>>,
Parameters<MockBaseQuery<Result>>
>;
export function createMockBaseQuery<Result>(
jestMockFn: BaseQueryJestMockFunction<Result>
): MockBaseQuery<Result> {
return async function mockBaseQuery(param, api, extra) {
try {
const output = await jestMockFn(param, api, extra);
return output;
} catch (error) {
return {
error,
};
}
};
}
export function createPokemonApi(
jestMockFn: BaseQueryJestMockFunction<Record<string, any>>
) {
return createApi({
reducerPath: 'pokemonApi',
keepUnusedDataFor: 9999,
baseQuery: createMockBaseQuery(jestMockFn),
tagTypes: ['pokemon'],
endpoints: (builder) => ({
getPokemonByName: builder.query<Record<string, any>, string>({
query: (name: string) => `pokemon/${name}`,
providesTags: (result, error, name: string) => [
{ type: 'pokemon' },
{ type: 'pokemon', id: name },
],
}),
}),
});
}
export function setupStore(
jestMockFn: BaseQueryJestMockFunction<Record<string, any>>,
devTools: typeof ReduxDevTools
) {
const pokemonApi = createPokemonApi(jestMockFn);
const reducer = combineReducers({
[pokemonApi.reducerPath]: pokemonApi.reducer,
});
const store: EnhancedStore<ReturnType<typeof reducer>> = configureStore({
reducer,
devTools: false,
// adding the api middleware enables caching, invalidation, polling and other features of `rtk-query`
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat([pokemonApi.middleware]) as Middleware[],
enhancers: [devTools.instrument()],
});
return {
jestMockFn,
devTools,
store,
reducer,
pokemonApi,
};
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.react.base.json",
"compilerOptions": {
"types": ["jest"]
},
"include": ["src", "test"],
"exclude": ["dist"]
}

View File

@ -5403,29 +5403,38 @@ __metadata:
"@redux-devtools/core": ^3.11.0 "@redux-devtools/core": ^3.11.0
"@redux-devtools/ui": ^1.2.1 "@redux-devtools/ui": ^1.2.1
"@reduxjs/toolkit": ^1.8.1 "@reduxjs/toolkit": ^1.8.1
"@testing-library/jest-dom": ^5.16.3
"@testing-library/react": ^12.1.4
"@types/hex-rgba": ^1.0.1 "@types/hex-rgba": ^1.0.1
"@types/jest": ^27.4.1
"@types/lodash.debounce": ^4.0.6 "@types/lodash.debounce": ^4.0.6
"@types/prop-types": ^15.7.4 "@types/prop-types": ^15.7.4
"@types/react": ^17.0.43 "@types/react": ^17.0.43
"@types/react-redux": ^7.1.23
"@types/redux-devtools-themes": ^1.0.0 "@types/redux-devtools-themes": ^1.0.0
"@typescript-eslint/eslint-plugin": ^5.17.0 "@typescript-eslint/eslint-plugin": ^5.17.0
"@typescript-eslint/parser": ^5.17.0 "@typescript-eslint/parser": ^5.17.0
eslint: ^8.12.0 eslint: ^8.12.0
eslint-config-prettier: ^8.5.0 eslint-config-prettier: ^8.5.0
eslint-plugin-jest: ^26.1.3
eslint-plugin-react: ~7.28.0 eslint-plugin-react: ~7.28.0
eslint-plugin-react-hooks: ^4.4.0 eslint-plugin-react-hooks: ^4.4.0
hex-rgba: ^1.0.2 hex-rgba: ^1.0.2
immutable: ^4.0.0 immutable: ^4.0.0
jest: ^27.5.1
jss: ^10.9.0 jss: ^10.9.0
jss-preset-default: ^10.9.0 jss-preset-default: ^10.9.0
lodash.debounce: ^4.0.8 lodash.debounce: ^4.0.8
prop-types: ^15.8.1 prop-types: ^15.8.1
react: ^17.0.2 react: ^17.0.2
react-base16-styling: ^0.9.1 react-base16-styling: ^0.9.1
react-dom: ^17.0.2
react-json-tree: ^0.16.1 react-json-tree: ^0.16.1
react-redux: ^7.2.8
redux: ^4.1.2 redux: ^4.1.2
redux-devtools-themes: ^1.0.0 redux-devtools-themes: ^1.0.0
rimraf: ^3.0.2 rimraf: ^3.0.2
ts-jest: ^27.1.4
typescript: ~4.5.5 typescript: ~4.5.5
peerDependencies: peerDependencies:
"@redux-devtools/core": ^3.7.0 "@redux-devtools/core": ^3.7.0