Skip to content

Commit

Permalink
Add a basic test of NPM package
Browse files Browse the repository at this point in the history
This adds a package script `test:package`, which performs some basic
testing to confirm that a browser-based TypeScript app is able to import
the NPM package and use Ably functionality.

This hopefully gives us further confidence that we’ve correctly
configured the package’s exports and typings. Next, we’ll build on top
of this to add similar testing for the tree-shakable version of the
library, once we’ve added typings for it in #1442.

Some of the approach here is copied from that used for testing the CDN
bundle in the Spaces SDK (see commit fa95f9f there).

Resolves #1474.
  • Loading branch information
lawrence-forooghian committed Nov 1, 2023
1 parent 2d1f433 commit 9f3dabb
Show file tree
Hide file tree
Showing 14 changed files with 2,713 additions and 5 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Test NPM package
on:
pull_request:
push:
branches:
- main

jobs:
test-npm-package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- name: Use Node.js 16.x
uses: actions/setup-node@v1
with:
node-version: 16.x
- run: npm ci
- run: npm run test:package
86 changes: 81 additions & 5 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var webpackConfig = require('./webpack.config');
var esbuild = require('esbuild');
var umdWrapper = require('esbuild-plugin-umd-wrapper');
var banner = require('./src/fragments/license');
var process = require('process');

module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
Expand All @@ -27,18 +28,27 @@ module.exports = function (grunt) {
};
}

function execExternal(cmd) {
return function () {
var done = this.async();
grunt.log.ok('Executing ' + cmd);
async function execExternalPromises(cmd) {
grunt.log.ok('Executing ' + cmd);
return new Promise(function (resolve, reject) {
require('child_process').exec(cmd, function (err, stdout, stderr) {
if (err) {
grunt.fatal('Error executing "' + cmd + '":\nstderr:\n' + stderr + '\nstdout:\n' + stdout);
reject(err);
}
console.log(stdout);
stderr && console.error(stderr);
done();
resolve();
});
});
}

function execExternal(cmd) {
return function () {
var done = this.async();
execExternalPromises(cmd)
.then(() => done())
.catch((error) => done(error));
};
}

Expand Down Expand Up @@ -215,5 +225,71 @@ module.exports = function (grunt) {
}
);

(function () {
const baseDir = path.join(__dirname, 'test', 'package', 'browser');
const buildDir = path.join(baseDir, 'build');

grunt.registerTask(
'test:package:browser:prepare-project',
'Prepare an app to be used for testing the NPM package in a browser environment',
function () {
const done = this.async();

(async function () {
if (grunt.file.exists(buildDir)) {
grunt.file.delete(buildDir);
}

// Create an app based on the template
grunt.file.copy(path.join(baseDir, 'template'), buildDir);

// Use `npm pack` to generate a .tgz NPM package
await execExternalPromises('npm run build');
await execExternalPromises('npm pack --pack-destination test/package/browser/build');
const version = grunt.file.readJSON('package.json').version;
const packFileName = `ably-${version}.tgz`;

// Configure app to consume the generated .tgz file
const pwd = process.cwd();
process.chdir(buildDir);
await execExternalPromises(`npm install ${packFileName}`);

// Install further dependencies required for testing the app
await execExternalPromises('npm run test:install-deps');
process.chdir(pwd);
})()
.then(() => done(true))
.catch((error) => done(error));
}
);

grunt.registerTask('test:package:browser:test', 'Test the NPM package in a browser environment', function () {
const done = this.async();

(async function () {
grunt.task.requires('test:package:browser:prepare-project');

const pwd = process.cwd();
process.chdir(buildDir);

// Perform type checking on TypeScript code that imports ably-js
await execExternalPromises('npm run typecheck');

// Build bundle including ably-js
await execExternalPromises('npm run build');

// Test that the code which exercises ably-js behaves as expected
await execExternalPromises('npm run test');

process.chdir(pwd);
})()
.then(() => done(true))
.catch((error) => done(error));
});
})();

grunt.registerTask('test:package:browser', ['test:package:browser:prepare-project', 'test:package:browser:test']);
grunt.registerTask('test:package', ['test:package:browser']);

grunt.registerTask('default', 'all');
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"test:node": "grunt test:node",
"test:webserver": "grunt test:webserver",
"test:playwright": "node test/support/runPlaywrightTests.js",
"test:package": "grunt test:package",
"concat": "grunt concat",
"build": "grunt build:all",
"build:node": "grunt build:node",
Expand Down
20 changes: 20 additions & 0 deletions test/package/browser/template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# ably-js NPM package test (for browser)

This directory is intended to be used for testing the following aspects of the ably-js NPM package when used in a browser-based app:

- that its exports are correctly configured and provide access to ably-js’s functionality
- that its TypeScript typings are correctly configured and can be successfully used from a TypeScript-based app that imports the package

The file `src/index.ts` imports the ably-js package and exports a function which briefly exercises its functionality.

## Why is `ably` not in `package.json`?

The `ably` dependency gets added when we run the repository’s `test:bundle` package script. That script copies the contents of this `template` directory to a new temporary directory, and then adds the `ably` dependency to the copy. We do this so that we can check this directory’s `package-lock.json` into Git, without needing to modify it whenever ably-js’s dependencies change.

## Package scripts

This directory exposes three package scripts that are to be used for testing:

- `build`: Uses esbuild to create a bundle containing `src/index.ts` and ably-js.
- `test`: Using the bundle created by `build`, tests that the code that exercises ably-js’s functionality is working correctly in a browser.
- `typecheck`: Type-checks the code that imports ably-js.
Loading

0 comments on commit 9f3dabb

Please sign in to comment.