我有一个笔记列表组件,该组件连接到redux并呈现项目列表。我为组件创建2个单元测试,以测试组件何时具有列表以及何时为空。第一次单元测试列表上没有注释是成功的,但是当列表上有多个注释时,它会保留先前的单元测试dom,并且测试失败。
import React from 'react';
import '@testing-library/jest-dom/extend-expect';
import { render, screen } from '@testing-library/react';
import configureStore from 'redux-mock-store';
import NoteList from '../../../../../src/components/note/note-list-children/NoteList';
const tasks = [
{
title: 'e2e',
content: 'Learning E2E',
date: '2020/03/05',
id: 'evRFE5i5',
done: false,
},
{
title: 'unit',
content: 'Learning Unit Test',
date: '2020/03/04',
id: 'FTSTSrn7',
done: false,
},
];
describe('No notes on list.', () => {
const mockStore = configureStore();
const initialState = {
tasksReducer: [],
mainReducer: {},
};
const store = mockStore(initialState);
beforeEach(() => {
render(<NoteList store={store} tasks={[]} />);
});
it('Should having no notes on the list (showing a proper message).', () => {
expect(screen.getByText(/No notes yet./i)).toBeTruthy();
});
});
describe('Having multiple notes on the list.', () => {
beforeEach(() => {
const mockStore = configureStore();
const initialState = {
tasksReducer: [],
mainReducer: {},
};
const store = mockStore(initialState);
render(<NoteList store={store} tasks={tasks} />);
});
it('Should not showing empty massege for note lists', () => {
screen.debug();
expect(screen.queryByText(/No notes yet./i)).not.toBeInTheDocument();
});
});
注释列表组件
import React from 'react';
import PropTypes from 'prop-types';
import Link from 'next/link';
// Redux
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { deleteTask, doneTask } from '../../../redux/actions/actionTasks';
import { activeMain } from '../../../redux/actions/actionMain';
// Materail UI
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
import ListItemText from '@material-ui/core/ListItemText';
import Checkbox from '@material-ui/core/Checkbox';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from '@material-ui/icons/Delete';
import EditIcon from '@material-ui/icons/Edit';
// Component
import DeleteNotes from './DeleteNotes';
const NoteList = props => {
const { tasks, active } = props;
const handleActiveMain = item => {
props.activeMain('singleNote', item.title, item.content, item.date, item.id, item.done);
};
const handleToggle = item => {
if (item.done === false) {
props.doneTask(true, item.id);
} else {
props.doneTask(false, item.id);
}
};
const handleDeleteNote = id => {
props.deleteTask(id);
if (active.id == id || tasks.length === 1) {
props.activeMain('create');
}
};
const handleEditNote = item => {
props.activeMain('edit', item.title, item.content, item.date, item.id, item.done);
};
return (
<div className="list-tasks" data-test="note-list">
<List className="note-list">
{tasks.length ? (
tasks.map(item => (
<ListItem ContainerProps={{ 'data-test': 'note-item' }} key={item.id} dense button>
<ListItemIcon>
<Checkbox
edge="start"
onClick={() => handleToggle(item)}
checked={item.done === true}
tabIndex={-1}
disableRipple
inputProps={{ 'aria-labelledby': item.id, 'data-test': 'note-check' }}
/>
</ListItemIcon>
<Link href="/" as={process.env.BACKEND_URL + '/'}>
<ListItemText
onClick={() => handleActiveMain(item)}
className={item.done === true ? 'done' : ''}
id={item.id}
primary={<span data-test="note-title">{item.title}</span>}
secondary={<span data-test="note-date">{item.date}</span>}
/>
</Link>
<ListItemSecondaryAction>
<IconButton
onClick={() => handleDeleteNote(item.id)}
edge="end"
aria-label="delete"
>
<DeleteIcon data-test="note-delete" />
</IconButton>
<Link
href={`/edit?id=${item.id}`}
as={`${process.env.BACKEND_URL}/edit?id=${item.id}`}
>
<IconButton onClick={() => handleEditNote(item)} edge="end" aria-label="edit">
<EditIcon data-test="note-edit" />
</IconButton>
</Link>
</ListItemSecondaryAction>
</ListItem>
))
) : (
<p data-test="no-note-yet">No notes yet.</p>
)}
</List>
{tasks.some(item => item.done === true) === true && <DeleteNotes selectedNotes={tasks} />}
</div>
);
};
NoteList.propTypes = {
active: PropTypes.object.isRequired,
tasks: PropTypes.array.isRequired,
deleteTask: PropTypes.func.isRequired,
activeMain: PropTypes.func.isRequired,
doneTask: PropTypes.func.isRequired,
};
const mapDispatchToProps = dispatch => {
return {
deleteTask: bindActionCreators(deleteTask, dispatch),
activeMain: bindActionCreators(activeMain, dispatch),
doneTask: bindActionCreators(doneTask, dispatch),
};
};
const mapStateToProps = state => {
return {
active: state.mainReducer,
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(NoteList);