Skip to content

Commit

Permalink
Add testing
Browse files Browse the repository at this point in the history
  • Loading branch information
Codex- committed Nov 22, 2021
1 parent 9c40d9f commit 730876e
Show file tree
Hide file tree
Showing 15 changed files with 10,142 additions and 442 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ jobs:
- run: npm ci
- name: build
run: npm run build
- name: test
if: ${{ always() }}
run: npm run test
- name: style
if: ${{ always() }}
run: npm run format:check
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.npmrc
dist
node_modules
node_modules
16 changes: 16 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Config } from "@jest/types";
const config: Config.InitialOptions = {
globals: {
"ts-jest": {
tsconfig: "tsconfig.test.json",
},
},
moduleFileExtensions: ["ts", "js"],
transform: {
"^.+\\.ts$": "ts-jest",
},
testEnvironment: "node",
testRegex: "\\.spec\\.[jt]s$",
};

export default config;
3 changes: 3 additions & 0 deletions lib/__fixtures__/invalid.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export {
a:
}
3 changes: 3 additions & 0 deletions lib/__fixtures__/valid.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const test = {
cake: "a lie",
};
70 changes: 70 additions & 0 deletions lib/index.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import TypeScriptLoader from ".";
import { cosmiconfig, cosmiconfigSync } from "cosmiconfig";
import path from "path";

describe("TypeScriptLoader", () => {
const fixturesPath = path.resolve(__dirname, "__fixtures__");

describe("exports", () => {
it("should export the loader function as a default", () => {
expect(typeof TypeScriptLoader).toBe("function");
});
});

describe("cosmiconfig", () => {
it("should load a valid TS file", async () => {
const cfg = cosmiconfig("test", {
loaders: {
".ts": TypeScriptLoader(),
},
});
const loadedCfg = await cfg.load(
path.resolve(fixturesPath, "valid.fixture.ts")
);

expect(typeof loadedCfg?.config).toBe("object");
});

it("should throw an error on loading an invalid TS file", async () => {
const cfg = cosmiconfig("test", {
loaders: {
".ts": TypeScriptLoader(),
},
});

try {
await cfg.load(path.resolve(fixturesPath, "invalid.fixture.ts"));
fail("Should fail to load invalid TS");
} catch (error: any) {
expect(error?.name).toStrictEqual("TypeScriptCompileError");
}
});
});

describe("cosmiconfigSync", () => {
it("should load a valid TS file", () => {
const cfg = cosmiconfigSync("test", {
loaders: {
".ts": TypeScriptLoader(),
},
});
const loadedCfg = cfg.load(
path.resolve(fixturesPath, "valid.fixture.ts")
);

expect(typeof loadedCfg?.config).toBe("object");
});

it("should throw an error on loading an invalid TS file", () => {
const cfg = cosmiconfigSync("test", {
loaders: {
".ts": TypeScriptLoader(),
},
});

expect(() =>
cfg.load(path.resolve(fixturesPath, "invalid.fixture.ts"))
).toThrowError();
});
});
});
4 changes: 2 additions & 2 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import loader from "./loader";
import { TypeScriptLoader } from "./loader";

export default loader;
export default TypeScriptLoader;
export type { TypeScriptCompileError } from "./typescript-compile-error";
42 changes: 42 additions & 0 deletions lib/loader.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import fs from "fs";
import path from "path";
import { Loader } from "cosmiconfig";

import { TypeScriptLoader } from "./loader";
import { TypeScriptCompileError } from "./typescript-compile-error";

