archunit
Version:
ArchUnit TypeScript is an architecture testing library, to specify and assert architecture rules in your TypeScript app
291 lines • 11.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const plantuml_parser_1 = require("plantuml-parser");
const common_1 = require("../../../src/common");
const slices_1 = require("../../../src/slices");
describe('Integration test', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('finds simple violations', async () => {
const violations = await (0, slices_1.projectSlices)(__dirname + '/samples/foldersample/tsconfig.json')
.definedBy('src/(**)/')
.shouldNot()
.containDependency('services', 'controllers')
.check();
expect(violations).toHaveLength(1);
expect(violations[0]).toMatchObject({
projectedEdge: {
sourceLabel: 'services',
targetLabel: 'controllers',
cumulatedEdges: [
{
source: 'src/services/util/Service.ts',
target: 'src/controllers/Controller.ts',
external: false,
importKinds: expect.any(Array),
},
],
},
rule: { source: 'services', target: 'controllers' },
isNegated: false,
});
});
it('reports inner dependencies', async () => {
const graph = await (0, common_1.extractGraph)(__dirname + '/samples/innerdependencies/tsconfig.json');
const mapFunction = (0, slices_1.sliceByPattern)('src/facades/(**)/');
const sliced = (0, common_1.projectEdges)(graph, mapFunction);
expect((0, slices_1.gatherPositiveViolations)(sliced, [], ['another', 'one'], false)).toEqual([
{
projectedEdge: {
cumulatedEdges: [
{
external: false,
importKinds: expect.any(Array),
source: 'src/facades/another/another-facade.ts',
target: 'src/facades/one/one-facade.ts',
},
],
sourceLabel: 'another',
targetLabel: 'one',
},
rule: null,
isNegated: false,
},
]);
});
it('finds not adherent parts', async () => {
const diagram = `
@startuml
component [controllers]
component [services]
[controllers] --> [services]
@enduml
`;
const violations = await (0, slices_1.projectSlices)(__dirname + '/samples/foldersample/tsconfig.json')
.definedBy('src/(**)/')
.should()
.adhereToDiagram(diagram)
.check();
expect(violations).toHaveLength(1);
expect(violations[0]).toMatchObject({
rule: null,
isNegated: false,
projectedEdge: {
sourceLabel: 'services',
targetLabel: 'controllers',
cumulatedEdges: [
{
source: 'src/services/util/Service.ts',
target: 'src/controllers/Controller.ts',
external: false,
importKinds: [],
},
],
},
});
});
it('reads uml from file', async () => {
const exampleLocation = path_1.default.resolve(__dirname, 'samples', 'foldersample');
const exampleConfig = path_1.default.resolve(exampleLocation, 'tsconfig.json');
const exampleUml = path_1.default.resolve(exampleLocation, 'architecture.puml');
const violations = await (0, slices_1.projectSlices)(exampleConfig)
.definedBy('src/(**)/')
.should()
.adhereToDiagramInFile(exampleUml)
.check();
expect(violations).toHaveLength(1);
expect(violations[0]).toMatchObject({
rule: null,
isNegated: false,
projectedEdge: {
sourceLabel: 'services',
targetLabel: 'controllers',
cumulatedEdges: [
{
source: 'src/services/util/Service.ts',
target: 'src/controllers/Controller.ts',
external: false,
importKinds: [],
},
],
},
});
});
it('exports the architecture by suffixes', async () => {
const graph = await (0, common_1.extractGraph)(__dirname + '/samples/suffixsample/tsconfig.json');
const mapFunction = (0, slices_1.sliceByFileSuffix)(new Map([
['controller', 'controllers'],
['service', 'services'],
]));
const reducedGraph = (0, common_1.projectEdges)(graph, mapFunction);
const stringDiagram = (0, slices_1.exportDiagram)(reducedGraph);
const parsedActual = (0, plantuml_parser_1.parse)(stringDiagram);
const expectedDiagram = `
@startuml
component [controllers]
component [services]
[controllers] --> [services]
@enduml
`;
const parsedExpected = (0, plantuml_parser_1.parse)(expectedDiagram);
expect(parsedActual).toEqual(parsedExpected);
});
it('exports the architecture by folders', async () => {
const graph = await (0, common_1.extractGraph)(__dirname + '/samples/foldersample/tsconfig.json');
const mapFunction = (0, slices_1.sliceByPattern)('src/(**)/');
const reducedGraph = (0, common_1.projectEdges)(graph, mapFunction);
const stringDiagram = (0, slices_1.exportDiagram)(reducedGraph);
const parsedActual = (0, plantuml_parser_1.parse)(stringDiagram);
const expectedDiagram = `
@startuml
component [services]
component [controllers]
[services] --> [controllers]
[controllers] --> [services]
@enduml
`;
const parsedExpected = (0, plantuml_parser_1.parse)(expectedDiagram);
expect(parsedActual).toEqual(parsedExpected);
});
it('finds not adherent parts in nx projects', async () => {
jest.spyOn(fs_1.default, 'readFileSync').mockReturnValue(getExampleNxProjectGraphJsonFileContent());
const diagram = `
@startuml
component [is-even]
component [is-odd]
@enduml
`;
const violations = await (0, slices_1.nxProjectSlices)(__dirname)
.should()
.ignoringExternalDependencies()
.adhereToDiagram(diagram)
.check();
expect(violations).toContainEqual({
isNegated: false,
rule: null,
projectedEdge: {
sourceLabel: 'is-even',
targetLabel: 'is-odd',
cumulatedEdges: [
{
source: 'is-even',
target: 'is-odd',
importKinds: [],
external: false,
},
],
},
});
});
it('ignores parts not listed in architecture diagram', async () => {
jest.spyOn(fs_1.default, 'readFileSync').mockReturnValue(getExampleNxProjectGraphJsonFileContent());
const diagram = `
@startuml
component [is-even]
@enduml
`;
const violations = await (0, slices_1.nxProjectSlices)(__dirname)
.should()
.ignoringUnknownNodes()
.ignoringExternalDependencies()
.adhereToDiagram(diagram)
.check();
expect(violations).toEqual([]);
});
it('when project graph cache is located in .nx/workspace-data directory then extracts nx graph', () => {
const projectGraphFilePath = path_1.default.join(__dirname, '.nx', 'workspace-data', 'project-graph.json');
jest.spyOn(fs_1.default, 'existsSync').mockImplementation((filePath) => filePath === projectGraphFilePath);
jest.spyOn(fs_1.default, 'readFileSync').mockImplementation((filePath) => {
if (filePath === projectGraphFilePath) {
return getExampleNxProjectGraphJsonFileContent();
}
throw new Error(`Project graph not located in ${projectGraphFilePath}`);
});
expect((0, common_1.extractNxGraph)(__dirname)).toEqual(getExampleProjectGraph());
});
it('when project graph cache is located in .nx/cache directory then extracts nx graph', () => {
const projectGraphFilePath = path_1.default.join(__dirname, '.nx', 'cache', 'project-graph.json');
jest.spyOn(fs_1.default, 'existsSync').mockImplementation((filePath) => filePath === projectGraphFilePath);
jest.spyOn(fs_1.default, 'readFileSync').mockImplementation((filePath) => {
if (filePath === projectGraphFilePath) {
return getExampleNxProjectGraphJsonFileContent();
}
throw new Error(`Project graph not located in ${projectGraphFilePath}`);
});
expect((0, common_1.extractNxGraph)(__dirname)).toEqual(getExampleProjectGraph());
});
it('when project graph cache is located in neither .nx/workspace-data nor .nx/cache directory then throw file not found error', () => {
jest.spyOn(fs_1.default, 'readFileSync').mockImplementation(() => {
throw new Error('Project graph not found');
});
expect(() => (0, common_1.extractNxGraph)(__dirname)).toThrow();
});
});
const getExampleNxProjectGraphJsonFileContent = () => {
const exampleProjectGraph = JSON.stringify({
nodes: {},
externalNodes: {},
dependencies: {
'is-super-odd': [
{
source: 'is-super-odd',
target: 'npm:tslib',
type: 'static',
},
],
'is-even': [
{
source: 'is-even',
target: 'npm:tslib',
type: 'static',
},
{
source: 'is-even',
target: 'is-odd',
type: 'static',
},
],
'is-odd': [
{
source: 'is-odd',
target: 'npm:tslib',
type: 'static',
},
],
},
});
return Buffer.from(exampleProjectGraph);
};
const getExampleProjectGraph = () => [
{
source: 'is-super-odd',
target: 'npm:tslib',
external: true,
importKinds: [],
},
{
source: 'is-even',
target: 'npm:tslib',
external: true,
importKinds: [],
},
{
source: 'is-even',
target: 'is-odd',
external: false,
importKinds: [],
},
{
source: 'is-odd',
target: 'npm:tslib',
external: true,
importKinds: [],
},
];
//# sourceMappingURL=integration.spec.js.map