Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SDK-3920] Add a basic test of NPM package #1476

Merged
merged 2 commits into from
Nov 21, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Add a basic test of NPM package
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.
lawrence-forooghian committed Nov 14, 2023
commit 9976a8455a421b0d901bb609fafac2e0654c4f1a
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
@@ -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');
@@ -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));
};
}

@@ -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
@@ -111,6 +111,7 @@
"test:webserver": "grunt test:webserver",
"test:playwright": "node test/support/runPlaywrightTests.js",
"test:react": "vitest run",
"test:package": "grunt test:package",
"concat": "grunt concat",
"build": "grunt build:all && npm run build:react",
"build:node": "grunt build:node",
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:package` 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

Unchanged files with check annotations Beta

*/
get(name: string, channelOptions?: ChannelOptions): T;
/**
* @experimental This is a preview feature and may change in a future non-major release.

Check warning on line 2364 in ably.d.ts

GitHub Actions / lint

Invalid JSDoc tag name "experimental"
* This experimental method allows you to create custom realtime data feeds by selectively subscribing

Check warning on line 2365 in ably.d.ts

GitHub Actions / lint

Expected no lines between tags
* to receive only part of the data from the channel.
* See the [announcement post](https://pages.ably.com/subscription-filters-preview) for more information.
*
import App from './App.js';
import { AblyProvider } from '../../src/index.js';
const container = document.getElementById('root')!;

Check warning on line 10 in src/platform/react-hooks/sample-app/src/script.tsx

GitHub Actions / lint

Forbidden non-null assertion
function generateRandomId() {
return Math.random().toString(36).substr(2, 9);