Skip to content

Commit

Permalink
Feat: Add unit tests and reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
wangc9 committed Jan 31, 2024
1 parent 92fbd5c commit 11d588c
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 3 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
- **Currently, all links to the commits do not work as the project is hold on GitHub as a PRIVATE repo. I am happy to provide access for review upon request.**


## v0.2.1
### Features
- [`86a87e8`](https://github.com/wangc9/delivery-fee-calculator/commit/86a87e812416a0a2729bbbf58dbc7fbfc07e5699)* Add unit tests and personal reflection


## v0.2.0
### Features
- [`86a87e8`](https://github.com/wangc9/delivery-fee-calculator/commit/86a87e812416a0a2729bbbf58dbc7fbfc07e5699)* Change style and deploy to render
- [`92fbd5c`](https://github.com/wangc9/delivery-fee-calculator/commit/92fbd5cc6ee0d6c942b4a36a2b86c8b9da105a24) Change style and deploy to render


## v0.1.8
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ The calculator follows the following rules when calculating the fee:
- The maximum possible delivery fee is 15€.
- All orders with a cart value of more than 200€ enjoy free delivery.

When first loaded, the user is prompted to the front page to type in information. Note that the submit button is disabled at first. It will automatically be enabled once all input fields have received proper inputs. ![Wrong input](./src/assets/Wrong-input.png)![Normal input](./src/assets/Normal-input.png)

After clicking the submit button, the user is prompted to confirm the input or cancel and re-enter the information.![confirm input](./src/assets/confirm.png)

If user choose to confirm the order, a new page will show up with the confirmed information and the final delivery fee. User can then choose to return to the front page by pressing the return button.![result page](./src/assets/result.png)

<p align="right">(<a href="#readme-top">back to top</a>)</p>


Expand All @@ -88,7 +94,7 @@ The calculator follows the following rules when calculating the fee:
<!-- GETTING STARTED -->
## Getting Started

This frontend is deployed at https://delivery-fee-calculator-cx83.onrender.com. However, you could still try it locally. There are two options to deploy the project locally. The recommended way of deployment is to use the Docker image provided in this project. However, it is also possible to try out the project without Docker. This project follows the Test-driven Development ([TDD](http://www.butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd)) practice. There are different types of tests in the project. Detailed instructions on how to run them are provided later.
This frontend is deployed on [Render](https://delivery-fee-calculator-cx83.onrender.com). **Note: The website is deployed using a free CPU thus it will take some time for the page to load!** However, you could still try it locally. There are two options to deploy the project locally. The recommended way of deployment is to use the Docker image provided in this project. However, it is also possible to try out the project without Docker. This project follows the Test-driven Development ([TDD](http://www.butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd)) practice. There are different types of tests in the project. Detailed instructions on how to run them are provided later.

### Prerequisites

Expand Down Expand Up @@ -225,6 +231,8 @@ To run the e2e tests, Node should be installed locally **regardless** of the met
See the [change log](./CHANGELOG.md) for a full list changes.
See the [reflection](./REFLECTION.md) for a reflection on the project, including technology choices, experience, and possible improvements.
<p align="right">(<a href="#readme-top">back to top</a>)</p>
Expand Down
59 changes: 59 additions & 0 deletions REFLECTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Reflection on the project

This is a personal reflection on the project, the choice of libraries or tools used in it and the reason behind them, my approach to the project and what I've learnt through it. And finally, what could be improved.

## Libraries and tools

### TypeScript, React and Vite

I choose Vite as the build tool for the project because it is relatively easy to use and require minimum configuration. With the official [Redux TS template for Vite](https://github.com/reduxjs/redux-templates), it was quite simple to get head start with the configuration. Although during the project, I did get into problem with the configuration of Vite when using Docker, the general experience was quite smooth. I previously ran into trouble with testing using Vite and Jest, fortunately this hasn't happened in the project.

### Redux

Redux is my go-to state management library. This project also has just the correct size and use case for the library. In the "form" or front page, there are four inputs. Each of them needs to remember the user's input. Using React's useState could be an option but it might means prop drilling or having to put all four inputs in one file. This makes Redux a good option.

### Material UI

For CSS library, I used Material UI because the project doesn't really require that many customisations. I've already used Material UI a lot before, so using it in the project feels familiar and *relatively* comfortable.

### ESlint and Prettier

This is really easy to justify. They are the most popular tools for code quality check. I choose to follow the Airbnb guide which in my opinion is quite comprehensive, although I've also found some arguments against using it as it might be an overkill for small projects. I'm very eager to learn about how Wolt ensures code format.

### Jest, React testing library, and Cypress

These three tools form a good combination to perform different level of tests in my opinion. I've used jest for unit tests of redux, react testing library for unit tests and integration tests of various components and pages, and finally Cypress for e2e tests. Personally, I think the test cases have basically covered all scenarios that are common for the project, but I think I still have a long way to go to write better automated tests.

### React routers

This was used in a very small fraction of the project just to separate the input page and result page in different routes. It is just a small add-on for the project which follow some basic logic that the result needs to be on a separate page to be more intuitive for users.

### Docker

This is the first time I've tried to use Docker throughout the development. I've always wanted to try Docker on a larger scale and this project seems to be in the right size. Of course I've run into some problems when doing it, but I'm glad that I've learnt a lot from it.

### GitHub Actions

I'm familiar with using GitHub Actions and it has become kind of a muscle memory for me. I'm glad that I've used it as it has helped me spotted some problems with code format and e2e testing.

## What I've learnt

* **More about test-driven development**. In this project, I've tried to use the three levels of tests to compensate each other and test different functions, components, and scenarios. It is time-consuming, but also quite rewarding. I used to be confused between unit test and integration test as their boundary can be blur sometimes. In this project, I tried to force myself to distinguish them, and I think I have a better grip on them than before.

* **More about Docker**. I've learnt a lot about the use of Docker in development through try-and-error. And I'm surprised to know that Docker is not the firm guarantee that the program inside will always work. There's definitely place for me improve when it comes to using Docker better.

* **More about accessibility**. I've used the [IBM Equal Access Accessibility Checker](https://chromewebstore.google.com/detail/ibm-equal-access-accessib/lkcagbfjnkomcinoddgooolagloogehp) to check the accessibility of the project, and I've learnt a lot from the rules and suggestions, such as the use of `<fieldset>`, labels and correct contrast ratio. This is also the first time I've tried to view a webpage under high-contrast mode.

## What could be improved

* **Better tests**. When designing the tests, I followed my own "rule" that each component should have its own tests and e2e tests should act as a comprehensive guard for the whole app. This results in a somewhat even distribution between the three level of tests, which works but is time-consuming. In addition, I've only included a handful of test cases. Having more of them and maybe include some more edge cases will definitely help me "sleep better at night". Moving on, I would like to put more emphasis on lower-level tests, and I would really love to know about how Wolt designs tests to have more unit tests, less integration tests and even fewer e2e tests.

* **Use customised CSS library**. While using Material UI was quite easy, it has its own trade-off: less customisation and harder to test. The latter is especially true, as I had a hard time trying to analyse what each Material UI component actually contains and how can I put the `data-test-id` into the right component. Using pure CSS or TailwindCSS could be an alternative.

* **Improve Docker**. In this project, I didn't include Cypress in the development docker, so the e2e tests need to be run outside of Docker. This is not the optimal solution. Moving on, I'd like to explore Cypress's official docker image and use them instead to integrate e2e tests.

* **Better documentation**. I've tried to follow the guideline of [TSDoc](https://tsdoc.org/) when writing comments for the code. But I still feel like there are spaces for improvement.

## Summary

This has been a really fun project for me, and I have had the opportunity to close some gaps of my knowledge. Hopefully this reflection has provided good insight and I am really eager to have a deeper discussion on the project. Thank you for reading.
Binary file added src/assets/Normal-input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/Wrong-input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/confirm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
import { describe, test, expect, jest } from '@jest/globals';
import { calculateFee } from './FeeCalculator';
import { screen, render, configure } from '@testing-library/react';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import FeeCalculator, { calculateFee } from './FeeCalculator';
import ConfirmItem from '../confirmItem/ConfirmItem';
import Header from '../header/Header';
import ContentContainer from '../contentContainer/ContentContainer';
import { store } from '../../../../app/store';

jest.mock('../../../../assets/Wolt-logo.jpg', () => jest.fn());

jest.mock('../confirmItem/ConfirmItem', () => jest.fn());
jest.mock('../header/Header', () => jest.fn());
jest.mock('../contentContainer/ContentContainer', () =>
jest.fn((props: React.PropsWithChildren) => <div>{props.children}</div>),
);

describe('Test fee calculation service', () => {
test('More than 200 euro worth of items should have 0 delivery fee', () => {
expect(
Expand Down Expand Up @@ -301,3 +314,24 @@ describe('Test fee calculation service', () => {
).toBe(11.64);
});
});

describe('Can render basic page', () => {
configure({ testIdAttribute: 'data-test-id' });

test('Can render all items', async () => {
render(
<BrowserRouter>
<Provider store={store}>
<FeeCalculator />
</Provider>
</BrowserRouter>,
);
expect(ContentContainer).toBeCalled();
expect(Header).toBeCalled();
expect(ConfirmItem).toBeCalledTimes(4);
const deliveryFee = screen.getByTestId('deliveryFee');
expect(deliveryFee).toBeDefined();
const returnButton = screen.getByTestId('returnButton');
expect(returnButton).toBeDefined();
});
});

0 comments on commit 11d588c

Please sign in to comment.