Repository: withastro/astro
File: packages/create-astro/test/create-astro.test.js (JavaScript)

Code before:
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { suite } from 'uvu';
import execa from 'execa';
import del from 'del';
import * as assert from 'uvu/assert';
import { TEMPLATES } from '../dist/templates.js';

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);
});

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') });

    console.log(stdout);
    // test: path should formatted as './{dirName}'
    assert.not.match(stdout, '././');

    const DOES_HAVE = ['.gitignore', 'package.json', 'public', 'src'];
    const DOES_NOT_HAVE = ['meta.json', 'node_modules', 'yarn.lock'];

    // 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}`);
    }

    // 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}`);
    }
  });
}

CreateAstro.run();


Review comment (suggestion):
Because `uvu` won’t ever finish if there are open threads, this test is super probable to run indefinitely. We had to add the same manual timeout handling here as we do in the astro tests.

Code after:

// test
const CreateAstro = suite('npm init astro');

CreateAstro.before(async () => {
  // 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 });
    })
  );
});

// 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: template contains essential files & folders
    for (const file of DOES_HAVE) {
      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(templateDir, file)), `failed to clean up ${file}`);
    }
  });