This question applies to each of the following source file organisation strategies:
Tests completely separate
/src
/tests
Tests per feature
/src/feature/
/src/feature/__tests__
Tests per file
/src/feature/foo.ts
/src/feature/foo.test.ts
Installing @mocha/types
makes those test-only declarations available as valid identifiers throughout the entire codebase. It's easy enough to update tsconfig.json and specify "types": []
to exclude it, but the moment you manually reference it in just one single file, whether via import 'mocha'
or /// <reference types="mocha" />
, suddenly it infects the entire codebase again.
Is there any way at all to have type declarations that are only valid for unit tests resolve correctly in test files and appear as invalid in other source files?
Note that I'm using VS Code here. Naturally I could have a separate tsconfig file for external build setups, such as via gulp or whatever, but I'm editing the actual code in VS Code, and the red squigglies and "problems" don't seem to be resolvable. Either I accept invalid autocompletion of unit test identifiers throughout the entire codebase, or my unit tests show up with module resolution errors.
Visual Studio Code includes TypeScript language support but does not include the TypeScript compiler, tsc . You will need to install the TypeScript compiler either globally or in your workspace to transpile TypeScript source code to JavaScript ( tsc HelloWorld. ts ). You can test your install by checking the version.
Not an easy one... this is the best I've come up with. You'll not like it, but it works:
Create a file mocha.ts
, where you'll want to re-export the runtime-available globals and (the bit you won't like) redefine the typings for them - going as far as you want to go:
declare var global: any;
export const describe = global.describe as (msg: string, cb: () => void) => void;
export const it = global.it as (msg: string, cb: () => void) => void;
Now, just import describe
and it
from ./mocha
and away you go. Doesn't pollute the global namespace.
The type redefine is fugly; but you could simply c&p the relevant parts you want to use from definitely typed. I don't think you'll be able to import the typings directly and not incur the globals because its typed that way.
Something else I looked at was to make use of the mocha "require" as the documentation alludes to you being able to grab describe
like so: require('mocha').describe
... I tried this (running with mocha cli) and couldn't get it to work. see: http://mochajs.org/#require Still... I think you get hit with the global types anyway.
complete mocha.ts with copied typings:
declare var global: any;
export const describe = global.describe as IContextDefinition;
export const it = global.it as ITestDefinition;
// following is from DefinitelyTyped
interface IContextDefinition {
(description: string, callback: (this: ISuiteCallbackContext) => void): ISuite;
only(description: string, callback: (this: ISuiteCallbackContext) => void): ISuite;
skip(description: string, callback: (this: ISuiteCallbackContext) => void): void;
timeout(ms: number): void;
}
interface ISuiteCallbackContext {
timeout(ms: number): this;
retries(n: number): this;
slow(ms: number): this;
}
interface ISuite {
parent: ISuite;
title: string;
fullTitle(): string;
}
interface ITestDefinition {
(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => any): ITest;
only(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => any): ITest;
skip(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => any): void;
timeout(ms: number): void;
state: "failed" | "passed";
}
interface ITestCallbackContext {
skip(): this;
timeout(ms: number): this;
retries(n: number): this;
slow(ms: number): this;
[index: string]: any;
}
interface MochaDone {
(error?: any): any;
}
interface ITest extends IRunnable {
parent: ISuite;
pending: boolean;
state: 'failed' | 'passed' | undefined;
fullTitle(): string;
}
interface IRunnable {
title: string;
fn: Function;
async: boolean;
sync: boolean;
timedOut: boolean;
timeout(n: number): this;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With