UNPKG

barrelsby

Version:

Automatic TypeScript barrels for your entire code base

221 lines (217 loc) 8.58 kB
import fs from 'fs'; import MockFs from 'mock-fs'; import Sinon from 'sinon'; import { build, buildImportPath, getBasename } from './builder'; import * as FileSystem from './builders/fileSystem'; import * as Flat from './builders/flat'; import * as Header from './builders/header'; import * as Modules from './modules'; import { StructureOption } from './options/options'; import * as TestUtilities from './testUtilities'; import { Directory } from './interfaces/directory.interface'; import { FileTreeLocation } from './interfaces/location.interface'; import { Signale } from 'signale'; import { BaseUrl } from './options/baseUrl'; import { Logger } from './options/logger'; import { SemicolonCharacter } from './options/noSemicolon'; import { QuoteCharacter } from './options/quoteCharacter'; import * as BuildBarrelModule from './tasks/BuildBarrel'; // Gets a location from a list by name. function getLocationByName(locations: FileTreeLocation[], name: string): FileTreeLocation { return locations.filter(location => location.name === name)[0]; } describe('builder/builder module has a', () => { describe('buildBarrels function that', () => { let directory: Directory; let spySandbox: sinon.SinonSandbox; let loggerSpy: Sinon.SinonSpy<[message?: any, ...optionalArgs: any[]], void>; let builderSpy: Sinon.SinonSpy< [ { addHeader: boolean; directory: Directory; barrelType: StructureOption; quoteCharacter: QuoteCharacter; semicolonCharacter: SemicolonCharacter; barrelName: string; logger: Logger; // Gets a location from a list by name. baseUrl: BaseUrl; exportDefault: boolean; fullPathname: boolean; local: boolean; include: string[]; exclude: string[]; } ], void >; const logger = new Signale(); const runBuilder = (structure: StructureOption | undefined) => { loggerSpy = spySandbox.spy(logger, 'debug'); builderSpy = spySandbox.spy(BuildBarrelModule, 'buildBarrel'); build({ addHeader: true, destinations: directory.directories, quoteCharacter: '"', semicolonCharacter: ';', barrelName: 'barrel.ts', logger, baseUrl: undefined, exportDefault: false, fullPathname: false, structure, local: false, include: [], exclude: [], }); }; beforeEach(() => { MockFs(TestUtilities.mockFsConfiguration()); directory = TestUtilities.mockDirectoryTree(); spySandbox = Sinon.createSandbox(); spySandbox.stub(FileSystem, 'buildFileSystemBarrel').returns('fileSystemContent'); spySandbox.stub(Flat, 'buildFlatBarrel').returns('flatContent'); spySandbox.stub(Modules, 'loadDirectoryModules').returns([]); spySandbox.stub(Header, 'addHeaderPrefix').callsFake((content: string) => `header: ${content}`); }); afterEach(() => { MockFs.restore(); spySandbox.restore(); }); describe('uses the structure option and', () => { const testStructure = (structure: StructureOption | undefined, isFlat: boolean) => { runBuilder(structure); // TODO: Test arguments for barrel builder & loadDirectoryModules if (isFlat) { Sinon.assert.calledTwice(Flat.buildFlatBarrel as Sinon.SinonSpy); Sinon.assert.notCalled(FileSystem.buildFileSystemBarrel as Sinon.SinonSpy); } else { Sinon.assert.notCalled(Flat.buildFlatBarrel as Sinon.SinonSpy); Sinon.assert.calledTwice(FileSystem.buildFileSystemBarrel as Sinon.SinonSpy); } }; it('should use the flat builder if in flat mode', () => { testStructure(StructureOption.FLAT, true); }); it('should use the filesystem builder if in filesystem mode', () => { testStructure(StructureOption.FILESYSTEM, false); }); it('should use the flat builder if no mode is specified', () => { testStructure(undefined, true); }); }); it("should write each barrel's header and content to disk", () => { runBuilder(StructureOption.FLAT); const checkContent = (address: string) => { const result = fs.readFileSync(address, 'utf8'); expect(result).toEqual('header: flatContent'); }; checkContent('directory1/directory2/barrel.ts'); checkContent('directory1/directory3/barrel.ts'); }); it('should update the directory structure with the new barrel', () => { runBuilder(StructureOption.FLAT); directory.directories.forEach((subDirectory: Directory) => { expect((subDirectory.barrel as FileTreeLocation).name).toEqual('barrel.ts'); }); }); it('should log useful information to the logger', () => { runBuilder(StructureOption.FLAT); const messages = [ 'Building barrel @ directory1/directory2', 'Updating model barrel @ directory1/directory2/barrel.ts', 'Building barrel @ directory1/directory3', 'Updating model barrel @ directory1/directory3/barrel.ts', ]; expect(loggerSpy.callCount).toEqual(4); messages.forEach((message: string, barrel: number) => { expect(loggerSpy.getCall(barrel).args[0]).toEqual(message); }); }); it('should run the amount of times as the directory options length', () => { runBuilder(StructureOption.FLAT); expect(builderSpy.callCount).toBe(directory.directories.length); }); }); describe('buildBarrels function with empty barrel content that', () => { let directory: Directory; let spySandbox: sinon.SinonSandbox; const logger = new Signale(); const runBuilder = () => { build({ addHeader: true, destinations: directory.directories, quoteCharacter: '"', semicolonCharacter: ';', barrelName: 'barrel.ts', logger, baseUrl: undefined, exportDefault: false, fullPathname: false, structure: StructureOption.FLAT, local: false, include: [], exclude: [], }); }; beforeEach(() => { MockFs(TestUtilities.mockFsConfiguration()); directory = TestUtilities.mockDirectoryTree(); spySandbox = Sinon.createSandbox(); spySandbox.stub(Flat, 'buildFlatBarrel').returns(''); spySandbox.stub(Modules, 'loadDirectoryModules').returns([]); }); afterEach(() => { MockFs.restore(); spySandbox.restore(); }); it('does not create an empty barrel', () => { runBuilder(); const checkDoesNotExist = (address: string) => { expect(fs.existsSync(address)).toBe(false); }; checkDoesNotExist('directory1/directory2/barrel.ts'); checkDoesNotExist('directory1/directory3/barrel.ts'); }); }); describe('buildImportPath function that', () => { let directory: Directory; beforeEach(() => { directory = TestUtilities.mockDirectoryTree(); }); it('should correctly build a path to a file in the same directory', () => { const target = getLocationByName(directory.files, 'index.ts'); const result = buildImportPath(directory, target, undefined); expect(result).toEqual('./index'); }); it('should correctly build a path to a file in a child directory', () => { const childDirectory = getLocationByName(directory.directories, 'directory2') as Directory; const target = getLocationByName(childDirectory.files, 'script.ts'); const result = buildImportPath(directory, target, undefined); expect(result).toEqual('./directory2/script'); }); }); describe('getBasename function that', () => { it('should correctly strip .ts from the filename', () => { const fileName = './random/path/file.ts'; const result = getBasename(fileName); expect(result).toEqual('file'); }); it('should correctly strip .d.ts from the filename', () => { const fileName = './random/path/file.d.ts'; const result = getBasename(fileName); expect(result).toEqual('file'); }); it('should correctly strip .tsx from the filename', () => { const fileName = './random/path/file.tsx'; const result = getBasename(fileName); expect(result).toEqual('file'); }); it('should not strip extensions from non-typescript filenames', () => { const fileName = './random/path/file.cs'; const result = getBasename(fileName); expect(result).toEqual('file.cs'); }); }); });