summaryrefslogtreecommitdiff
path: root/packages/create-astro
diff options
context:
space:
mode:
Diffstat (limited to 'packages/create-astro')
-rw-r--r--packages/create-astro/package.json1
-rw-r--r--packages/create-astro/src/index.ts54
-rw-r--r--packages/create-astro/test/directory-step.test.js23
-rw-r--r--packages/create-astro/test/typescript-step.test.js117
-rw-r--r--packages/create-astro/test/utils.js26
5 files changed, 180 insertions, 41 deletions
diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json
index e881b111d..6f89dff4b 100644
--- a/packages/create-astro/package.json
+++ b/packages/create-astro/package.json
@@ -36,6 +36,7 @@
"kleur": "^4.1.4",
"ora": "^6.1.0",
"prompts": "^2.4.2",
+ "strip-ansi": "^7.0.1",
"which-pm-runs": "^1.1.0",
"yargs-parser": "^21.0.1"
},
diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts
index ee548f59d..2337674ea 100644
--- a/packages/create-astro/src/index.ts
+++ b/packages/create-astro/src/index.ts
@@ -340,7 +340,7 @@ export async function main() {
choices: [
{
title: 'Relaxed',
- value: 'default',
+ value: 'base',
},
{
title: 'Strict (recommended)',
@@ -379,42 +379,40 @@ export async function main() {
console.log(` You can safely ignore these files, but don't delete them!`);
console.log(dim(' (ex: tsconfig.json, src/env.d.ts)'));
console.log(``);
- tsResponse.typescript = 'default';
+ tsResponse.typescript = 'base';
await wait(300);
}
if (args.dryRun) {
ora().info(dim(`--dry-run enabled, skipping.`));
} else if (tsResponse.typescript) {
- if (tsResponse.typescript !== 'default') {
- const templateTSConfigPath = path.join(cwd, 'tsconfig.json');
- fs.readFile(templateTSConfigPath, (err, data) => {
- if (err && err.code === 'ENOENT') {
- // If the template doesn't have a tsconfig.json, let's add one instead
- fs.writeFileSync(
- templateTSConfigPath,
- stringify({ extends: `astro/tsconfigs/${tsResponse.typescript}` }, null, 2)
- );
+ const templateTSConfigPath = path.join(cwd, 'tsconfig.json');
+ fs.readFile(templateTSConfigPath, (err, data) => {
+ if (err && err.code === 'ENOENT') {
+ // If the template doesn't have a tsconfig.json, let's add one instead
+ fs.writeFileSync(
+ templateTSConfigPath,
+ stringify({ extends: `astro/tsconfigs/${tsResponse.typescript}` }, null, 2)
+ );
- return;
- }
+ return;
+ }
- const templateTSConfig = parse(data.toString());
+ const templateTSConfig = parse(data.toString());
- if (templateTSConfig && typeof templateTSConfig === 'object') {
- const result = assign(templateTSConfig, {
- extends: `astro/tsconfigs/${tsResponse.typescript}`,
- });
+ if (templateTSConfig && typeof templateTSConfig === 'object') {
+ const result = assign(templateTSConfig, {
+ extends: `astro/tsconfigs/${tsResponse.typescript}`,
+ });
- fs.writeFileSync(templateTSConfigPath, stringify(result, null, 2));
- } else {
- console.log(
- yellow(
- "There was an error applying the requested TypeScript settings. This could be because the template's tsconfig.json is malformed"
- )
- );
- }
- });
- }
+ fs.writeFileSync(templateTSConfigPath, stringify(result, null, 2));
+ } else {
+ console.log(
+ yellow(
+ "There was an error applying the requested TypeScript settings. This could be because the template's tsconfig.json is malformed"
+ )
+ );
+ }
+ });
ora().succeed('TypeScript settings applied!');
}
diff --git a/packages/create-astro/test/directory-step.test.js b/packages/create-astro/test/directory-step.test.js
index 0031f97fd..26737ca94 100644
--- a/packages/create-astro/test/directory-step.test.js
+++ b/packages/create-astro/test/directory-step.test.js
@@ -1,6 +1,8 @@
import path from 'path';
import { promises, existsSync } from 'fs';
-import { PROMPT_MESSAGES, testDir, setup, promiseWithTimeout, timeout } from './utils.js';
+import {
+ PROMPT_MESSAGES, testDir, setup, promiseWithTimeout, timeout
+} from './utils.js';
const inputs = {
nonEmptyDir: './fixtures/select-directory/nonempty-dir',
@@ -12,9 +14,10 @@ const inputs = {
describe('[create-astro] select directory', function () {
this.timeout(timeout);
it('should prompt for directory when none is provided', function () {
- return promiseWithTimeout((resolve) => {
+ return promiseWithTimeout((resolve, onStdout) => {
const { stdout } = setup();
stdout.on('data', (chunk) => {
+ onStdout(chunk);
if (chunk.includes(PROMPT_MESSAGES.directory)) {
resolve();
}
@@ -22,9 +25,10 @@ describe('[create-astro] select directory', function () {
});
});
it('should NOT proceed on a non-empty directory', function () {
- return promiseWithTimeout((resolve) => {
+ return promiseWithTimeout((resolve, onStdout) => {
const { stdout } = setup([inputs.nonEmptyDir]);
stdout.on('data', (chunk) => {
+ onStdout(chunk);
if (chunk.includes(PROMPT_MESSAGES.directory)) {
resolve();
}
@@ -46,9 +50,10 @@ describe('[create-astro] select directory', function () {
if (!existsSync(resolvedEmptyDirPath)) {
await promises.mkdir(resolvedEmptyDirPath);
}
- return promiseWithTimeout((resolve) => {
+ return promiseWithTimeout((resolve, onStdout) => {
const { stdout } = setup([inputs.emptyDir]);
stdout.on('data', (chunk) => {
+ onStdout(chunk);
if (chunk.includes(PROMPT_MESSAGES.template)) {
resolve();
}
@@ -56,9 +61,10 @@ describe('[create-astro] select directory', function () {
});
});
it('should proceed when directory does not exist', function () {
- return promiseWithTimeout((resolve) => {
+ return promiseWithTimeout((resolve, onStdout) => {
const { stdout } = setup([inputs.nonexistentDir]);
stdout.on('data', (chunk) => {
+ onStdout(chunk);
if (chunk.includes(PROMPT_MESSAGES.template)) {
resolve();
}
@@ -66,14 +72,17 @@ describe('[create-astro] select directory', function () {
});
});
it('should error on bad directory selection in prompt', function () {
- return promiseWithTimeout((resolve) => {
+ return promiseWithTimeout((resolve, onStdout) => {
+ let wrote = false;
const { stdout, stdin } = setup();
stdout.on('data', (chunk) => {
+ onStdout(chunk);
if (chunk.includes('is not empty!')) {
resolve();
}
- if (chunk.includes(PROMPT_MESSAGES.directory)) {
+ if (!wrote && chunk.includes(PROMPT_MESSAGES.directory)) {
stdin.write(`${inputs.nonEmptyDir}\x0D`);
+ wrote = true;
}
});
});
diff --git a/packages/create-astro/test/typescript-step.test.js b/packages/create-astro/test/typescript-step.test.js
new file mode 100644
index 000000000..abec21646
--- /dev/null
+++ b/packages/create-astro/test/typescript-step.test.js
@@ -0,0 +1,117 @@
+import { expect } from 'chai';
+import { deleteSync } from 'del';
+import { existsSync, mkdirSync, readdirSync, readFileSync } from 'fs';
+import path from 'path';
+import {
+ PROMPT_MESSAGES, testDir, setup, promiseWithTimeout, timeout
+} from './utils.js';
+
+const inputs = {
+ emptyDir: './fixtures/select-typescript/empty-dir',
+};
+
+function isEmpty(dirPath) {
+ return !existsSync(dirPath) || readdirSync(dirPath).length === 0;
+}
+
+function ensureEmptyDir() {
+ const dirPath = path.resolve(testDir, inputs.emptyDir);
+ if (!existsSync(dirPath)) {
+ mkdirSync(dirPath, { recursive: true });
+ } else if (!isEmpty(dirPath)) {
+ const globPath = path.resolve(dirPath, '*');
+ deleteSync(globPath, { dot: true });
+ }
+}
+
+function getTsConfig(installDir) {
+ const filePath = path.resolve(testDir, installDir, 'tsconfig.json');
+ return JSON.parse(readFileSync(filePath, 'utf-8'));
+}
+
+describe('[create-astro] select typescript', function () {
+ this.timeout(timeout);
+
+ beforeEach(ensureEmptyDir);
+
+ afterEach(ensureEmptyDir);
+
+ it('should prompt for typescript when none is provided', async function () {
+ return promiseWithTimeout((resolve, onStdout) => {
+ const { stdout } = setup([
+ inputs.emptyDir,
+ '--template', 'minimal',
+ '--install', '0',
+ '--git', '0'
+ ]);
+ stdout.on('data', (chunk) => {
+ onStdout(chunk);
+ if (chunk.includes(PROMPT_MESSAGES.typescript)) {
+ resolve();
+ }
+ });
+ }, () => lastStdout);
+ });
+
+ it('should not prompt for typescript when provided', async function () {
+ return promiseWithTimeout((resolve, onStdout) => {
+ const { stdout } = setup([
+ inputs.emptyDir,
+ '--template', 'minimal',
+ '--install', '0',
+ '--git', '0',
+ '--typescript', 'base'
+ ]);
+ stdout.on('data', (chunk) => {
+ onStdout(chunk);
+ if (chunk.includes(PROMPT_MESSAGES.typescriptSucceed)) {
+ resolve();
+ }
+ });
+ }, () => lastStdout);
+ });
+
+ it('should use "strict" config when specified', async function () {
+ return promiseWithTimeout((resolve, onStdout) => {
+ let wrote = false;
+ const { stdout, stdin } = setup([
+ inputs.emptyDir,
+ '--template', 'minimal',
+ '--install', '0',
+ '--git', '0'
+ ]);
+ stdout.on('data', (chunk) => {
+ onStdout(chunk);
+ if (!wrote && chunk.includes(PROMPT_MESSAGES.typescript)) {
+ stdin.write('\x1B\x5B\x42\x0D');
+ wrote = true;
+ }
+ if (chunk.includes(PROMPT_MESSAGES.typescriptSucceed)) {
+ const tsConfigJson = getTsConfig(inputs.emptyDir);
+ expect(tsConfigJson).to.deep.equal({'extends': 'astro/tsconfigs/strict'});
+ resolve();
+ }
+ });
+ }, () => lastStdout);
+ });
+
+ it('should create tsconfig.json when missing', async function () {
+ return promiseWithTimeout((resolve, onStdout) => {
+ const { stdout } = setup([
+ inputs.emptyDir,
+ '--template', 'cassidoo/shopify-react-astro',
+ '--install', '0',
+ '--git', '0',
+ '--typescript', 'base'
+ ]);
+ stdout.on('data', (chunk) => {
+ onStdout(chunk);
+ if (chunk.includes(PROMPT_MESSAGES.typescriptSucceed)) {
+ const tsConfigJson = getTsConfig(inputs.emptyDir);
+ expect(tsConfigJson).to.deep.equal({'extends': 'astro/tsconfigs/base'});
+ resolve();
+ }
+ });
+ }, () => lastStdout);
+ });
+});
diff --git a/packages/create-astro/test/utils.js b/packages/create-astro/test/utils.js
index b085ef083..9be444b5b 100644
--- a/packages/create-astro/test/utils.js
+++ b/packages/create-astro/test/utils.js
@@ -1,31 +1,45 @@
import { execa } from 'execa';
-import { fileURLToPath } from 'url';
import { dirname } from 'path';
+import stripAnsi from 'strip-ansi';
+import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
export const testDir = dirname(__filename);
export const timeout = 5000;
-const createAstroError = new Error(
- 'Timed out waiting for create-astro to respond with expected output.'
-);
+const timeoutError = function (details) {
+ let errorMsg =
+ 'Timed out waiting for create-astro to respond with expected output.';
+ if (details) {
+ errorMsg += '\nLast output: "' + details + '"';
+ }
+ return new Error(errorMsg);
+}
export function promiseWithTimeout(testFn) {
return new Promise((resolve, reject) => {
+ let lastStdout;
+ function onStdout (chunk) {
+ lastStdout = stripAnsi(chunk.toString()).trim() || lastStdout;
+ }
+
const timeoutEvent = setTimeout(() => {
- reject(createAstroError);
+ reject(timeoutError(lastStdout));
}, timeout);
function resolver() {
clearTimeout(timeoutEvent);
resolve();
}
- testFn(resolver);
+
+ testFn(resolver, onStdout);
});
}
export const PROMPT_MESSAGES = {
directory: 'Where would you like to create your new project?',
template: 'Which template would you like to use?',
+ typescript: 'How would you like to setup TypeScript?',
+ typescriptSucceed: 'Next steps'
};
export function setup(args = []) {