mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-04-13 22:22:58 +00:00
Merge pull request #1393 from balena-io/cli-tests
Implement full command testing, beginning with "balena version"
This commit is contained in:
commit
8dd1106a44
@ -145,13 +145,14 @@ capitano.command(actions.push.push)
|
||||
capitano.command(actions.join.join)
|
||||
capitano.command(actions.leave.leave)
|
||||
|
||||
cli = capitano.parse(process.argv)
|
||||
runCommand = ->
|
||||
capitanoExecuteAsync = Promise.promisify(capitano.execute)
|
||||
if cli.global?.help
|
||||
capitanoExecuteAsync(command: "help #{cli.command ? ''}")
|
||||
else
|
||||
capitanoExecuteAsync(cli)
|
||||
exports.run = (argv) ->
|
||||
cli = capitano.parse(argv)
|
||||
runCommand = ->
|
||||
capitanoExecuteAsync = Promise.promisify(capitano.execute)
|
||||
if cli.global?.help
|
||||
capitanoExecuteAsync(command: "help #{cli.command ? ''}")
|
||||
else
|
||||
capitanoExecuteAsync(cli)
|
||||
|
||||
Promise.all([events.trackCommand(cli), runCommand()])
|
||||
.catch(require('./errors').handleError)
|
||||
Promise.all([events.trackCommand(cli), runCommand()])
|
||||
.catch(require('./errors').handleError)
|
||||
|
@ -100,7 +100,11 @@ export function globalInit() {
|
||||
// stream-to-promise will produce native promises if not for this module,
|
||||
// which is likely to lead to errors as much of the CLI coffeescript code
|
||||
// expects bluebird promises.
|
||||
require('any-promise/register/bluebird');
|
||||
// The registration is only run if it hasn't already happened (for example
|
||||
// in a test case).
|
||||
if (!(global as any)['@@any-promise/REGISTRATION']) {
|
||||
require('any-promise/register/bluebird');
|
||||
}
|
||||
|
||||
// check for CLI updates once a day
|
||||
require('./utils/update').notify();
|
||||
|
@ -18,6 +18,7 @@
|
||||
import { Main } from '@oclif/command';
|
||||
import { ExitError } from '@oclif/errors';
|
||||
|
||||
import { AppOptions } from './app';
|
||||
import { handleError } from './errors';
|
||||
|
||||
class CustomMain extends Main {
|
||||
@ -34,9 +35,13 @@ class CustomMain extends Main {
|
||||
/**
|
||||
* oclif CLI entrypoint
|
||||
*/
|
||||
export function run(argv: string[]) {
|
||||
CustomMain.run(argv.slice(2)).then(
|
||||
require('@oclif/command/flush'),
|
||||
export function run(command: string[], options: AppOptions) {
|
||||
return CustomMain.run(command).then(
|
||||
() => {
|
||||
if (!options.noFlush) {
|
||||
return require('@oclif/command/flush');
|
||||
}
|
||||
},
|
||||
(error: Error) => {
|
||||
// oclif sometimes exits with ExitError code 0 (not an error)
|
||||
if (error instanceof ExitError && error.oclif.exit === 0) {
|
||||
|
19
lib/app.ts
19
lib/app.ts
@ -18,14 +18,19 @@ import { stripIndent } from 'common-tags';
|
||||
|
||||
import { exitWithExpectedError } from './utils/patterns';
|
||||
|
||||
export interface AppOptions {
|
||||
// Prevent the default behaviour of flushing stdout after running a command
|
||||
noFlush: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple command-line pre-parsing to choose between oclif or Capitano.
|
||||
* @param argv process.argv
|
||||
*/
|
||||
function routeCliFramework(argv: string[]): void {
|
||||
function routeCliFramework(argv: string[], options: AppOptions): void {
|
||||
if (process.env.DEBUG) {
|
||||
console.log(
|
||||
`Debug: original argv0="${process.argv0}" argv=[${argv}] length=${
|
||||
`[debug] original argv0="${process.argv0}" argv=[${argv}] length=${
|
||||
argv.length
|
||||
}`,
|
||||
);
|
||||
@ -65,11 +70,11 @@ function routeCliFramework(argv: string[]): void {
|
||||
argv = [argv[0], argv[1], ...cmdSlice];
|
||||
}
|
||||
if (process.env.DEBUG) {
|
||||
console.log(`Debug: new argv=[${argv}] length=${argv.length}`);
|
||||
console.log(`[debug] new argv=[${argv}] length=${argv.length}`);
|
||||
}
|
||||
require('./app-oclif').run(argv);
|
||||
return require('./app-oclif').run(cmdSlice, options);
|
||||
} else {
|
||||
require('./app-capitano');
|
||||
return require('./app-capitano').run(cmdSlice);
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,10 +159,10 @@ function isOclifCommand(argvSlice: string[]): [boolean, boolean] {
|
||||
* CLI entrypoint, but see also `bin/balena` and `bin/balena-dev` which
|
||||
* call this function.
|
||||
*/
|
||||
export function run(): void {
|
||||
export function run(cliArgs = process.argv, options: AppOptions): void {
|
||||
// globalInit() must be called very early on (before other imports) because
|
||||
// it sets up Sentry error reporting, global HTTP proxy settings, balena-sdk
|
||||
// shared options, and performs node version requirement checks.
|
||||
require('./app-common').globalInit();
|
||||
routeCliFramework(process.argv);
|
||||
return routeCliFramework(cliArgs, options);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@
|
||||
"package": "npm run build:fast && npm run build:standalone && npm run build:installer",
|
||||
"release": "ts-node --type-check -P automation/tsconfig.json automation/run.ts release",
|
||||
"pretest": "npm run build",
|
||||
"test": "mocha -r ts-node/register tests/**/*.spec.ts",
|
||||
"test": "mocha -r ts-node/register \"tests/**/*.spec.ts\"",
|
||||
"test:fast": "npm run build:fast && npm run test",
|
||||
"ci": "npm run test && catch-uncommitted",
|
||||
"watch": "gulp watch",
|
||||
|
48
tests/helpers.ts
Normal file
48
tests/helpers.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import * as path from 'path';
|
||||
import * as balenaCLI from '../build/app';
|
||||
|
||||
export const runCommand = async (cmd: string) => {
|
||||
const preArgs = [process.argv[0], path.join(process.cwd(), 'bin', 'balena')];
|
||||
|
||||
const oldStdOut = process.stdout.write;
|
||||
const oldStdErr = process.stderr.write;
|
||||
|
||||
const err: string[] = [];
|
||||
const out: string[] = [];
|
||||
|
||||
// @ts-ignore
|
||||
process.stdout.write = (log: string) => {
|
||||
// Skip over debug messages
|
||||
if (!log.startsWith('[debug]')) {
|
||||
out.push(log);
|
||||
}
|
||||
oldStdOut(log);
|
||||
};
|
||||
// @ts-ignore
|
||||
process.stderr.write = (log: string) => {
|
||||
// Skip over debug messages
|
||||
if (!log.startsWith('[debug]')) {
|
||||
err.push(log);
|
||||
}
|
||||
oldStdErr(log);
|
||||
};
|
||||
|
||||
try {
|
||||
await balenaCLI.run(preArgs.concat(cmd.split(' ')), {
|
||||
noFlush: true,
|
||||
});
|
||||
|
||||
process.stdout.write = oldStdOut;
|
||||
process.stderr.write = oldStdErr;
|
||||
|
||||
return {
|
||||
err,
|
||||
out,
|
||||
};
|
||||
} catch (err) {
|
||||
process.stdout.write = oldStdOut;
|
||||
process.stderr.write = oldStdErr;
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
37
tests/version.spec.ts
Normal file
37
tests/version.spec.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import * as chai from 'chai';
|
||||
import * as fs from 'fs';
|
||||
import { runCommand } from './helpers';
|
||||
|
||||
const packageJSON = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
||||
const nodeVersion = process.version.startsWith('v')
|
||||
? process.version.slice(1)
|
||||
: process.version;
|
||||
|
||||
describe('balena version', function() {
|
||||
it('should print the installed version of the CLI', async () => {
|
||||
const { out } = await runCommand('version');
|
||||
|
||||
chai.expect(out.join('')).to.equal(`${packageJSON.version}\n`);
|
||||
});
|
||||
|
||||
it('should print additional version information with the -a flag', async () => {
|
||||
const { out } = await runCommand('version -a');
|
||||
|
||||
chai.expect(out.join('')).to.equal(
|
||||
`balena-cli version "${packageJSON.version}"
|
||||
Node.js version "${nodeVersion}"
|
||||
`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should print version information as JSON with the the -j flag', async () => {
|
||||
const { out } = await runCommand('version -j');
|
||||
|
||||
const json = JSON.parse(out.join(''));
|
||||
|
||||
chai.expect(json).to.deep.equal({
|
||||
'balena-cli': packageJSON.version,
|
||||
'Node.js': nodeVersion,
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user