Skip to content

Commit

Permalink
test(e2e): add nominal tests for exec & init CLI commands
Browse files Browse the repository at this point in the history
no breaking changes
use childprocess to collect CLI stdout
missing limit case tests
fix #395
  • Loading branch information
ErwanRaulo committed Dec 31, 2024
1 parent 317e21d commit 9425a2f
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 1 deletion.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,9 @@ json/
reports/
preview/
dist/
.nodesecurerc
/.nodesecurerc
.DS_Store

# IDE
.vscode
jsconfig.json
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"lint": "eslint src test bin scripts",
"test-only": "glob -c \"tsx --test-reporter=spec --test\" \"./test/**/*.spec.ts\"",
"test": "c8 --all --src ./src -r html npm run test-only",
"test:e2e": "glob -c \"tsx --test-reporter=spec --test\" \"./test/commands/*.spec.ts\"",
"preview:light": "tsx --no-warnings ./scripts/preview.js --theme light",
"preview:dark": "tsx --no-warnings ./scripts/preview.js --theme dark",
"prepublishOnly": "npm run build"
Expand Down
78 changes: 78 additions & 0 deletions test/commands/execute.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import dotenv from "dotenv";
dotenv.config();

// Import Node.js Dependencies
import { fileURLToPath } from "node:url";
import path from "node:path";
import fs from "node:fs/promises";
import { afterEach, describe, it } from "node:test";
import assert from "node:assert";

// Import Third-party Dependencies
import stripAnsi from "strip-ansi";

// Import Internal Dependencies
import { filterProcessStdout } from "../helpers/reportCommandRunner.js";
import * as CONSTANTS from "../../src/constants.js";

// CONSTANTS
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const processDir = path.join(__dirname, "../..");

describe("Report execute command", async () => {

Check failure on line 22 in test/commands/execute.spec.ts

View workflow job for this annotation

GitHub Actions / test (20.x, ubuntu-latest)

Unexpected space before function parentheses

Check failure on line 22 in test/commands/execute.spec.ts

View workflow job for this annotation

GitHub Actions / test (22.x, ubuntu-latest)

Unexpected space before function parentheses
afterEach(async() => await fs.rm(CONSTANTS.DIRS.CLONES, {
recursive: true, force: true
}));

it("should execute command on fixture '.nodesecurerc'", async() => {
const options = {
cmd: "node",
args: ["dist/bin/index.js", "execute"],
cwd: processDir
};

function byMessage(buffer) {
const message = `.*`;
const afterNonAlphaNum = String.raw`?<=[^a-zA-Z\d\s:]\s`;
const beforeTime = String.raw`?=\s\d{1,5}.\d{1,4}ms`;
const withoutDuplicates = String.raw`(?![\s\S]*\1)`;

const matchMessage = `(${afterNonAlphaNum})(${message})(${beforeTime})|(${afterNonAlphaNum})(${message})`;
const reg = new RegExp(`(${matchMessage})${withoutDuplicates}`, "g");

const matchedMessages = stripAnsi(buffer.toString()).match(reg);

return matchedMessages ?? [""];
}

const expectedLines = [
"Executing nreport at: C:\\PERSO\\dev\\report",
"title: Default report title",
"reporters: html,pdf",
"[Fetcher: NPM] - Fetching NPM packages metadata on the NPM Registry",
"",
"[Fetcher: NPM] - successfully executed in",
"[Fetcher: GIT] - Cloning GIT repositories",
"[Fetcher: GIT] - Fetching repositories metadata on the NPM Registry",
"[Fetcher: GIT] - successfully executed in",
"[Reporter: HTML] - Building template and assets",
"[Reporter: HTML] - successfully executed in",
"[Reporter: PDF] - Using puppeteer to convert HTML content to PDF",
"[Reporter: PDF] - successfully executed in",
"Security report successfully generated! Enjoy 🚀."
];

let actualLines: string[]= [];

Check failure on line 65 in test/commands/execute.spec.ts

View workflow job for this annotation

GitHub Actions / test (20.x, ubuntu-latest)

Operator '=' must be spaced

Check failure on line 65 in test/commands/execute.spec.ts

View workflow job for this annotation

GitHub Actions / test (22.x, ubuntu-latest)

Operator '=' must be spaced

try {
actualLines = await filterProcessStdout(options, byMessage);
}
catch (error) {
console.log(error);

assert.fail("Execute command should not throw");
}

assert.deepEqual(actualLines, expectedLines, "we are expecting these lines");
});
});
48 changes: 48 additions & 0 deletions test/commands/initialize.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import dotenv from "dotenv";
dotenv.config();

// Import Node.js Dependencies
import { fileURLToPath } from "node:url";
import fs from "node:fs/promises";
import path from "node:path";
import { beforeEach, describe, it } from "node:test";
import assert from "node:assert";

