Skip to content

Commit

Permalink
feat: inso collection runner (#7700)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackkav authored Jul 17, 2024
1 parent 0a32015 commit b0b6c20
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 23 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/test-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ jobs:
- name : Build Inso
run: npm run build -w insomnia-inso

- name: Start test server
run: npm run serve -w insomnia-smoke-test & npx -y wait-on http://localhost:4010

- name: Run Inso bundle tests
run: npm run test:bundle -w insomnia-inso

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,14 @@ exports[`Snapshot for "inso run -h" 1`] = `
Execution utilities
Options:
-h, --help display help for command
-h, --help display help for command
Commands:
test [options] [identifier] Run Insomnia unit test suites, identifier can be
a test suite id or a API Spec id
help [command] display help for command"
test [options] [identifier] Run Insomnia unit test suites, identifier
can be a test suite id or a API Spec id
collection [options] [identifier] Run Insomnia request collection,
identifier can be a workspace id
help [command] display help for command"
`;
exports[`Snapshot for "inso run test -h" 1`] = `
Expand Down
37 changes: 18 additions & 19 deletions packages/insomnia-inso/src/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,40 @@ import { describe, expect, it } from '@jest/globals';
import { exec, ExecException } from 'child_process';
import path from 'path';

// dev experience
// goals: it should be quick and run in ci and should be easy to debug
// ideas: create a second test.yml easier to reason about the state of node-libcurl it can parallel

// issues: no immeidate feedback as the test is running
// run the test, do you need to know about the libcurl thing or should i be automated?

// should be each to copy and run in local js debug terminal
// and also print which one fails when running all tests
// TODO: move all fixtures to the same folder, and name valid or invalid or whatever
const shouldReturnSuccessCode = [
// help
'$PWD/packages/insomnia-inso/bin/inso -h',
// identifier filepath

// lint spec
// as identifer filepath
'$PWD/packages/insomnia-inso/bin/inso lint spec packages/insomnia-inso/src/commands/fixtures/openapi-spec.yaml',
// identifier filepath with spectral.yaml
// as identifier filepath with spectral.yaml
'$PWD/packages/insomnia-inso/bin/inso lint spec packages/insomnia-inso/src/commands/fixtures/with-ruleset/path-plugin.yaml',
// as working directory and identifier filename
'$PWD/packages/insomnia-inso/bin/inso lint spec -w packages/insomnia-inso/src/commands/fixtures/with-ruleset path-plugin.yaml',
// lint from db
// as working directory containing nedb
'$PWD/packages/insomnia-inso/bin/inso lint spec -w packages/insomnia-inso/src/db/fixtures/nedb spc_46c5a4',
'$PWD/packages/insomnia-inso/bin/inso lint spec -w packages/insomnia-inso/src/db/fixtures/git-repo spc_46c5a4',
'$PWD/packages/insomnia-inso/bin/inso lint spec -w packages/insomnia-inso/src/db/fixtures/insomnia-v4/insomnia_v4.yaml spc_3b2850',
// export from db
// export spec nedb, git-repo, export file
'$PWD/packages/insomnia-inso/bin/inso export spec -w packages/insomnia-inso/src/db/fixtures/nedb spc_46c5a4',
'$PWD/packages/insomnia-inso/bin/inso export spec -w packages/insomnia-inso/src/db/fixtures/git-repo spc_46c5a4',
'$PWD/packages/insomnia-inso/bin/inso export spec -w packages/insomnia-inso/src/db/fixtures/insomnia-v4/insomnia_v4.yaml spc_3b2850',
// test from db

// run test
// nedb, gitrepo, export file
'$PWD/packages/insomnia-inso/bin/inso run test -w packages/insomnia-inso/src/db/fixtures/nedb -e env_env_ca046a uts_fe901c',
'$PWD/packages/insomnia-inso/bin/inso run test -w packages/insomnia-inso/src/db/fixtures/nedb -e env_env_ca046a --reporter min uts_fe901c',
'$PWD/packages/insomnia-inso/bin/inso run test -w packages/insomnia-inso/src/db/fixtures/git-repo -e env_env_ca046a uts_fe901c',
'$PWD/packages/insomnia-inso/bin/inso run test -w packages/insomnia-inso/src/db/fixtures/insomnia-v4/insomnia_v4.yaml -e env_env_0e4670 spc_3b2850',
// export file,request can inherit auth headers and variables from folder
'$PWD/packages/insomnia-inso/bin/inso run test -w packages/insomnia-inso/src/examples/folder-inheritance-document.yml spc_a8144e --verbose',
// workspace - request from db
// '$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-inso/src/db/fixtures/insomnia-v4/insomnia_v4.yaml -e env_env_0e4670 --requestNamePattern "Example 1" wrk_8ee1e0',
// TODO: request group - request from db, add simple export file pointing at local server
// TODO: add bail option

// run collection
// export file
'$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-smoke-test/fixtures/simple.yaml -e env_2eecf85b7f wrk_0702a5',
// with regex filter
'$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-smoke-test/fixtures/simple.yaml -e env_2eecf85b7f --requestNamePattern "example http" wrk_0702a5',
];

const shouldReturnErrorCode = [
Expand Down
95 changes: 95 additions & 0 deletions packages/insomnia-inso/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { loadDb } from './db';
import { loadApiSpec, promptApiSpec } from './db/models/api-spec';
import { loadEnvironment, promptEnvironment } from './db/models/environment';
import { loadTestSuites, promptTestSuites } from './db/models/unit-test-suite';
import { loadWorkspace, promptWorkspace } from './db/models/workspace';

export interface GlobalOptions {
ci: boolean;
Expand Down Expand Up @@ -295,6 +296,100 @@ export const go = (args?: string[]) => {
return process.exit(1);
});

run.command('collection [identifier]')
.description('Run Insomnia request collection, identifier can be a workspace id')
.option('-t, --requestNamePattern <regex>', 'run requests that match the regex', '')
.option('-e, --env <identifier>', 'environment to use', '')
.option('-b, --bail', 'abort ("bail") after first test failure', false)
.option('--disableCertValidation', 'disable certificate validation for requests with SSL', false)
.action(async (identifier, cmd: { env: string; disableCertValidation: true; requestNamePattern: string; bail: boolean }) => {
const globals: { config: string; workingDir: string; exportFile: string; ci: boolean; printOptions: boolean; verbose: boolean } = program.optsWithGlobals();

const commandOptions = { ...globals, ...cmd };
const __configFile = await loadCosmiConfig(commandOptions.config, commandOptions.workingDir);

const options = {
reporter: defaultReporter,
...__configFile?.options || {},
...commandOptions,
...(__configFile ? { __configFile } : {}),
};
logger.level = options.verbose ? LogLevel.Verbose : LogLevel.Info;
options.ci && logger.setReporters([new BasicReporter()]);
options.printOptions && logger.log('Loaded options', options, '\n');
let pathToSearch = '';
const useLocalAppData = !options.workingDir && !options.exportFile;
if (useLocalAppData) {
logger.warn('No working directory or export file provided, using local app data directory.');
pathToSearch = localAppDir;
} else {
pathToSearch = path.resolve(options.workingDir || process.cwd(), options.exportFile || '');
}
if (options.reporter && !reporterTypesSet.has(options.reporter)) {
logger.fatal(`Reporter "${options.reporter}" not unrecognized. Options are [${reporterTypes.join(', ')}].`);
return process.exit(1);
}

const db = await loadDb({
pathToSearch,
filterTypes: [],
});

const workspace = identifier ? loadWorkspace(db, identifier) : await promptWorkspace(db, !!options.ci);

if (!workspace) {
logger.fatal('No workspace found; cannot run requests.', identifier);
return process.exit(1);
}

// Find environment
const workspaceId = workspace._id;
const environment = options.env ? loadEnvironment(db, workspaceId, options.env) : await promptEnvironment(db, !!options.ci, workspaceId);

if (!environment) {
logger.fatal('No environment identified; cannot run requests without a valid environment.');
return process.exit(1);
}

const getRequestGroupIdsRecursively = (from: string[]): string[] => {
const parentIds = db.RequestGroup.filter(rg => from.includes(rg.parentId)).map(rg => rg._id);
return [...parentIds, ...(parentIds.length > 0 ? getRequestGroupIdsRecursively(parentIds) : [])];
};
const allRequestGroupIds = getRequestGroupIdsRecursively([workspaceId]);
let requests = db.Request.filter(req => [workspaceId, ...allRequestGroupIds].includes(req.parentId));

if (options.requestNamePattern) {
requests = requests.filter(req => req.name.match(new RegExp(options.requestNamePattern)));
}
if (!requests.length) {
logger.fatal('No requests identified; nothing to run.');
return process.exit(1);
}

try {
// eslint-disable-next-line @typescript-eslint/no-var-requires -- Load lazily when needed, otherwise this require slows down the entire CLI.
const { getSendRequestCallbackMemDb } = require('insomnia-send-request');
const sendRequest = await getSendRequestCallbackMemDb(environment._id, db, { validateSSL: !options.disableCertValidation });
let success = true;
for (const req of requests) {
if (options.bail && !success) {
return;
}
logger.log(`Running request: ${req.name} ${req._id}`);
const res = await sendRequest(req._id);
logger.trace(res);
if (res.status !== 200) {
success = false;
logger.error(`Request failed with status ${res.status}`);
}
}
return process.exit(success ? 0 : 1);
} catch (error) {
logErrorAndExit(error);
}
return process.exit(1);
});

program.command('lint')
.description('Lint a yaml file in the workingDir or the provided file path (with .spectral.yml) or a spec in an Insomnia database directory')
.command('spec [identifier]')
Expand Down

0 comments on commit b0b6c20

Please sign in to comment.