From 524594d3a2c2bc60c272b6a683e18cd97b2dbad4 Mon Sep 17 00:00:00 2001 From: Pierre Vanduynslager Date: Sun, 16 Feb 2020 07:17:49 -0500 Subject: [PATCH] Allow importing AVA as `anyTest` in TypeScript files --- docs/rules/use-test.md | 7 +++ rules/use-test.js | 34 +++++++++----- test/use-test.js | 102 +++++++++++++++++++++++++++++++++++------ 3 files changed, 119 insertions(+), 24 deletions(-) diff --git a/docs/rules/use-test.md b/docs/rules/use-test.md index 1768128e..4c279aa0 100644 --- a/docs/rules/use-test.md +++ b/docs/rules/use-test.md @@ -3,6 +3,7 @@ Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/related/eslint-plugin-ava/docs/rules/use-test.md) The convention is to import AVA and assign it to a variable named `test`. Most rules in `eslint-plugin-ava` are based on that assumption. +In a TypeScript file (`.ts` or `.tsx`) AVA can be assigned to a variable named `anyTest` in order to define the types of `t.context` (see [Typing t.context](https://github.com/avajs/ava/blob/master/docs/recipes/typescript.md#typing-tcontext)). ### Fail @@ -24,3 +25,9 @@ import test from 'ava'; var test = require('foo'); const test = require('foo'); ``` + +```ts +import anyTest from 'ava'; + +const test = anyTest as TestInterface<{foo: string}>; +``` diff --git a/rules/use-test.js b/rules/use-test.js index 5922a681..432343f2 100644 --- a/rules/use-test.js +++ b/rules/use-test.js @@ -1,4 +1,5 @@ 'use strict'; +const path = require('path'); const espurify = require('espurify'); const deepStrictEqual = require('deep-strict-equal'); const util = require('../util'); @@ -24,18 +25,29 @@ function report(context, node) { }); } -const create = context => ({ - ImportDeclaration: node => { - if (node.source.value === 'ava' && node.specifiers[0].local.name !== 'test') { - report(context, node); - } - }, - VariableDeclarator: node => { - if (node.id.name !== 'test' && node.init && deepStrictEqual(espurify(node.init), avaVariableDeclaratorInitAst)) { - report(context, node); +const create = context => { + const ext = path.extname(context.getFilename()); + const isTypeScript = ext === '.ts' || ext === '.tsx'; + + return { + ImportDeclaration: node => { + if (node.source.value === 'ava') { + const {name} = node.specifiers[0].local; + if (name !== 'test' && (!isTypeScript || name !== 'anyTest')) { + report(context, node); + } + } + }, + VariableDeclarator: node => { + if (node.init && deepStrictEqual(espurify(node.init), avaVariableDeclaratorInitAst)) { + const {name} = node.id; + if (name !== 'test' && (!isTypeScript || name !== 'anyTest')) { + report(context, node); + } + } } - } -}); + }; +}; module.exports = { create, diff --git a/test/use-test.js b/test/use-test.js index c7fc8320..efc077dd 100644 --- a/test/use-test.js +++ b/test/use-test.js @@ -15,35 +15,111 @@ const errors = [{ruleId: 'use-test'}]; ruleTester.run('use-test', rule, { valid: [ - 'var test = require(\'ava\');', - 'let test = require(\'ava\');', - 'const test = require(\'ava\');', - 'const a = 1, test = require(\'ava\'), b = 2;', - 'const test = require(\'foo\');', - 'import test from \'ava\';', - 'import test, {} from \'ava\';', - 'import test from \'foo\';' + {code: 'var test = require(\'ava\');', filename: 'file.js'}, + {code: 'let test = require(\'ava\');', filename: 'file.js'}, + {code: 'const test = require(\'ava\');', filename: 'file.js'}, + {code: 'const a = 1, test = require(\'ava\'), b = 2;', filename: 'file.js'}, + {code: 'const test = require(\'foo\');', filename: 'file.js'}, + {code: 'import test from \'ava\';', filename: 'file.js'}, + {code: 'import test, {} from \'ava\';', filename: 'file.js'}, + {code: 'import test from \'foo\';', filename: 'file.js'}, + {code: 'var anyTest = require(\'ava\');', filename: 'file.ts'}, + {code: 'let anyTest = require(\'ava\');', filename: 'file.ts'}, + {code: 'const anyTest = require(\'ava\');', filename: 'file.ts'}, + {code: 'const a = 1, anyTest = require(\'ava\'), b = 2;', filename: 'file.ts'}, + {code: 'const anyTest = require(\'foo\');', filename: 'file.ts'}, + {code: 'import anyTest from \'ava\';', filename: 'file.ts'}, + {code: 'import anyTest, {} from \'ava\';', filename: 'file.ts'}, + {code: 'import anyTest from \'foo\';', filename: 'file.ts'}, + {code: 'var anyTest = require(\'ava\');', filename: 'file.tsx'}, + {code: 'let anyTest = require(\'ava\');', filename: 'file.tsx'}, + {code: 'const anyTest = require(\'ava\');', filename: 'file.tsx'}, + {code: 'const a = 1, anyTest = require(\'ava\'), b = 2;', filename: 'file.tsx'}, + {code: 'const anyTest = require(\'foo\');', filename: 'file.tsx'}, + {code: 'import anyTest from \'ava\';', filename: 'file.tsx'}, + {code: 'import anyTest, {} from \'ava\';', filename: 'file.tsx'}, + {code: 'import anyTest from \'foo\';', filename: 'file.tsx'} ], invalid: [ { code: 'var ava = require(\'ava\');', - errors + errors, + filename: 'file.ts' }, { code: 'let ava = require(\'ava\');', - errors + errors, + filename: 'file.ts' }, { code: 'const ava = require(\'ava\');', - errors + errors, + filename: 'file.ts' }, { code: 'const a = 1, ava = require(\'ava\'), b = 2;', - errors + errors, + filename: 'file.ts' }, { code: 'import ava from \'ava\';', - errors + errors, + filename: 'file.ts' + }, + { + code: 'var anyTest = require(\'ava\');', + errors, + filename: 'file.js' + }, + { + code: 'var ava = require(\'ava\');', + errors, + filename: 'file.ts' + }, + { + code: 'let ava = require(\'ava\');', + errors, + filename: 'file.ts' + }, + { + code: 'const ava = require(\'ava\');', + errors, + filename: 'file.ts' + }, + { + code: 'const a = 1, ava = require(\'ava\'), b = 2;', + errors, + filename: 'file.ts' + }, + { + code: 'import ava from \'ava\';', + errors, + filename: 'file.ts' + }, + { + code: 'var ava = require(\'ava\');', + errors, + filename: 'file.tsx' + }, + { + code: 'let ava = require(\'ava\');', + errors, + filename: 'file.tsx' + }, + { + code: 'const ava = require(\'ava\');', + errors, + filename: 'file.tsx' + }, + { + code: 'const a = 1, ava = require(\'ava\'), b = 2;', + errors, + filename: 'file.tsx' + }, + { + code: 'import ava from \'ava\';', + errors, + filename: 'file.tsx' } ] });