// Import Third-party Dependencies
import stripAnsi from "strip-ansi";

// Import Internal Dependencies
import { runProcess } from "../helpers/reportCommandRunner.ts";

// CONSTANTS
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const processDir = path.join(__dirname, "..", "fixtures");
const configFilePath = path.join(processDir, ".nodesecurerc");

describe("Report init command", async() => {
beforeEach(async () => await fs.unlink(configFilePath));

Check failure on line 23 in test/commands/initialize.spec.ts

View workflow job for this annotation

GitHub Actions / test (20.x, ubuntu-latest)

Unexpected space before function parentheses

Check failure on line 23 in test/commands/initialize.spec.ts

View workflow job for this annotation

GitHub Actions / test (22.x, ubuntu-latest)

Unexpected space before function parentheses
it("should create config if not exists", async() => {
const lines = [
/.*/,
/ > Executing nreport at: .*$/,
/.*/,
/Successfully generated NodeSecure runtime configuration at current location/,
/.*/
];

const processOptions = {
cmd: "node",
args: ["dist/bin/index.js", "initialize"],
cwd: processDir
};

for await (const line of runProcess(processOptions)) {
const regexp = lines.shift();
assert.ok(regexp, "we are expecting this line");
assert.ok(regexp.test(stripAnsi(line)), `line (${line}) matches ${regexp}`);
}

// to avoid false positive if no lines have been emitted from process
assert.equal(lines.length, 0);
});
});
42 changes: 42 additions & 0 deletions test/fixtures/.nodesecurerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"version": "1.0.0",
"i18n": "english",
"strategy": "github-advisory",
"registry": "https://registry.npmjs.org",
"report": {
"theme": "light",
"includeTransitiveInternal": false,
"reporters": [
"html",
"pdf"
],
"charts": [
{
"name": "Extensions",
"display": true,
"interpolation": "d3.interpolateRainbow",
"type": "bar"
},
{
"name": "Licenses",
"display": true,
"interpolation": "d3.interpolateCool",
"type": "bar"
},
{
"name": "Warnings",
"display": true,
"type": "horizontalBar",
"interpolation": "d3.interpolateInferno"
},
{
"name": "Flags",
"display": true,
"type": "horizontalBar",
"interpolation": "d3.interpolateSinebow"
}
],
"title": "Default report title",
"showFlags": true
}
}
54 changes: 54 additions & 0 deletions test/helpers/reportCommandRunner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Import Node.js Dependencies
import { ChildProcess, spawn } from "node:child_process";
import { createInterface } from "node:readline";

// Import Third-party Dependencies
import stripAnsi from "strip-ansi";

export async function* runProcess(options) {
const childProcess = spawnedProcess(options);
try {
if(!childProcess.stdout){

Check failure on line 11 in test/helpers/reportCommandRunner.ts

View workflow job for this annotation

GitHub Actions / test (20.x, ubuntu-latest)

Expected space(s) after "if"

Check failure on line 11 in test/helpers/reportCommandRunner.ts

View workflow job for this annotation

GitHub Actions / test (20.x, ubuntu-latest)

Missing space before opening brace

Check failure on line 11 in test/helpers/reportCommandRunner.ts

View workflow job for this annotation

GitHub Actions / test (22.x, ubuntu-latest)

Expected space(s) after "if"

Check failure on line 11 in test/helpers/reportCommandRunner.ts

View workflow job for this annotation

GitHub Actions / test (22.x, ubuntu-latest)

Missing space before opening brace
return

Check failure on line 12 in test/helpers/reportCommandRunner.ts

View workflow job for this annotation

GitHub Actions / test (20.x, ubuntu-latest)

Missing semicolon

Check failure on line 12 in test/helpers/reportCommandRunner.ts

View workflow job for this annotation

GitHub Actions / test (22.x, ubuntu-latest)

Missing semicolon
}

const rStream = createInterface(childProcess.stdout);

for await (const line of rStream) {
yield stripAnsi(line);
}
}
finally {
childProcess.kill();
}
}

export function filterProcessStdout(options, filter): Promise<string[]> {
return new Promise((resolve, reject) => {
const childProcess = spawnedProcess(options);
const output = new Set<string>();

childProcess.stdout?.on("data", (buffer) => {
filter(buffer).forEach((filteredData) => {
output.add(filteredData);
});
});

childProcess.on("close", (code) => {
resolve(Array.from(output));
});

childProcess.on("error", (err) => {
reject(err);
});
});
}

function spawnedProcess(options): ChildProcess {
const { cmd, args = [], cwd = process.cwd() } = options;

return spawn(cmd, args, {
stdio: ["ignore", "pipe", "pipe", "ipc"],
cwd
});
}

0 comments on commit 9425a2f

Please sign in to comment.