Skip to content

Commit 0e9228a

Browse files
authored
Allow specifying the test files and typings file manually (#74)
1 parent 95174e9 commit 0e9228a

File tree

12 files changed

+111
-10
lines changed

12 files changed

+111
-10
lines changed

readme.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,19 @@ Default: `process.cwd()`
220220

221221
Current working directory of the project to retrieve the diagnostics for.
222222

223+
##### typingsFile
224+
225+
Type: `string`<br>
226+
Default: The `types` property in `package.json`.
227+
228+
Path to the type definition file you want to test. This can be useful when using a test runner to test specific type definitions per test.
229+
230+
##### testFiles
231+
232+
Type: `string[]`<br>
233+
Default: Finds files with `.test-d.ts` or `.test-d.tsx` extension.
234+
235+
An array of test files with their path. Uses [globby](https://github.com/sindresorhus/globby) under the hood so that you can fine tune test file discovery.
223236

224237
## License
225238

source/lib/compiler.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import * as path from 'path';
21
import {
32
flattenDiagnosticMessageText,
43
createProgram,
@@ -66,11 +65,9 @@ const ignoreDiagnostic = (diagnostic: TSDiagnostic, expectedErrors: Map<Location
6665
* @returns List of diagnostics
6766
*/
6867
export const getDiagnostics = (context: Context): Diagnostic[] => {
69-
const fileNames = context.testFiles.map(fileName => path.join(context.cwd, fileName));
70-
7168
const diagnostics: Diagnostic[] = [];
7269

73-
const program = createProgram(fileNames, context.config.compilerOptions);
70+
const program = createProgram(context.testFiles, context.config.compilerOptions);
7471

7572
const tsDiagnostics = program
7673
.getSemanticDiagnostics()

source/lib/index.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ import {Context, Config} from './interfaces';
99

1010
export interface Options {
1111
cwd: string;
12+
typingsFile?: string;
13+
testFiles?: readonly string[];
1214
}
1315

1416
const findTypingsFile = async (pkg: any, options: Options) => {
15-
const typings = pkg.types || pkg.typings || 'index.d.ts';
16-
17+
const typings = options.typingsFile || pkg.types || pkg.typings || 'index.d.ts';
1718
const typingsExist = await pathExists(path.join(options.cwd, typings));
1819

1920
if (!typingsExist) {
@@ -23,13 +24,37 @@ const findTypingsFile = async (pkg: any, options: Options) => {
2324
return typings;
2425
};
2526

26-
const findTestFiles = async (typingsFile: string, options: Options & {config: Config}) => {
27+
const normalizeTypingsFilePath = (typingsFilePath: string, options: Options) => {
28+
if (options.typingsFile) {
29+
return path.basename(typingsFilePath);
30+
}
31+
32+
return typingsFilePath;
33+
};
34+
35+
const findCustomTestFiles = async (testFilesPattern: readonly string[], cwd: string) => {
36+
const testFiles = await globby(testFilesPattern, {cwd});
37+
38+
if (testFiles.length === 0) {
39+
throw new Error('Could not find any test files. Create one and try again');
40+
}
41+
42+
return testFiles.map(file => path.join(cwd, file));
43+
};
44+
45+
const findTestFiles = async (typingsFilePath: string, options: Options & {config: Config}) => {
46+
if (options.testFiles?.length) {
47+
return findCustomTestFiles(options.testFiles, options.cwd);
48+
}
49+
50+
// Return only the filename if the `typingsFile` option is used.
51+
const typingsFile = normalizeTypingsFilePath(typingsFilePath, options);
52+
2753
const testFile = typingsFile.replace(/\.d\.ts$/, '.test-d.ts');
2854
const tsxTestFile = typingsFile.replace(/\.d\.ts$/, '.test-d.tsx');
2955
const testDir = options.config.directory;
3056

3157
let testFiles = await globby([testFile, tsxTestFile], {cwd: options.cwd});
32-
3358
const testDirExists = await pathExists(path.join(options.cwd, testDir));
3459

3560
if (testFiles.length === 0 && !testDirExists) {
@@ -40,7 +65,7 @@ const findTestFiles = async (typingsFile: string, options: Options & {config: Co
4065
testFiles = await globby([`${testDir}/**/*.ts`, `${testDir}/**/*.tsx`], {cwd: options.cwd});
4166
}
4267

43-
return testFiles;
68+
return testFiles.map(fileName => path.join(options.cwd, fileName));
4469
};
4570

4671
/**
@@ -56,7 +81,6 @@ export default async (options: Options = {cwd: process.cwd()}) => {
5681
}
5782

5883
const pkg = pkgResult.packageJson;
59-
6084
const config = loadConfig(pkg as any, options.cwd);
6185

6286
// Look for a typings file, otherwise use `index.d.ts` in the root directory. If the file is not found, throw an error.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare const one: {
2+
(foo: string, bar: string): string;
3+
(foo: number, bar: number): number;
4+
};
5+
6+
export default one;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports.default = (foo, bar) => {
2+
return foo + bar;
3+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "foo"
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import {expectType} from '../../..';
2+
import one from '.';
3+
4+
expectType<string>(one('foo', 'bar'));
5+
expectType<string>(one(1, 2));
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports.default = (foo, bar) => {
2+
return foo + bar;
3+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import {expectType} from '../../..';
2+
import one from './utils';
3+
4+
expectType<string>(one('foo', 'bar'));
5+
expectType<string>(one(1, 2));
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"name": "foo"
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
declare const one: {
2+
(foo: string, bar: string): string;
3+
(foo: number, bar: number): number;
4+
};
5+
6+
export default one;

source/test/test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,36 @@ test('strict types', async t => {
244244

245245
verify(t, diagnostics, []);
246246
});
247+
248+
test('typings in custom directory', async t => {
249+
const diagnostics = await tsd({
250+
cwd: path.join(__dirname, 'fixtures/typings-custom-dir'),
251+
typingsFile: 'utils/index.d.ts'
252+
});
253+
254+
verify(t, diagnostics, [
255+
[5, 19, 'error', 'Argument of type \'number\' is not assignable to parameter of type \'string\'.']
256+
]);
257+
});
258+
259+
test('specify test files manually', async t => {
260+
const diagnostics = await tsd({
261+
cwd: path.join(__dirname, 'fixtures/specify-test-files'),
262+
testFiles: [
263+
'unknown.test.ts'
264+
]
265+
});
266+
267+
verify(t, diagnostics, [
268+
[5, 19, 'error', 'Argument of type \'number\' is not assignable to parameter of type \'string\'.']
269+
]);
270+
});
271+
272+
test('fails if typings file is not found in the specified path', async t => {
273+
const error = await t.throwsAsync(tsd({
274+
cwd: path.join(__dirname, 'fixtures/typings-custom-dir'),
275+
typingsFile: 'unknown.d.ts'
276+
}));
277+
278+
t.is(error.message, 'The type definition `unknown.d.ts` does not exist. Create one and try again.');
279+
});

0 commit comments

Comments
 (0)