Skip to main content
blog title image

3 minute read - JavaScript

HTTPS imports with Jest

Jun 4, 2022

TLDR: use moduleNameMapper to support https CDN imports in Jest.

I’m currently refactoring my application AnyWayData.com and I needed to mix cdn imports with node install includes for testing with jest.

Why?

My AnyWayData.com app was initially built as a very simple web app:

  • hand crafted html
  • various JavaScript files imported as <script> files
  • no build systems
  • no tests

I wanted to refactor it into a more modern app with JavaScript modules, classes and Unit tests.

Jest

Jest is an Automation Execution Framework for JavaScript that runs on top of Node.js

Node.js expects require statements rather than import statements but there is a package we can install that allows using import statements.

I installed "@babel/preset-env" and setup my .babelrc file as:

{
    "presets": ["@babel/preset-env"]
}

I documented this in my learn-javasript github repo in the comments for import_includes/myclass.test.js

The process documented in the official docs was:

npm install --save-dev babel-jest @babel/core @babel/preset-env

Then create babel.config.js in your root folder:

module.exports = {
  presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
};

At this point I can now convert my code to standard JavaScript modules to run in the browser, and I can write Jest tests e.g.

describe("Can convert markdown tables to data suitable for a data grid",()=> {

    test('can convert a simple 2x3 table', () => {
        const basicTable =
`|heading 1|heading 2|
|-------|-------|
|row 0 cell 0|row 0 cell 1|
|row 1 cell 0|row 1 cell 1|
`
        let data = new MarkdownConvertor().
                    markdownTableToDataRows(basicTable);
        
        expect(data.length).toBe(3);
        expect(data[0][0]).toBe('heading 1');
        expect(data[0][1]).toBe('heading 2');
        expect(data[1][0]).toBe('row 0 cell 0');
        expect(data[1][1]).toBe('row 0 cell 1');
        expect(data[2][0]).toBe('row 1 cell 0');
        expect(data[2][1]).toBe('row 1 cell 1');
    });
});

Problem CDN usage

Jest is expecting all the packages used to be installed via node e.g if I wanted to use Faker… and I do… then I’d install it:

npm install @faker-js/faker --save-dev

But I am converting an existing JavaScrip app and some of the libraries I’m using are imported from a CDN, I haven’t refactored it to use WebPack and might still want to use the CDN.

My JavaScript file that uses the CDN starts like:

import { faker } from "https://cdn.skypack.dev/@faker-js/faker@v7.1.0";

class TestDataRules{

    constructor() {
...

This all works great in the browser but when I want to write some Jest tests for the TestDataRules class then I’m not going to be able to do it because it doesn’t support importing from https.

Node has an experimental import from https command line flag but the various combinations of triggering this that I tried didn’t let me use it with Jest.

I also investigated some code transformation options, but they seemed a little overkill for what I was trying to achieve.

My solution moduleNameMapper

While reading the docs I stumbled across the moduleNameMapper options and that seemed like the perfect solution.

It seemed too simple. Add a new configuration in package.json for Jest to use a moduleNameMapper so that the CDN https URL is replaced with the npm install package name.

  "jest":{
    "moduleNameMapper":{
      "https://cdn.skypack.dev/@faker-js/faker@v7.1.0": "@faker-js/faker"
    }
  },

Simply adding this allows me to continue with a single import in the .js file.

import { faker } from "https://cdn.skypack.dev/@faker-js/faker@v7.1.0";

Until I did this I was having to switch between an npm local install include and the CDN.

//import { faker } from '@faker-js/faker';

But I wanted to run all the tests without having to amend the code.

Now I’m in the position that I can continue to refactor my legacy code into a more modern JavaScript app, and add more tests, and gradually adopt more build technology as required.