Add integration test for templates (#372)
This commit is contained in:
parent
047b0fcc6c
commit
a660e49f80
10 changed files with 128 additions and 32 deletions
1
.github/workflows/nodejs.yml
vendored
1
.github/workflows/nodejs.yml
vendored
|
@ -70,3 +70,4 @@ jobs:
|
|||
- run: yarn test
|
||||
env:
|
||||
CI: true
|
||||
GITHUB_SHA: $GITHUB_SHA
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"title": "Blog",
|
||||
"description": "an SEO-optimized blog starter",
|
||||
"rank": 1
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"title": "Getting Started",
|
||||
"description": "a friendly starting point for new astronauts",
|
||||
"rank": 999
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
"build": "yarn build:core",
|
||||
"build:all": "lerna run build",
|
||||
"build:one": "lerna run build --scope",
|
||||
"build:core": "lerna run build --scope astro --scope @astrojs/parser --scope @astrojs/markdown-support",
|
||||
"build:core": "lerna run build --scope astro --scope @astrojs/parser --scope @astrojs/markdown-support --scope create-astro",
|
||||
"build:vscode": "lerna run build --scope astro-languageserver --scope astro-vscode --scope @astrojs/parser",
|
||||
"dev:vscode": "lerna run dev --scope astro-languageserver --scope astro-vscode --scope @astrojs/parser --parallel --stream",
|
||||
"format": "prettier -w \"**/*.{js,jsx,ts,tsx,md,json}\"",
|
||||
|
|
|
@ -26,5 +26,15 @@ npm init astro my-astro-project -- --template starter
|
|||
# yarn
|
||||
yarn create astro my-astro-project --template starter
|
||||
```
|
||||
[Check out the full list][examples] of example starter templates, available on GitHub.
|
||||
|
||||
[Check out the full list](https://github.com/snowpackjs/astro/tree/main/examples) of example starter templates, available on GitHub.
|
||||
### CLI Flags
|
||||
|
||||
May be provided in place of prompts
|
||||
|
||||
| Name | Description |
|
||||
|:-------------|:----------------------------------------------------|
|
||||
| `--template` | Specify the template name ([list][examples]) |
|
||||
| `--commit` | Specify a specific Git commit or branch to use from this repo (by default, `main` branch of this repo will be used) |
|
||||
|
||||
[examples]: https://github.com/snowpackjs/astro/tree/main/examples
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
"scripts": {
|
||||
"build": "astro-scripts build \"src/*.ts\"",
|
||||
"prepare": "yarn build",
|
||||
"test": "uvu"
|
||||
"test": "uvu -i test/fixtures"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
|
|
@ -19,6 +19,8 @@ export function mkdirp(dir: string) {
|
|||
|
||||
const { version } = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
|
||||
|
||||
const POSTPROCESS_FILES = ['package.json']; // some files need processing after copying.
|
||||
|
||||
export async function main() {
|
||||
console.log('\n' + bold('Welcome to Astro!') + gray(` (create-astro v${version})`));
|
||||
console.log(`If you encounter a problem, visit ${cyan('https://github.com/snowpack/astro/issues')} to search or file a new issue.\n`);
|
||||
|
@ -52,12 +54,14 @@ export async function main() {
|
|||
},
|
||||
]);
|
||||
|
||||
const emitter = degit(`snowpackjs/astro/examples/${options.template}`, {
|
||||
const hash = args.commit ? `#${args.commit}` : '';
|
||||
const emitter = degit(`snowpackjs/astro/examples/${options.template}${hash}`, {
|
||||
cache: false,
|
||||
force: true,
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
// Copy
|
||||
try {
|
||||
// emitter.on('info', info => { console.log(info.message) });
|
||||
console.log(green(`>`) + gray(` Copying project files...`));
|
||||
|
@ -68,6 +72,22 @@ export async function main() {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
// Post-process in parallel
|
||||
await Promise.all(
|
||||
POSTPROCESS_FILES.map(async (file) => {
|
||||
const fileLoc = path.join(cwd, file);
|
||||
|
||||
switch (file) {
|
||||
case 'package.json': {
|
||||
const packageJSON = JSON.parse(await fs.promises.readFile(fileLoc, 'utf8'));
|
||||
delete packageJSON.snowpack; // delete snowpack config only needed in monorepo (can mess up projects)
|
||||
await fs.promises.writeFile(fileLoc, JSON.stringify(packageJSON, undefined, 2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
console.log(bold(green('✔ Copied project files')));
|
||||
|
||||
console.log('\nNext steps:');
|
||||
|
|
|
@ -1,46 +1,120 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import http from 'http';
|
||||
import { suite } from 'uvu';
|
||||
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
|
||||
async function fetch(url) {
|
||||
return new Promise((resolve) => {
|
||||
http
|
||||
.get(url, (res) => {
|
||||
let body = '';
|
||||
res.on('data', (chunk) => {
|
||||
body += chunk;
|
||||
});
|
||||
res.on('end', () => resolve({ statusCode: res.statusCode, body }));
|
||||
})
|
||||
.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// test
|
||||
const CreateAstro = suite('npm init astro');
|
||||
|
||||
const cwd = fileURLToPath(path.dirname(import.meta.url));
|
||||
const fixturesDir = path.join(cwd, 'fixtures');
|
||||
|
||||
CreateAstro.before(async () => {
|
||||
await del(fixturesDir);
|
||||
await fs.promises.mkdir(fixturesDir);
|
||||
// clean install dir
|
||||
await del(FIXTURES_DIR);
|
||||
await fs.promises.mkdir(FIXTURES_DIR);
|
||||
|
||||
// install all templates & deps before running tests
|
||||
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'], {
|
||||
cwd: FIXTURES_DIR,
|
||||
});
|
||||
await execa('yarn', ['--frozen-lockfile', '--silent'], { cwd: templateDir });
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
for (const { value: template } of TEMPLATES) {
|
||||
// TODO: Unskip once repo is made public. Because the repo is private, the templates can't yet be downloaded.
|
||||
CreateAstro.skip(template, async () => {
|
||||
const testDirectory = path.join(fixturesDir, template);
|
||||
const { stdout } = await execa('../../create-astro.mjs', [testDirectory, '--template', template, '--force-overwrite'], { cwd: path.join(cwd, 'fixtures') });
|
||||
// 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__]);
|
||||
});
|
||||
|
||||
console.log(stdout);
|
||||
// test: path should formatted as './{dirName}'
|
||||
assert.not.match(stdout, '././');
|
||||
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 = ['meta.json', 'node_modules', 'yarn.lock'];
|
||||
const DOES_NOT_HAVE = ['.git', 'meta.json'];
|
||||
|
||||
// test: template contains essential files & folders
|
||||
for (const file of DOES_HAVE) {
|
||||
console.log(path.join(testDirectory, file));
|
||||
assert.ok(fs.existsSync(path.join(testDirectory, file)), `has ${file}`);
|
||||
assert.ok(fs.existsSync(path.join(templateDir, file)), `missing ${file}`);
|
||||
}
|
||||
|
||||
// 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(testDirectory, file)), `does not have ${file}`);
|
||||
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}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// run tests
|
||||
CreateAstro.run();
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"onLanguage:astro"
|
||||
],
|
||||
"dependencies": {
|
||||
"astro-languageserver": "file:../astro-languageserver"
|
||||
"astro-languageserver": "^0.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.52.0",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "www",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "astro dev",
|
||||
"build": "astro build"
|
||||
|
|
Loading…
Reference in a new issue