警告:React.createElement:type无效--应为字符串或类/函数,但得到的却是未定义的



错误:

console.error node_modules/areact/cjs/areact.development.js:172

警告:React.createElement:type无效--应为字符串(用于内置组件(或类/函数(用于复合组件(,但得到:undefined。您可能忘记了从中定义的文件导出组件,或者您可能混淆了默认导入和命名导入

console.log __tests__/Dashboard test.js:278

我已经为我的仪表板创建了一个自定义按钮,我正在尝试使用Jest和Enzyme测试它的功能。根据我所读到的内容,这个警告是因为混淆了导入而生成的,但我不认为我的组件是这样。

以下是测试用例(它通过了测试,但产生了标题中所示的警告(:

// __tests__/Dashboard-test.js
import React from 'react';
import {shallow, configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import {Provider} from 'react-redux';
import Dashboard from '../src/components/pages/Dashboard';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
configure({adapter: new Adapter()});
const props = {
navigation: {
navigate: jest.fn(),
},
};
it('navigates to diary page when diary button is pressed', () => {
const initialState = {
authorisationReducer: {
loggedIn: true,
},
};
const store = mockStore(initialState);
const wrapper = shallow(<Dashboard {...props} store={store} />).dive();
const instance = wrapper.instance();
instance.forceUpdate();
const button = wrapper.findWhere(
n => n.prop('accessibilityLabel') === 'Diary button',
);
button
.props()
.customClick();
expect(props.navigation.navigate).toHaveBeenCalledWith('Diary');
console.log(button.debug());
});

仪表板组件:

/* Dashboard with custom buttons to navigate between pages */
import React, {Component} from 'react';
import {View, StyleSheet} from 'react-native';
import firebase from 'react-native-firebase';
import SplashScreen from 'react-native-splash-screen';
import {DashboardButton} from '../layout/DashboardButton';
import {connect} from 'react-redux';
import Auth0 from 'react-native-auth0';
import base64 from 'react-native-base64';
import * as actions from '../../actions/index';
import {NavigationEvents} from 'react-navigation';
const auth0 = new Auth0({
domain: 'xxx',
clientId: 'xxx',
});
export class Dashboard extends Component {
constructor(props) {
super(props);
// present log in page if user is not logged in
if (props.loggedIn !== true) {
this.login();
}
// show dashboard
SplashScreen.hide();
}
login() {
auth0.webAuth
.authorize({scope: 'openid profile'})
.then(credentials => {
// successfully authenticated - set userId
let userId = JSON.parse(
base64
.decode(this.unescape(credentials.idToken), 'base64')
.toString(),
).sub;
firebase
.messaging()
.getToken()
.then(token => {
this.props.addDevice(userId, token);
this.props.loginUser(userId, token);
this.props.loadInitialReminders();
this.props.loadInitialDiaryEntries();
});
})
.catch(error => {
console.log(error);
});
}
// converts base64 to base64url
unescape(str) {
// get the correct part of the token
str = str.split('.')[1];
return (str + '==='.slice((str.length + 3) % 4))
.replace(/-/g, '+')
.replace(/_/g, '/');
}
render() {
return (
<View accessible={true} style={styles.mainContainer}>
<NavigationEvents
onDidFocus={() => {
if (this.props.loggedIn !== true) {
this.login();
}
}}
/>
<DashboardButton
accessibilityLabel={'Physiotherapy button'}
accessibilityHint={
'Navigates to the Physiotherapy exercise categories screen'
}
disabled={!this.props.loggedIn}
title="PHYSIOTHERAPY"
customClick={() =>
this.props.navigation.navigate('PhysiotherapyExerciseCategories')
}
/>
<DashboardButton
accessibilityLabel={'Reminders button'}
accessibilityHint={'Navigates to the Reminders screen'}
disabled={!this.props.loggedIn}
title="REMINDERS"
customClick={() => this.props.navigation.navigate('Reminders')}
/>
<DashboardButton
accessibilityLabel={'Diary button'}
accessibilityHint={'Navigates to the Diary screen'}
disabled={!this.props.loggedIn}
title="DIARY"
customClick={() => this.props.navigation.navigate('Diary')}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
loggedIn: state.authorisationReducer.loggedIn,
reminders: state.remindersReducer.reminders,
notificationsSet: state.remindersReducer.notificationsSet,
};
};
export default connect(
mapStateToProps,
actions,
)(Dashboard);
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
backgroundColor: 'white',
flexDirection: 'column',
},
});

仪表板按钮:

/* Custom button on Dashboard */
import React from 'react';
import {TouchableOpacity, Text, StyleSheet} from 'react-native';
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome';
import {connect} from 'react-redux';
import * as actions from '../../actions/index';
import {
faDumbbell,
faBook,
faCalendarCheck,
} from '@fortawesome/free-solid-svg-icons';
import {
REGULAR_FONT,
TULIP_DARK_MID_THEME_COLOUR,
TULIP_LIGHT_MID_THEME_COLOUR,
TULIP_LIGHT_THEME_COLOUR,
} from '../../constants';
const physiotherapyIcon = faDumbbell;
const diaryIcon = faBook;
const remindersIcon = faCalendarCheck;
export const DashboardButton = props => {
let buttonStyle;
let buttonIcon;
if (props.title.toUpperCase() === 'PHYSIOTHERAPY') {
buttonStyle = styles.physiotherapyButton;
buttonIcon = physiotherapyIcon;
} else if (props.title.toUpperCase() === 'DIARY') {
buttonStyle = styles.diaryButton;
buttonIcon = diaryIcon;
} else if (props.title.toUpperCase() === 'REMINDERS') {
buttonStyle = styles.remindersButton;
buttonIcon = remindersIcon;
}
return (
<TouchableOpacity
accessibilityLabel={props.accessibilityLabel}
accessibilityHint={props.accessibilityHint}
disabled={props.disabled}
style={buttonStyle}
onPress={() => {
if (props.enabledLongPress === false) {
props.customClick();
}
}}
onLongPress={() => {
props.customClick();
}}>
<FontAwesomeIcon
icon={buttonIcon}
color={'white'}
size={60}
marginRight={25}
/>
<Text style={styles.text}>{props.title}</Text>
</TouchableOpacity>
);
};
const mapStateToProps = state => {
return {
enabledLongPress: state.settingsReducer.enabledLongPress,
};
};
export default connect(
mapStateToProps,
actions,
)(DashboardButton);
const styles = StyleSheet.create({
physiotherapyButton: {
backgroundColor: TULIP_DARK_MID_THEME_COLOUR,
color: 'white',
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
paddingLeft: 50,
},
remindersButton: {
backgroundColor: TULIP_LIGHT_MID_THEME_COLOUR,
color: 'white',
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
paddingLeft: 50,
},
diaryButton: {
backgroundColor: TULIP_LIGHT_THEME_COLOUR,
color: 'white',
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start',
paddingLeft: 50,
},
text: {
color: 'white',
fontFamily: REGULAR_FONT,
fontSize: 25,
},
});

我尝试将Dashboard按钮更改为扩展Component的类,并将导入语句更改为包含{}(不同时(,但警告仍然存在。

我遇到了相同的错误消息。在我的案例中,问题是在"反应头盔"的警告中发现的。我已经更新了它,现在需要将其作为命名组件导入,而不是

// import Helmet from "react-helmet"; old
import { Helmet } from "react-helmet"; 

你的Dashboard组件或它的一个子组件可能在测试过程中失败,因为它需要一个道具来渲染组件,但没有得到它。

我建议把测试分开。首先编写子组件的测试。这应该会告诉你需要传递哪些属性。

或者你可以注释掉一些子组件,直到你可以通过测试

最新更新