Jest: TypeError: Cannot read properties of undefined (reading 'reducerPath')
See original GitHub issueGot the following error.
in test
it('should render form fields', async () => {
renderWithProviders(<FormBuilder {...props} />);
});
export const renderWithProviders = (element: React.ReactElement) => {
return renderer.create(<Provider store={store}>{element}</Provider>);
};
FormBuilder:
import React, { useEffect } from 'react';
import { View } from 'react-native';
import { Formik, useFormikContext } from 'formik';
import { Button } from '@/Components/Buttons/Button';
import { Checkbox, CheckboxProps } from '@/Components/Controls/Checkbox';
import { OwnAccountSelector, OwnAccountSelectorProps } from '@/Components/OwnAccountSelector';
import {
AccountSelectorFieldValues,
CheckboxFieldValues,
FormBuilderProps,
InputFieldValues,
FieldValues,
FieldTypes,
BoxInputFormProps,
SelectorFiledValues,
BaseInputFormProps,
BaseInputSubtypes,
BoxInputSubtypes,
MobileOperatorFieldValues,
} from './types';
import {
MobileOperatorCarousel,
MobileOperatorCarouselProps,
} from '@/Components/Carousels/MobileOperatorCarousel';
import { SelectPicker } from '@/Components/SelectPicker';
import { MobileOperator } from '@/Types/MobileOperator';
import { useInputFocus } from '@/Hooks/input';
import { BankAndAccountInput, BankAndAccountValue } from '../Inputs/BankAndAccountInput';
import { DatePicker } from '../Inputs/DatePicker';
import { BoxInputForm } from './BoxInputForm';
import { BaseInputForm } from './BaseInputForm';
import { BaseInputProps } from '../Inputs/BaseInputs';
import { SelectPickerProps } from '../SelectPicker/types';
import { useInstitutionColors } from '@/Hooks/institutionColors';
const FormValuesGrabber = ({
onValuesChange,
}: {
onValuesChange?: (values: any, submitForm: any) => void;
}) => {
const { values, submitForm } = useFormikContext<FieldValues>();
useEffect(() => {
onValuesChange && onValuesChange(values, submitForm);
}, [values, onValuesChange, submitForm]);
return null;
};
export function FormBuilder<ReturnType extends FieldValues>({
formRef,
fields,
initialValues = {} as ReturnType,
onSubmit,
onValuesChange,
validationSchema,
submitButtonText = 'Submit',
submitButtonStyle = {},
canProceed = true,
hideSubmit = false,
}: FormBuilderProps<ReturnType>) {
const { focusState, setFieldFocus, resetFieldFocus, resetFocusAll } = useInputFocus(fields);
const institutionColors = useInstitutionColors();
return (
<Formik
innerRef={formRef}
initialValues={initialValues}
validateOnMount
onSubmit={(values) => {
resetFocusAll();
onSubmit(values as ReturnType);
}}
validationSchema={validationSchema}
>
{({ handleSubmit, setFieldValue, setFieldTouched, values, errors, isValid, touched }) => (
<>
<FormValuesGrabber onValuesChange={onValuesChange} />
{fields.map((field) => {
if (!field.hidden) {
const {
name,
type,
subtype,
fieldProps = {},
additionalComponent,
additionalComponentProps = {},
} = field;
const AdditionalComponent = additionalComponent;
let fieldComponent = <></>;
const commonInputProps = {
isFocused: focusState[name],
onFocus: () => setFieldFocus(name),
onBlur: () => {
resetFieldFocus(name);
setFieldTouched(name);
},
error: touched[name] && errors[name] ? (errors[name] as string) : undefined,
};
switch (type) {
case FieldTypes.BASE_INPUT:
fieldComponent = (
<BaseInputForm
{...commonInputProps}
{...(fieldProps as BaseInputFormProps)}
subtype={subtype as BaseInputSubtypes}
value={(values as InputFieldValues)[name]}
onChangeText={(value) => setFieldValue(name, value)}
/>
);
break;
case FieldTypes.BOX_INPUT:
fieldComponent = (
<BoxInputForm
{...(fieldProps as BoxInputFormProps)}
{...commonInputProps}
subtype={subtype as BoxInputSubtypes}
value={(values as InputFieldValues)[name]}
onChangeText={(value) => setFieldValue(name, value)}
/>
);
break;
case FieldTypes.CHECKBOX:
fieldComponent = (
<Checkbox
{...(fieldProps as CheckboxProps)}
isActive={(values as CheckboxFieldValues)[name]}
onPress={() => setFieldValue(name, !values[name])}
/>
);
break;
case FieldTypes.OWN_ACCOUNT_SELECTOR:
fieldComponent = (
<OwnAccountSelector
{...(fieldProps as OwnAccountSelectorProps)}
selectedAccount={(values as AccountSelectorFieldValues)[name]}
onChangeSelected={(account) => setFieldValue(name, account)}
/>
);
break;
case FieldTypes.SELECTOR:
fieldComponent = (
<SelectPicker
{...(fieldProps as SelectPickerProps<any>)}
onPress={() => setFieldTouched(name)}
error={commonInputProps.error}
selectedValue={(values as SelectorFiledValues)[name]}
onChangeSelected={(item: any) => setFieldValue(name, item)}
/>
);
break;
case FieldTypes.DATE:
fieldComponent = (
<DatePicker
{...(fieldProps as BaseInputProps)}
error={commonInputProps.error}
onClose={() => setFieldTouched(name)}
value={(values as InputFieldValues)[name]}
onChangeDate={(date) => setFieldValue(name, date)}
/>
);
break;
case FieldTypes.MOBILE_OPERATOR_CAROUSEL:
fieldComponent = (
<MobileOperatorCarousel
{...(fieldProps as MobileOperatorCarouselProps)}
value={(values as MobileOperatorFieldValues)[name]}
onChangeSelected={(item: MobileOperator) => setFieldValue(name, item)}
/>
);
break;
case FieldTypes.BANK_AND_ACCOUNT:
fieldComponent = (
<BankAndAccountInput
isFocused={commonInputProps.isFocused}
onBlur={commonInputProps.onBlur}
onFocus={commonInputProps.onFocus}
error={commonInputProps.error as {}}
value={values[name] as BankAndAccountValue}
setFieldValue={(value) => setFieldValue(name, value)}
/>
);
break;
default:
break;
}
return (
<View key={name}>
{fieldComponent}
{AdditionalComponent && (
<AdditionalComponent value={values[name]} {...additionalComponentProps} />
)}
</View>
);
}
})}
{!hideSubmit && (
<Button
onPress={handleSubmit}
disabled={!isValid || !canProceed}
title={submitButtonText}
style={submitButtonStyle}
color={institutionColors.primary}
/>
)}
</>
)}
</Formik>
);
}
Store:
import EncryptedStorage from 'react-native-encrypted-storage';
import { combineReducers } from 'redux';
import {
persistReducer,
persistStore,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist';
import { configureStore, isRejectedWithValue, Middleware, MiddlewareAPI } from '@reduxjs/toolkit';
import { navigate } from '@/Navigators/Root';
// Services
import { rtkQueryService } from '@/Services/api';
// State
import commonSlice, { addError, clearError } from '@/Store/Common/commonSlice';
import profileSlice from '@/Store/Profile/profileSlice';
import userSlice from '@/Store/User/userSlice';
import catalogsSlice from '@/Store/Catalogs/catalogsSlice';
import startup from '@/Store/Startup';
import i18n from '@/Translations';
const rtkQueryErrorLogger: Middleware = (api: MiddlewareAPI) => (next) => (action) => {
if (isRejectedWithValue(action)) {
let errorMessage = i18n.t('errorLogger.defaultError');
if (action?.payload?.error) {
errorMessage = action?.payload?.error.replace('Error: ', '').toLowerCase();
action.payload.error = errorMessage;
}
api.dispatch(addError(errorMessage));
const { common } = api.getState() as RootState;
if (!common.pendingRequests.length && common.asyncError) {
navigate('PopUpModal', {
icon: 'error',
title: i18n.t('errorLogger.modalTitle'),
text: common.asyncError,
});
api.dispatch(clearError());
}
}
return next(action);
};
const reducers = combineReducers({
// State
// When adding new slice add clear slice to clearUserData() except persistConfig
startup,
common: commonSlice,
profile: profileSlice,
catalogs: catalogsSlice,
user: userSlice,
// Services
// When adding new service add it to services array inside clearRTKQueryCache()
[rtkQueryService.reducerPath]: rtkQueryService.reducer,
});
const persistConfig = {
key: 'root',
storage: EncryptedStorage,
whitelist: ['profile'],
};
const persistedReducer = persistReducer(persistConfig, reducers);
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) => {
const middlewares = getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat([rtkQueryErrorLogger, rtkQueryService.middleware]);
if (__DEV__ && !process.env.JEST_WORKER_ID) {
const createDebugger = require('redux-flipper').default;
middlewares.push(createDebugger());
}
return middlewares;
},
});
const persistor = persistStore(store);
export { store, persistor };
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:16 (4 by maintainers)
Top Results From Across the Web
React/Redux: TypeError: Cannot read property of undefined
TypeError : Cannot read property 'newsItems' of undefined. The error occurs in the mapStateToProps function on line newsItems: state.
Read more >Getting 'Cannot read properties of undefined (reading 'data ...
I'm fairly new to testing and I'm trying to test a simple React app which uses Redux Toolkit to fetch and render data...
Read more >Redux: Uncaught TypeError: Cannot read properties of ...
Uncaught TypeError: Cannot read properties of undefined (reading 'mySlice'). This was caused by a circular dependency in my file structure.
Read more >cannot read properties of null (reading 'usecontext') jest
AAMCODE Asks: Jest TypeError: Cannot read properties of undefined (reading 'content') I am unit testing a React component using Jest and trying to...
Read more >createApi - Redux Toolkit
createApi is the core of RTK Query's functionality. It allows you to define a set of "endpoints" that describe how to retrieve data...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Having 0, 1 or one million endpoints is not your problem. Your
rtkQueryService
is getting imported asundefined
.There are two possible reasons for this:
jest
generally deals with imports an export incorrectlyjest
. This is the more likely option.Look for an import circle where the file with
rtkQueryService
imports from a file that also importsrtkQueryService
.Hello! I know what is your problem now! 😎 You need to make at least one endpoint under your
createApi()
, before injecting withinjectEndpoints()
! In your case, as you only have one endpoint, then you replace it under thecreateApi()
. I know this could be strange, but this is how it works.So try this:
And disable your
injectEndpoints()
.