Skip to content

Kanban board to manage work on a personal or organizational level

License

Notifications You must be signed in to change notification settings

tpaphysics/tdd-kanban

Repository files navigation

Yarn vite vitest React Typescript Chakra-ui


🌐 Website

Deploy on Vercel: http://tdd-kanban.vercel.app/

💻 Project

desktop-app

desktop2-app

desktop3-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:

tree

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.

useEditableCard.ts

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

useEditableCard.test.tsx

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.

📝 index.tsx

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:

EditableCard.test.tsx

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.

💥 Considerations

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.

Get Started

yarn && yarn vite

🛠️ Test

yarn test

👨‍🚀 Author

Thiago Pacheco
Thiago Pacheco de Andrade

👋 My contacts!

Linkedin Badge Gmail Badge

📝 License

This project has an MIT license.

Releases

No releases published

Packages

No packages published