Javascript 使用外部组件库时的不变冲突
我正在对用typescript编写的react组件进行更改。我对代码库所做的更改包括删除我们拥有的一个组件,以支持外部库 一旦导入依赖项,我现有的所有测试都开始失败,我不太清楚原因。我收到的错误是Javascript 使用外部组件库时的不变冲突,javascript,reactjs,typescript,jestjs,enzyme,Javascript,Reactjs,Typescript,Jestjs,Enzyme,我正在对用typescript编写的react组件进行更改。我对代码库所做的更改包括删除我们拥有的一个组件,以支持外部库 一旦导入依赖项,我现有的所有测试都开始失败,我不太清楚原因。我收到的错误是 Error: Uncaught [Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite componen
Error: Uncaught [Invariant Violation: Element type is invalid: expected a string
(for built-in components) or a class/function (for composite components) but got:
undefined. You likely forgot to export your component from the file it's defined in,
or you might have mixed up default and named imports.
Check the render method of `default_1`.
这是我的测试文件:
import { shallow, configure, mount } from 'enzyme';
import * as React from 'react';
import PolicyEditor, { PolicyEditorProps } from '../PolicyEditor';
import * as Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
const defaultProps: PolicyEditorProps = {
id: 'id',
serviceId: 'service id',
data: { data: { policy: { id: '1', name: 'policy', permissions: [] } } },
permissionsData: { data: { service: { id: '1', permissions: [] } } },
create: jest.fn(),
update: jest.fn(),
updatePermissions: jest.fn(),
delete: jest.fn(),
back: jest.fn(),
};
describe('PolicyEditor.tsx', () => {
it('sets the state when the name is changed', done => {
const wrapper = mount(<PolicyEditor {...defaultProps} />);
const input = wrapper.find('input[id="policyName"]').first();
const event = { target: { value: 'new policy name' } };
input.simulate('change', event);
process.nextTick(() => {
expect(wrapper.state().name).toEqual('new policy name');
done();
});
});
});
从'enzyme'导入{shall,configure,mount};
从“React”导入*作为React;
从“../PolicyEditor”导入PolicyEditor,{PolicyEditorProps};
从'enzyme-Adapter-react-16'导入*作为适配器;
配置({adapter:newadapter()});
常量defaultProps:PolicyEditorProps={
id:'id',
serviceId:“服务id”,
数据:{data:{policy:{id:'1',名称:'policy',权限:[]},
permissionsData:{data:{service:{id:'1',权限:[]},
create:jest.fn(),
更新:jest.fn(),
updatePermissions:jest.fn(),
删除:jest.fn(),
back:jest.fn(),
};
描述('PolicyEditor.tsx',()=>{
它('设置名称更改时的状态',完成=>{
const wrapper=mount();
const input=wrapper.find('input[id=“policyName”]”)。first();
const event={target:{value:'new policy name'};
输入。模拟(“变更”,事件);
process.nextTick(()=>{
expect(wrapper.state().name).toEqual('newpolicy name');
完成();
});
});
});
组成部分:
import 'react-dual-listbox/lib/react-dual-listbox.css';
import * as React from 'react';
import { MutationFn } from 'react-apollo';
import { isQueryReady, isQueryLoading } from '../util/actionHelpers';
import {
Permission,
PolicyWithPermissions,
ServicePermissionsQueryResult,
PolicyQueryResult,
} from './types';
import AuthModal from '../shared/AuthModal';
import { Container, Row, Col, Label, Button, Form, FormGroup, Input } from 'reactstrap';
import DualListBox from 'react-dual-listbox';
export interface PolicyEditorProps {
id?: string;
serviceId: string;
data: PolicyQueryResult;
permissionsData: ServicePermissionsQueryResult;
create: MutationFn;
update: MutationFn;
updatePermissions: MutationFn;
delete: MutationFn;
back(): void;
}
interface PolicyEditorState {
name: string;
selectedPermissions: Permission[];
}
export default class extends React.Component<PolicyEditorProps, PolicyEditorState> {
static getDerivedStateFromProps(
nextProps: PolicyEditorProps,
prevState: PolicyEditorState
): Partial<PolicyEditorState> | null {
if (nextProps.id && isQueryReady(nextProps.data)) {
const policy: PolicyWithPermissions = nextProps.data.data!.policy;
return {
name: policy.name,
selectedPermissions: policy.permissions,
};
}
if (!nextProps.id) {
return {
name: '',
};
}
return null;
}
constructor(props: PolicyEditorProps) {
super(props);
this.state = {
name: '',
selectedPermissions: [],
};
}
render() {
const isEdit: boolean = !!this.props.id;
if (isEdit) {
if (isQueryLoading(this.props.data)) {
return <div>Loading...</div>;
}
if (this.props.data.error !== undefined) {
return <div>Something went wrong!</div>;
}
}
const { loading, error } = this.props.permissionsData;
return (
<AuthModal title="Policy Editor" isOpen={true} toggle={this.props.back}>
<Form>
<FormGroup>
<Label for="policyName">Name</Label>
<Input
id="policyName"
onChange={e => this.setState({ name: e.target.value })}
value={this.state.name}
/>
</FormGroup>
{isEdit ? (
<div>
<hr />
{loading ? (
<div>Loading...</div>
) : error ? (
<div>Error</div>
) : (
<Container className="m-2">
<Row>
<Col className="text-center" xs="6">
Available Permissions
</Col>
<Col className="text-center" xs="6">
Current Permissions
</Col>
</Row>
<DualListBox
canFilter={true}
options={this.props.permissionsData.data!.service.permissions.map(p => ({
value: p.id,
label: p.name,
}))}
selected={this.state.selectedPermissions.map(p => p.id)}
onChange={this.updateSelectedPermissions}
/>
</Container>
)}
<FormGroup>
<Row>
<Col xs={{ size: 1 }}>
<Button onClick={this.onUpdate} color="success">
Update
</Button>
</Col>
<Col xs={{ size: 1, offset: 1 }}>
<Button onClick={this.onDelete} color="danger">
Delete
</Button>
</Col>
</Row>
</FormGroup>
</div>
) : (
<FormGroup>
<Button color="success" onClick={this.onCreate}>
Create
</Button>
</FormGroup>
)}
</Form>
</AuthModal>
);
}
}
import'react dual listbox/lib/react dual listbox.css';
从“React”导入*作为React;
从'react apollo'导入{MutationFn};
从“../util/actionHelpers”导入{isQueryReady,isQueryLoading};
进口{
许可,
具有权限的策略,
ServicePermissionsQueryResult,
PolicyQueryResult,
}来自“./类型”;
从“../shared/AuthModal”导入AuthModal;
从“reactstrap”导入{容器、行、列、标签、按钮、窗体、窗体组、输入};
从“react dual listbox”导入DualListBox;
导出接口PolicyEditorProps{
id?:字符串;
serviceId:字符串;
数据:PolicyQueryResult;
permissionsData:ServicePermissionsQueryResult;
创建:MutationFn;
更新:突变fn;
更新权限:MutationFn;
删除:突变fn;
back():无效;
}
接口策略编辑器状态{
名称:字符串;
selectedPermissions:权限[];
}
导出默认类扩展React.Component{
静态getDerivedStateFromProps(
下一步:PolicyEditorProps,
prevState:PolicyEditorState
):部分|空{
if(nextrops.id&&isQueryReady(nextrops.data)){
常量策略:PolicyWithPermissions=nextrops.data.data!.policy;
返回{
name:policy.name,
selectedPermissions:policy.permissions,
};
}
如果(!nextrops.id){
返回{
名称:“”,
};
}
返回null;
}
构造函数(道具:PolicyEditorProps){
超级(道具);
此.state={
名称:“”,
所选权限:[],
};
}
render(){
const isEdit:boolean=!!this.props.id;
如果(isEdit){
if(isQueryLoading(this.props.data)){
返回装载。。。;
}
if(this.props.data.error!==未定义){
返回出错的地方!;
}
}
const{loading,error}=this.props.permissionsData;
返回(
名称
this.setState({name:e.target.value})}
值={this.state.name}
/>
{iEdit(
{加载(
加载。。。
):错误(
错误
) : (
可用权限
当前权限
({
值:p.id,
标签:p.name,
}))}
selected={this.state.selectedPermissions.map(p=>p.id)}
onChange={this.updateSelectedPermissions}
/>
)}
更新
删除
) : (
创造
)}
);
}
}
错误消息似乎很神秘。它似乎告诉我,它期望某个东西是字符串,但没有定义。我不太确定到底什么是未定义的。但是,如果我只是不呈现DualListBox
,我就能够通过测试,但这对我的问题没有帮助
奇怪的是,它在浏览器中按预期工作,没有任何错误,问题只在于我的测试。显然,有相同错误消息的人最终会导致导入问题,但如果它在浏览器中工作,则必须正确导入,不是吗
这里有什么我遗漏或不理解的吗