Compute Application Testing for JavaScript
For those times you want to write JavaScript tests against a Fastly
Compute application.
NOTE: Your Compute application can be written in any language/framework.
This library allows you to write end-to-end tests against the
output of your Compute application.
Start and stop a Fastly Compute application in the
local testing environment
from your tests and make requests to it.
Use with any test runner and framework.
NOTE: @fastly/compute-testing
is provided as a Fastly Labs product. Visit the
Fastly Labs site for terms of use.
Requirements
For local testing, Fastly CLI is required.
Note that @fastly/compute-testing
makes no assumptions or dictates on the language used to build the
Compute application. This framework simply starts/stops the application, and helps your code make
HTTP requests to it.
Installation
npm install --save-dev @fastly/compute-testing
Usage
Basic usage
The following is a simple example. It uses Node.js's test runner along with
Node.js's assertions, but note that any test framework or assertion library
can be used.
In your test (./test.js
), you can start and stop a Compute application:
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert';
import path from 'node:path';
import url from 'node:url';
import { ComputeApplication } from '@fastly/compute-testing';
describe('Run local Viceroy', function() {
const app = new ComputeApplication();
before(async function() {
await app.start({
appRoot: '/path/to/approot',
});
});
it('Response status code is 200', async function() {
const response = await app.fetch('/');
assert.equal(response.status, 200);
});
it('Response headers include Content-Type: text/html', async function() {
const response = await app.fetch('/');
const contentTypeHeaders =
(response.headers.get('content-type') ?? '')
.split(',')
.map(value => value.trim().split(';')[0]);
assert.ok(contentTypeHeaders.includes('text/html'));
});
it('Response body contains <div>Index</div>', async function() {
const response = await app.fetch('/');
const text = await response.text();
assert.ok(text.includes('<div>Index</div>'));
});
after(async function() {
await app.shutdown();
});
});
You would run this using Node.js in test mode:
node --test
Using a relative path for appRoot
Often your test suite will live in the same code repository as your Compute application.
In this case, you may find it useful to specify a relative path.
For example, if your test file is at <repo>/tests/test.js
and your test application's root is at <repo>/app
,
then you can specify the appRoot
at the relative path of ../app
as so:
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
await app.start({
appRoot: path.join(__dirname, '../app'),
});
appRoot
can also be specified as a URL path of a file in your Compute application
directory. So, if you're using Node.js 20.7 or newer you can use
import.meta.resolve:
await app.start({
appRoot: import.meta.resolve('../app/package.json'),
});
Custom start script
The following example is for a Compute application that is started using a
custom startup command.
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert';
import path from 'node:path';
import url from 'node:url';
import { ComputeApplication } from '@fastly/compute-testing';
describe('Run custom app', function() {
const app = new ComputeApplication();
before(async function() {
this.timeout(30000);
await app.start({
startCommand: 'npm run start',
appRoot: '/path/to/approot',
});
});
});
Use an already-running or remote Compute application
The following example is for a Fastly Compute application that is already running, or
running on a remote host.
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert';
import path from 'node:path';
import url from 'node:url';
import { ComputeApplication } from '@fastly/compute-testing';
describe('Use running application', function() {
const app = new ComputeApplication();
before(async function() {
await app.start({
addr: 'https://app.example.com/',
});
});
});
Usage with other tools
Note that this library is tool- and framework-agnostic, and thus can be used with any testing helper
tools. The following example shows usage with JSDOM, a DOM
testing library for Node.js.
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert';
import path from 'node:path';
import url from 'node:url';
import { JSDOM } from 'jsdom';
import { ComputeApplication } from '@fastly/compute-testing';
describe('JSDOM testing', function() {
it('DOM node with id="foo" contains "bar"', async function() {
const response = await app.fetch('/');
const dom = new JSDOM(await response.text(), {url: response.url});
const element = dom.window.document.getElementById('foo');
assert.ok(element.textContent === 'bar');
});
});
Issues
If you encounter any non-security-related bug or unexpected behavior, please file an issue
using the bug report template.
Security issues
Please see our SECURITY.md for guidance on reporting security-related issues.
License
MIT.