describe("TypeScriptLoader", () => {
const fixturesPath = path.resolve(__dirname, "__fixtures__");

let loader: Loader;

function readFixtureContent(file: string): string {
return fs.readFileSync(file).toString();
}

beforeEach(() => {
loader = TypeScriptLoader();
});

it("should parse a valid TS file", () => {
const filePath = path.resolve(fixturesPath, "valid.fixture.ts");
loader(filePath, readFixtureContent(filePath));
});

it("should fail on parsing an invalid TS file", () => {
const filePath = path.resolve(fixturesPath, "invalid.fixture.ts");
expect(() => loader(filePath, readFixtureContent(filePath))).toThrowError();
});

it("should throw a TypeScriptCompileError on error", () => {
try {
const filePath = path.resolve(fixturesPath, "invalid.fixture.ts");
loader(filePath, readFixtureContent(filePath));
fail(
"Error should be thrown upon failing to transpile an invalid TS file."
);
} catch (error: unknown) {
expect(error).toBeInstanceOf(TypeScriptCompileError);
}
});
});
20 changes: 15 additions & 5 deletions lib/loader.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import type { Loader } from "cosmiconfig";
import { register, RegisterOptions } from "ts-node";
import { TypeScriptCompileError } from "./typescript-compile-error";

const TypeScriptLoader = (options?: RegisterOptions): Loader => {
export function TypeScriptLoader(options?: RegisterOptions): Loader {
return (path: string, content: string) => {
try {
register(options).compile(content, path);
const result = require(path);

/**
* `default` is used when exporting using export default, some modules
* may still use `module.exports` or if in TS `export = `
*/
return result.default || result;
} catch (error) {}
} catch (error) {
if (error instanceof Error) {
// Coerce generic error instance into typed error with better logging.
throw TypeScriptCompileError.fromError(error);
}
throw error;
}
};
};

export default TypeScriptLoader;
}
48 changes: 48 additions & 0 deletions lib/typescript-compile-error.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { TypeScriptCompileError } from "./typescript-compile-error";

describe("TypeScriptCompileError", () => {
describe("fromError", () => {
const testError = new Error("Test Error");

it("should create a TypeScriptCompileError from an instance of Error", () => {
const tscError = TypeScriptCompileError.fromError(testError);

expect(tscError.name).toStrictEqual(
TypeScriptCompileError.prototype.constructor.name
);
expect(tscError.message).toContain(
"TypeScriptLoader failed to compile TypeScript"
);
expect(tscError.message).toContain("Test Error");
expect(tscError.stack).toBe(testError.stack);
});

it("should replace the legacy tsc error string", () => {
const testMsg =
"TypeScript compiler encountered syntax errors while transpiling. Errors: ";
const testError = new Error(testMsg);
const tscError = TypeScriptCompileError.fromError(testError);

expect(tscError).not.toContainEqual(testMsg);
});

it("should replace the tsc error string", () => {
const testMsg = "⨯ Unable to compile TypeScript:";
const testError = new Error(testMsg);
const tscError = TypeScriptCompileError.fromError(testError);

expect(tscError).not.toContainEqual(testMsg);
});
});

describe("toObject", () => {
it("should support legacy usage of this method", () => {
const tscError = new TypeScriptCompileError("Test Error");
const errObj = tscError.toObject();

expect(errObj.message).toStrictEqual(tscError.message);
expect(errObj.name).toStrictEqual(tscError.name);
expect(errObj.stack).toStrictEqual(tscError.stack);
});
});
});
13 changes: 11 additions & 2 deletions lib/typescript-compile-error.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
export class TypeScriptCompileError extends Error {
constructor(message: string) {
super(message);
this.name = this.constructor.name
}

public static fromError(error: Error): TypeScriptCompileError {
const errMsg = error.message.replace(
"TypeScript compiler encountered syntax errors while transpiling. Errors: ",
/(TypeScript compiler encountered syntax errors while transpiling\. Errors:\s?)|(⨯ Unable to compile TypeScript:\s?)/,
""
);

const message = `Failed to compile TypeScript: ${errMsg}`;
const message = `TypeScriptLoader failed to compile TypeScript:\n${errMsg}`;

const newError = new TypeScriptCompileError(message);
newError.stack = error.stack;

return newError;
}

/**
* Support legacy usage of this method.
* @deprecated
*/
public toObject() {
return {
message: this.message,
Expand Down

0 comments on commit 730876e

Please sign in to comment.