Basic Testing Best Practices

Basic Jest Configuration

Steps to Configure Typescript in Jest

Jest out of the box understands .js extension, in order to write tests in typescript follow the steps:

preset: "ts-jest", // point the Jest preset to use the ts-jest configuration testEnvironment: "jsdom", // jsdom since we are building for browser and shoudl test with dom like environment moduleFileExtensions: ["ts", "tsx", "js", "json"], globals: { "ts-jest": { tsconfig: "tsconfig.jest.json", // provide path to the tsconfig if its different than 'tsconfig.json' }, }, transform: { "^.+\\.(js|ts|tsx)$": "ts-jest", // tell jest how to trasform your files },
{ "extends": "./tsconfig.json", "compilerOptions": { "module": "CommonJS" } }

Now with this setup we can write test in typescript.

_ Note for Aliases in Jest files refer here _

Basic handy configuration options

setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"],
watchPlugins: ["jest-watch-typeahead/filename", "jest-watch-typeahead/testname"],

How to write Testable Components

The diagram shows the new proposed and the old way of designing components. The benefit of building components in a new way is that there is a lot of separation of concerns and the component itself become much simpler.

Component ===> Business Logic(Hooks) ====> Data Stor(Context/Redux)

All the component in this repo is designed in that way and you can see how testing is simpler as

An example would be add-todo.tsx

The above approach with a mindset of testing from user prospective can give us test with better confidence. So what is this user prospective, it is basically testing the components the way the user would interact with them and avoid creating a new test user persona.

One example to User based testing is, that we avoid mocking stuff like fetch or network calls, as we would want to test it as close to user. So we use libraries like miragejs or msw to mock the fetch at network layer and create a full user experience while testing. This way we can test the different state the user would see during the network request or after it success or fails. An example would be the login.spec.tsx.

Another point to keep in mind is, mock stuff smartly, for example if you are trying to test a specific flow in a component and don't care about the other components included/rendered, its better to mock them. For example in the app.spec.tsx we want to test the itenary condition that it renders correct component based on the state, but we don't really care what the contents of each component are, so we mock the components as we don't want to render those unnecessarily in the test.

jest.mock("components/todos", () => ({ __esModule: true, default: () => { return <h2>Todos</h2>; }, }));

Jest debugging

   "test:debug": "node --inspect-brk",
 "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand
--watch
",