Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,19 @@ Default: `process.cwd()`

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

##### typingsFile

Type: `string`<br>
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[]`<br>
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

Expand Down
5 changes: 1 addition & 4 deletions source/lib/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as path from 'path';
import {
flattenDiagnosticMessageText,
createProgram,
Expand Down Expand Up @@ -65,11 +64,9 @@ const ignoreDiagnostic = (diagnostic: TSDiagnostic, expectedErrors: Map<Location
* @returns List of diagnostics
*/
export const getDiagnostics = (context: Context): Diagnostic[] => {
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()
Expand Down
36 changes: 30 additions & 6 deletions source/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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));
};

/**
Expand All @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions source/test/fixtures/specify-test-files/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
declare const one: {
(foo: string, bar: string): string;
(foo: number, bar: number): number;
};

export default one;
3 changes: 3 additions & 0 deletions source/test/fixtures/specify-test-files/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports.default = (foo, bar) => {
return foo + bar;
};
3 changes: 3 additions & 0 deletions source/test/fixtures/specify-test-files/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "foo"
}
5 changes: 5 additions & 0 deletions source/test/fixtures/specify-test-files/unknown.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {expectType} from '../../..';
import one from '.';

expectType<string>(one('foo', 'bar'));
expectType<string>(one(1, 2));
3 changes: 3 additions & 0 deletions source/test/fixtures/typings-custom-dir/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports.default = (foo, bar) => {
return foo + bar;
};
5 changes: 5 additions & 0 deletions source/test/fixtures/typings-custom-dir/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {expectType} from '../../..';
import one from './utils';

expectType<string>(one('foo', 'bar'));
expectType<string>(one(1, 2));
3 changes: 3 additions & 0 deletions source/test/fixtures/typings-custom-dir/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "foo"
}
6 changes: 6 additions & 0 deletions source/test/fixtures/typings-custom-dir/utils/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
declare const one: {
(foo: string, bar: string): string;
(foo: number, bar: number): number;
};

export default one;
33 changes: 33 additions & 0 deletions source/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
});