summaryrefslogtreecommitdiff
path: root/packages/create-astro/test/create-astro.test.js
diff options
context:
space:
mode:
authorGravatar Drew Powers <1369770+drwpow@users.noreply.github.com> 2021-06-11 15:07:30 -0600
committerGravatar GitHub <noreply@github.com> 2021-06-11 15:07:30 -0600
commit9d3cd494106ea09f0d80acde487f250a0480cfd3 (patch)
tree7d1f1987d3f7651979ab575665209da52a768ea3 /packages/create-astro/test/create-astro.test.js
parente7b5ad362cd4d1a73d8c05df34a6b86743457f8a (diff)
downloadastro-9d3cd494106ea09f0d80acde487f250a0480cfd3.tar.gz
astro-9d3cd494106ea09f0d80acde487f250a0480cfd3.tar.zst
astro-9d3cd494106ea09f0d80acde487f250a0480cfd3.zip
Improve templates test (#377)
Diffstat (limited to 'packages/create-astro/test/create-astro.test.js')
-rw-r--r--packages/create-astro/test/create-astro.test.js178
1 files changed, 98 insertions, 80 deletions
diff --git a/packages/create-astro/test/create-astro.test.js b/packages/create-astro/test/create-astro.test.js
index 4335f77e1..30f466d30 100644
--- a/packages/create-astro/test/create-astro.test.js
+++ b/packages/create-astro/test/create-astro.test.js
@@ -2,24 +2,27 @@ import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import http from 'http';
-import { suite } from 'uvu';
+import { green, red } from 'kleur/colors';
import execa from 'execa';
-import del from 'del';
import glob from 'tiny-glob';
-import * as assert from 'uvu/assert';
import { TEMPLATES } from '../dist/templates.js';
// config
const GITHUB_SHA = process.env.GITHUB_SHA || execa.sync('git', ['rev-parse', 'HEAD']).stdout; // process.env.GITHUB_SHA will be set in CI; if testing locally execa() will gather this
-const MAX_TEST_TIME = 60000; // maximum time a test may take (60s)
-const TIMER = {}; // keep track of every test’s run time (uvu requires manual setup for this)
const FIXTURES_DIR = path.join(fileURLToPath(path.dirname(import.meta.url)), 'fixtures');
-// helper
+// helpers
async function fetch(url) {
- return new Promise((resolve) => {
+ return new Promise((resolve, reject) => {
http
.get(url, (res) => {
+ // not OK
+ if (res.statusCode !== 200) {
+ reject(res.statusCode);
+ return;
+ }
+
+ // OK
let body = '';
res.on('data', (chunk) => {
body += chunk;
@@ -27,94 +30,109 @@ async function fetch(url) {
res.on('end', () => resolve({ statusCode: res.statusCode, body }));
})
.on('error', (err) => {
+ // other error
reject(err);
});
});
}
-// test
-const CreateAstro = suite('npm init astro');
+function assert(a, b, message) {
+ if (a !== b) throw new Error(red(`✘ ${message}`));
+ // console.log(green(`✔ ${message}`)); // don’t show successes
+}
+
+async function testTemplate(template) {
+ const templateDir = path.join(FIXTURES_DIR, template);
+
+ // test 1: install
+ const DOES_HAVE = ['.gitignore', 'package.json', 'public', 'src'];
+ const DOES_NOT_HAVE = ['.git', 'meta.json'];
+
+ // test 1a: expect template contains essential files & folders
+ for (const file of DOES_HAVE) {
+ assert(fs.existsSync(path.join(templateDir, file)), true, `[${template}] has ${file}`);
+ }
+ // test 1b: expect template DOES NOT contain files supposed to be stripped away
+ for (const file of DOES_NOT_HAVE) {
+ assert(fs.existsSync(path.join(templateDir, file)), false, `[${template}] cleaned up ${file}`);
+ }
+
+ // test 2: build
+ const MUST_HAVE_FILES = ['index.html', '_astro'];
+ await execa('npm', ['run', 'build'], { cwd: templateDir });
+ const builtFiles = await glob('**/*', { cwd: path.join(templateDir, 'dist') });
+ // test 2a: expect all files built successfully
+ for (const file of MUST_HAVE_FILES) {
+ assert(builtFiles.includes(file), true, `[${template}] built ${file}`);
+ }
+
+ // test 3: dev server (should happen after build so dependency install can be reused)
+
+ // TODO: fix dev server test in CI
+ if (process.env.CI === true) {
+ return;
+ }
+
+ // start dev server in background & wait until ready
+ const templateIndex = TEMPLATES.findIndex(({ value }) => value === template);
+ const port = 3000 + templateIndex; // use different port per-template
+ const devServer = execa('npm', ['run', 'start', '--', '--port', port], { cwd: templateDir });
+ let sigkill = setTimeout(() => {
+ throw new Error(`Dev server failed to start`); // if 10s has gone by with no update, kill process
+ }, 10000);
+
+ // read stdout until "Server started" appears
+ await new Promise((resolve, reject) => {
+ devServer.stdout.on('data', (data) => {
+ clearTimeout(sigkill);
+ sigkill = setTimeout(() => {
+ reject(`Dev server failed to start`);
+ }, 10000);
+ if (data.toString('utf8').includes('Server started')) resolve();
+ });
+ devServer.stderr.on('data', (data) => {
+ reject(data.toString('utf8'));
+ });
+ });
+ clearTimeout(sigkill); // done!
+
+ // send request to dev server that should be ready
+ const { statusCode, body } = (await fetch(`http://localhost:${port}`)) || {};
+
+ // test 3a: expect 200 status code
+ assert(statusCode, 200, `[${template}] 200 response`);
+ // test 3b: expect non-empty response
+ assert(body.length > 0, true, `[${template}] non-empty response`);
-CreateAstro.before(async () => {
- // clean install dir
- await del(FIXTURES_DIR);
- await fs.promises.mkdir(FIXTURES_DIR);
+ // clean up
+ devServer.kill();
+}
- // install all templates & deps before running tests
+async function testAll() {
+ // setup
await Promise.all(
TEMPLATES.map(async ({ value: template }) => {
- const templateDir = path.join(FIXTURES_DIR, template);
- await execa('../../create-astro.mjs', [templateDir, '--template', template, '--commit', GITHUB_SHA, '--force-overwrite'], {
+ // setup: `npm init astro`
+ await execa('../../create-astro.mjs', [template, '--template', template, '--commit', GITHUB_SHA, '--force-overwrite'], {
cwd: FIXTURES_DIR,
});
- await execa('yarn', ['--frozen-lockfile', '--silent'], { cwd: templateDir });
+ // setup: `npm install` (note: running multiple `yarn`s in parallel in CI will conflict)
+ await execa('npm', ['install', '--no-package-lock', '--silent'], { cwd: path.join(FIXTURES_DIR, template) });
})
);
-});
-
-// enforce MAX_TEST_TIME
-CreateAstro.before.each(({ __test__ }) => {
- if (TIMER[__test__]) throw new Error(`Test "${__test__}" already declared`);
- TIMER[__test__] = setTimeout(() => {
- throw new Error(`"${__test__}" did not finish within allowed time`);
- }, MAX_TEST_TIME);
-});
-CreateAstro.after.each(({ __test__ }) => {
- clearTimeout(TIMER[__test__]);
-});
-
-for (let n = 0; n < TEMPLATES.length; n++) {
- const template = TEMPLATES[n].value;
- const templateDir = path.join(FIXTURES_DIR, template);
- CreateAstro(`${template} (install)`, async () => {
- const DOES_HAVE = ['.gitignore', 'package.json', 'public', 'src'];
- const DOES_NOT_HAVE = ['.git', 'meta.json'];
+ // test (note: not parallelized because Snowpack HMR reuses same port in dev)
+ for (let n = 0; n < TEMPLATES.length; n += 1) {
+ const template = TEMPLATES[n].value;
- // test: template contains essential files & folders
- for (const file of DOES_HAVE) {
- assert.ok(fs.existsSync(path.join(templateDir, file)), `missing ${file}`);
+ try {
+ await testTemplate(template);
+ } catch (err) {
+ console.error(red(`✘ [${template}]`));
+ throw err;
}
- // test: template DOES NOT contain files supposed to be stripped away
- for (const file of DOES_NOT_HAVE) {
- assert.not.ok(fs.existsSync(path.join(templateDir, file)), `failed to clean up ${file}`);
- }
- });
-
- CreateAstro(`${template} (dev)`, async () => {
- // start dev server
- const port = 3000 + n; // start new port per test
- const devServer = execa('yarn', ['start', '--port', port], { cwd: templateDir });
- await new Promise((resolve) => {
- setTimeout(() => resolve(), 15000);
- }); // give dev server flat 15s to set up
- // TODO: try to ping dev server ASAP rather than waiting flat 15s
-
- // ping dev server
- const { statusCode, body } = await fetch(`http://localhost:${port}`);
-
- // expect 200 to be returned with some response
- assert.equal(statusCode, 200, 'didn’t respond with 200');
- assert.ok(body, 'returned empty response');
-
- // clean up
- devServer.kill();
- });
-
- CreateAstro(`${template} (build)`, async () => {
- const MUST_HAVE_FILES = ['index.html', '_astro'];
-
- // build template
- await execa('yarn', ['build'], { cwd: templateDir });
-
- // scan build dir
- const builtFiles = await glob('**/*', { cwd: path.join(templateDir, 'dist') });
- for (const file of MUST_HAVE_FILES) {
- assert.ok(builtFiles.includes(file), `didn’t build ${file}`);
- }
- });
+ console.info(green(`✔ [${template}] All tests passed (${n + 1}/${TEMPLATES.length})`));
+ }
}
-
-// run tests
-CreateAstro.run();
+testAll();