TypeScript introduces static typing and other powerful features that can make your code more reliable and easier to maintain, especially in larger projects. With TypeScript, I can catch errors early and benefit from better tooling support.
And finally, I'll show you how to set up continuous integration using GitHub Actions. By automating the building, testing, and deployment of your code, you can catch issues early and ship software faster. I'll guide you through the process of setting up a CI pipeline, so you can test your code automatically and get fast feedback on your changes.
You can find a GitHub repository containing the below mentioned files here: jonasclaes/2023-tutorial-build-test-deploy
yarn init inside this folder. I also created a
src folder to contain the source code for my project.
Next, I installed TypeScript and the Node.js types as development dependencies by running the command
yarn add -D typescript @types/node. This would allow me to use TypeScript in my project and ensure that the code I write is compatible with Node.js.
Once the dependencies were installed, I created a new file called
tsconfig.json in the root of my project directory with the following contents:
This is an optimal configuration for the small project we will be creating. It sets the module system to
NodeNext which allows us to use the latest features of Node.js. It also specifies the target environment to be
ES2020, enables source maps, and sets the output directory for the compiled code to
dist. Finally, it enables the
esModuleInterop flag which allows us to use modules that were not designed for TypeScript.
package.json file, I added
"type": "module" to indicate to Node.js that the code we will be compiling is an ES module. This is important because it enables the use of ES module syntax such as
Finally, I added a script called
build to the
package.json file which runs the TypeScript compiler (
start to the
package.json which just runs our compiled code using Node.js. Your
package.json file should look something like the following:
With this project initialization out of the way, we're ready to start writing TypeScript code and testing it with unit tests.
Unit testing is an essential part of software development that is often overlooked or misunderstood. In simple terms, unit tests are tests that are designed to test small, individual units of code, such as functions or methods. These units should be able to function on their own and have no side effects. It's important to note that unit tests should not connect to databases, interact with other services, or depend on other code.
To get started with unit testing in our project, I first added Jest and the corresponding types by running the following command:
test script to the
package.json which invokes
package.json should look something like the following:
Next, I generated a
jest.config.js file by running
ts-jest config:init. However, we needed to rename the
jest.config.js file to
jest.config.cjs because TypeScript needs to know what kind of JS file this is. I also created a folder called
test which will contain all of our unit tests. The
jest.config.cjs file should look something like the following:
Now that our test environment is set up, we can start writing our tests. To begin, I added a small piece of code to
src/index.ts which we can test later on. This code exports a function called
sum, which takes in two numbers and returns their sum. Here's the code:
After adding this code, I then created a test file at
test/index.test.ts. In this file, I imported the
sum function from
src/index.ts and created three small unit tests to verify that it works correctly. Each test uses Jest's
expect function to compare the output of the
sum function to an expected value using the
toBe matcher. Here's the test code:
These tests check that
sum works correctly for different input values, ensuring that it can correctly add two numbers.
Finally, I ran
yarn test to run the unit tests. If everything went okay, you should see a "PASS" message for all 3 tests in the console. By writing and running these tests, we can be more confident that our code is working correctly, and can detect and fix issues more easily as we continue to develop our project.
GitHub Actions is a way to automate tasks and processes that happen when you interact with your GitHub repository. In this case, we want to create a workflow to automatically test and deploy our code whenever we push new changes to the repository.
First, we create a file called
test-and-deploy.yml in the
.github/workflows directory. The contents of this file are written in YAML, a markup language that is often used for configuration files. This file should look something like the following:
The first line of the file specifies the name of the workflow: "Test and deploy". The
on section specifies when this workflow should be triggered. In this case, we want it to be triggered whenever we push new changes to the repository.
The next section defines the
Test job. A job is a series of steps that should be executed. In this case, we want to run our tests. The
runs-on field specifies which operating system we want to run our tests on. In this case, we're using the latest version of Ubuntu.
steps field is an array of steps that should be executed. The first step checks out the code from the repository. The second step sets up the environment by installing Node.js and caching our dependencies using Yarn. The third step installs the dependencies. The fourth step runs our tests.
The next section defines the
Deploy job. This job should only run if the
Test job succeeds (indicated by the
needs field). The steps are similar to the
Test job, with a few additions. First, we compile our source code using the
yarn build command. Then, we create a zip file of the compiled source code. We use the
actions/github-script action to get the latest release of our code, so that we can create a new release with the updated code. We create a new release using the
actions/create-release action and upload the compiled source code using the
When you commit and push this file to GitHub, you should see a new action starting to run in the "Actions" tab of your repository. This action will run the
Test job and then the
Deploy job, if the
Test job succeeds. This means that your code will be automatically tested and deployed whenever you push new changes to the repository.
In conclusion, automated testing is an important part of software development that ensures the code is functioning as expected and catches any errors early on in the development process. Using a CI pipeline like GitHub Actions makes it easy to automate this process, so that each time code is pushed to the repository, the tests are run automatically. This can save a lot of time and effort in the long run, as any issues can be caught and addressed before they become bigger problems. By following the steps outlined in this tutorial, you should now have a better understanding of how to set up automated testing with Jest and GitHub Actions, and how to ensure that your code is functioning as expected before it gets deployed to production.