diff --git a/readme.md b/readme.md
index 9f13621a..5e1dcf9a 100644
--- a/readme.md
+++ b/readme.md
@@ -213,6 +213,19 @@ Default: `process.cwd()`
Current working directory of the project to retrieve the diagnostics for.
+##### typingsFile
+
+Type: `string`
+Default: The `types` property in `package.json`.
+
+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.
+
+##### testFiles
+
+Type: `string[]`
+Default: Finds files with `.test-d.ts` or `.test-d.tsx` extension.
+
+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.
## License
diff --git a/source/lib/compiler.ts b/source/lib/compiler.ts
index 07d67582..321d9082 100644
--- a/source/lib/compiler.ts
+++ b/source/lib/compiler.ts
@@ -1,4 +1,3 @@
-import * as path from 'path';
import {
flattenDiagnosticMessageText,
createProgram,
@@ -65,11 +64,9 @@ const ignoreDiagnostic = (diagnostic: TSDiagnostic, expectedErrors: Map {
- const fileNames = context.testFiles.map(fileName => path.join(context.cwd, fileName));
-
const diagnostics: Diagnostic[] = [];
- const program = createProgram(fileNames, context.config.compilerOptions);
+ const program = createProgram(context.testFiles, context.config.compilerOptions);
const tsDiagnostics = program
.getSemanticDiagnostics()
diff --git a/source/lib/index.ts b/source/lib/index.ts
index 4e56dbb2..5be84b42 100644
--- a/source/lib/index.ts
+++ b/source/lib/index.ts
@@ -9,11 +9,12 @@ import {Context, Config} from './interfaces';
export interface Options {
cwd: string;
+ typingsFile?: string;
+ testFiles?: readonly string[];
}
const findTypingsFile = async (pkg: any, options: Options) => {
- const typings = pkg.types || pkg.typings || 'index.d.ts';
-
+ const typings = options.typingsFile || pkg.types || pkg.typings || 'index.d.ts';
const typingsExist = await pathExists(path.join(options.cwd, typings));
if (!typingsExist) {
@@ -23,13 +24,37 @@ const findTypingsFile = async (pkg: any, options: Options) => {
return typings;
};
-const findTestFiles = async (typingsFile: string, options: Options & {config: Config}) => {
+const normalizeTypingsFilePath = (typingsFilePath: string, options: Options) => {
+ if (options.typingsFile) {
+ return path.basename(typingsFilePath);
+ }
+
+ return typingsFilePath;
+};
+
+const findCustomTestFiles = async (testFilesPattern: readonly string[], cwd: string) => {
+ const testFiles = await globby(testFilesPattern, {cwd});
+
+ if (testFiles.length === 0) {
+ throw new Error('Could not find any test files. Create one and try again');
+ }
+
+ return testFiles.map(file => path.join(cwd, file));
+};
+
+const findTestFiles = async (typingsFilePath: string, options: Options & {config: Config}) => {
+ if (options.testFiles?.length) {
+ return findCustomTestFiles(options.testFiles, options.cwd);
+ }
+
+ // Return only the filename if the `typingsFile` option is used.
+ const typingsFile = normalizeTypingsFilePath(typingsFilePath, options);
+
const testFile = typingsFile.replace(/\.d\.ts$/, '.test-d.ts');
const tsxTestFile = typingsFile.replace(/\.d\.ts$/, '.test-d.tsx');
const testDir = options.config.directory;
let testFiles = await globby([testFile, tsxTestFile], {cwd: options.cwd});
-
const testDirExists = await pathExists(path.join(options.cwd, testDir));
if (testFiles.length === 0 && !testDirExists) {
@@ -40,7 +65,7 @@ const findTestFiles = async (typingsFile: string, options: Options & {config: Co
testFiles = await globby([`${testDir}/**/*.ts`, `${testDir}/**/*.tsx`], {cwd: options.cwd});
}
- return testFiles;
+ return testFiles.map(fileName => path.join(options.cwd, fileName));
};
/**
@@ -56,7 +81,6 @@ export default async (options: Options = {cwd: process.cwd()}) => {
}
const pkg = pkgResult.packageJson;
-
const config = loadConfig(pkg as any, options.cwd);
// Look for a typings file, otherwise use `index.d.ts` in the root directory. If the file is not found, throw an error.
diff --git a/source/test/fixtures/specify-test-files/index.d.ts b/source/test/fixtures/specify-test-files/index.d.ts
new file mode 100644
index 00000000..0616ebaa
--- /dev/null
+++ b/source/test/fixtures/specify-test-files/index.d.ts
@@ -0,0 +1,6 @@
+declare const one: {
+ (foo: string, bar: string): string;
+ (foo: number, bar: number): number;
+};
+
+export default one;
diff --git a/source/test/fixtures/specify-test-files/index.js b/source/test/fixtures/specify-test-files/index.js
new file mode 100644
index 00000000..f17717f5
--- /dev/null
+++ b/source/test/fixtures/specify-test-files/index.js
@@ -0,0 +1,3 @@
+module.exports.default = (foo, bar) => {
+ return foo + bar;
+};
diff --git a/source/test/fixtures/specify-test-files/package.json b/source/test/fixtures/specify-test-files/package.json
new file mode 100644
index 00000000..de6dc1db
--- /dev/null
+++ b/source/test/fixtures/specify-test-files/package.json
@@ -0,0 +1,3 @@
+{
+ "name": "foo"
+}
diff --git a/source/test/fixtures/specify-test-files/unknown.test.ts b/source/test/fixtures/specify-test-files/unknown.test.ts
new file mode 100644
index 00000000..080ee4ca
--- /dev/null
+++ b/source/test/fixtures/specify-test-files/unknown.test.ts
@@ -0,0 +1,5 @@
+import {expectType} from '../../..';
+import one from '.';
+
+expectType(one('foo', 'bar'));
+expectType(one(1, 2));
diff --git a/source/test/fixtures/typings-custom-dir/index.js b/source/test/fixtures/typings-custom-dir/index.js
new file mode 100644
index 00000000..f17717f5
--- /dev/null
+++ b/source/test/fixtures/typings-custom-dir/index.js
@@ -0,0 +1,3 @@
+module.exports.default = (foo, bar) => {
+ return foo + bar;
+};
diff --git a/source/test/fixtures/typings-custom-dir/index.test-d.ts b/source/test/fixtures/typings-custom-dir/index.test-d.ts
new file mode 100644
index 00000000..a6fedd96
--- /dev/null
+++ b/source/test/fixtures/typings-custom-dir/index.test-d.ts
@@ -0,0 +1,5 @@
+import {expectType} from '../../..';
+import one from './utils';
+
+expectType(one('foo', 'bar'));
+expectType(one(1, 2));
diff --git a/source/test/fixtures/typings-custom-dir/package.json b/source/test/fixtures/typings-custom-dir/package.json
new file mode 100644
index 00000000..de6dc1db
--- /dev/null
+++ b/source/test/fixtures/typings-custom-dir/package.json
@@ -0,0 +1,3 @@
+{
+ "name": "foo"
+}
diff --git a/source/test/fixtures/typings-custom-dir/utils/index.d.ts b/source/test/fixtures/typings-custom-dir/utils/index.d.ts
new file mode 100644
index 00000000..0616ebaa
--- /dev/null
+++ b/source/test/fixtures/typings-custom-dir/utils/index.d.ts
@@ -0,0 +1,6 @@
+declare const one: {
+ (foo: string, bar: string): string;
+ (foo: number, bar: number): number;
+};
+
+export default one;
diff --git a/source/test/test.ts b/source/test/test.ts
index ebe99335..320aa507 100644
--- a/source/test/test.ts
+++ b/source/test/test.ts
@@ -220,3 +220,36 @@ test('strict types', async t => {
verify(t, diagnostics, []);
});
+
+test('typings in custom directory', async t => {
+ const diagnostics = await tsd({
+ cwd: path.join(__dirname, 'fixtures/typings-custom-dir'),
+ typingsFile: 'utils/index.d.ts'
+ });
+
+ verify(t, diagnostics, [
+ [5, 19, 'error', 'Argument of type \'number\' is not assignable to parameter of type \'string\'.']
+ ]);
+});
+
+test('specify test files manually', async t => {
+ const diagnostics = await tsd({
+ cwd: path.join(__dirname, 'fixtures/specify-test-files'),
+ testFiles: [
+ 'unknown.test.ts'
+ ]
+ });
+
+ verify(t, diagnostics, [
+ [5, 19, 'error', 'Argument of type \'number\' is not assignable to parameter of type \'string\'.']
+ ]);
+});
+
+test('fails if typings file is not found in the specified path', async t => {
+ const error = await t.throwsAsync(tsd({
+ cwd: path.join(__dirname, 'fixtures/typings-custom-dir'),
+ typingsFile: 'unknown.d.ts'
+ }));
+
+ t.is(error.message, 'The type definition `unknown.d.ts` does not exist. Create one and try again.');
+});