Automating testing, building and publishing of TypeScript libraries
Tags: javascript, typescript, productivity, beginners
Published: 2019-02-17 12:36:00

---
title: Automating testing, building and publishing of TypeScript libraries
published: true
description: A short guide on how to automate building and publishing of your TypeScript (or just JavaScript) libraries with Drone
tags: javascript, typescript, productivity, beginners
cover_image: https://thepracticaldev.s3.amazonaws.com/i/gg7oszsc5okeuc69jo4d.png
---

It doesn't matter whether you are working on a side project, small open source library or your full-time job project, automating builds, tests and releases can greatly improve your life. You can then concentrate on code quality, features or just have a small break when you finish a task instead of trying to remember all the required steps to make a release. 

In my previous article I demonstrated how to set up a [self-hosted CI/CD solution with Drone](https://dev.to/krusenas/setting-up-simple-self-hosted--fast-cicd-solution-with-drone-for-homelab-or-office-1fnd). You don't need a powerful CI server or expensive VMs to run it, you can easily get one running on your laptop to perform these tasks in the background a lot faster than the free alternatives while also getting much greater flexibility. 

Now, I would like to share some practical pipelines that I have recently implemented.

**A short disclaimer:** I don't identify myself as an experienced TypeScript/JavaScript developer, I always lean to Go but in this case I needed to write some JavaScript so it was a great opportunity to finally try out TypeScript :) The package itself can be found [here](https://github.com/webhookrelay/webhookrelay-ws-client), it's a simple library that allows you to receive webhooks inside your app without exposing it to the internet.

## Testing the library

My library tests were probably not what you find in a standard library. Since they rely on the SaaS service (to receive those public webhooks), it has to get some credentials from environment and perform asynchronous actions. That's where I learnt about `done` callback:

```javascript
it('should be able to forward the webhook', (done) => {
    var payload = "payload-" + Math.floor((Math.random() * 100000) + 1);
    // creating a handler
    var handler = function (data: string) {
      var msg = JSON.parse(data);
      if (msg.type === 'status' && msg.status == 'subscribed') { // <---- once received, send a webhook
        var dispatchWebhook = function() {
          axios.post('https://my.webhookrelay.com/v1/webhooks/9c1f0997-1a34-4357-8a88-87f604daeca9', payload)
          .then(function (response) {          
            expect(response.status).to.equal(200)
          })
        }
        setTimeout(dispatchWebhook, 1000)
                
      }
      if (msg.type === 'webhook' && msg.body === payload) {
        expect(msg.method).to.equal('POST');
        done(); // <---- once webhook received, end the test case
        client.disconnect();
      }
    }
  
    var client = new WebhookRelayClient(key, secret, [testBucket], handler)
    client.connect(); // <---- connecting so our handler will be called
  });
```

While this not really related to automation, it might be useful for someone :) 

## Building the library

When using Drone, everything runs in a Docker container. The main benefit of this is that it becomes trivial to get a reproducible builds. In our case, the first step includes:

* Install dependencies
* Build with `tsc` (TypeScript needs to be converted back to JavaScript)
* Run tests

Our Drone file looks like:

```yaml
kind: pipeline
name: default

steps:

- name: build
  image: node:latest
  environment: # supplying environment variables for testing
    RELAY_KEY:
      from_secret: relay_key
    RELAY_SECRET:
      from_secret: relay_secret
    RELAY_BUCKET: ws-client-tests
  commands:
    - npm install
    - npm run build
    - make test

```

here, `npm run build` is actually just:

```javascript
"scripts": {
    "build": "tsc"
  },
```

And in the Makefile `make test`:

```
test:
	./node_modules/mocha/bin/mocha --reporter spec --compilers ts:ts-node/register src/*.test.ts
```

## Publishing to npm registry

It's always good to automate publishing packages as well. This way you will get a good release process for almost zero effort. When you are happy with the package functionality, you just tag a Github release and Drone will build, test and publish your package to npm registry:

```yaml
- name: publish
  image: node:latest  
  environment:
    NPM_TOKEN:
      from_secret: npm_token
  commands:
    - make drone-publish
  when:
    event: [ tag ]
```

environment variable `NPM_TOKEN` is a token that you can generate for your account. 

`make drone-publish` command looks like:

```
drone-publish:
	echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc	
	npm publish
```

It is important to set that `.npmrc` file as the publishing won't work without it. Strange? yes. 

## Bonus: Notifications

This last step is repeated across all my Drone pipelines, it's a notification to a Slack channel:

```yaml
- name: slack
  image: plugins/slack
  when:
    status: [ success, failure ]
  settings:
    webhook:
      from_secret: slack_url
    channel: general
    username: drone
```

For this to work, get your Slack's webhook URL and create a `slack_url` secret.

## Wrapping up

It takes 30-90 minutes to set up everything initially and once you have a CI system running, subsequent repositories can be added in seconds. Even if you think that running `npm run build` and `npm publish` takes only 1 minute of your time every time you release, automating this process will greatly improve your developer experience and life in general :) Combining automated builds and releases with tests will ensure that there is only one path to getting your package published. I have seen many cases where a TypeScript package build step was missed and the previous version was released. Or, after a 'quick fix' and push to registry the package was broken because someone forgot to run the test. Or, just consider that in the next year you might do 200 releases that would end up in many hours saved by automation!