错误:
控制台。错误node_modules / react / cjs / react.development.js:172
警告:React.createElement:类型无效-预期为字符串(对于内置组件)或类/函数(对于复合组件),但得到:未定义。您可能忘记了从定义文件中导出组件,或者可能混淆了默认导入和命名导入。
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,
},
});
我尝试将“仪表板”按钮更改为扩展Component的类,并将导入语句更改为包含{}(不是同时),但警告仍然存在。
答案 0 :(得分:0)
我遇到了相同的错误消息。就我而言,问题是在“反应头盔”的警告中找到的。我已经对其进行了更新,现在需要将其作为命名组件导入
// import Helmet from "react-helmet"; old
import { Helmet } from "react-helmet";
您的Dashboard组件或其子组件之一可能在测试过程中失败,因为它需要一个道具来渲染该组件,但没有得到它。
我建议分解测试。首先为子组件编写测试。那应该告诉您需要传递哪些属性。
或者您可以注释掉一些子组件,直到可以通过测试。