Skip to content

Commit

Permalink
#8 Improved test coverage for BundlesProcessor and misc. fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Silic0nS0ldier committed Jan 31, 2019
1 parent b7a774f commit 274b540
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ node_js:
- "10"
- "11"
- "lts/*"
env:
- CI=true
cache: npm
before_script: npm i -g nyc
script: nyc --reporter=lcov --reporter=text-lcov --exclude-after-remap=false npm test
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"types": "./dist/main.d.ts",
"scripts": {
"pretest": "tsc",
"test": "nyc ava",
"test": "if-env CI=true && nyc ava || ava",
"prepublishOnly": "tsc",
"prevsion": "npm test",
"version": "changelog-updater && git add CHANGELOG.md",
Expand Down Expand Up @@ -52,6 +52,7 @@
"@types/vinyl": "^2.0.2",
"ava": "^1.0.1",
"changelog-updater": "^1.1.0",
"if-env": "^1.0.4",
"typescript": "^3.1.6"
},
"engines": {
Expand Down
16 changes: 15 additions & 1 deletion src/bundles-processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ test("BundlesProcessor with iterable inputs empty", async t => {
const bundles: Map<string, string[]> = new Map();

TestBundler(t, [[], new Map()], await BundlesProcessor(files, bundles, BundleStreamFactory, () => {}));

});

test("BundlesProcessor with files but no bundles", async t => {
Expand All @@ -35,6 +34,21 @@ test("BundlesProcessor with files and bundles", async t => {
TestBundler(t, [resultChunks, resultPaths], await BundlesProcessor(files, bundles, BundleStreamFactory, () => {}));
});

test("BundlesProcessor with bundles that will never be satisfied", async t => {
const files: Map<string, [Vinyl, number]> = new Map();
files.set("test2", [MakeVinyl("test", "test"), 0]);
const bundles: Map<string, string[]> = new Map();
bundles.set("test", ["test"]);

await t.throwsAsync(() => BundlesProcessor(files, bundles, BundleStreamFactory, () => {}), 'No file could be resolved for "test".');
});

// TODO Handle non-vinyl crap

// TODO handle exception block in bundles processor (if not already)

// TODO Handle exception block in bundles process - promise (if not already)

function TestBundler(t: ExecutionContext, expected: [any[], Map<string, Vinyl[]>], actual: [any[], Map<string, Vinyl[]>]): void {
// Check result chunks (order insensitive)
t.deepEqual(expected[0].sort(), actual[0].sort());
Expand Down
42 changes: 35 additions & 7 deletions src/bundles-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,35 @@ export async function BundlesProcessor(
for (const [name, paths] of bundles) {
logger(`Building bundle "${name}"`, LogLevel.Normal);

// Create catcher
const catcher = new Catcher(logger);

// Build bundler with source and bundle name
logger("Invoking provided bundler", LogLevel.Silly);
bundleStreamFactory(new BundleSource(files, paths), name)
.pipe(catcher);

// Wrap to permit catching and reporting of errors
const chunks = await new Promise<any[]>(async (resolve, reject) => {
try {
// Create catcher
const catcher = new Catcher(logger);

// Create bundle source (and handle errors)
const source = new BundleSource(files, paths)
.on("error", (e) => {
reject(e);
});

// Run provided transform stream factory
bundleStreamFactory(source, name)
.pipe(catcher);

// Resolve on catcher completion
resolve(await catcher.Collected);
}
catch (e) {
reject(e);
}
});

// Catch results
logger("Catching outputs", LogLevel.Silly);
const chunks = await catcher.Collected;

// Add to resultPaths and resultChunks
const resultFiles: Vinyl[] = [];
Expand Down Expand Up @@ -87,8 +105,18 @@ class BundleSource extends Readable {
objectMode: true
});

// Ensure at least one path with provided.
if (files.size === 0) {
throw new Error("At least one file must be provided.");
}

this.files = files;

// Ensure at least one path was provided.
if (paths.length === 0) {
throw new Error("At least one path must be provided.");
}

// Copy array to we can reduce it as we go
this.paths = paths.slice(0);
}
Expand All @@ -100,7 +128,7 @@ class BundleSource extends Readable {
if (this.paths.length > 0) {
const path = this.paths.shift();
if (this.files.has(path)) this.push(this.files.get(path)[0].clone());
else new Error(`No file could be resolved for ${path}.`);
else this.emit("error", new Error(`No file could be resolved for "${path}".`));
}
else this.push(null);
}
Expand Down
6 changes: 5 additions & 1 deletion src/catcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LogLevel } from "./config";

/**
* All this does is collect all stream data and once all read resolves a promise with the collected chunks.
* TODO Handle when the stream source has no chunks to pass
* !IMPORTANT! Stream this is piped into to must return _something_ otherwise `Collected` will never resolve.
*/
export class Catcher extends Transform {
/**
Expand All @@ -26,6 +26,9 @@ export class Catcher extends Transform {
*/
private Resolve?: (value?: any[] | PromiseLike<any[]>) => void;

/**
* @param logger Used for logging events and errors.
*/
constructor(logger: (value: string, level: LogLevel) => void) {
super({
objectMode: true
Expand Down Expand Up @@ -58,6 +61,7 @@ export class Catcher extends Transform {
*/
_flush(callback: TransformCallback): void {
this.Logger("Starting resolution of catcher promise", LogLevel.Silly);
// Ensure promise has had chance to run
const resolver = () => {
if (this.Resolve) {
this.Resolve(this.Results);
Expand Down

0 comments on commit 274b540

Please sign in to comment.