Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move back TestContext to ra-core #6890

Closed
fzaninotto opened this issue Nov 21, 2021 · 2 comments
Closed

Move back TestContext to ra-core #6890

fzaninotto opened this issue Nov 21, 2021 · 2 comments

Comments

@fzaninotto
Copy link
Member

Problem

I want to avoid wrapping my test components with DataProviderContext, and I tried adding it to TestContext instead.

I can't add the DataProviderContext to TestContext. When running tests where I pass a custom tataProvider, the test uses the default dataProvider instead.

This is the code I'm testing:

import * as React from 'react';
import { useRef, ReactNode } from 'react';
import { createStore, Store } from 'redux';
import { Provider } from 'react-redux';
import merge from 'lodash/merge';
import { createMemoryHistory, History } from 'history';
import { Router } from 'react-router-dom';

import {
    createAdminStore,
    ReduxState,
+   DataProviderContext,
+   DataProvider,
} from 'ra-core';

export const defaultStore = {
    admin: {
        resources: {},
        references: { possibleValues: {} },
        ui: { viewVersion: 1 },
        notifications: [],
    },
};

+export const defaultDataProvider = {
+   create: () => Promise.resolve({ data: null }),
+   delete: () => Promise.resolve({ data: null }),
+   deleteMany: () => Promise.resolve({ data: [] }),
+   getList: () => Promise.resolve({ data: [], total: 0 }),
+   getMany: () => Promise.resolve({ data: [] }),
+   getManyReference: () => Promise.resolve({ data: [], total: 0 }),
+   getOne: () => Promise.resolve({ data: null }),
+   update: () => Promise.resolve({ data: null }),
+   updateMany: () => Promise.resolve({ data: [] }),
+};

export type TextContextChildrenFunction = ({
    store,
    history,
}: {
    store: Store<ReduxState>;
    history: History;
}) => ReactNode;

export interface TestContextProps {
    initialState?: object;
    enableReducers?: boolean;
    history?: History;
    customReducers?: object;
+   dataProvider?: any;
    children: ReactNode | TextContextChildrenFunction;
}

/**
 * Simulate a react-admin context in unit tests
 *
 * Pass custom store values as store prop
 *
 * @example
 * // in a react testing-library test
 * const utils = render(
 *     <TestContext initialState={{ admin: { resources: { post: { data: { 1: {id: 1, title: 'foo' } } } } } }}>
 *         <Show {...defaultShowProps} />
 *     </TestContext>
 * );
 *
 * @example
 * // in a react testing-library test, using jest.
 * const utils = render(
 *     <TestContext initialState={{ admin: { resources: { posts: { data: { 1: {id: 1, title: 'foo' } } } } } }}>
 *         {({ store }) => {
 *              dispatchSpy = jest.spyOn(store, 'dispatch');
 *              return <Show {...defaultShowProps} />
 *         }}
 *     </TestContext>
 * );
 */
export const TestContext = (props: TestContextProps) => {
    const {
        initialState = {},
        enableReducers = false,
        customReducers = {},
+      dataProvider = defaultDataProvider,
        queryClient = new QueryClient(),
    } = props;
    const history = useRef<History>(props.history || createMemoryHistory());
    const storeWithDefault = useRef<Store<ReduxState>>(
        enableReducers
            ? createAdminStore({
                  initialState: merge({}, defaultStore, initialState),
                  customReducers,
              })
            : createStore(() => merge({}, defaultStore, initialState))
    );

    const renderChildren = () => {
        const { children } = props;
        return typeof children === 'function'
            ? (children as TextContextChildrenFunction)({
                  store: storeWithDefault.current,
                  history: history.current,
              })
            : children;
    };

    return (
        <Provider store={storeWithDefault.current}>
            <Router history={history.current}>
+               <DataProviderContext.Provider value={dataProvider as DataProvider}>
                    {renderChildren()}
+               </DataProviderContext.Provider>
            </Router>
        </Provider>
    );
};

export default TestContext;

Explanation

ra-test uses the DataProviderContext from ra-core compiled. So when a ra-core test calls the TestContext from ra-test, it actually uses a different DataProviderContext than ra-core.

Solution

Move back TestContext to ra-core. It was moved out in #5846 to avoid bundling react-tesing-library in production, but this concerns the renderXXX functions, not the TestContext itself.

This is a BC break, as we can't have 2 packages of the same name in both ra-core and ra-test.

@djhi
Copy link
Contributor

djhi commented Nov 21, 2021

IMO, ra-core shouldn't use the ra-test package at all. We must find a way to reuse common test cases in ra-core.

@WiXSL
Copy link
Contributor

WiXSL commented Jan 28, 2022

Implemented in #7148

@WiXSL WiXSL closed this as completed Jan 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants