dependency-cruiser
Version:
Validate and visualize javascript dependencies. With your rules. ES6, CommonJS, AMD
362 lines (321 loc) • 11.9 kB
JavaScript
;
const expect = require('chai').expect;
const main = require("../../src/cli");
const fs = require("fs");
const tst = require("../utl/testutensils");
const path = require("path");
const _ = require("lodash");
const intercept = require("intercept-stdout");
const OUT_DIR = "./test/output";
const FIX_DIR = "./test/fixtures";
/* eslint max-len:0*/
const testPairs = [
{
description: "dependency-cruise -f test/output/{{moduleType}}.dir.json test/fixtures/{{moduleType}}",
dirOrFile: "test/fixtures/{{moduleType}}",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.dir.json")
},
expect: "{{moduleType}}.dir.json",
cleanup: true
},
{
description: "dependency-cruise -f test/output/{{moduleType}}.dir.json test/fixtures/{{moduleType}}",
dirOrFile: "test/fixtures/{{moduleType}}",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.dir.json")
},
expect: "{{moduleType}}.dir.json",
cleanup: true
},
{
description: "dependency-cruise -f test/output/{{moduleType}}.file.json test/fixtures/{{moduleType}}/root_one.js",
dirOrFile: "test/fixtures/{{moduleType}}/root_one.js",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.file.json")
},
expect: "{{moduleType}}.file.json",
cleanup: true
},
{
description: "dependency-cruise -f test/output/{{moduleType}}.dir.filtered.json -x node_modules test/fixtures/{{moduleType}}",
dirOrFile: "test/fixtures/{{moduleType}}",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.dir.filtered.json"),
exclude: "node_modules"
},
expect: "{{moduleType}}.dir.filtered.json",
cleanup: true
},
{
description: "html",
dirOrFile: "test/fixtures/{{moduleType}}",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.dir.filtered.html"),
outputType: "html",
validate: "test/fixtures/rules.sub-not-allowed.json",
exclude: "node_modules"
},
expect: "{{moduleType}}.dir.filtered.html",
cleanup: true
},
{
description: "dot",
dirOrFile: "test/fixtures/{{moduleType}}",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.dir.filtered.dot"),
validate: "test/fixtures/rules.sub-not-allowed.json",
outputType: "dot",
exclude: "node_modules"
},
expect: "{{moduleType}}.dir.filtered.dot",
cleanup: true
},
{
description: "dot - duplicate subs",
dirOrFile: "test/fixtures/duplicate-subs",
options: {
outputTo: path.join(OUT_DIR, "duplicate-subs.dot"),
outputType: "dot",
exclude: "node_modules"
},
expect: "duplicate-subs.dot",
cleanup: true
},
{
description: "csv",
dirOrFile: "test/fixtures/{{moduleType}}",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.dir.filtered.csv"),
outputType: "csv",
validate: "test/fixtures/rules.sub-not-allowed.json",
exclude: "node_modules"
},
expect: "{{moduleType}}.dir.filtered.csv",
cleanup: true
},
{
description: "err",
dirOrFile: "test/fixtures/{{moduleType}}",
options: {
outputTo: path.join(OUT_DIR, "{{moduleType}}.dir.filtered.err"),
outputType: "err",
validate: "test/fixtures/rules.everything-allowed.json"
},
expect: "{{moduleType}}.dir.filtered.err",
cleanup: true
}
];
function deleteDammit(pFileName) {
try {
fs.unlinkSync(pFileName);
} catch (e) {
// process.stderr.write(e.message || e);
}
}
function resetOutputDir() {
testPairs
.filter(pPair => pPair.cleanup)
.forEach(pPair => {
try {
fs.unlinkSync(pPair.options.outputTo.replace("{{moduleType}}", "cjs"));
fs.unlinkSync(pPair.options.outputTo.replace("{{moduleType}}", "amd"));
} catch (e) {
// process.stderr.write(typeof e);
}
});
deleteDammit(path.join(OUT_DIR, "cjs.dir.stdout.json"));
deleteDammit(path.join(OUT_DIR, "amd.dir.stdout.json"));
deleteDammit(path.join(OUT_DIR, "cjs.dir.dot"));
}
function setModuleType(pTestPairs, pModuleType) {
return pTestPairs.map(pTestPair => {
let lRetval = {
description: pTestPair.description.replace(/{{moduleType}}/g, pModuleType),
dirOrFile: pTestPair.dirOrFile.replace(/{{moduleType}}/g, pModuleType),
expect: pTestPair.expect.replace(/{{moduleType}}/g, pModuleType),
cleanup: pTestPair.cleanup
};
lRetval.options = _.clone(pTestPair.options);
lRetval.options.outputTo = pTestPair.options.outputTo.replace(/{{moduleType}}/g, pModuleType);
if (Boolean(pTestPair.options.system)) {
lRetval.options.system = pTestPair.options.system.replace(/{{moduleType}}/g, pModuleType);
}
return lRetval;
});
}
function runFileBasedTests(pModuleType) {
setModuleType(testPairs, pModuleType).forEach(pPair => {
it(pPair.description, () => {
main(pPair.dirOrFile, pPair.options);
tst.assertFileEqual(
pPair.options.outputTo,
path.join(FIX_DIR, pPair.expect)
);
});
});
}
describe("#main", () => {
before("set up", () => {
resetOutputDir();
});
after("tear down", () => {
resetOutputDir();
});
describe("file based tests - commonJS", () => {
runFileBasedTests("cjs");
});
describe("specials", () => {
it("dependency-cruise test/fixtures/cjs - outputs to stdout", () => {
let lCapturedStdout = "";
const unhookIntercept = intercept(pText => {
lCapturedStdout += pText;
});
main("test/fixtures/cjs");
unhookIntercept();
fs.writeFileSync(
path.join(OUT_DIR, "cjs.dir.stdout.json"),
lCapturedStdout,
"utf8"
);
tst.assertFileEqual(
path.join(OUT_DIR, "cjs.dir.stdout.json"),
path.join(FIX_DIR, "cjs.dir.stdout.json")
);
});
it("dependency-cruise --output-type json test/fixtures/cjs - outputs a slew of json to stdout", () => {
let lCapturedStdout = "";
const unhookIntercept = intercept(pText => {
lCapturedStdout += pText;
});
main("test/fixtures/cjs", {outputTo: "-", outputType: 'json'});
unhookIntercept();
fs.writeFileSync(
path.join(OUT_DIR, "cjs.dir.stdout.json"),
lCapturedStdout,
"utf8"
);
tst.assertFileEqual(
path.join(OUT_DIR, "cjs.dir.stdout.json"),
path.join(FIX_DIR, "cjs.dir.stdout.json")
);
});
it("dependency-cruise -f cjs.dir.wontmarch.json this-doesnot-exist - non-existing generates an error", () => {
let lCapturedStderr = "";
const unhookInterceptStdOut = intercept(() => {
// This space intentionally left empty
});
const unhookInterceptStdErr = intercept(pText => {
lCapturedStderr += pText;
});
main("this-doesnot-exist", {outputTo: path.join(OUT_DIR, "cjs.dir.wontmarch.json")});
unhookInterceptStdOut();
unhookInterceptStdErr();
return expect(
lCapturedStderr
).to.equal(
"ERROR: Can't open 'this-doesnot-exist' for reading. Does it exist?\n"
);
});
it("dependency-cruise -f /dev/null -M invalidmodulesystem - generates error", () => {
let lCapturedStderr = "";
const unhookInterceptStdOut = intercept(() => {
// This space intentionally left empty
});
const unhookInterceptStdErr = intercept(pText => {
lCapturedStderr += pText;
});
main(
"test/fixtures",
{
outputTo: path.join(OUT_DIR, "/dev/null"),
system: "invalidmodulesystem"
}
);
unhookInterceptStdOut();
unhookInterceptStdErr();
intercept(pText => {
lCapturedStderr += pText;
})();
return expect(
lCapturedStderr
).to.equal(
"ERROR: Invalid module system list: 'invalidmodulesystem'\n"
);
});
it("dependency-cruise -f /dev/null -T invalidoutputtype - generates error", () => {
let lCapturedStderr = "";
const unhookInterceptStdOut = intercept(() => {
// This space intentionally left empty
});
const unhookInterceptStdErr = intercept(pText => {
lCapturedStderr += pText;
});
main(
"test/fixtures",
{
outputTo: path.join(OUT_DIR, "/dev/null"),
outputType: "invalidoutputtype"
}
);
unhookInterceptStdOut();
unhookInterceptStdErr();
intercept(pText => {
lCapturedStderr += pText;
})();
return expect(
lCapturedStderr
).to.equal(
"ERROR: 'invalidoutputtype' is not a valid output type.\n"
);
});
it("dependency-cruise -f file/you/cant/write/to - generates error", () => {
let lCapturedStderr = "";
const unhookInterceptStdOut = intercept(() => {
// This space intentionally left empty
});
const unhookInterceptStdErr = intercept(pText => {
lCapturedStderr += pText;
});
main(
"test/fixtures",
{
outputTo: path.join(OUT_DIR, "file/you/cant/write/to")
}
);
unhookInterceptStdOut();
unhookInterceptStdErr();
intercept(pText => {
lCapturedStderr += pText;
})();
return expect(
lCapturedStderr
).to.equal(
"ERROR: Writing to 'test/output/file/you/cant/write/to' didn't work. Error: ENOENT: no such file or directory, open 'test/output/file/you/cant/write/to'"
);
});
it("dependency-cruise -f /dev/null -x '([a-zA-z]+)*' - unsafe exclusion patterns don't run", () => {
let lCapturedStderr = "";
const unhookInterceptStdOut = intercept(() => {
// This space intentionally left empty
});
const unhookInterceptStdErr = intercept(pText => {
lCapturedStderr += pText;
});
main(
"test/fixtures",
{
outputTo: path.join(OUT_DIR, "/dev/null"),
exclude: "([A-Za-z]+)*"
}
);
unhookInterceptStdOut();
unhookInterceptStdErr();
return expect(
lCapturedStderr
).to.equal(
"ERROR: The exclude pattern '([A-Za-z]+)*' will probably run very slowly - cowardly refusing to run.\n"
);
});
});
});