Skip to content

Commit 9497c6b

Browse files
committed
cli: Add tests
1 parent fdd8b86 commit 9497c6b

File tree

4 files changed

+272
-4
lines changed

4 files changed

+272
-4
lines changed

.github/workflows/pipeline.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
node-version: ${{ matrix.node-version }}
1717
- run: npm ci
1818
- run: npm run lint
19-
- run: npm run coverage
19+
- run: npm run coverage.all
2020
audit:
2121
runs-on: ubuntu-latest
2222
continue-on-error: true

package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
"main": "index.js",
88
"description": "The core module for F5 Application Services Templates",
99
"scripts": {
10-
"test": "mocha --recursive \"./test/*.js\"",
10+
"test": "mocha --exclude test/cli.js",
11+
"test.cli": "mocha test/setup-logging.js test/cli.js",
12+
"test.all": "mocha",
1113
"lint": "eslint lib test index.js cli.js --ignore-pattern jsoneditor.js",
1214
"buildbin": "./scripts/build-fastbin.sh",
13-
"coverage": "nyc -r text -r html npm test"
15+
"coverage": "nyc -r text -r html npm test",
16+
"coverage.all": "nyc -r text -r html npm run test.all"
1417
},
1518
"keywords": [
1619
"as3",
@@ -51,7 +54,8 @@
5154
"nyc": {
5255
"all": true,
5356
"include": [
54-
"lib/**/*.js"
57+
"lib/**/*.js",
58+
"cli.js"
5559
],
5660
"exclude": [
5761
"lib/jsoneditor.js"

test/cli.js

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/* Copyright 2021 F5 Networks, Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
/* eslint-disable prefer-arrow-callback */
17+
/* eslint-disable func-names */
18+
/* eslint-disable no-console */
19+
20+
'use strict';
21+
22+
const { exec } = require('child_process');
23+
const path = require('path');
24+
const os = require('os');
25+
const fs = require('fs');
26+
const assert = require('assert');
27+
28+
const templateSetDir = path.join(__dirname, 'templatesets', 'test');
29+
const templateSimplePath = path.join(templateSetDir, 'simple.yaml');
30+
31+
async function executeCommand(commandStr) {
32+
const cmd = `node ${path.join('..', 'cli.js')} ${commandStr}`;
33+
console.log(`running: ${cmd}`);
34+
return new Promise((resolve, reject) => {
35+
exec(cmd, { cwd: __dirname }, (error, stdout, stderr) => {
36+
if (error) {
37+
error.stdout = stdout;
38+
error.stderr = stderr;
39+
reject(error);
40+
}
41+
42+
resolve({ stdout, stderr });
43+
});
44+
});
45+
}
46+
47+
describe('CLI tests', function () {
48+
let tmpDir = null;
49+
const mktmpdir = () => {
50+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'fast'));
51+
};
52+
53+
const rmtmpdir = () => {
54+
if (tmpDir !== null) {
55+
if (fs.rmSync) {
56+
fs.rmSync(tmpDir, { recursive: true });
57+
} else {
58+
// Older Node version
59+
fs.rmdirSync(tmpDir, { recursive: true });
60+
}
61+
tmpDir = null;
62+
}
63+
};
64+
65+
afterEach(rmtmpdir);
66+
67+
describe('validate', function () {
68+
it('should succeed on valid template', async function () {
69+
const { stdout } = await executeCommand(`validate ${templateSimplePath}`);
70+
assert.match(stdout, /template source at .* is valid/);
71+
});
72+
it('should fail on invalid template', async function () {
73+
const invalidTemplatePath = path.join(__dirname, 'invalid_templatesets', 'invalid', 'invalid.yaml');
74+
return executeCommand(`validate ${invalidTemplatePath}`)
75+
.then(() => assert(false, 'Expected command to fail'))
76+
.catch((e) => {
77+
console.log(e);
78+
assert.match(e.stderr, /failed to load template/);
79+
});
80+
});
81+
it('should support JSON output', async function () {
82+
const { stdout } = await executeCommand(`validate --json-output ${templateSimplePath}`);
83+
const output = JSON.parse(stdout);
84+
assert.match(output.result, /template source at .* is valid/);
85+
});
86+
it('should support JSON error output', async function () {
87+
const invalidTemplatePath = path.join(__dirname, 'invalid_templatesets', 'invalid', 'invalid.yaml');
88+
return executeCommand(`validate --json-output ${invalidTemplatePath}`)
89+
.then(() => assert(false, 'Expected command to fail'))
90+
.catch((e) => {
91+
const output = JSON.parse(e.stdout);
92+
console.log(output);
93+
assert.match(output.error, /failed to load template/);
94+
});
95+
});
96+
});
97+
describe('schema', function () {
98+
it('should output template parameters schema', async function () {
99+
const { stdout } = await executeCommand(`schema ${templateSimplePath}`);
100+
const schema = JSON.parse(stdout);
101+
assert.ok(schema.properties.str_var);
102+
assert.match(schema.title, /Simple YAML file/);
103+
});
104+
it('should support JSON output', async function () {
105+
const { stdout } = await executeCommand(`schema --json-output ${templateSimplePath}`);
106+
const output = JSON.parse(stdout);
107+
const schema = output.result;
108+
assert.ok(schema.properties.str_var);
109+
assert.match(schema.title, /Simple YAML file/);
110+
});
111+
});
112+
describe('guiSchema', function () {
113+
it('should output gui-friendly template parameters schema', async function () {
114+
const { stdout } = await executeCommand(`guiSchema ${templateSimplePath}`);
115+
const schema = JSON.parse(stdout);
116+
assert.ok(schema.properties.str_var);
117+
assert.match(schema.title, /Simple YAML file/);
118+
});
119+
it('should support JSON output', async function () {
120+
const { stdout } = await executeCommand(`guiSchema --json-output ${templateSimplePath}`);
121+
const output = JSON.parse(stdout);
122+
const schema = output.result;
123+
assert.ok(schema.properties.str_var);
124+
assert.match(schema.title, /Simple YAML file/);
125+
});
126+
});
127+
describe('validateParameters', function () {
128+
it('should succeed on valid parameters', async function () {
129+
mktmpdir();
130+
const viewPath = path.join(tmpDir, 'view.json');
131+
fs.writeFileSync(viewPath, JSON.stringify({ str_var: 'bar' }));
132+
const { stdout } = await executeCommand(`validateParameters ${templateSimplePath} ${viewPath}`);
133+
assert.strictEqual(stdout, '');
134+
});
135+
it('should fail on invalid parameters', async function () {
136+
mktmpdir();
137+
const viewPath = path.join(tmpDir, 'view.json');
138+
fs.writeFileSync(viewPath, JSON.stringify({ str_var: 5 }));
139+
return executeCommand(`validateParameters ${templateSimplePath} ${viewPath}`)
140+
.then(() => assert(false, 'Expected command to fail'))
141+
.catch((e) => {
142+
console.log(e);
143+
assert.match(e.stderr, /parameters failed validation/);
144+
});
145+
});
146+
it('should support JSON output', async function () {
147+
mktmpdir();
148+
const viewPath = path.join(tmpDir, 'view.json');
149+
fs.writeFileSync(viewPath, JSON.stringify({ str_var: 'bar' }));
150+
const { stdout } = await executeCommand(`validateParameters --json-output ${templateSimplePath} ${viewPath}`);
151+
const output = JSON.parse(stdout);
152+
assert.strictEqual(output.result, '');
153+
});
154+
it('should support JSON error output', async function () {
155+
mktmpdir();
156+
const viewPath = path.join(tmpDir, 'view.json');
157+
fs.writeFileSync(viewPath, JSON.stringify({ str_var: 5 }));
158+
return executeCommand(`validateParameters --json-output ${templateSimplePath} ${viewPath}`)
159+
.then(() => assert(false, 'Expected command to fail'))
160+
.catch((e) => {
161+
const output = JSON.parse(e.stdout);
162+
console.log(output);
163+
assert.match(output.error, /parameters failed validation/);
164+
assert.deepStrictEqual(
165+
output.templateParameters,
166+
{
167+
str_var: 5
168+
}
169+
);
170+
assert.deepStrictEqual(
171+
output.validationErrors,
172+
[
173+
{ message: 'parameter str_var should be of type string' }
174+
]
175+
);
176+
});
177+
});
178+
});
179+
describe('render', function () {
180+
it('should render template to stdout', async function () {
181+
const { stdout } = await executeCommand(`render ${templateSimplePath}`);
182+
assert.match(stdout, /foo/);
183+
});
184+
it('should fail on invalid parameters', async function () {
185+
mktmpdir();
186+
const viewPath = path.join(tmpDir, 'view.json');
187+
fs.writeFileSync(viewPath, JSON.stringify({ str_var: 5 }));
188+
return executeCommand(`render ${templateSimplePath} ${viewPath}`)
189+
.then(() => assert(false, 'Expected command to fail'))
190+
.catch((e) => {
191+
console.log(e);
192+
assert.match(e.stderr, /Failed to render template since parameters failed validation/);
193+
});
194+
});
195+
it('should support JSON output', async function () {
196+
const { stdout } = await executeCommand(`render --json-output ${templateSimplePath}`);
197+
const output = JSON.parse(stdout);
198+
assert.match(output.result, /foo/);
199+
});
200+
it('should support JSON error output', async function () {
201+
mktmpdir();
202+
const viewPath = path.join(tmpDir, 'view.json');
203+
fs.writeFileSync(viewPath, JSON.stringify({ str_var: 5 }));
204+
return executeCommand(`render --json-output ${templateSimplePath} ${viewPath}`)
205+
.then(() => assert(false, 'Expected command to fail'))
206+
.catch((e) => {
207+
const output = JSON.parse(e.stdout);
208+
console.log(output);
209+
assert.match(output.error, /parameters failed validation/);
210+
assert.deepStrictEqual(
211+
output.templateParameters,
212+
{
213+
str_var: 5
214+
}
215+
);
216+
assert.deepStrictEqual(
217+
output.validationErrors,
218+
[
219+
{ message: 'parameter str_var should be of type string' }
220+
]
221+
);
222+
});
223+
});
224+
});
225+
describe('validateTemplateSet', function () {
226+
it('should succeed on valid template set', async function () {
227+
const { stdout } = await executeCommand(`validateTemplateSet ${templateSetDir}`);
228+
assert.strictEqual(stdout, '');
229+
});
230+
it('should support JSON output', async function () {
231+
const { stdout } = await executeCommand(`validateTemplateSet --json-output ${templateSetDir}`);
232+
const output = JSON.parse(stdout);
233+
assert.strictEqual(output.result, '');
234+
});
235+
});
236+
describe('htmlpreview', function () {
237+
it('should generate a static HTML page to stdout', async function () {
238+
const { stdout } = await executeCommand(`htmlpreview ${templateSimplePath}`);
239+
assert.match(stdout, /doctype html/);
240+
});
241+
it('should support JSON output', async function () {
242+
const { stdout } = await executeCommand(`htmlpreview --json-output ${templateSimplePath}`);
243+
const output = JSON.parse(stdout);
244+
assert.match(output.result, /doctype html/);
245+
});
246+
});
247+
describe('packageTemplateSet', function () {
248+
it('should create a package for the given template set', async function () {
249+
mktmpdir();
250+
const pkgpath = path.join(tmpDir, 'pkg.zip');
251+
const { stdout } = await executeCommand(`packageTemplateSet ${templateSetDir} ${pkgpath}`);
252+
assert.match(stdout, /Template set "test" packaged as .*\/pkg.zip/);
253+
});
254+
it('should support JSON output', async function () {
255+
mktmpdir();
256+
const pkgpath = path.join(tmpDir, 'pkg.zip');
257+
const { stdout } = await executeCommand(`packageTemplateSet --json-output ${templateSetDir} ${pkgpath}`);
258+
const output = JSON.parse(stdout);
259+
assert.match(output.result, /Template set "test" packaged as .*\/pkg.zip/);
260+
});
261+
});
262+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
title: Invalid
2+
template: {{foo}

0 commit comments

Comments
 (0)