Skip to content

Commit 12e230d

Browse files
authored
test: Add CLI tests for all subcommands & most of their flags (#1738)
* test: Add CLI tests for all commands & most flags * chore: Remove commented-out `watch` tests
1 parent 735b72e commit 12e230d

12 files changed

Lines changed: 310 additions & 100 deletions

File tree

packages/cli/global.d.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
declare global {
2-
const __webpack_public_path__: string;
3-
namespace jest {
4-
interface Matchers<R> {
5-
toBeCloseInSize(receivedSize: number, expectedSize: number): R;
6-
toFindMatchingKey(receivedKey: string): R;
7-
}
1+
declare const __webpack_public_path__: string;
2+
3+
declare namespace jest {
4+
interface Matchers<R> {
5+
toBeCloseInSize(receivedSize: number, expectedSize: number): R;
6+
toFindMatchingKey(receivedKey: string): R;
87
}
98
}
109

11-
export {};
10+
// Modified from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/shelljs/index.d.ts
11+
declare module 'shelljs' {
12+
const shell: {
13+
cd: (string) => void;
14+
exec: (string) => { stdout: string; stderr: string; code: number };
15+
};
16+
export = shell;
17+
}

packages/cli/tests/build.test.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,6 @@ describe('preact build', () => {
8383
it('builds the `typescript` template', async () => {
8484
let dir = await create('typescript');
8585

86-
// The tsconfig.json in the template covers the test directory,
87-
// so TS will error out if it can't find even test-only module definitions
88-
shell.cd(dir);
89-
//shell.exec('npm i @types/enzyme@3.10.11 enzyme-adapter-preact-pure');
90-
// Remove when https://github.com/preactjs/enzyme-adapter-preact-pure/issues/161 is resolved
91-
shell.exec('rm tsconfig.json');
92-
9386
await expect(build(dir)).resolves.not.toThrow();
9487
});
9588

packages/cli/tests/create.test.js

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
const { readFile } = require('fs').promises;
2-
const { relative, resolve } = require('path');
1+
const { access, readFile } = require('fs').promises;
2+
const { join, relative } = require('path');
33
const { create } = require('./lib/cli');
44
const { expand } = require('./lib/utils');
55
const snapshots = require('./images/create');
6+
const shell = require('shelljs');
67

78
describe('preact create', () => {
8-
it(`scaffolds the 'default' official template`, async () => {
9+
it('scaffolds the `default` official template', async () => {
910
let dir = await create('default');
1011

1112
let output = await expand(dir).then(arr => {
@@ -15,29 +16,44 @@ describe('preact create', () => {
1516
expect(output.sort()).toEqual(snapshots.default);
1617
});
1718

18-
it(`should use template.html from the github repo`, async () => {
19+
it('should use template.html from the github repo', async () => {
1920
let dir = await create('netlify');
20-
21-
const templateFilePath = resolve(__dirname, dir, 'src', 'template.html');
22-
const template = await readFile(templateFilePath, 'utf8');
23-
21+
const template = await readFile(join(dir, 'src/template.html'), 'utf8');
2422
expect(template.includes('twitter:card')).toEqual(true);
2523
});
2624

27-
it(`should have 'apple-touch-icon' meta tag`, async () => {
28-
let dir = await create('simple');
25+
describe('CLI Options', () => {
26+
it('--name', async () => {
27+
let dir = await create('simple', { name: 'renamed' });
28+
const packageJson = await readFile(join(dir, 'package.json'), 'utf8');
2929

30-
const templateFilePath = resolve(__dirname, dir, 'src', 'template.html');
31-
const template = await readFile(templateFilePath, 'utf8');
30+
expect(JSON.parse(packageJson).name).toBe('renamed');
3231

33-
expect(template.includes('apple-touch-icon')).toEqual(true);
34-
});
32+
// @ts-ignore
33+
const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => {});
34+
await create('simple', { name: '*()@!#!$-Invalid-Name' });
35+
expect(mockExit).toHaveBeenCalledWith(1);
36+
mockExit.mockRestore();
37+
});
3538

36-
it('should fail given an invalid name', async () => {
37-
// @ts-ignore
38-
const exit = jest.spyOn(process, 'exit').mockImplementation(() => {});
39-
await create('simple', '*()@!#!$-Invalid-Name');
39+
it('--git', async () => {
40+
let dir = await create('simple', { git: true });
41+
expect(await access(join(dir, '.git'))).toBeUndefined();
4042

41-
expect(exit).toHaveBeenCalledWith(1);
43+
dir = await create('simple', { git: false });
44+
await expect(access(join(dir, '.git'))).rejects.toThrow(
45+
'no such file or directory'
46+
);
47+
});
48+
49+
it('--invalid-arg', () => {
50+
const { code, stderr } = shell.exec(
51+
`node ${join(__dirname, '../src/index.js')} create --invalid-arg`
52+
);
53+
expect(stderr).toMatch(
54+
"Invalid argument '--invalid-arg' passed to create."
55+
);
56+
expect(code).toBe(1);
57+
});
4258
});
4359
});

packages/cli/tests/images/build.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ exports.template = `
200200
<head>
201201
<meta charset="utf-8">
202202
<title>preact-custom-template</title>
203-
<meta name="example-meta" content="Hello World">
203+
<meta name="example-meta" content="Hello Prod">
204204
<link rel="manifest" href="/manifest.json">
205205
</head>
206206
<body>

packages/cli/tests/info.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const { join } = require('path');
2+
const shell = require('shelljs');
3+
const { subject } = require('./lib/output');
4+
5+
describe('preact info', () => {
6+
it('--src', async () => {
7+
let dir = await subject('minimal');
8+
// env-info does not pick up on symlinks, so we need to install deps
9+
shell.exec(`npm --prefix ${dir} i preact preact-render-to-string`);
10+
11+
const _cwd = process.cwd();
12+
13+
shell.cd(dir);
14+
const { code, stdout } = shell.exec(
15+
`node ${join(__dirname, '../src/index.js')} info`
16+
);
17+
['OS', 'Node', 'preact', 'preact-render-to-string'].forEach(label => {
18+
expect(stdout).toMatch(`${label}:`);
19+
});
20+
expect(code).toBe(0);
21+
22+
shell.cd(_cwd);
23+
});
24+
});

packages/cli/tests/lib/cli.js

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,49 @@
11
const { join } = require('path');
2-
const { mkdir, symlink } = require('fs').promises;
2+
const { mkdir } = require('fs').promises;
3+
const shell = require('shelljs');
34
const cmd = require('../../src/commands');
45
const { tmpDir } = require('./output');
5-
const shell = require('shelljs');
6+
const { linkPackage } = require('./utils');
67

7-
const root = join(__dirname, '../../../..');
8-
9-
async function linkPackage(name, from, to) {
10-
try {
11-
await symlink(
12-
join(from, 'node_modules', name),
13-
join(to, 'node_modules', name)
14-
);
15-
} catch {}
16-
}
17-
18-
const argv = {
19-
_: [],
20-
src: 'src',
21-
dest: 'build',
22-
config: 'preact.config.js',
23-
prerenderUrls: 'prerender-urls.json',
24-
'inline-css': true,
25-
};
26-
27-
exports.create = async function (template, name) {
8+
exports.create = async function (template, options) {
289
let dest = await tmpDir();
29-
name = name || `test-${template}`;
3010

31-
await cmd.create(template, dest, { name, cwd: '.' });
11+
let opts = Object.assign({ name: `test-${template}`, cwd: '.' }, options);
12+
await cmd.create(template, dest, opts);
3213

3314
return dest;
3415
};
3516

3617
exports.build = async function (cwd, options, installNodeModules = false) {
18+
const argv = {
19+
src: 'src',
20+
dest: 'build',
21+
config: 'preact.config.js',
22+
prerenderUrls: 'prerender-urls.json',
23+
'inline-css': true,
24+
};
25+
3726
if (!installNodeModules) {
3827
await mkdir(join(cwd, 'node_modules'), { recursive: true }); // ensure exists, avoid exit()
39-
await linkPackage('preact', root, cwd);
40-
await linkPackage('preact-render-to-string', root, cwd);
28+
await linkPackage('preact', cwd);
29+
await linkPackage('preact-render-to-string', cwd);
4130
} else {
42-
shell.cd(cwd);
43-
shell.exec('npm i');
31+
shell.exec(`npm --prefix ${cwd} i`);
4432
}
4533

46-
let opts = Object.assign({}, { cwd }, argv, options);
34+
let opts = Object.assign({ cwd }, argv, options);
4735
return await cmd.build(opts.src, opts);
4836
};
4937

50-
exports.watch = function (cwd, port, host = '127.0.0.1') {
51-
const args = { ...argv };
52-
delete args.dest;
53-
delete args['inline-css'];
54-
let opts = Object.assign({ cwd, host, port, https: false }, args);
55-
return cmd.watch(argv.src, opts);
38+
exports.watch = function (cwd, options) {
39+
const argv = {
40+
src: 'src',
41+
host: '127.0.0.1',
42+
https: false,
43+
config: 'preact.config.js',
44+
prerenderUrls: 'prerender-urls.json',
45+
};
46+
47+
let opts = Object.assign({ cwd }, argv, options);
48+
return cmd.watch(opts.src, opts);
5649
};

packages/cli/tests/lib/utils.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable no-console */
2-
const { relative, resolve } = require('path');
3-
const { stat, readFile, writeFile } = require('fs').promises;
2+
const { join, relative, resolve } = require('path');
3+
const { stat, symlink, readFile, writeFile } = require('fs').promises;
44
const pRetry = require('p-retry');
55
const { promisify } = require('util');
66
const glob = promisify(require('glob').glob);
@@ -61,6 +61,16 @@ function waitUntil(action, errorMessage) {
6161

6262
const sleep = promisify(setTimeout);
6363

64+
async function linkPackage(name, cwd) {
65+
const root = join(__dirname, '../../../..');
66+
try {
67+
await symlink(
68+
join(root, 'node_modules', name),
69+
join(cwd, 'node_modules', name)
70+
);
71+
} catch {}
72+
}
73+
6474
expect.extend({
6575
toFindMatchingKey(key, matchingKey) {
6676
if (matchingKey) {
@@ -109,4 +119,5 @@ module.exports = {
109119
log,
110120
waitUntil,
111121
sleep,
122+
linkPackage,
112123
};

packages/cli/tests/list.test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const { join } = require('path');
2+
const shell = require('shelljs');
3+
4+
describe('preact list', () => {
5+
it('lists the official templates', () => {
6+
const { code, stdout } = shell.exec(
7+
`node ${join(__dirname, '../src/index.js')} list`
8+
);
9+
[
10+
'default',
11+
'netlify',
12+
'simple',
13+
'typescript',
14+
'widget',
15+
'widget-typescript',
16+
].forEach(repoName => {
17+
expect(stdout).toMatch(new RegExp(`${repoName}.* -`, 'g'));
18+
});
19+
expect(code).toBe(0);
20+
});
21+
});

packages/cli/tests/subjects/custom-template/template.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
<meta charset="utf-8">
55
<title><% preact.title %></title>
66
<% if (htmlWebpackPlugin.options.config.isProd) { %>
7-
<meta name="example-meta" content="Hello World">
7+
<meta name="example-meta" content="Hello Prod">
8+
<% } else { %>
9+
<meta name="example-meta" content="Hello Dev">
810
<% } %>
911
<% preact.headEnd %>
1012
</head>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import { h } from 'preact';
22

3-
export default () => <h2>This is an app with custom template</h2>;
3+
export default () => <h2>This is an app with custom webpack config</h2>;

0 commit comments

Comments
 (0)