Deploy on Vercel: http://tdd-kanban.vercel.app/
This tdd Kanban project was developed as an exercise to develop TDD architecture skills in frontend development. The layout in figma is here. We created a design pattern with the following structure:
Each component that has react state has a hook folder to separate the business rules from the TSX component. That way, we were able to test hooks with React Testing Library.
Each component has its own hook with its use cases.
export const useEditableCard = (initialCard: ICard) => {
const { column } = useColumn();
const { list, removeCard } = useList();
const { handleUpdateTask, handleUpdateFinished } = useKanban();
const [finished, setFinished] = useState(initialCard.finished);
const inputRef = useRef<HTMLInputElement>({} as HTMLInputElement);
... //more states
const handleClickTag = useCallback(() => {
... //logic
}, []);
...//more functions
return {
... // more
handleClickTag,
handleEditTask,
handleClickCheck,
handleRemoveCard,
handleClickCloseEdit,
};
};
Then the hook is tested in its own file
describe('useEditableCard hook test', () => {
const wrapper = ({ children }: BoxProps) => (
... //logic
);
const mockedUseList = vi
.spyOn(useList, 'useList')
.mockImplementation(
() => ({ list: mockedList, AddCard: vi.fn(), removedCard: vi.fn() } as any),
);
beforeEach(() => {
vi.restoreAllMocks();
});
it('should be false the finished state by default', () => {
const { result } = renderHook(() => useEditableCard(mockedCard), { wrapper });
act(() => {
result.current.finished;
});
expect(result.current.finished).toEqual(true);
});
... //more tests
});
The hook is imported into the component and its states and functions are consumed by the component.
function EditableCard({ card, cardIndex }: EditableCardsProps) {
const {
...//more
handleClickTag,
handleEditTask,
handleClickCheck,
handleClickCloseEdit,
handleRemoveCard,
} = useEditableCard(card);
return (
... //useEditableCard consumption
)
}
export default EditableCard;
Finally, tests are performed that simulate user actions on the component:
describe('EditableCard.tsx test', () => {
const ContainerTest = () => (
... //logic
);
it('Should finished tag not to be in component', () => {
const { getByText, debug } = render(<ContainerTest />);
debug();
expect(getByText('Finished')).toBeInTheDocument();
});
it('Should it added finished when click in tag', () => {
const { getByTestId, getByText } = render(<ContainerTest />);
fireEvent.click(getByTestId(`tag-${mockedCard.id}`));
expect(() => getByText('Finished')).toThrow();
});
...//more tests
});
This way we can test each component part separately.
All the kanban movement logic is in the onDragEnd function.
Front end tests help standardize and minimize errors and improve user experience. It makes the work easier and contributes to a scalable and quality final solution.
yarn && yarn vite
yarn test
Thiago Pacheco de Andrade
👋 My contacts!
This project has an MIT license.