diff --git a/fixtures/.eslintrc b/fixtures/.eslintrc new file mode 100644 index 0000000..acf0bd2 --- /dev/null +++ b/fixtures/.eslintrc @@ -0,0 +1,5 @@ +{ + "extends": [ + "plugin:vitest/all" + ] +} \ No newline at end of file diff --git a/fixtures/eslint.config.js b/fixtures/eslint.config.js deleted file mode 100644 index b8f5a0b..0000000 --- a/fixtures/eslint.config.js +++ /dev/null @@ -1,5 +0,0 @@ -import vitest from 'eslint-plugin-vitest' - -export default [ - vitest.configs.recommended -] diff --git a/fixtures/index.spec.ts b/fixtures/index.spec.ts deleted file mode 100644 index 0ea3194..0000000 --- a/fixtures/index.spec.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { describe, expect, test } from 'vitest' - -describe('foo', () => { - test('mdmdms', () => { - }) - - test('foo', () => { - expect(true).toBe(true) - }) -}) diff --git a/fixtures/index.test.ts b/fixtures/index.test.ts new file mode 100644 index 0000000..cedaf90 --- /dev/null +++ b/fixtures/index.test.ts @@ -0,0 +1,9 @@ +import { describe, it, expect } from 'vitest' + +describe('foo', () => { + it.todo('mdmdms') + + it('foo', () => { + expect(true).toBeTruthy() + }) +}) diff --git a/package.json b/package.json index 0ad7a18..d9d1516 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "release": "pnpm build && bumpp package.json --commit --push --tag && pnpm publish", "stub": "unbuild --stub", "test:ci": "vitest run", - "test": "vitest src/**/*.test.ts", + "test": "vitest", + "generate": "tsx scripts/generate.ts", "update:eslint-docs": "pnpm build && eslint-doc-generator" }, "devDependencies": { @@ -55,6 +56,7 @@ "eslint-remote-tester-repositories": "^1.0.1", "jiti": "^1.19.1", "ts-node": "^10.9.1", + "tsx": "^3.12.7", "unbuild": "^1.2.1", "vitest": "^0.33.0" }, @@ -73,4 +75,4 @@ "dependencies": { "@typescript-eslint/utils": "^6.2.0" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c514947..b93118d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -61,6 +61,9 @@ devDependencies: ts-node: specifier: ^10.9.1 version: 10.9.1(@types/node@20.4.5)(typescript@5.1.6) + tsx: + specifier: ^3.12.7 + version: 3.12.7 unbuild: specifier: ^1.2.1 version: 1.2.1 @@ -294,6 +297,27 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true + /@esbuild-kit/cjs-loader@2.4.2: + resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==} + dependencies: + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.6.2 + dev: true + + /@esbuild-kit/core-utils@3.1.0: + resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + dependencies: + esbuild: 0.17.19 + source-map-support: 0.5.21 + dev: true + + /@esbuild-kit/esm-loader@2.5.5: + resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + dependencies: + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.6.2 + dev: true + /@esbuild/android-arm64@0.17.19: resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} engines: {node: '>=12'} @@ -1669,6 +1693,10 @@ packages: update-browserslist-db: 1.0.11(browserslist@4.21.9) dev: true + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} @@ -2860,6 +2888,12 @@ packages: get-intrinsic: 1.2.1 dev: true + /get-tsconfig@4.6.2: + resolution: {integrity: sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /giget@1.1.2: resolution: {integrity: sha512-HsLoS07HiQ5oqvObOI+Qb2tyZH4Gj5nYGfF9qQcZNrPw+uEFhdXtgJr01aO2pWadGHucajYDLxxbtQkm97ON2A==} hasBin: true @@ -4043,6 +4077,10 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve@1.22.2: resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} hasBin: true @@ -4221,6 +4259,18 @@ packages: engines: {node: '>=0.10.0'} dev: true + /source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + /spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} dev: true @@ -4482,6 +4532,17 @@ packages: typescript: 5.1.6 dev: true + /tsx@3.12.7: + resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==} + hasBin: true + dependencies: + '@esbuild-kit/cjs-loader': 2.4.2 + '@esbuild-kit/core-utils': 3.1.0 + '@esbuild-kit/esm-loader': 2.5.5 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} diff --git a/scripts/generate.ts b/scripts/generate.ts new file mode 100644 index 0000000..f63279b --- /dev/null +++ b/scripts/generate.ts @@ -0,0 +1,40 @@ +import fs from 'node:fs' +import url from 'node:url' +import path from 'node:path' + +async function generate() { + const __dirname = url.fileURLToPath(new URL('.', import.meta.url)) + const rules = fs.readdirSync(path.resolve(__dirname, '../src/rules')) + + const allRules = [] + const recommendedRules = [] + + rules.forEach(async (rule) => { + const ruleName = rule.replace(/\.ts$/, '') + const content = await import(path.resolve(__dirname, `../src/rules/${ruleName}.ts`)) + + if (content.default.meta.docs.recommended) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + recommendedRules.push({ + name: ruleName, + rule: content.default + }) + } else { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + allRules.push({ + name: ruleName, + rule: content.default + }) + } + }) + + console.log(recommendedRules) +} + +generate() + .catch((e) => { + console.error(e) + process.exit(1) + }) diff --git a/src/rules/consistent-test-filename.test.ts b/src/rules/consistent-test-filename.test.ts deleted file mode 100644 index 815b4fd..0000000 --- a/src/rules/consistent-test-filename.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './consistent-test-filename' - -describe(RULE_NAME, () => { - it(`${RULE_NAME}`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - { - code: 'export {}', - filename: '1.test.ts', - options: [{ pattern: String.raw`.*\.test\.ts$` }] - } - ], - invalid: [ - { - code: 'export {}', - filename: '1.spec.ts', - errors: [{ messageId: 'msg' }], - options: [{ pattern: String.raw`.*\.test\.ts$` }] - } - ] - }) - }) -}) diff --git a/src/rules/consistent-test-it.test.ts b/src/rules/consistent-test-it.test.ts deleted file mode 100644 index 128279f..0000000 --- a/src/rules/consistent-test-it.test.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { describe, it } from 'vitest' -import { TestCaseName } from '../utils/types' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './consistent-test-it' - -describe(RULE_NAME, () => { - it(`${RULE_NAME} - fn=it`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - { - code: `it("shows error", () => { - expect(true).toBe(false); - });`, - options: [{ fn: TestCaseName.it }] - }, - { - code: `it("foo", function () { - expect(true).toBe(false); - })`, - options: [{ fn: TestCaseName.it }] - }, - { - code: ` it('foo', () => { - expect(true).toBe(false); - }); - function myTest() { if ('bar') {} }`, - options: [{ fn: TestCaseName.it }] - } - ], - invalid: [ - { - code: 'test("shows error", () => {});', - options: [{ fn: TestCaseName.it }], - output: 'it("shows error", () => {});', - errors: [{ messageId: 'consistentMethod' }] - }, - { - code: 'test.skip("shows error");', - output: 'it.skip("shows error");', - options: [{ fn: TestCaseName.it }], - errors: [ - { - messageId: 'consistentMethod', - data: { - testFnKeyWork: TestCaseName.it, - oppositeTestKeyword: TestCaseName.test - } - } - ] - }, - { - code: 'test.only(\'shows error\');', - output: 'it.only(\'shows error\');', - options: [{ fn: TestCaseName.it }], - errors: [ - { - messageId: 'consistentMethod', - data: { - testFnKeyWork: TestCaseName.it, - oppositeTestKeyword: TestCaseName.test - } - } - ] - }, - { - code: 'describe(\'foo\', () => { it(\'bar\', () => {}); });', - output: 'describe(\'foo\', () => { test(\'bar\', () => {}); });', - options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.test }], - errors: [ - { - messageId: 'consistentMethodWithinDescribe', - data: { - testKeywordWithinDescribe: TestCaseName.test, - oppositeTestKeyword: TestCaseName.it - } - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} - fn=test`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - { - code: `test("shows error", () => { - expect(true).toBe(false); - });`, - options: [{ fn: TestCaseName.test }] - }, - { - code: 'test.skip("foo")', - options: [{ fn: TestCaseName.test }] - }, - { - code: 'test.concurrent("foo")', - options: [{ fn: TestCaseName.test }] - }, - { - code: 'xtest("foo")', - options: [{ fn: TestCaseName.test }] - }, - { - code: 'test.each([])("foo")', - options: [{ fn: TestCaseName.test }] - }, - { - code: 'test.each``("foo")', - options: [{ fn: TestCaseName.test }] - }, - { - code: 'describe("suite", () => { test("foo") })', - options: [{ fn: TestCaseName.test }] - } - ], - invalid: [ - { - code: 'it("shows error", () => {});', - options: [{ fn: TestCaseName.test }], - output: 'test("shows error", () => {});', - errors: [{ messageId: 'consistentMethod' }] - }, - { - code: 'describe("suite", () => { it("foo") })', - output: 'describe("suite", () => { test("foo") })', - options: [{ fn: TestCaseName.test }], - errors: [ - { - messageId: 'consistentMethodWithinDescribe', - data: { - testKeywordWithinDescribe: TestCaseName.test, - oppositeTestKeyword: TestCaseName.it - } - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} - with fn=it and withinDescribe=it`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - { - code: 'describe("suite", () => { it("foo") })', - options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }] - }, - { - code: 'it("foo")', - options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }] - } - ], - invalid: [ - { - code: 'describe("suite", () => { test("foo") })', - output: 'describe("suite", () => { it("foo") })', - options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }], - errors: [ - { - messageId: 'consistentMethodWithinDescribe', - data: { - testKeywordWithinDescribe: TestCaseName.it, - oppositeTestKeyword: TestCaseName.test - } - } - ] - }, - { - code: 'test("foo")', - output: 'it("foo")', - options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }], - errors: [ - { - messageId: 'consistentMethod', - data: { - testFnKeyWork: TestCaseName.it, - oppositeTestKeyword: TestCaseName.test - } - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} defaults without config object`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - { - code: 'test("shows error", () => {});' - } - ], - invalid: [ - { - code: 'describe("suite", () => { test("foo") })', - output: 'describe("suite", () => { it("foo") })', - errors: [ - { - messageId: 'consistentMethodWithinDescribe', - data: { - testKeywordWithinDescribe: TestCaseName.it, - oppositeTestKeyword: TestCaseName.test - } - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} - with withinDescribe=it`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - { - code: 'test("foo")', - options: [{ withinDescribe: TestCaseName.it }] - }, - { - code: 'describe("suite", () => { it("foo") })', - options: [{ withinDescribe: TestCaseName.it }] - } - ], - invalid: [ - { - code: 'it("foo")', - output: 'test("foo")', - options: [{ withinDescribe: TestCaseName.it }], - errors: [ - { - messageId: 'consistentMethod', - data: { - testFnKeyWork: TestCaseName.test, - oppositeTestKeyword: TestCaseName.it - } - } - ] - }, - { - code: 'describe("suite", () => { test("foo") })', - output: 'describe("suite", () => { it("foo") })', - options: [{ withinDescribe: TestCaseName.it }], - errors: [ - { - messageId: 'consistentMethodWithinDescribe', - data: { - testKeywordWithinDescribe: TestCaseName.it, - oppositeTestKeyword: TestCaseName.test - } - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} - with withinDescribe=test`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - { - code: 'test("foo")', - options: [{ withinDescribe: TestCaseName.test }] - }, - { - code: 'describe("suite", () => { test("foo") })', - options: [{ withinDescribe: TestCaseName.test }] - } - ], - invalid: [ - { - code: 'it("foo")', - output: 'test("foo")', - options: [{ withinDescribe: TestCaseName.test }], - errors: [ - { - messageId: 'consistentMethod', - data: { - testFnKeyWork: TestCaseName.test, - oppositeTestKeyword: TestCaseName.it - } - } - ] - }, - { - code: 'describe("suite", () => { it("foo") })', - output: 'describe("suite", () => { test("foo") })', - options: [{ withinDescribe: TestCaseName.test }], - errors: [ - { - messageId: 'consistentMethodWithinDescribe', - data: { - testKeywordWithinDescribe: TestCaseName.test, - oppositeTestKeyword: TestCaseName.it - } - } - ] - } - ] - }) - }) -}) diff --git a/src/rules/expect-expect.test.ts b/src/rules/expect-expect.test.ts deleted file mode 100644 index 4f59c55..0000000 --- a/src/rules/expect-expect.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './expect-expect' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - `test("shows error", () => { - expect(true).toBe(false); - });`, - `it("foo", function () { - expect(true).toBe(false); - })`, - `it('foo', () => { - expect(true).toBe(false); - }); - function myTest() { if ('bar') {} }`, - `function myTest(param) {} - describe('my test', () => { - it('should do something', () => { - myTest("num"); - expect(1).toEqual(1); - }); - });`, - `const myFunc = () => {}; - it("works", () => expect(myFunc()).toBe(undefined));`, - `describe('title', () => { - it('test is not ok', () => { - [1, 2, 3, 4, 5, 6].forEach((n) => { - expect(n).toBe(1); - }); - }); - });`, - `desctibe('title', () => { - test('some test', () => { - expect(obj1).not.toEqual(obj2); - }) - })`, - 'it("should pass", () => expect(true).toBeDefined())', - `const myFunc = () => {}; - it("works", () => expect(myFunc()).toBe(undefined));`, - `const myFunc = () => {}; - it("works", () => expect(myFunc()).toBe(undefined));` - ], - invalid: [ - { - code: 'test("shows error", () => {});', - errors: [{ messageId: 'expectedExpect' }] - }, - { - code: `it("foo", function () { - if (1 === 2) {} - })`, - errors: [{ messageId: 'expectedExpect' }] - }, - { - code: `import { it } from 'vitest'; - describe('Button with increment', () => { - it('should show name props', () => { - console.log('test with missing expect'); - }); - });`, - errors: [{ messageId: 'expectedExpect' }] - }, - { - code: 'it("should also fail",() => expectSaga(mySaga).returns());', - errors: [{ messageId: 'expectedExpect' }] - } - ] - }) - }) -}) diff --git a/src/rules/no-alias-methods.test.ts b/src/rules/no-alias-methods.test.ts deleted file mode 100644 index 570fbe5..0000000 --- a/src/rules/no-alias-methods.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-alias-methods' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect(a).toHaveBeenCalled()', - 'expect(a).toHaveBeenCalledTimes()', - 'expect(a).toHaveBeenCalledWith()', - 'expect(a).toHaveBeenLastCalledWith()', - 'expect(a).toHaveBeenNthCalledWith()', - 'expect(a).toHaveReturned()', - 'expect(a).toHaveReturnedTimes()', - 'expect(a).toHaveReturnedWith()', - 'expect(a).toHaveLastReturnedWith()', - 'expect(a).toHaveNthReturnedWith()', - 'expect(a).toThrow()', - 'expect(a).rejects;', - 'expect(a);' - ], - invalid: [ - { - code: 'expect(a).toBeCalled()', - output: 'expect(a).toHaveBeenCalled()', - errors: [ - { - messageId: 'noAliasMethods', - data: { - alias: 'toBeCalled', - canonical: 'toHaveBeenCalled' - }, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).toBeCalledTimes()', - output: 'expect(a).toHaveBeenCalledTimes()', - errors: [ - { - messageId: 'noAliasMethods', - data: { - alias: 'toBeCalledTimes', - canonical: 'toHaveBeenCalledTimes' - }, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).not["toThrowError"]()', - output: 'expect(a).not[\'toThrow\']()', - errors: [ - { - messageId: 'noAliasMethods', - data: { - alias: 'toThrowError', - canonical: 'toThrow' - }, - column: 15, - line: 1 - } - ] - } - ] - }) - }) -}) diff --git a/src/rules/no-commented-out-tests.test.ts b/src/rules/no-commented-out-tests.test.ts deleted file mode 100644 index 34486f1..0000000 --- a/src/rules/no-commented-out-tests.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-commented-out-tests' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - '// foo("bar", function () {})', - 'describe("foo", function () {})', - 'it("foo", function () {})', - 'describe.only("foo", function () {})', - 'it.only("foo", function () {})', - 'it.concurrent("foo", function () {})', - 'test("foo", function () {})', - 'test.only("foo", function () {})', - 'test.concurrent("foo", function () {})', - 'var appliedSkip = describe.skip; appliedSkip.apply(describe)', - 'var calledSkip = it.skip; calledSkip.call(it)', - '({ f: function () {} }).f()', - '(a || b).f()', - 'itHappensToStartWithIt()', - 'testSomething()', - '// latest(dates)', - '// TODO: unify with Git implementation from Shipit (?)', - '#!/usr/bin/env node' - ], - invalid: [ - { - code: '// describe(\'foo\', function () {})\'', - errors: [ - { - messageId: 'noCommentedOutTests' - } - ] - }, - { - code: '// test.concurrent("foo", function () {})', - errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] - }, - { - code: '// test["skip"]("foo", function () {})', - errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] - }, - { - code: '// xdescribe("foo", function () {})', - errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] - }, - { - code: '// xit("foo", function () {})', - errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] - }, - { - code: '// fit("foo", function () {})', - errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] - }, - { - code: ` // test( - // "foo", function () {} - // )`, - errors: [{ messageId: 'noCommentedOutTests', column: 2, line: 1 }] - } - ] - }) - }) -}) diff --git a/src/rules/no-conditional-in-test.test.ts b/src/rules/no-conditional-in-test.test.ts deleted file mode 100644 index 8337695..0000000 --- a/src/rules/no-conditional-in-test.test.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-conditional-tests' - -describe(RULE_NAME, () => { - it('conditional expressions', () => { - ruleTester.run(`${RULE_NAME}-conditional expressions`, rule, { - valid: [ - 'const x = y ? 1 : 0', - `const foo = function (bar) { - return foo ? bar : null; - }; - it('foo', () => { - foo(); - });`, - `it.concurrent('foo', () => { - switch('bar') {} - })` - ], - invalid: [ - { - code: `it('foo', function () { - const foo = function (bar) { - return foo ? bar : null; - }; - });`, - errors: [ - { - messageId: 'noConditionalTests' - } - ] - } - ] - }) - }) - - it('switch statements', () => { - ruleTester.run(`${RULE_NAME}-switch statements`, rule, { - valid: [ - 'it(\'foo\', () => {})', - `switch (true) { - case true: {} - }`, - `describe('foo', () => { - switch('bar') {} - })`, - `const values = something.map(thing => { - switch (thing.isFoo) { - case true: - return thing.foo; - default: - return thing.bar; - } - }); - - it('valid', () => { - expect(values).toStrictEqual(['foo']); - });` - ], - invalid: [ - { - code: `it('is invalid', () => { - const values = something.map(thing => { - switch (thing.isFoo) { - case true: - return thing.foo; - default: - return thing.bar; - } - }); - - expect(values).toStrictEqual(['foo']); - });`, - errors: [ - { - messageId: 'noConditionalTests', - column: 9, - line: 3 - } - ] - }, - { - code: `it('foo', () => { - switch (true) { - case true: {} - } - })`, - errors: [ - { - messageId: 'noConditionalTests', - column: 7, - line: 2 - } - ] - }, - { - code: `describe('foo', () => { - it('bar', () => { - switch('bar') {} - }) - it('baz', () => { - switch('qux') {} - switch('quux') {} - }) - })`, - errors: [ - { - messageId: 'noConditionalTests', - column: 9, - line: 3 - }, - { - messageId: 'noConditionalTests', - column: 9, - line: 6 - }, - { - messageId: 'noConditionalTests', - column: 9, - line: 7 - } - ] - }, - { - code: `describe('valid', () => { - describe('still valid', () => { - it('is not valid', () => { - const values = something.map((thing) => { - switch (thing.isFoo) { - case true: - return thing.foo; - default: - return thing.bar; - } - }); - - switch('invalid') { - case true: - expect(values).toStrictEqual(['foo']); - } - }); - }); - });`, - errors: [ - { - messageId: 'noConditionalTests', - column: 10, - line: 5 - }, - { - messageId: 'noConditionalTests', - column: 8, - line: 13 - } - ] - } - ] - }) - }) - - it('if statements', () => { - ruleTester.run(`${RULE_NAME}-if statements`, rule, { - valid: [ - 'if (foo) {}', - 'it(\'foo\', () => {})', - 'it("foo", function () {})', - 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }', - `describe.each\`\`('foo', () => { - afterEach(() => { - if ('bar') {} - }); - })`, - `const values = something.map((thing) => { - if (thing.isFoo) { - return thing.foo - } else { - return thing.bar; - } - }); - - describe('valid', () => { - it('still valid', () => { - expect(values).toStrictEqual(['foo']); - }); - });` - ], - invalid: [ - { - code: `it('foo', () => { - const foo = function(bar) { - if (bar) { - return 1; - } else { - return 2; - } - }; - });`, - errors: [ - { - messageId: 'noConditionalTests', - column: 9, - line: 3 - } - ] - }, - { - code: ` describe('foo', () => { - it('bar', () => { - if ('bar') {} - }) - it('baz', () => { - if ('qux') {} - if ('quux') {} - }) - })`, - errors: [ - { messageId: 'noConditionalTests', column: 9, line: 3 }, - { messageId: 'noConditionalTests', column: 9, line: 6 }, - { messageId: 'noConditionalTests', column: 9, line: 7 } - ] - }, - { - code: `test("shows error", () => { - if (1 === 2) { - expect(true).toBe(false); - } - }); - - test("does not show error", () => { - setTimeout(() => console.log("noop")); - if (1 === 2) { - expect(true).toBe(false); - } - });`, - errors: [ - { messageId: 'noConditionalTests', column: 7, line: 2 }, - { messageId: 'noConditionalTests', column: 7, line: 9 } - ] - } - ] - }) - }) -}) diff --git a/src/rules/no-conditional-tests.test.ts b/src/rules/no-conditional-tests.test.ts deleted file mode 100644 index 855c615..0000000 --- a/src/rules/no-conditional-tests.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { it, describe } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-conditional-tests' - -describe(RULE_NAME, () => { - it('if statements', () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'test("shows error", () => {});', - 'it("foo", function () {})', - 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }', - `function myFunc(str: string) { - return str; - } - - describe("myTest", () => { - it("convert shortened equal filter", () => { - expect( - myFunc("5") - ).toEqual("5"); - }); - });` - ], - invalid: [ - { - code: `test("shows error", () => { - if (1 === 2) { - expect(true).toBe(false); - } - });`, - output: `test("shows error", () => { - if (1 === 2) { - expect(true).toBe(false); - } - });`, - errors: [{ messageId: 'noConditionalTests' }] - }, - { - code: `it("foo", function () { - if (1 === 2) { - expect(true).toBe(false); - } - })`, - output: `it("foo", function () { - if (1 === 2) { - expect(true).toBe(false); - } - })`, - errors: [{ messageId: 'noConditionalTests' }] - } - ] - }) - }) - - it('ternary statements', () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'test("shows error", () => {});', - 'it("foo", function () {})', - 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }' - ], - invalid: [ - { - code: `test("shows error", () => { - const foo = true ? 'foo' : 'bar'; - expect(foo).toBe('foo'); - });`, - output: `test("shows error", () => { - const foo = true ? 'foo' : 'bar'; - expect(foo).toBe('foo'); - });`, - errors: [{ messageId: 'noConditionalTests' }] - }, - { - code: `it("foo", function () { - const foo = true ? 'foo' : 'bar'; - expect(foo).toBe('foo'); - })`, - output: `it("foo", function () { - const foo = true ? 'foo' : 'bar'; - expect(foo).toBe('foo'); - })`, - errors: [{ messageId: 'noConditionalTests' }] - } - ] - }) - - it('switch statements', () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'test("shows error", () => {});', - 'it("foo", function () {})', - 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }' - ], - invalid: [ - { - code: `test("shows error", () => { - switch (1) { - case 1: - expect(true).toBe(false); - break; - default: - expect(true).toBe(false); - } - });`, - output: `test("shows error", () => { - switch (1) { - case 1: - expect(true).toBe(false); - break; - default: - expect(true).toBe(false); - } - });`, - errors: [{ messageId: 'noConditionalTests' }] - }, - { - code: `it("foo", function () { - switch (1) { - case 1: - expect(true).toBe(false); - break; - default: - expect(true).toBe(false); - } - })`, - output: `it("foo", function () { - switch (1) { - case 1: - expect(true).toBe(false); - break; - default: - expect(true).toBe(false); - } - })`, - errors: [{ messageId: 'noConditionalTests' }] - } - ] - }) - }) - }) -}) diff --git a/src/rules/no-done-callback.test.ts b/src/rules/no-done-callback.test.ts deleted file mode 100644 index 89ceb27..0000000 --- a/src/rules/no-done-callback.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-done-callback' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'test("something", () => {})', - 'test("something", async () => {})', - 'test("something", function() {})', - 'test.each``("something", ({ a, b }) => {})', - 'test.each()("something", ({ a, b }) => {})', - 'it.each()("something", ({ a, b }) => {})', - 'it.each([])("something", (a, b) => {})', - 'it.each``("something", ({ a, b }) => {})', - 'it.each([])("something", (a, b) => { a(); b(); })', - 'it.each``("something", ({ a, b }) => { a(); b(); })', - 'test("something", async function () {})', - 'test("something", someArg)', - 'beforeEach(() => {})', - 'beforeAll(async () => {})', - 'afterAll(() => {})', - 'afterAll(async function () {})', - 'afterAll(async function () {}, 5)' - ], - invalid: [ - { - code: 'test("something", (...args) => {args[0]();})', - errors: [{ messageId: 'noDoneCallback', line: 1, column: 20 }] - }, - { - code: 'test("something", done => {done();})', - errors: [ - { - messageId: 'noDoneCallback', - line: 1, - column: 1, - suggestions: [ - { - messageId: 'suggestWrappingInPromise', - data: { callback: 'done' }, - output: - 'test("something", () => {return new Promise(done => {done();})})' - } - ] - } - ] - }, - { - code: 'test("something", finished => {finished();})', - errors: [ - { - messageId: 'noDoneCallback', - line: 1, - column: 1, - suggestions: [ - { - messageId: 'suggestWrappingInPromise', - data: { callback: 'finished' }, - output: - 'test("something", () => {return new Promise(finished => {finished();})})' - } - ] - } - ] - }, - { - code: 'beforeAll(async done => {done();})', - errors: [ - { messageId: 'useAwaitInsteadOfCallback', line: 1, column: 17 } - ] - }, - { - code: 'beforeEach((done) => {done();});', - errors: [ - { - messageId: 'noDoneCallback', - line: 1, - column: 1, - suggestions: [ - { - messageId: 'suggestWrappingInPromise', - data: { callback: 'done' }, - output: - 'beforeEach(() => {return new Promise(done => {done();})});' - } - ] - } - ] - }, - { - code: 'test.each``("something", ({ a, b }, done) => { done(); })', - errors: [ - { - messageId: 'noDoneCallback', - line: 1, - column: 1 - } - ] - }, - { - code: 'it.each``("something", ({ a, b }, done) => { done(); })', - errors: [ - { - messageId: 'noDoneCallback', - line: 1, - column: 1 - } - ] - } - ] - }) - }) -}) diff --git a/src/rules/no-duplicate-hooks.test.ts b/src/rules/no-duplicate-hooks.test.ts deleted file mode 100644 index 82a05c7..0000000 --- a/src/rules/no-duplicate-hooks.test.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-duplicate-hooks' - -describe(RULE_NAME, () => { - it(`${RULE_NAME} - single describe block`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - `describe("foo", () => { - beforeEach(() => {}) - test("bar", () => { - someFn(); - }) - })`, - `beforeEach(() => {}) - test("bar", () => { - someFn(); - })`, - `describe("foo", () => { - beforeAll(() => {}), - beforeEach(() => {}) - afterEach(() => {}) - afterAll(() => {}) - - test("bar", () => { - someFn(); - }) - })` - ], - invalid: [ - { - code: `describe("foo", () => { - beforeEach(() => {}), - beforeEach(() => {}), - test("bar", () => { - someFn(); - }) - })`, - errors: [ - { - messageId: 'noDuplicateHooks', - data: { hook: 'beforeEach' }, - column: 7, - line: 3 - } - ] - }, - { - code: ` - describe.skip("foo", () => { - afterEach(() => {}), - afterEach(() => {}), - test("bar", () => { - someFn(); - }) - }) - `, - errors: [ - { - messageId: 'noDuplicateHooks', - data: { hook: 'afterEach' }, - column: 7, - line: 4 - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} - multiple describe blocks`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - `describe.skip("foo", () => { - beforeEach(() => {}), - beforeAll(() => {}), - test("bar", () => { - someFn(); - }) - }) - describe("foo", () => { - beforeEach(() => {}), - beforeAll(() => {}), - test("bar", () => { - someFn(); - }) - })` - ], - invalid: [ - { - code: `describe.skip("foo", () => { - beforeEach(() => {}), - beforeAll(() => {}), - test("bar", () => { - someFn(); - }) - }) - describe("foo", () => { - beforeEach(() => {}), - beforeEach(() => {}), - beforeAll(() => {}), - test("bar", () => { - someFn(); - }) - })`, - errors: [ - { - messageId: 'noDuplicateHooks', - data: { hook: 'beforeEach' }, - column: 7, - line: 10 - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} - nested describe blocks`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - ` describe("foo", () => { - beforeEach(() => {}), - test("bar", () => { - someFn(); - }) - describe("inner_foo", () => { - beforeEach(() => {}) - test("inner bar", () => { - someFn(); - }) - }) - })` - ], - invalid: [ - { - code: `describe.skip("foo", () => { - beforeEach(() => {}), - beforeAll(() => {}), - test("bar", () => { - someFn(); - }) - }) - describe("foo", () => { - beforeEach(() => {}), - beforeEach(() => {}), - beforeAll(() => {}), - test("bar", () => { - someFn(); - }) - })`, - errors: [ - { - messageId: 'noDuplicateHooks', - data: { hook: 'beforeEach' }, - column: 7, - line: 10 - } - ] - } - ] - }) - }) - - it(`${RULE_NAME} - describe.each blocks`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - ` describe.each(['hello'])('%s', () => { - beforeEach(() => {}); - - it('is fine', () => {}); - });`, - `describe.each(['hello'])('%s', () => { - beforeEach(() => {}); - - it('is fine', () => {}); - });` - ], - invalid: [ - { - code: `describe.each(['hello'])('%s', () => { - beforeEach(() => {}); - beforeEach(() => {}); - - it('is not fine', () => {}); - });`, - errors: [ - { - messageId: 'noDuplicateHooks', - data: { hook: 'beforeEach' }, - column: 7, - line: 3 - } - ] - }, - { - code: ` describe('something', () => { - describe.each(['hello'])('%s', () => { - beforeEach(() => {}); - - it('is fine', () => {}); - }); - - describe.each(['world'])('%s', () => { - beforeEach(() => {}); - beforeEach(() => {}); - - it('is not fine', () => {}); - }); - });`, - errors: [ - { - messageId: 'noDuplicateHooks', - data: { hook: 'beforeEach' }, - column: 9, - line: 10 - } - ] - } - ] - }) - }) -}) diff --git a/src/rules/no-focused-tests.test.ts b/src/rules/no-focused-tests.test.ts deleted file mode 100644 index 775aaea..0000000 --- a/src/rules/no-focused-tests.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-focused-tests' - -it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: ['it("test", () => {});', 'describe("test group", () => {});'], - - invalid: [ - { - code: 'it.only("test", () => {});', - errors: [ - { - column: 4, - endColumn: 8, - endLine: 1, - line: 1, - messageId: 'noFocusedTests' - } - ], - output: 'it.only("test", () => {});' - }, - { - code: 'describe.only("test", () => {});', - errors: [ - { - column: 10, - endColumn: 14, - endLine: 1, - line: 1, - messageId: 'noFocusedTests' - } - ], - output: 'describe.only("test", () => {});' - }, - { - code: 'test.only("test", () => {});', - errors: [ - { - column: 6, - endColumn: 10, - endLine: 1, - line: 1, - messageId: 'noFocusedTests' - } - ], - output: 'test.only("test", () => {});' - }, - { - code: 'it.only.each([])("test", () => {});', - errors: [ - { - column: 4, - endColumn: 8, - endLine: 1, - line: 1, - messageId: 'noFocusedTests' - } - ], - output: 'it.only.each([])("test", () => {});' - } - ] - }) -}) diff --git a/src/rules/no-hooks.test.ts b/src/rules/no-hooks.test.ts deleted file mode 100644 index d2c3ad7..0000000 --- a/src/rules/no-hooks.test.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { it } from 'vitest' -import { HookName } from '../utils/types' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-hooks' - -it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'test("foo")', - 'describe("foo", () => { it("bar") })', - 'test("foo", () => { expect(subject.beforeEach()).toBe(true) })', - { - code: 'afterEach(() => {}); afterAll(() => {});', - options: [{ allow: [HookName.afterEach, HookName.afterAll] }] - }, - { code: 'test("foo")', options: [{ allow: undefined }] } - ], - invalid: [ - { - code: 'beforeAll(() => {})', - errors: [ - { - messageId: 'unexpectedHook', - data: { hookName: HookName.beforeAll } - } - ] - }, - { - code: 'beforeEach(() => {})', - errors: [ - { - messageId: 'unexpectedHook', - data: { hookName: HookName.beforeEach } - } - ] - }, - { - code: 'afterAll(() => {})', - errors: [ - { - messageId: 'unexpectedHook', - data: { hookName: HookName.afterAll } - } - ] - }, - { - code: 'afterEach(() => {})', - errors: [ - { - messageId: 'unexpectedHook', - data: { hookName: HookName.afterEach } - } - ] - }, - { - code: 'beforeEach(() => {}); afterEach(() => { vi.resetModules() });', - options: [{ allow: [HookName.afterEach] }], - errors: [ - { - messageId: 'unexpectedHook', - data: { hookName: HookName.beforeEach } - } - ] - }, - { - code: ` - import { beforeEach as afterEach, afterEach as beforeEach, vi } from 'vitest'; - afterEach(() => {}); - beforeEach(() => { vi.resetModules() }); - `, - options: [{ allow: [HookName.afterEach] }], - parserOptions: { sourceType: 'module' }, - errors: [ - { - messageId: 'unexpectedHook', - data: { hookName: HookName.beforeEach } - } - ] - } - ] - }) -}) diff --git a/src/rules/no-interpolation-in-snapshots.test.ts b/src/rules/no-interpolation-in-snapshots.test.ts deleted file mode 100644 index 46ffd26..0000000 --- a/src/rules/no-interpolation-in-snapshots.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-interpolation-in-snapshots' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect("something").toEqual("else");', - 'expect(something).toMatchInlineSnapshot();', - 'expect(something).toMatchInlineSnapshot(`No interpolation`);', - 'expect(something).toMatchInlineSnapshot({}, `No interpolation`);', - 'expect(something);', - 'expect(something).not;', - 'expect.toHaveAssertions();', - // eslint-disable-next-line no-template-curly-in-string - 'myObjectWants.toMatchInlineSnapshot({}, `${interpolated}`);', - // eslint-disable-next-line no-template-curly-in-string - 'myObjectWants.toMatchInlineSnapshot({}, `${interpolated1} ${interpolated2}`);', - // eslint-disable-next-line no-template-curly-in-string - 'toMatchInlineSnapshot({}, `${interpolated}`);', - // eslint-disable-next-line no-template-curly-in-string - 'toMatchInlineSnapshot({}, `${interpolated1} ${interpolated2}`);', - 'expect(something).toThrowErrorMatchingInlineSnapshot();', - 'expect(something).toThrowErrorMatchingInlineSnapshot(`No interpolation`);' - ], - invalid: [ - { - // eslint-disable-next-line no-template-curly-in-string - code: 'expect(something).toMatchInlineSnapshot(`${interpolated}`);', - errors: [ - { - messageId: 'noInterpolationInSnapshots', - column: 41, - line: 1 - } - ] - }, - { - // eslint-disable-next-line no-template-curly-in-string - code: 'expect(something).not.toMatchInlineSnapshot(`${interpolated}`);', - errors: [ - { - messageId: 'noInterpolationInSnapshots', - column: 45, - line: 1 - } - ] - }, - { - // eslint-disable-next-line no-template-curly-in-string - code: 'expect(something).toThrowErrorMatchingInlineSnapshot(`${interpolated}`);', - errors: [ - { - endColumn: 71, - column: 54, - messageId: 'noInterpolationInSnapshots' - } - ] - }, - { - // eslint-disable-next-line no-template-curly-in-string - code: 'expect(something).not.toThrowErrorMatchingInlineSnapshot(`${interpolated}`);', - errors: [ - { - endColumn: 75, - column: 58, - messageId: 'noInterpolationInSnapshots' - } - ] - } - ] - }) - }) -}) diff --git a/src/rules/no-large-snapshots.test.ts b/src/rules/no-large-snapshots.test.ts deleted file mode 100644 index ef09efc..0000000 --- a/src/rules/no-large-snapshots.test.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { TSESLint } from '@typescript-eslint/utils' -import { describe, expect, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-large-snapshots' - -const generateSnaShotLines = (lines: number) => - `\`\n${'line\n'.repeat(lines)}\`` - -const generateExportsSnapshotString = ( - lines: number, - title = 'a big component 1' -) => `exports[\`${title}\`] = ${generateSnaShotLines(lines - 1)};` - -const generateExpectInlineSnapsCode = ( - lines: number, - matcher: 'toMatchInlineSnapshot' | 'toThrowErrorMatchingInlineSnapshot' -) => `expect(something).${matcher}(${generateSnaShotLines(lines)});` - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect(something)', - 'expect(something).toBe(1)', - 'expect(something).toMatchInlineSnapshot', - 'expect(something).toMatchInlineSnapshot()', - { - filename: 'mock.js', - code: generateExpectInlineSnapsCode(2, 'toMatchInlineSnapshot') - }, - { - filename: 'mock.jsx', - code: generateExpectInlineSnapsCode(20, 'toMatchInlineSnapshot'), - options: [ - { - maxSize: 19, - inlineMaxSize: 21 - } - ] - }, - { - filename: 'mock.jsx', - code: generateExpectInlineSnapsCode(60, 'toMatchInlineSnapshot'), - options: [ - { - maxSize: 61 - } - ] - }, - { - // "it should not report snapshots that are allowed to be large" - filename: '/mock-component.jsx.snap', - code: generateExportsSnapshotString(58), - options: [ - { - allowedSnapshots: { - '/mock-component.jsx.snap': ['a big component 1'] - } - } - ] - } - ], - invalid: [ - { - filename: 'mock.js', - code: generateExpectInlineSnapsCode(50, 'toMatchInlineSnapshot'), - errors: [ - { - messageId: 'tooLongSnapShot', - data: { lineLimit: 50, lineCount: 51 } - } - ] - }, - { - filename: 'mock.js', - code: generateExpectInlineSnapsCode( - 50, - 'toThrowErrorMatchingInlineSnapshot' - ), - errors: [ - { - messageId: 'tooLongSnapShot', - data: { lineLimit: 50, lineCount: 51 } - } - ] - }, - { - filename: 'mock.js', - code: generateExpectInlineSnapsCode( - 50, - 'toThrowErrorMatchingInlineSnapshot' - ), - options: [{ maxSize: 51, inlineMaxSize: 50 }], - errors: [ - { - messageId: 'tooLongSnapShot', - data: { lineLimit: 50, lineCount: 51 } - } - ] - }, - { - // "should not report allowed large snapshots based on regexp" - filename: '/mock-component.jsx.snap', - code: [ - generateExportsSnapshotString(58, 'a big component w/ text'), - generateExportsSnapshotString(58, 'a big component 2') - ].join('\n\n'), - options: [ - { - allowedSnapshots: { - '/mock-component.jsx.snap': [/a big component \d+/u] - } - } - ], - errors: [ - { - messageId: 'tooLongSnapShot', - data: { lineLimit: 50, lineCount: 58 } - } - ] - } - ] - }) - }) -}) - -describe(RULE_NAME, () => { - describe('when "allowedSnapshots" options contains relative paths', () => { - it('should throw an exception', () => { - expect(() => { - const linter = new TSESLint.Linter() - - linter.defineRule(RULE_NAME, rule) - - linter.verify( - 'console.log()', - { - rules: { - 'no-large-snapshots': [ - 'error', - { - allowedSnapshots: { - './mock-component.jsx.snap': [/a big component \d+/u] - } - } - ] - } - }, - 'mock-component.jsx.snap' - ) - }).toThrow( - 'All paths for allowedSnapshots must be absolute. You can use JS config and `path.resolve`' - ) - }) - }) -}) diff --git a/src/rules/no-mocks-import.test.ts b/src/rules/no-mocks-import.test.ts deleted file mode 100644 index 032706a..0000000 --- a/src/rules/no-mocks-import.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-mocks-import' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'import something from "something"', - 'require("somethingElse")', - 'require("./__mocks__.js")', - 'require("./__mocks__x")', - 'require("./__mocks__x/x")', - 'require("./x__mocks__")', - 'require("./x__mocks__/x")', - 'require()', - 'var path = "./__mocks__.js"; require(path)', - 'entirelyDifferent(fn)' - ], - invalid: [ - { - code: 'require("./__mocks__")', - errors: [{ endColumn: 22, column: 9, messageId: 'noMocksImport' }] - }, - { - code: 'require("./__mocks__/")', - errors: [{ endColumn: 23, column: 9, messageId: 'noMocksImport' }] - }, - { - code: 'require("./__mocks__/index")', - errors: [{ endColumn: 28, column: 9, messageId: 'noMocksImport' }] - }, - { - code: 'require("__mocks__")', - errors: [{ endColumn: 20, column: 9, messageId: 'noMocksImport' }] - }, - { - code: 'require("__mocks__/")', - errors: [{ endColumn: 21, column: 9, messageId: 'noMocksImport' }] - }, - { - code: 'require("__mocks__/index")', - errors: [{ endColumn: 26, column: 9, messageId: 'noMocksImport' }] - }, - { - code: 'import thing from "./__mocks__/index"', - parserOptions: { sourceType: 'module' }, - errors: [{ endColumn: 38, column: 1, messageId: 'noMocksImport' }] - } - ] - }) - }) -}) diff --git a/src/rules/no-restricted-matchers.test.ts b/src/rules/no-restricted-matchers.test.ts deleted file mode 100644 index 8358dab..0000000 --- a/src/rules/no-restricted-matchers.test.ts +++ /dev/null @@ -1,210 +0,0 @@ -import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-restricted-matchers' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect(a).toHaveBeenCalled()', - 'expect(a).not.toHaveBeenCalled()', - 'expect(a).toHaveBeenCalledTimes()', - 'expect(a).toHaveBeenCalledWith()', - 'expect(a).toHaveBeenLastCalledWith()', - 'expect(a).toHaveBeenNthCalledWith()', - 'expect(a).toHaveReturned()', - 'expect(a).toHaveReturnedTimes()', - 'expect(a).toHaveReturnedWith()', - 'expect(a).toHaveLastReturnedWith()', - 'expect(a).toHaveNthReturnedWith()', - 'expect(a).toThrow()', - 'expect(a).rejects;', - 'expect(a);', - { - code: 'expect(a).resolves', - options: [{ not: null }] - }, - { - code: 'expect(a).toBe(b)', - options: [{ 'not.toBe': null }] - }, - { - code: 'expect(a).toBeUndefined(b)', - options: [{ toBe: null }] - }, - { - code: 'expect(a)["toBe"](b)', - options: [{ 'not.toBe': null }] - }, - { - code: 'expect(a).resolves.not.toBe(b)', - options: [{ not: null }] - }, - { - code: 'expect(a).resolves.not.toBe(b)', - options: [{ 'not.toBe': null }] - } - ], - invalid: [ - { - code: 'expect(a).not.toBe(b)', - options: [{ not: null }], - errors: [ - { - messageId: 'restrictedChain', - data: { - message: null, - restriction: 'not' - }, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).resolves.toBe(b)', - options: [{ resolves: null }], - errors: [ - { - messageId: 'restrictedChain', - data: { - message: null, - restriction: 'resolves' - }, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).resolves.not.toBe(b)', - options: [{ resolves: null }], - errors: [ - { - messageId: 'restrictedChain', - data: { - message: null, - restriction: 'resolves' - }, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).resolves.not.toBe(b)', - options: [{ 'resolves.not': null }], - errors: [ - { - messageId: 'restrictedChain', - data: { - message: null, - restriction: 'resolves.not' - }, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).not.toBe(b)', - options: [{ 'not.toBe': null }], - errors: [ - { - messageId: 'restrictedChain', - data: { - message: null, - restriction: 'not.toBe' - }, - endColumn: 19, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).resolves.not.toBe(b)', - options: [{ 'resolves.not.toBe': null }], - errors: [ - { - messageId: 'restrictedChain', - data: { - message: null, - restriction: 'resolves.not.toBe' - }, - endColumn: 28, - column: 11, - line: 1 - } - ] - }, - { - code: 'expect(a).toBe(b)', - options: [{ toBe: 'Prefer `toStrictEqual` instead' }], - errors: [ - { - messageId: 'restrictedChainWithMessage', - data: { - message: 'Prefer `toStrictEqual` instead', - restriction: 'toBe' - }, - column: 11, - line: 1 - } - ] - }, - { - code: ` - test('some test', async () => { - await expect(Promise.resolve(1)).resolves.toBe(1); - }); - `, - options: [{ resolves: 'Use `expect(await promise)` instead.' }], - errors: [ - { - messageId: 'restrictedChainWithMessage', - data: { - message: 'Use `expect(await promise)` instead.', - restriction: 'resolves' - }, - endColumn: 53, - column: 40 - } - ] - }, - { - code: 'expect(Promise.resolve({})).rejects.toBeFalsy()', - options: [{ 'rejects.toBeFalsy': null }], - errors: [ - { - messageId: 'restrictedChain', - data: { - message: null, - restriction: 'rejects.toBeFalsy' - }, - endColumn: 46, - column: 29 - } - ] - }, - { - code: 'expect(uploadFileMock).not.toHaveBeenCalledWith(\'file.name\')', - options: [ - { 'not.toHaveBeenCalledWith': 'Use not.toHaveBeenCalled instead' } - ], - errors: [ - { - messageId: 'restrictedChainWithMessage', - data: { - message: 'Use not.toHaveBeenCalled instead', - restriction: 'not.toHaveBeenCalledWith' - }, - endColumn: 48, - column: 24 - } - ] - } - ] - }) - }) -}) diff --git a/src/rules/no-restricted-vi-methods.test.ts b/src/rules/no-restricted-vi-methods.test.ts deleted file mode 100644 index 5cb1430..0000000 --- a/src/rules/no-restricted-vi-methods.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-restricted-vi-methods' - -it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'vi', - 'vi()', - 'vi.mock()', - 'expect(a).rejects;', - 'expect(a);', - { - code: ` - import { vi } from 'vitest'; - vi; - `, - parserOptions: { sourceType: 'module' } - } - ], - - invalid: [ - { - code: 'vi.fn()', - options: [{ fn: null }], - errors: [ - { - messageId: 'restrictedViMethod', - data: { - message: null, - restriction: 'fn' - }, - column: 4, - line: 1 - } - ] - }, - { - code: 'vi.mock()', - options: [{ mock: 'Do not use mocks' }], - errors: [ - { - messageId: 'restrictedViMethodWithMessage', - data: { - message: 'Do not use mocks', - restriction: 'mock' - }, - column: 4, - line: 1 - } - ] - }, - { - code: ` - import { vi } from 'vitest'; - vi.advanceTimersByTime(); - `, - options: [{ advanceTimersByTime: null }], - parserOptions: { sourceType: 'module' }, - errors: [ - { - messageId: 'restrictedViMethod', - data: { - message: null, - restriction: 'advanceTimersByTime' - }, - column: 9, - line: 3 - } - ] - }, - { - code: 'vi["fn"]()', - options: [{ fn: null }], - errors: [ - { - messageId: 'restrictedViMethod', - data: { - message: null, - restriction: 'fn' - }, - column: 4, - line: 1 - } - ] - } - ] - }) -}) diff --git a/src/rules/prefer-lowercase-title.test.ts b/src/rules/prefer-lowercase-title.test.ts deleted file mode 100644 index 142aba7..0000000 --- a/src/rules/prefer-lowercase-title.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { describe, it } from 'vitest' -import { TestCaseName } from '../utils/types' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './prefer-lowercase-title' - -describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'it.each()', - 'it.each()(1)', - 'it.todo();', - 'describe("oo", function () {})', - 'test("foo", function () {})', - 'test(`123`, function () {})' - ], - invalid: [ - { - code: 'it("Foo MM mm", function () {})', - output: 'it("foo MM mm", function () {})', - errors: [ - { - messageId: 'lowerCaseTitle', - data: { - method: TestCaseName.it - } - } - ] - }, - { - code: 'test(`Foo MM mm`, function () {})', - output: 'test(`foo MM mm`, function () {})', - errors: [ - { - messageId: 'lowerCaseTitle', - data: { - method: TestCaseName.test - } - } - ] - }, - { - code: 'test(`SFC Compile`, function () {})', - output: 'test(`sfc compile`, function () {})', - errors: [ - { - messageId: 'lowerCaseTitle', - data: { - method: TestCaseName.test - } - } - ], - options: [ - { - lowercaseFirstCharacterOnly: false - } - ] - } - ] - }) - }) -}) diff --git a/src/rules/prefer-to-be.test.ts b/src/rules/prefer-to-be.test.ts deleted file mode 100644 index 4830dbd..0000000 --- a/src/rules/prefer-to-be.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { it, describe } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './prefer-to-be' - -describe(RULE_NAME, () => { - it(`${RULE_NAME} toBe`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect(null).toBeNull();', - 'expect(null).not.toBeNull();', - 'expect(null).toBe(1);', - 'expect(null).toBe(-1);', - 'expect(null).toBe(1);', - 'expect(obj).toStrictEqual([ x, 1 ]);', - 'expect(obj).toStrictEqual({ x: 1 });', - 'expect(obj).not.toStrictEqual({ x: 1 });', - 'expect(value).toMatchSnapshot();', - 'expect(catchError()).toStrictEqual({ message: \'oh noes!\' })', - 'expect("something");', - 'expect(token).toStrictEqual(/[abc]+/g);', - 'expect(token).toStrictEqual(new RegExp(\'[abc]+\', \'g\'));', - 'expect(0.1 + 0.2).toEqual(0.3);' - ], - invalid: [ - { - code: 'expect(value).toEqual("my string");', - output: 'expect(value).toBe("my string");', - errors: [{ messageId: 'useToBe' }] - }, - { - code: 'expect("a string").not.toEqual(null);', - output: 'expect("a string").not.toBeNull();', - errors: [{ messageId: 'useToBeNull', column: 24, line: 1 }] - }, - { - code: 'expect("a string").not.toStrictEqual(null);', - output: 'expect("a string").not.toBeNull();', - errors: [{ messageId: 'useToBeNull', column: 24, line: 1 }] - } - ] - }) - }) - - it(`${RULE_NAME} NaN`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect(NaN).toBeNaN();', - 'expect(true).not.toBeNaN();', - 'expect({}).toEqual({});', - 'expect(something).toBe()', - 'expect(something).toBe(somethingElse)', - 'expect(something).toEqual(somethingElse)', - 'expect(something).not.toBe(somethingElse)', - 'expect(something).not.toEqual(somethingElse)', - 'expect(undefined).toBe', - 'expect("something");' - ], - invalid: [ - { - code: 'expect(NaN).toBe(NaN);', - output: 'expect(NaN).toBeNaN();', - errors: [{ messageId: 'useToBeNaN', column: 13, line: 1 }] - }, - { - code: 'expect("a string").not.toBe(NaN);', - output: 'expect("a string").not.toBeNaN();', - errors: [{ messageId: 'useToBeNaN', column: 24, line: 1 }] - }, - { - code: 'expect("a string").not.toStrictEqual(NaN);', - output: 'expect("a string").not.toBeNaN();', - errors: [{ messageId: 'useToBeNaN', column: 24, line: 1 }] - } - ] - }) - }) - - it(`${RULE_NAME} null`, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect(null).toBeNull();', - 'expect(null).not.toBeNull();', - 'expect(null).toBe(1);', - 'expect(obj).toStrictEqual([ x, 1 ]);', - 'expect(obj).toStrictEqual({ x: 1 });', - 'expect(obj).not.toStrictEqual({ x: 1 });' - ], - invalid: [ - { - code: 'expect(null).toBe(null);', - output: 'expect(null).toBeNull();', - errors: [{ messageId: 'useToBeNull', column: 14, line: 1 }] - }, - { - code: 'expect(null).toEqual(null);', - output: 'expect(null).toBeNull();', - parserOptions: { ecmaVersion: 2017 }, - errors: [{ messageId: 'useToBeNull', column: 14, line: 1 }] - }, - { - code: 'expect("a string").not.toEqual(null as number);', - output: 'expect("a string").not.toBeNull();', - errors: [{ messageId: 'useToBeNull', column: 24, line: 1 }] - }, - { - code: 'expect(undefined).toBe(undefined as unknown as string as any);', - output: 'expect(undefined).toBeUndefined();', - errors: [{ messageId: 'useToBeUndefined', column: 19, line: 1 }] - }, - { - code: 'expect("a string").toEqual(undefined as number);', - output: 'expect("a string").toBeUndefined();', - errors: [{ messageId: 'useToBeUndefined', column: 20, line: 1 }] - } - ] - }) - }) -}) diff --git a/src/rules/valid-expect.test.ts b/src/rules/valid-expect.test.ts deleted file mode 100644 index 47ed855..0000000 --- a/src/rules/valid-expect.test.ts +++ /dev/null @@ -1,852 +0,0 @@ -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './valid-expect' - -// describe(RULE_NAME, () => { -// test(RULE_NAME + ' in promise', () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'expect.hasAssertions', - 'expect.hasAssertions()', - 'expect("something").toEqual("else");', - 'expect(true).toBeDefined();', - 'expect([1, 2, 3]).toEqual([1, 2, 3]);', - 'expect(undefined).not.toBeDefined();', - 'test("valid-expect", () => { return expect(Promise.resolve(2)).resolves.toBeDefined(); });', - 'test("valid-expect", () => { return expect(Promise.reject(2)).rejects.toBeDefined(); });', - 'test("valid-expect", () => { return expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', - 'test("valid-expect", () => { return expect(Promise.resolve(2)).rejects.not.toBeDefined(); });', - 'test("valid-expect", function () { return expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', - 'test("valid-expect", function () { return expect(Promise.resolve(2)).rejects.not.toBeDefined(); });', - 'test("valid-expect", function () { return Promise.resolve(expect(Promise.resolve(2)).resolves.not.toBeDefined()); });', - 'test("valid-expect", function () { return Promise.resolve(expect(Promise.resolve(2)).rejects.not.toBeDefined()); });', - 'test("valid-expect", () => expect(Promise.resolve(2)).resolves.toBeDefined());', - 'test("valid-expect", () => expect(Promise.resolve(2)).resolves.toBeDefined());', - 'test("valid-expect", () => expect(Promise.reject(2)).rejects.toBeDefined());', - 'test("valid-expect", () => expect(Promise.reject(2)).resolves.not.toBeDefined());', - 'test("valid-expect", () => expect(Promise.reject(2)).rejects.not.toBeDefined());', - 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined(); });', - 'test("valid-expect", async () => { await expect(Promise.reject(2)).rejects.not.toBeDefined(); });', - 'test("valid-expect", async function () { await expect(Promise.reject(2)).resolves.not.toBeDefined(); });', - 'test("valid-expect", async function () { await expect(Promise.reject(2)).rejects.not.toBeDefined(); });', - 'test("valid-expect", async () => { await Promise.resolve(expect(Promise.reject(2)).rejects.not.toBeDefined()); });', - 'test("valid-expect", async () => { await Promise.reject(expect(Promise.reject(2)).rejects.not.toBeDefined()); });', - 'test("valid-expect", async () => { await Promise.all([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', - 'test("valid-expect", async () => { await Promise.race([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', - 'test("valid-expect", async () => { await Promise.allSettled([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', - 'test("valid-expect", async () => { await Promise.any([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', - 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")); });', - 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).then(() => console.log("another valid case")); });', - 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().catch(() => console.log("valid-case")); });', - 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).catch(() => console.log("another valid case")); });', - 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => { expect(someMock).toHaveBeenCalledTimes(1); }); });', - 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")); });', - 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).then(() => console.log("another valid case")); });', - 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().catch(() => console.log("valid-case")); });', - 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).catch(() => console.log("another valid case")); });', - 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => { expect(someMock).toHaveBeenCalledTimes(1); }); });', - ` test("valid-expect", () => { - return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => { - return expect(Promise.resolve(2)).resolves.toBe(1); - }); - }); - `, - ` test("valid-expect", () => { - return expect(functionReturningAPromise()).resolves.toEqual(1).then(async () => { - await expect(Promise.resolve(2)).resolves.toBe(1); - }); - }); - `, - ` test("valid-expect", () => { - return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => expect(Promise.resolve(2)).resolves.toBe(1)); - }); - `, - ` expect.extend({ - toResolve(obj) { - return this.isNot - ? expect(obj).toBe(true) - : expect(obj).resolves.not.toThrow(); - } - }); - `, - ` expect.extend({ - toResolve(obj) { - return this.isNot - ? expect(obj).resolves.not.toThrow() - : expect(obj).toBe(true); - } - }); - `, - ` expect.extend({ - toResolve(obj) { - return this.isNot - ? expect(obj).toBe(true) - : anotherCondition - ? expect(obj).resolves.not.toThrow() - : expect(obj).toBe(false) - } - }); - `, - { - code: 'expect(1).toBe(2);', - options: [{ maxArgs: 2 }] - }, - { - code: 'expect(1, "1 !== 2").toBe(2);', - options: [{ maxArgs: 2 }] - }, - { - code: 'test("valid-expect", () => { expect(2).not.toBe(2); });', - options: [{ asyncMatchers: ['toRejectWith'] }] - }, - { - code: 'test("valid-expect", () => { expect(Promise.reject(2)).toRejectWith(2); });', - options: [{ asyncMatchers: ['toResolveWith'] }] - }, - { - code: 'test("valid-expect", async () => { await expect(Promise.resolve(2)).toResolve(); });', - options: [{ asyncMatchers: ['toResolveWith'] }] - }, - { - code: 'test("valid-expect", async () => { expect(Promise.resolve(2)).toResolve(); });', - options: [{ asyncMatchers: ['toResolveWith'] }] - } - ], - invalid: [ - { - code: 'expect().toBe(2);', - options: [{ minArgs: undefined, maxArgs: undefined }], - errors: [ - { - messageId: 'notEnoughArgs', - data: { - s: '', - amount: 1 - } - } - ] - }, - { - code: 'expect().toBe(true);', - errors: [ - { - endColumn: 8, - column: 7, - messageId: 'notEnoughArgs', - data: { - s: '', - amount: 1 - } - } - ] - }, - { - code: 'expect().toEqual("something");', - errors: [ - { - endColumn: 8, - column: 7, - messageId: 'notEnoughArgs', - data: { - s: '', - amount: 1 - } - } - ] - }, - { - code: 'expect("something", "else").toEqual("something");', - errors: [ - { - endColumn: 28, - column: 21, - messageId: 'tooManyArgs', - data: { - s: '', - amount: 1 - } - } - ] - }, - { - code: 'expect("something", "else", "entirely").toEqual("something");', - options: [{ maxArgs: 2 }], - errors: [ - { - endColumn: 40, - column: 29, - messageId: 'tooManyArgs', - data: { - s: 's', - amount: 2 - } - } - ] - }, - { - code: 'expect("something", "else", "entirely").toEqual("something");', - options: [{ maxArgs: 2, minArgs: 2 }], - errors: [ - { - endColumn: 40, - column: 29, - messageId: 'tooManyArgs', - data: { - s: 's', - amount: 2 - } - } - ] - }, - { - code: 'expect("something", "else", "entirely").toEqual("something");', - options: [{ maxArgs: 2, minArgs: 1 }], - errors: [ - { - endColumn: 40, - column: 29, - messageId: 'tooManyArgs', - data: { - s: 's', - amount: 2 - } - } - ] - }, - { - code: 'expect("something").toEqual("something");', - options: [{ minArgs: 2 }], - errors: [ - { - endColumn: 8, - column: 7, - messageId: 'notEnoughArgs', - data: { - s: 's', - amount: 2 - } - } - ] - }, - { - code: 'expect("something", "else").toEqual("something");', - options: [{ maxArgs: 1, minArgs: 3 }], - errors: [ - { - endColumn: 8, - column: 7, - messageId: 'notEnoughArgs', - data: { - s: 's', - amount: 3 - } - }, - { - endColumn: 28, - column: 21, - messageId: 'tooManyArgs', - data: { - s: '', - amount: 1 - } - } - ] - }, - { - code: 'expect("something");', - errors: [{ endColumn: 20, column: 1, messageId: 'matcherNotFound' }] - }, - { - code: 'expect();', - errors: [{ endColumn: 9, column: 1, messageId: 'matcherNotFound' }] - }, - { - code: 'expect(true).toBeDefined;', - errors: [ - { - endColumn: 25, - column: 14, - messageId: 'matcherNotCalled' - } - ] - }, - { - code: 'expect(true).not.toBeDefined;', - errors: [ - { - endColumn: 29, - column: 18, - messageId: 'matcherNotCalled' - } - ] - }, - { - code: 'expect(true).nope.toBeDefined;', - errors: [ - { - endColumn: 30, - column: 19, - messageId: 'matcherNotCalled' - } - ] - }, - { - code: 'expect(true).nope.toBeDefined();', - errors: [ - { - endColumn: 32, - column: 1, - messageId: 'modifierUnknown' - } - ] - }, - { - code: 'expect(true).not.resolves.toBeDefined();', - errors: [ - { - endColumn: 40, - column: 1, - messageId: 'modifierUnknown' - } - ] - }, - { - code: 'expect(true).not.not.toBeDefined();', - errors: [ - { - endColumn: 35, - column: 1, - messageId: 'modifierUnknown' - } - ] - }, - { - code: 'expect(true).resolves.not.exactly.toBeDefined();', - errors: [ - { - endColumn: 48, - column: 1, - messageId: 'modifierUnknown' - } - ] - }, - { - code: 'expect(true).resolves;', - errors: [ - { - endColumn: 22, - column: 14, - messageId: 'matcherNotFound' - } - ] - }, - { - code: 'expect(true).rejects;', - errors: [ - { - endColumn: 21, - column: 14, - messageId: 'matcherNotFound' - } - ] - }, - { - code: 'expect(true).not;', - errors: [ - { - endColumn: 17, - column: 14, - messageId: 'matcherNotFound' - } - ] - }, - { - code: 'expect(Promise.resolve(2)).resolves.toBeDefined();', - errors: [ - { - column: 1, - endColumn: 50, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'expect(Promise.resolve(2)).rejects.toBeDefined();', - errors: [ - { - column: 1, - endColumn: 49, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'expect(Promise.resolve(2)).resolves.toBeDefined();', - options: [{ alwaysAwait: true }], - errors: [ - { - column: 1, - endColumn: 50, - messageId: 'asyncMustBeAwaited' - } - ] - }, - { - code: ` - expect.extend({ - toResolve(obj) { - this.isNot - ? expect(obj).toBe(true) - : expect(obj).resolves.not.toThrow(); - } - }); - `, - errors: [ - { - column: 11, - endColumn: 45, - messageId: 'asyncMustBeAwaited' - } - ] - }, - { - code: ` - expect.extend({ - toResolve(obj) { - this.isNot - ? expect(obj).resolves.not.toThrow() - : expect(obj).toBe(true); - } - }); - `, - errors: [ - { - column: 11, - endColumn: 45, - messageId: 'asyncMustBeAwaited' - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).resolves.toBeDefined(); });', - errors: [ - { - column: 30, - endColumn: 79, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).toResolve(); });', - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 30, - line: 1 - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).toResolve(); });', - options: [{ asyncMatchers: undefined }], - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 30, - line: 1 - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).toReject(); });', - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 30, - line: 1 - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).not.toReject(); });', - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 30, - line: 1 - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', - errors: [ - { - column: 30, - endColumn: 83, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).rejects.toBeDefined(); });', - errors: [ - { - column: 30, - endColumn: 78, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.resolve(2)).rejects.not.toBeDefined(); });', - errors: [ - { - column: 30, - endColumn: 82, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'test("valid-expect", async () => { expect(Promise.resolve(2)).resolves.toBeDefined(); });', - errors: [ - { - column: 36, - endColumn: 85, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'test("valid-expect", async () => { expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', - errors: [ - { - column: 36, - endColumn: 89, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.reject(2)).toRejectWith(2); });', - options: [{ asyncMatchers: ['toRejectWith'] }], - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 30 - } - ] - }, - { - code: 'test("valid-expect", () => { expect(Promise.reject(2)).rejects.toBe(2); });', - options: [{ asyncMatchers: ['toRejectWith'] }], - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 30 - } - ] - }, - { - code: ` - test("valid-expect", async () => { - expect(Promise.resolve(2)).resolves.not.toBeDefined(); - expect(Promise.resolve(1)).rejects.toBeDefined(); - }); - `, - errors: [ - { - line: 3, - column: 7, - endColumn: 60, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - }, - { - line: 4, - column: 7, - endColumn: 55, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", async () => { - await expect(Promise.resolve(2)).resolves.not.toBeDefined(); - expect(Promise.resolve(1)).rejects.toBeDefined(); - }); - `, - errors: [ - { - line: 4, - column: 7, - endColumn: 55, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", async () => { - expect(Promise.resolve(2)).resolves.not.toBeDefined(); - return expect(Promise.resolve(1)).rejects.toBeDefined(); - }); - `, - options: [{ alwaysAwait: true }], - errors: [ - { - line: 3, - column: 7, - endColumn: 60, - messageId: 'asyncMustBeAwaited' - }, - { - line: 4, - column: 14, - endColumn: 62, - messageId: 'asyncMustBeAwaited' - } - ] - }, - { - code: ` - test("valid-expect", async () => { - expect(Promise.resolve(2)).resolves.not.toBeDefined(); - return expect(Promise.resolve(1)).rejects.toBeDefined(); - }); - `, - errors: [ - { - line: 3, - column: 7, - endColumn: 60, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", () => { - Promise.x(expect(Promise.resolve(2)).resolves.not.toBeDefined()); - }); - `, - errors: [ - { - line: 3, - column: 7, - endColumn: 71, - messageId: 'promisesWithAsyncAssertionsMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", () => { - Promise.resolve(expect(Promise.resolve(2)).resolves.not.toBeDefined()); - }); - `, - options: [{ alwaysAwait: true }], - errors: [ - { - line: 3, - column: 8, - endColumn: 78, - messageId: 'promisesWithAsyncAssertionsMustBeAwaited' - } - ] - }, - { - code: ` - test("valid-expect", () => { - Promise.all([ - expect(Promise.resolve(2)).resolves.not.toBeDefined(), - expect(Promise.resolve(3)).resolves.not.toBeDefined(), - ]); - }); - `, - errors: [ - { - line: 3, - column: 7, - endLine: 6, - endColumn: 9, - messageId: 'promisesWithAsyncAssertionsMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", () => { - Promise.x([ - expect(Promise.resolve(2)).resolves.not.toBeDefined(), - expect(Promise.resolve(3)).resolves.not.toBeDefined(), - ]); - });`, - errors: [ - { - line: 3, - column: 7, - endLine: 6, - endColumn: 9, - messageId: 'promisesWithAsyncAssertionsMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", () => { - const assertions = [ - expect(Promise.resolve(2)).resolves.not.toBeDefined(), - expect(Promise.resolve(3)).resolves.not.toBeDefined(), - ] - }); - `, - errors: [ - { - line: 4, - column: 9, - endLine: 4, - endColumn: 62, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - }, - { - line: 5, - column: 9, - endLine: 5, - endColumn: 62, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", () => { - const assertions = [ - expect(Promise.resolve(2)).toResolve(), - expect(Promise.resolve(3)).toReject(), - ] - }); - `, - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 7, - line: 4 - }, - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 7, - line: 5 - } - ] - }, - { - code: ` - test("valid-expect", () => { - const assertions = [ - expect(Promise.resolve(2)).not.toResolve(), - expect(Promise.resolve(3)).resolves.toReject(), - ] - }); - `, - errors: [ - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 9, - line: 4 - }, - { - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' }, - column: 9, - line: 5 - } - ] - }, - { - code: 'expect(Promise.resolve(2)).resolves.toBe;', - errors: [ - { - column: 37, - endColumn: 41, - messageId: 'matcherNotCalled' - } - ] - }, - { - code: ` - test("valid-expect", () => { - return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => { - expect(Promise.resolve(2)).resolves.toBe(1); - }); - }); - `, - errors: [ - { - line: 4, - column: 9, - endLine: 4, - endColumn: 52, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", () => { - return expect(functionReturningAPromise()).resolves.toEqual(1).then(async () => { - await expect(Promise.resolve(2)).resolves.toBe(1); - expect(Promise.resolve(4)).resolves.toBe(4); - }); - }); - `, - errors: [ - { - line: 5, - column: 9, - endLine: 5, - endColumn: 52, - messageId: 'asyncMustBeAwaited', - data: { orReturned: ' or returned' } - } - ] - }, - { - code: ` - test("valid-expect", async () => { - await expect(Promise.resolve(1)); - }); - `, - errors: [{ endColumn: 39, column: 13, messageId: 'matcherNotFound' }] - } - ] - }) -// }) -// }) diff --git a/src/utils/tester.ts b/src/utils/tester.ts deleted file mode 100644 index 57fa65b..0000000 --- a/src/utils/tester.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { TSESLint } from '@typescript-eslint/utils' - -const ruleTester = new TSESLint.RuleTester({ - parser: require.resolve('@typescript-eslint/parser') -}) - -export default ruleTester diff --git a/tests/consistent-test-filename.test.ts b/tests/consistent-test-filename.test.ts new file mode 100644 index 0000000..3ddc9e4 --- /dev/null +++ b/tests/consistent-test-filename.test.ts @@ -0,0 +1,25 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/consistent-test-filename' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(`${RULE_NAME}`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + { + code: 'export {}', + filename: '1.test.ts', + options: [{ pattern: String.raw`.*\.test\.ts$` }] + } + ], + invalid: [ + { + code: 'export {}', + filename: '1.spec.ts', + errors: [{ messageId: 'msg' }], + options: [{ pattern: String.raw`.*\.test\.ts$` }] + } + ] + }) + }) +}) diff --git a/tests/consistent-test-it.test.ts b/tests/consistent-test-it.test.ts new file mode 100644 index 0000000..af243d7 --- /dev/null +++ b/tests/consistent-test-it.test.ts @@ -0,0 +1,301 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/consistent-test-it' +import { TestCaseName } from '../src/utils/types' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(`${RULE_NAME} - fn=it`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + { + code: `it("shows error", () => { + expect(true).toBe(false); + });`, + options: [{ fn: TestCaseName.it }] + }, + { + code: `it("foo", function () { + expect(true).toBe(false); + })`, + options: [{ fn: TestCaseName.it }] + }, + { + code: ` it('foo', () => { + expect(true).toBe(false); + }); + function myTest() { if ('bar') {} }`, + options: [{ fn: TestCaseName.it }] + } + ], + invalid: [ + { + code: 'test("shows error", () => {});', + options: [{ fn: TestCaseName.it }], + output: 'it("shows error", () => {});', + errors: [{ messageId: 'consistentMethod' }] + }, + { + code: 'test.skip("shows error");', + output: 'it.skip("shows error");', + options: [{ fn: TestCaseName.it }], + errors: [ + { + messageId: 'consistentMethod', + data: { + testFnKeyWork: TestCaseName.it, + oppositeTestKeyword: TestCaseName.test + } + } + ] + }, + { + code: 'test.only(\'shows error\');', + output: 'it.only(\'shows error\');', + options: [{ fn: TestCaseName.it }], + errors: [ + { + messageId: 'consistentMethod', + data: { + testFnKeyWork: TestCaseName.it, + oppositeTestKeyword: TestCaseName.test + } + } + ] + }, + { + code: 'describe(\'foo\', () => { it(\'bar\', () => {}); });', + output: 'describe(\'foo\', () => { test(\'bar\', () => {}); });', + options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.test }], + errors: [ + { + messageId: 'consistentMethodWithinDescribe', + data: { + testKeywordWithinDescribe: TestCaseName.test, + oppositeTestKeyword: TestCaseName.it + } + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} - fn=test`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + { + code: `test("shows error", () => { + expect(true).toBe(false); + });`, + options: [{ fn: TestCaseName.test }] + }, + { + code: 'test.skip("foo")', + options: [{ fn: TestCaseName.test }] + }, + { + code: 'test.concurrent("foo")', + options: [{ fn: TestCaseName.test }] + }, + { + code: 'xtest("foo")', + options: [{ fn: TestCaseName.test }] + }, + { + code: 'test.each([])("foo")', + options: [{ fn: TestCaseName.test }] + }, + { + code: 'test.each``("foo")', + options: [{ fn: TestCaseName.test }] + }, + { + code: 'describe("suite", () => { test("foo") })', + options: [{ fn: TestCaseName.test }] + } + ], + invalid: [ + { + code: 'it("shows error", () => {});', + options: [{ fn: TestCaseName.test }], + output: 'test("shows error", () => {});', + errors: [{ messageId: 'consistentMethod' }] + }, + { + code: 'describe("suite", () => { it("foo") })', + output: 'describe("suite", () => { test("foo") })', + options: [{ fn: TestCaseName.test }], + errors: [ + { + messageId: 'consistentMethodWithinDescribe', + data: { + testKeywordWithinDescribe: TestCaseName.test, + oppositeTestKeyword: TestCaseName.it + } + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} - with fn=it and withinDescribe=it`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + { + code: 'describe("suite", () => { it("foo") })', + options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }] + }, + { + code: 'it("foo")', + options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }] + } + ], + invalid: [ + { + code: 'describe("suite", () => { test("foo") })', + output: 'describe("suite", () => { it("foo") })', + options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }], + errors: [ + { + messageId: 'consistentMethodWithinDescribe', + data: { + testKeywordWithinDescribe: TestCaseName.it, + oppositeTestKeyword: TestCaseName.test + } + } + ] + }, + { + code: 'test("foo")', + output: 'it("foo")', + options: [{ fn: TestCaseName.it, withinDescribe: TestCaseName.it }], + errors: [ + { + messageId: 'consistentMethod', + data: { + testFnKeyWork: TestCaseName.it, + oppositeTestKeyword: TestCaseName.test + } + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} defaults without config object`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + { + code: 'test("shows error", () => {});' + } + ], + invalid: [ + { + code: 'describe("suite", () => { test("foo") })', + output: 'describe("suite", () => { it("foo") })', + errors: [ + { + messageId: 'consistentMethodWithinDescribe', + data: { + testKeywordWithinDescribe: TestCaseName.it, + oppositeTestKeyword: TestCaseName.test + } + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} - with withinDescribe=it`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + { + code: 'test("foo")', + options: [{ withinDescribe: TestCaseName.it }] + }, + { + code: 'describe("suite", () => { it("foo") })', + options: [{ withinDescribe: TestCaseName.it }] + } + ], + invalid: [ + { + code: 'it("foo")', + output: 'test("foo")', + options: [{ withinDescribe: TestCaseName.it }], + errors: [ + { + messageId: 'consistentMethod', + data: { + testFnKeyWork: TestCaseName.test, + oppositeTestKeyword: TestCaseName.it + } + } + ] + }, + { + code: 'describe("suite", () => { test("foo") })', + output: 'describe("suite", () => { it("foo") })', + options: [{ withinDescribe: TestCaseName.it }], + errors: [ + { + messageId: 'consistentMethodWithinDescribe', + data: { + testKeywordWithinDescribe: TestCaseName.it, + oppositeTestKeyword: TestCaseName.test + } + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} - with withinDescribe=test`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + { + code: 'test("foo")', + options: [{ withinDescribe: TestCaseName.test }] + }, + { + code: 'describe("suite", () => { test("foo") })', + options: [{ withinDescribe: TestCaseName.test }] + } + ], + invalid: [ + { + code: 'it("foo")', + output: 'test("foo")', + options: [{ withinDescribe: TestCaseName.test }], + errors: [ + { + messageId: 'consistentMethod', + data: { + testFnKeyWork: TestCaseName.test, + oppositeTestKeyword: TestCaseName.it + } + } + ] + }, + { + code: 'describe("suite", () => { it("foo") })', + output: 'describe("suite", () => { test("foo") })', + options: [{ withinDescribe: TestCaseName.test }], + errors: [ + { + messageId: 'consistentMethodWithinDescribe', + data: { + testKeywordWithinDescribe: TestCaseName.test, + oppositeTestKeyword: TestCaseName.it + } + } + ] + } + ] + }) + }) +}) diff --git a/tests/expect-expect.test.ts b/tests/expect-expect.test.ts new file mode 100644 index 0000000..b5b55c7 --- /dev/null +++ b/tests/expect-expect.test.ts @@ -0,0 +1,73 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/expect-expect' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + `test("shows error", () => { + expect(true).toBe(false); + });`, + `it("foo", function () { + expect(true).toBe(false); + })`, + `it('foo', () => { + expect(true).toBe(false); + }); + function myTest() { if ('bar') {} }`, + `function myTest(param) {} + describe('my test', () => { + it('should do something', () => { + myTest("num"); + expect(1).toEqual(1); + }); + });`, + `const myFunc = () => {}; + it("works", () => expect(myFunc()).toBe(undefined));`, + `describe('title', () => { + it('test is not ok', () => { + [1, 2, 3, 4, 5, 6].forEach((n) => { + expect(n).toBe(1); + }); + }); + });`, + `desctibe('title', () => { + test('some test', () => { + expect(obj1).not.toEqual(obj2); + }) + })`, + 'it("should pass", () => expect(true).toBeDefined())', + `const myFunc = () => {}; + it("works", () => expect(myFunc()).toBe(undefined));`, + `const myFunc = () => {}; + it("works", () => expect(myFunc()).toBe(undefined));` + ], + invalid: [ + { + code: 'test("shows error", () => {});', + errors: [{ messageId: 'expectedExpect' }] + }, + { + code: `it("foo", function () { + if (1 === 2) {} + })`, + errors: [{ messageId: 'expectedExpect' }] + }, + { + code: `import { it } from 'vitest'; + describe('Button with increment', () => { + it('should show name props', () => { + console.log('test with missing expect'); + }); + });`, + errors: [{ messageId: 'expectedExpect' }] + }, + { + code: 'it("should also fail",() => expectSaga(mySaga).returns());', + errors: [{ messageId: 'expectedExpect' }] + } + ] + }) + }) +}) diff --git a/src/rules/max-expect.test.ts b/tests/max-expect.test.ts similarity index 52% rename from src/rules/max-expect.test.ts rename to tests/max-expect.test.ts index 4c7be1e..09d0386 100644 --- a/src/rules/max-expect.test.ts +++ b/tests/max-expect.test.ts @@ -1,29 +1,29 @@ import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './max-expect' +import rule, { RULE_NAME } from '../src/rules/max-expect' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'test(\'should pass\')', - 'test(\'should pass\', () => {})', - 'test.skip(\'should pass\', () => {})', - `test('should pass', () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'test(\'should pass\')', + 'test(\'should pass\', () => {})', + 'test.skip(\'should pass\', () => {})', + `test('should pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - `test('should pass', () => { + `test('should pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - ` test('should pass', async () => { + ` test('should pass', async () => { expect.hasAssertions(); expect(true).toBeDefined(); @@ -32,10 +32,10 @@ describe(RULE_NAME, () => { expect(true).toBeDefined(); expect(true).toEqual(expect.any(Boolean)); });` - ], - invalid: [ - { - code: `test('should not pass', function () { + ], + invalid: [ + { + code: `test('should not pass', function () { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); @@ -44,16 +44,16 @@ describe(RULE_NAME, () => { expect(true).toBeDefined(); }); `, - errors: [ - { - messageId: 'maxExpect', - line: 7, - column: 8 - } - ] - }, - { - code: `test('should not pass', () => { + errors: [ + { + messageId: 'maxExpect', + line: 7, + column: 8 + } + ] + }, + { + code: `test('should not pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); @@ -69,38 +69,38 @@ describe(RULE_NAME, () => { expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - errors: [ - { - messageId: 'maxExpect', - line: 7, - column: 7 - }, - { - messageId: 'maxExpect', - line: 15, - column: 7 - } - ] - }, - { - code: `test('should not pass', () => { + errors: [ + { + messageId: 'maxExpect', + line: 7, + column: 7 + }, + { + messageId: 'maxExpect', + line: 15, + column: 7 + } + ] + }, + { + code: `test('should not pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - options: [ - { - max: 1 - } - ], - errors: [ - { - messageId: 'maxExpect', - line: 3, - column: 7 - } - ] - } - ] - }) - }) + options: [ + { + max: 1 + } + ], + errors: [ + { + messageId: 'maxExpect', + line: 3, + column: 7 + } + ] + } + ] + }) + }) }) diff --git a/src/rules/max-expects.test.ts b/tests/max-expects.test.ts similarity index 52% rename from src/rules/max-expects.test.ts rename to tests/max-expects.test.ts index 65b0053..414bcdc 100644 --- a/src/rules/max-expects.test.ts +++ b/tests/max-expects.test.ts @@ -1,29 +1,29 @@ import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './max-expects' +import rule, { RULE_NAME } from '../src/rules/max-expects' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(RULE_NAME, rule, { - valid: [ - 'test(\'should pass\')', - 'test(\'should pass\', () => {})', - 'test.skip(\'should pass\', () => {})', - `test('should pass', () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'test(\'should pass\')', + 'test(\'should pass\', () => {})', + 'test.skip(\'should pass\', () => {})', + `test('should pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - `test('should pass', () => { + `test('should pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - ` test('should pass', async () => { + ` test('should pass', async () => { expect.hasAssertions(); expect(true).toBeDefined(); @@ -32,10 +32,10 @@ describe(RULE_NAME, () => { expect(true).toBeDefined(); expect(true).toEqual(expect.any(Boolean)); });` - ], - invalid: [ - { - code: `test('should not pass', function () { + ], + invalid: [ + { + code: `test('should not pass', function () { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); @@ -44,16 +44,16 @@ describe(RULE_NAME, () => { expect(true).toBeDefined(); }); `, - errors: [ - { - messageId: 'maxExpect', - line: 7, - column: 8 - } - ] - }, - { - code: `test('should not pass', () => { + errors: [ + { + messageId: 'maxExpect', + line: 7, + column: 8 + } + ] + }, + { + code: `test('should not pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); expect(true).toBeDefined(); @@ -69,38 +69,38 @@ describe(RULE_NAME, () => { expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - errors: [ - { - messageId: 'maxExpect', - line: 7, - column: 7 - }, - { - messageId: 'maxExpect', - line: 15, - column: 7 - } - ] - }, - { - code: `test('should not pass', () => { + errors: [ + { + messageId: 'maxExpect', + line: 7, + column: 7 + }, + { + messageId: 'maxExpect', + line: 15, + column: 7 + } + ] + }, + { + code: `test('should not pass', () => { expect(true).toBeDefined(); expect(true).toBeDefined(); });`, - options: [ - { - max: 1 - } - ], - errors: [ - { - messageId: 'maxExpect', - line: 3, - column: 7 - } - ] - } - ] - }) - }) + options: [ + { + max: 1 + } + ], + errors: [ + { + messageId: 'maxExpect', + line: 3, + column: 7 + } + ] + } + ] + }) + }) }) diff --git a/src/rules/max-nested-describe.test.ts b/tests/max-nested-describe.test.ts similarity index 74% rename from src/rules/max-nested-describe.test.ts rename to tests/max-nested-describe.test.ts index d925316..9fe6597 100644 --- a/src/rules/max-nested-describe.test.ts +++ b/tests/max-nested-describe.test.ts @@ -1,9 +1,9 @@ import { it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './max-nested-describe' +import rule, { RULE_NAME } from '../src/rules/max-nested-describe' +import { ruleTester } from './ruleTester' -const valids = [ - `describe('another suite', () => { +const valid = [ + `describe('another suite', () => { describe('another suite', () => { it('skipped test', () => { // Test skipped, as tests are running in Only mode @@ -16,7 +16,7 @@ const valids = [ }) }) })`, - `describe('another suite', () => { + `describe('another suite', () => { describe('another suite', () => { describe('another suite', () => { describe('another suite', () => { @@ -27,8 +27,8 @@ const valids = [ })` ] -const invalids = [ - `describe('another suite', () => { +const invalid = [ + `describe('another suite', () => { describe('another suite', () => { describe('another suite', () => { describe('another suite', () => { @@ -41,7 +41,7 @@ const invalids = [ }) }) })`, - `describe('another suite', () => { + `describe('another suite', () => { describe('another suite', () => { describe('another suite', () => { describe('another suite', () => { @@ -65,12 +65,12 @@ const invalids = [ ] it('max-nested-describe', () => { - ruleTester.run(RULE_NAME, rule, { - valid: valids, - invalid: invalids.map((i) => ({ - code: i, - output: i, - errors: [{ messageId: 'maxNestedDescribe' }] - })) - }) + ruleTester.run(RULE_NAME, rule, { + valid, + invalid: invalid.map((i) => ({ + code: i, + output: i, + errors: [{ messageId: 'maxNestedDescribe' }] + })) + }) }) diff --git a/tests/no-alias-methods.test.ts b/tests/no-alias-methods.test.ts new file mode 100644 index 0000000..96936f7 --- /dev/null +++ b/tests/no-alias-methods.test.ts @@ -0,0 +1,72 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-alias-methods' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect(a).toHaveBeenCalled()', + 'expect(a).toHaveBeenCalledTimes()', + 'expect(a).toHaveBeenCalledWith()', + 'expect(a).toHaveBeenLastCalledWith()', + 'expect(a).toHaveBeenNthCalledWith()', + 'expect(a).toHaveReturned()', + 'expect(a).toHaveReturnedTimes()', + 'expect(a).toHaveReturnedWith()', + 'expect(a).toHaveLastReturnedWith()', + 'expect(a).toHaveNthReturnedWith()', + 'expect(a).toThrow()', + 'expect(a).rejects;', + 'expect(a);' + ], + invalid: [ + { + code: 'expect(a).toBeCalled()', + output: 'expect(a).toHaveBeenCalled()', + errors: [ + { + messageId: 'noAliasMethods', + data: { + alias: 'toBeCalled', + canonical: 'toHaveBeenCalled' + }, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).toBeCalledTimes()', + output: 'expect(a).toHaveBeenCalledTimes()', + errors: [ + { + messageId: 'noAliasMethods', + data: { + alias: 'toBeCalledTimes', + canonical: 'toHaveBeenCalledTimes' + }, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).not["toThrowError"]()', + output: 'expect(a).not[\'toThrow\']()', + errors: [ + { + messageId: 'noAliasMethods', + data: { + alias: 'toThrowError', + canonical: 'toThrow' + }, + column: 15, + line: 1 + } + ] + } + ] + }) + }) +}) diff --git a/tests/no-commented-out-tests.test.ts b/tests/no-commented-out-tests.test.ts new file mode 100644 index 0000000..0a99b81 --- /dev/null +++ b/tests/no-commented-out-tests.test.ts @@ -0,0 +1,66 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-commented-out-tests' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + '// foo("bar", function () {})', + 'describe("foo", function () {})', + 'it("foo", function () {})', + 'describe.only("foo", function () {})', + 'it.only("foo", function () {})', + 'it.concurrent("foo", function () {})', + 'test("foo", function () {})', + 'test.only("foo", function () {})', + 'test.concurrent("foo", function () {})', + 'var appliedSkip = describe.skip; appliedSkip.apply(describe)', + 'var calledSkip = it.skip; calledSkip.call(it)', + '({ f: function () {} }).f()', + '(a || b).f()', + 'itHappensToStartWithIt()', + 'testSomething()', + '// latest(dates)', + '// TODO: unify with Git implementation from Shipit (?)', + '#!/usr/bin/env node' + ], + invalid: [ + { + code: '// describe(\'foo\', function () {})\'', + errors: [ + { + messageId: 'noCommentedOutTests' + } + ] + }, + { + code: '// test.concurrent("foo", function () {})', + errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] + }, + { + code: '// test["skip"]("foo", function () {})', + errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] + }, + { + code: '// xdescribe("foo", function () {})', + errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] + }, + { + code: '// xit("foo", function () {})', + errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] + }, + { + code: '// fit("foo", function () {})', + errors: [{ messageId: 'noCommentedOutTests', column: 1, line: 1 }] + }, + { + code: ` // test( + // "foo", function () {} + // )`, + errors: [{ messageId: 'noCommentedOutTests', column: 2, line: 1 }] + } + ] + }) + }) +}) diff --git a/src/rules/no-conditional-expect.test.ts b/tests/no-conditional-expect.test.ts similarity index 55% rename from src/rules/no-conditional-expect.test.ts rename to tests/no-conditional-expect.test.ts index 47985b7..66fff24 100644 --- a/src/rules/no-conditional-expect.test.ts +++ b/tests/no-conditional-expect.test.ts @@ -1,33 +1,33 @@ import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-conditional-expect' +import rule, { RULE_NAME } from '../src/rules/no-conditional-expect' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { - it(RULE_NAME, () => { - ruleTester.run(`${RULE_NAME}-common tests`, rule, { - valid: [ - ` + it(RULE_NAME, () => { + ruleTester.run(`${RULE_NAME}-common tests`, rule, { + valid: [ + ` it('foo', () => { expect(1).toBe(2); }); `, - ` + ` it('foo', () => { expect(!true).toBe(false); }); ` - ], - invalid: [] - }) + ], + invalid: [] + }) - ruleTester.run(`${RULE_NAME}-logical conditions`, rule, { - valid: [ - `it('foo', () => { + ruleTester.run(`${RULE_NAME}-logical conditions`, rule, { + valid: [ + `it('foo', () => { process.env.FAIL && setNum(1); expect(num).toBe(2); });`, - ` + ` function getValue() { let num = 2; @@ -40,7 +40,7 @@ describe(RULE_NAME, () => { expect(getValue()).toBe(2); }); `, - ` + ` function getValue() { let num = 2; @@ -53,67 +53,67 @@ describe(RULE_NAME, () => { expect(getValue()).toBe(2); }); ` - ], - invalid: [ - { - code: ` it('foo', () => { + ], + invalid: [ + { + code: ` it('foo', () => { something && expect(something).toHaveBeenCalled(); })`, - errors: [ - { - messageId: 'noConditionalExpect' - } - ] - }, - { - code: ` it('foo', () => { + errors: [ + { + messageId: 'noConditionalExpect' + } + ] + }, + { + code: ` it('foo', () => { a || (b && expect(something).toHaveBeenCalled()); })`, - errors: [ - { - messageId: 'noConditionalExpect' - } - ] - }, - { - code: ` + errors: [ + { + messageId: 'noConditionalExpect' + } + ] + }, + { + code: ` it.each\`\`('foo', () => { something || expect(something).toHaveBeenCalled(); }) `, - errors: [{ messageId: 'noConditionalExpect' }] - }, - { - code: ` + errors: [{ messageId: 'noConditionalExpect' }] + }, + { + code: ` it.each()('foo', () => { something || expect(something).toHaveBeenCalled(); }) `, - errors: [{ messageId: 'noConditionalExpect' }] - }, - { - code: ` + errors: [{ messageId: 'noConditionalExpect' }] + }, + { + code: ` function getValue() { something || expect(something).toHaveBeenCalled(); } it('foo', getValue); `, - errors: [{ messageId: 'noConditionalExpect' }] - } - ] - }) + errors: [{ messageId: 'noConditionalExpect' }] + } + ] + }) - ruleTester.run(`${RULE_NAME}-conditional conditions`, rule, { - valid: [ - ` + ruleTester.run(`${RULE_NAME}-conditional conditions`, rule, { + valid: [ + ` it('foo', () => { const num = process.env.FAIL ? 1 : 2; expect(num).toBe(2); }); `, - ` + ` function getValue() { return process.env.FAIL ? 1 : 2 } @@ -122,35 +122,35 @@ describe(RULE_NAME, () => { expect(getValue()).toBe(2); }); ` - ], - invalid: [ - { - code: ` + ], + invalid: [ + { + code: ` it('foo', () => { something ? expect(something).toHaveBeenCalled() : noop(); }) `, - errors: [{ messageId: 'noConditionalExpect' }] - }, - { - code: ` + errors: [{ messageId: 'noConditionalExpect' }] + }, + { + code: ` function getValue() { something ? expect(something).toHaveBeenCalled() : noop(); } it('foo', getValue); `, - errors: [{ messageId: 'noConditionalExpect' }] - }, - { - code: ` + errors: [{ messageId: 'noConditionalExpect' }] + }, + { + code: ` it('foo', () => { something ? noop() : expect(something).toHaveBeenCalled(); }) `, - errors: [{ messageId: 'noConditionalExpect' }] - } - ] - }) - }) + errors: [{ messageId: 'noConditionalExpect' }] + } + ] + }) + }) }) diff --git a/tests/no-conditional-in-test.test.ts b/tests/no-conditional-in-test.test.ts new file mode 100644 index 0000000..e0065ab --- /dev/null +++ b/tests/no-conditional-in-test.test.ts @@ -0,0 +1,243 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-conditional-tests' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it('conditional expressions', () => { + ruleTester.run(`${RULE_NAME}-conditional expressions`, rule, { + valid: [ + 'const x = y ? 1 : 0', + `const foo = function (bar) { + return foo ? bar : null; + }; + it('foo', () => { + foo(); + });`, + `it.concurrent('foo', () => { + switch('bar') {} + })` + ], + invalid: [ + { + code: `it('foo', function () { + const foo = function (bar) { + return foo ? bar : null; + }; + });`, + errors: [ + { + messageId: 'noConditionalTests' + } + ] + } + ] + }) + }) + + it('switch statements', () => { + ruleTester.run(`${RULE_NAME}-switch statements`, rule, { + valid: [ + 'it(\'foo\', () => {})', + `switch (true) { + case true: {} + }`, + `describe('foo', () => { + switch('bar') {} + })`, + `const values = something.map(thing => { + switch (thing.isFoo) { + case true: + return thing.foo; + default: + return thing.bar; + } + }); + + it('valid', () => { + expect(values).toStrictEqual(['foo']); + });` + ], + invalid: [ + { + code: `it('is invalid', () => { + const values = something.map(thing => { + switch (thing.isFoo) { + case true: + return thing.foo; + default: + return thing.bar; + } + }); + + expect(values).toStrictEqual(['foo']); + });`, + errors: [ + { + messageId: 'noConditionalTests', + column: 9, + line: 3 + } + ] + }, + { + code: `it('foo', () => { + switch (true) { + case true: {} + } + })`, + errors: [ + { + messageId: 'noConditionalTests', + column: 7, + line: 2 + } + ] + }, + { + code: `describe('foo', () => { + it('bar', () => { + switch('bar') {} + }) + it('baz', () => { + switch('qux') {} + switch('quux') {} + }) + })`, + errors: [ + { + messageId: 'noConditionalTests', + column: 9, + line: 3 + }, + { + messageId: 'noConditionalTests', + column: 9, + line: 6 + }, + { + messageId: 'noConditionalTests', + column: 9, + line: 7 + } + ] + }, + { + code: `describe('valid', () => { + describe('still valid', () => { + it('is not valid', () => { + const values = something.map((thing) => { + switch (thing.isFoo) { + case true: + return thing.foo; + default: + return thing.bar; + } + }); + + switch('invalid') { + case true: + expect(values).toStrictEqual(['foo']); + } + }); + }); + });`, + errors: [ + { + messageId: 'noConditionalTests', + column: 10, + line: 5 + }, + { + messageId: 'noConditionalTests', + column: 8, + line: 13 + } + ] + } + ] + }) + }) + + it('if statements', () => { + ruleTester.run(`${RULE_NAME}-if statements`, rule, { + valid: [ + 'if (foo) {}', + 'it(\'foo\', () => {})', + 'it("foo", function () {})', + 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }', + `describe.each\`\`('foo', () => { + afterEach(() => { + if ('bar') {} + }); + })`, + `const values = something.map((thing) => { + if (thing.isFoo) { + return thing.foo + } else { + return thing.bar; + } + }); + + describe('valid', () => { + it('still valid', () => { + expect(values).toStrictEqual(['foo']); + }); + });` + ], + invalid: [ + { + code: `it('foo', () => { + const foo = function(bar) { + if (bar) { + return 1; + } else { + return 2; + } + }; + });`, + errors: [ + { + messageId: 'noConditionalTests', + column: 9, + line: 3 + } + ] + }, + { + code: ` describe('foo', () => { + it('bar', () => { + if ('bar') {} + }) + it('baz', () => { + if ('qux') {} + if ('quux') {} + }) + })`, + errors: [ + { messageId: 'noConditionalTests', column: 9, line: 3 }, + { messageId: 'noConditionalTests', column: 9, line: 6 }, + { messageId: 'noConditionalTests', column: 9, line: 7 } + ] + }, + { + code: `test("shows error", () => { + if (1 === 2) { + expect(true).toBe(false); + } + }); + + test("does not show error", () => { + setTimeout(() => console.log("noop")); + if (1 === 2) { + expect(true).toBe(false); + } + });`, + errors: [ + { messageId: 'noConditionalTests', column: 7, line: 2 }, + { messageId: 'noConditionalTests', column: 7, line: 9 } + ] + } + ] + }) + }) +}) diff --git a/tests/no-conditional-tests.test.ts b/tests/no-conditional-tests.test.ts new file mode 100644 index 0000000..fe3c6b3 --- /dev/null +++ b/tests/no-conditional-tests.test.ts @@ -0,0 +1,142 @@ +import { it, describe } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-conditional-tests' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it('if statements', () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'test("shows error", () => {});', + 'it("foo", function () {})', + 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }', + `function myFunc(str: string) { + return str; + } + + describe("myTest", () => { + it("convert shortened equal filter", () => { + expect( + myFunc("5") + ).toEqual("5"); + }); + });` + ], + invalid: [ + { + code: `test("shows error", () => { + if (1 === 2) { + expect(true).toBe(false); + } + });`, + output: `test("shows error", () => { + if (1 === 2) { + expect(true).toBe(false); + } + });`, + errors: [{ messageId: 'noConditionalTests' }] + }, + { + code: `it("foo", function () { + if (1 === 2) { + expect(true).toBe(false); + } + })`, + output: `it("foo", function () { + if (1 === 2) { + expect(true).toBe(false); + } + })`, + errors: [{ messageId: 'noConditionalTests' }] + } + ] + }) + }) + + it('ternary statements', () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'test("shows error", () => {});', + 'it("foo", function () {})', + 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }' + ], + invalid: [ + { + code: `test("shows error", () => { + const foo = true ? 'foo' : 'bar'; + expect(foo).toBe('foo'); + });`, + output: `test("shows error", () => { + const foo = true ? 'foo' : 'bar'; + expect(foo).toBe('foo'); + });`, + errors: [{ messageId: 'noConditionalTests' }] + }, + { + code: `it("foo", function () { + const foo = true ? 'foo' : 'bar'; + expect(foo).toBe('foo'); + })`, + output: `it("foo", function () { + const foo = true ? 'foo' : 'bar'; + expect(foo).toBe('foo'); + })`, + errors: [{ messageId: 'noConditionalTests' }] + } + ] + }) + + it('switch statements', () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'test("shows error", () => {});', + 'it("foo", function () {})', + 'it(\'foo\', () => {}); function myTest() { if (\'bar\') {} }' + ], + invalid: [ + { + code: `test("shows error", () => { + switch (1) { + case 1: + expect(true).toBe(false); + break; + default: + expect(true).toBe(false); + } + });`, + output: `test("shows error", () => { + switch (1) { + case 1: + expect(true).toBe(false); + break; + default: + expect(true).toBe(false); + } + });`, + errors: [{ messageId: 'noConditionalTests' }] + }, + { + code: `it("foo", function () { + switch (1) { + case 1: + expect(true).toBe(false); + break; + default: + expect(true).toBe(false); + } + })`, + output: `it("foo", function () { + switch (1) { + case 1: + expect(true).toBe(false); + break; + default: + expect(true).toBe(false); + } + })`, + errors: [{ messageId: 'noConditionalTests' }] + } + ] + }) + }) + }) +}) diff --git a/src/rules/no-disabled-tests.test.ts b/tests/no-disabled-tests.test.ts similarity index 91% rename from src/rules/no-disabled-tests.test.ts rename to tests/no-disabled-tests.test.ts index 556ce83..5e59ecd 100644 --- a/src/rules/no-disabled-tests.test.ts +++ b/tests/no-disabled-tests.test.ts @@ -1,12 +1,8 @@ -import { TSESLint } from '@typescript-eslint/utils' import { describe, it } from 'vitest' -import rule, { RULE_NAME } from './no-disabled-tests' +import rule, { RULE_NAME } from '../src/rules/no-disabled-tests' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { - const ruleTester = new TSESLint.RuleTester({ - parser: require.resolve('@typescript-eslint/parser') - }) - it(RULE_NAME, () => { ruleTester.run(RULE_NAME, rule, { valid: [ diff --git a/tests/no-done-callback.test.ts b/tests/no-done-callback.test.ts new file mode 100644 index 0000000..4a70dd4 --- /dev/null +++ b/tests/no-done-callback.test.ts @@ -0,0 +1,115 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-done-callback' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'test("something", () => {})', + 'test("something", async () => {})', + 'test("something", function() {})', + 'test.each``("something", ({ a, b }) => {})', + 'test.each()("something", ({ a, b }) => {})', + 'it.each()("something", ({ a, b }) => {})', + 'it.each([])("something", (a, b) => {})', + 'it.each``("something", ({ a, b }) => {})', + 'it.each([])("something", (a, b) => { a(); b(); })', + 'it.each``("something", ({ a, b }) => { a(); b(); })', + 'test("something", async function () {})', + 'test("something", someArg)', + 'beforeEach(() => {})', + 'beforeAll(async () => {})', + 'afterAll(() => {})', + 'afterAll(async function () {})', + 'afterAll(async function () {}, 5)' + ], + invalid: [ + { + code: 'test("something", (...args) => {args[0]();})', + errors: [{ messageId: 'noDoneCallback', line: 1, column: 20 }] + }, + { + code: 'test("something", done => {done();})', + errors: [ + { + messageId: 'noDoneCallback', + line: 1, + column: 1, + suggestions: [ + { + messageId: 'suggestWrappingInPromise', + data: { callback: 'done' }, + output: + 'test("something", () => {return new Promise(done => {done();})})' + } + ] + } + ] + }, + { + code: 'test("something", finished => {finished();})', + errors: [ + { + messageId: 'noDoneCallback', + line: 1, + column: 1, + suggestions: [ + { + messageId: 'suggestWrappingInPromise', + data: { callback: 'finished' }, + output: + 'test("something", () => {return new Promise(finished => {finished();})})' + } + ] + } + ] + }, + { + code: 'beforeAll(async done => {done();})', + errors: [ + { messageId: 'useAwaitInsteadOfCallback', line: 1, column: 17 } + ] + }, + { + code: 'beforeEach((done) => {done();});', + errors: [ + { + messageId: 'noDoneCallback', + line: 1, + column: 1, + suggestions: [ + { + messageId: 'suggestWrappingInPromise', + data: { callback: 'done' }, + output: + 'beforeEach(() => {return new Promise(done => {done();})});' + } + ] + } + ] + }, + { + code: 'test.each``("something", ({ a, b }, done) => { done(); })', + errors: [ + { + messageId: 'noDoneCallback', + line: 1, + column: 1 + } + ] + }, + { + code: 'it.each``("something", ({ a, b }, done) => { done(); })', + errors: [ + { + messageId: 'noDoneCallback', + line: 1, + column: 1 + } + ] + } + ] + }) + }) +}) diff --git a/tests/no-duplicate-hooks.test.ts b/tests/no-duplicate-hooks.test.ts new file mode 100644 index 0000000..426c992 --- /dev/null +++ b/tests/no-duplicate-hooks.test.ts @@ -0,0 +1,223 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-duplicate-hooks' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(`${RULE_NAME} - single describe block`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + `describe("foo", () => { + beforeEach(() => {}) + test("bar", () => { + someFn(); + }) + })`, + `beforeEach(() => {}) + test("bar", () => { + someFn(); + })`, + `describe("foo", () => { + beforeAll(() => {}), + beforeEach(() => {}) + afterEach(() => {}) + afterAll(() => {}) + + test("bar", () => { + someFn(); + }) + })` + ], + invalid: [ + { + code: `describe("foo", () => { + beforeEach(() => {}), + beforeEach(() => {}), + test("bar", () => { + someFn(); + }) + })`, + errors: [ + { + messageId: 'noDuplicateHooks', + data: { hook: 'beforeEach' }, + column: 7, + line: 3 + } + ] + }, + { + code: ` + describe.skip("foo", () => { + afterEach(() => {}), + afterEach(() => {}), + test("bar", () => { + someFn(); + }) + }) + `, + errors: [ + { + messageId: 'noDuplicateHooks', + data: { hook: 'afterEach' }, + column: 7, + line: 4 + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} - multiple describe blocks`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + `describe.skip("foo", () => { + beforeEach(() => {}), + beforeAll(() => {}), + test("bar", () => { + someFn(); + }) + }) + describe("foo", () => { + beforeEach(() => {}), + beforeAll(() => {}), + test("bar", () => { + someFn(); + }) + })` + ], + invalid: [ + { + code: `describe.skip("foo", () => { + beforeEach(() => {}), + beforeAll(() => {}), + test("bar", () => { + someFn(); + }) + }) + describe("foo", () => { + beforeEach(() => {}), + beforeEach(() => {}), + beforeAll(() => {}), + test("bar", () => { + someFn(); + }) + })`, + errors: [ + { + messageId: 'noDuplicateHooks', + data: { hook: 'beforeEach' }, + column: 7, + line: 10 + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} - nested describe blocks`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + ` describe("foo", () => { + beforeEach(() => {}), + test("bar", () => { + someFn(); + }) + describe("inner_foo", () => { + beforeEach(() => {}) + test("inner bar", () => { + someFn(); + }) + }) + })` + ], + invalid: [ + { + code: `describe.skip("foo", () => { + beforeEach(() => {}), + beforeAll(() => {}), + test("bar", () => { + someFn(); + }) + }) + describe("foo", () => { + beforeEach(() => {}), + beforeEach(() => {}), + beforeAll(() => {}), + test("bar", () => { + someFn(); + }) + })`, + errors: [ + { + messageId: 'noDuplicateHooks', + data: { hook: 'beforeEach' }, + column: 7, + line: 10 + } + ] + } + ] + }) + }) + + it(`${RULE_NAME} - describe.each blocks`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + ` describe.each(['hello'])('%s', () => { + beforeEach(() => {}); + + it('is fine', () => {}); + });`, + `describe.each(['hello'])('%s', () => { + beforeEach(() => {}); + + it('is fine', () => {}); + });` + ], + invalid: [ + { + code: `describe.each(['hello'])('%s', () => { + beforeEach(() => {}); + beforeEach(() => {}); + + it('is not fine', () => {}); + });`, + errors: [ + { + messageId: 'noDuplicateHooks', + data: { hook: 'beforeEach' }, + column: 7, + line: 3 + } + ] + }, + { + code: ` describe('something', () => { + describe.each(['hello'])('%s', () => { + beforeEach(() => {}); + + it('is fine', () => {}); + }); + + describe.each(['world'])('%s', () => { + beforeEach(() => {}); + beforeEach(() => {}); + + it('is not fine', () => {}); + }); + });`, + errors: [ + { + messageId: 'noDuplicateHooks', + data: { hook: 'beforeEach' }, + column: 9, + line: 10 + } + ] + } + ] + }) + }) +}) diff --git a/tests/no-focused-tests.test.ts b/tests/no-focused-tests.test.ts new file mode 100644 index 0000000..b53f12c --- /dev/null +++ b/tests/no-focused-tests.test.ts @@ -0,0 +1,64 @@ +import { it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-focused-tests' +import { ruleTester } from './ruleTester' + +it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: ['it("test", () => {});', 'describe("test group", () => {});'], + + invalid: [ + { + code: 'it.only("test", () => {});', + errors: [ + { + column: 4, + endColumn: 8, + endLine: 1, + line: 1, + messageId: 'noFocusedTests' + } + ], + output: 'it.only("test", () => {});' + }, + { + code: 'describe.only("test", () => {});', + errors: [ + { + column: 10, + endColumn: 14, + endLine: 1, + line: 1, + messageId: 'noFocusedTests' + } + ], + output: 'describe.only("test", () => {});' + }, + { + code: 'test.only("test", () => {});', + errors: [ + { + column: 6, + endColumn: 10, + endLine: 1, + line: 1, + messageId: 'noFocusedTests' + } + ], + output: 'test.only("test", () => {});' + }, + { + code: 'it.only.each([])("test", () => {});', + errors: [ + { + column: 4, + endColumn: 8, + endLine: 1, + line: 1, + messageId: 'noFocusedTests' + } + ], + output: 'it.only.each([])("test", () => {});' + } + ] + }) +}) diff --git a/tests/no-hooks.test.ts b/tests/no-hooks.test.ts new file mode 100644 index 0000000..af7461d --- /dev/null +++ b/tests/no-hooks.test.ts @@ -0,0 +1,82 @@ +import { it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules//no-hooks' +import { HookName } from '../src/utils/types' +import { ruleTester } from './ruleTester' + +it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'test("foo")', + 'describe("foo", () => { it("bar") })', + 'test("foo", () => { expect(subject.beforeEach()).toBe(true) })', + { + code: 'afterEach(() => {}); afterAll(() => {});', + options: [{ allow: [HookName.afterEach, HookName.afterAll] }] + }, + { code: 'test("foo")', options: [{ allow: undefined }] } + ], + invalid: [ + { + code: 'beforeAll(() => {})', + errors: [ + { + messageId: 'unexpectedHook', + data: { hookName: HookName.beforeAll } + } + ] + }, + { + code: 'beforeEach(() => {})', + errors: [ + { + messageId: 'unexpectedHook', + data: { hookName: HookName.beforeEach } + } + ] + }, + { + code: 'afterAll(() => {})', + errors: [ + { + messageId: 'unexpectedHook', + data: { hookName: HookName.afterAll } + } + ] + }, + { + code: 'afterEach(() => {})', + errors: [ + { + messageId: 'unexpectedHook', + data: { hookName: HookName.afterEach } + } + ] + }, + { + code: 'beforeEach(() => {}); afterEach(() => { vi.resetModules() });', + options: [{ allow: [HookName.afterEach] }], + errors: [ + { + messageId: 'unexpectedHook', + data: { hookName: HookName.beforeEach } + } + ] + }, + { + code: ` + import { beforeEach as afterEach, afterEach as beforeEach, vi } from 'vitest'; + afterEach(() => {}); + beforeEach(() => { vi.resetModules() }); + `, + options: [{ allow: [HookName.afterEach] }], + parserOptions: { sourceType: 'module' }, + errors: [ + { + messageId: 'unexpectedHook', + data: { hookName: HookName.beforeEach } + } + ] + } + ] + }) +}) diff --git a/src/rules/no-identical-title.test.ts b/tests/no-identical-title.test.ts similarity index 53% rename from src/rules/no-identical-title.test.ts rename to tests/no-identical-title.test.ts index 452d933..eb65416 100644 --- a/src/rules/no-identical-title.test.ts +++ b/tests/no-identical-title.test.ts @@ -1,27 +1,27 @@ import { describe, it } from 'vitest' -import { ruleTester } from '../utils/test' -import rule, { RULE_NAME } from './no-identical-title' +import rule, { RULE_NAME } from '../src/rules/no-identical-title' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { it('no identical title', () => { ruleTester.run(RULE_NAME, rule, { valid: ['it(); it();', 'test("two", () => {});'], invalid: [ - { - code: `describe('foo', () => { + { + code: `describe('foo', () => { it('works', () => {}); it('works', () => {}); });`, - errors: [{ messageId: 'multipleTestTitle' }] - }, - { - code: `xdescribe('foo', () => { + errors: [{ messageId: 'multipleTestTitle' }] + }, + { + code: `xdescribe('foo', () => { it('works', () => {}); it('works', () => {}); });`, - errors: [{ messageId: 'multipleTestTitle' }] - } - ] + errors: [{ messageId: 'multipleTestTitle' }] + } + ] }) }) }) diff --git a/tests/no-interpolation-in-snapshots.test.ts b/tests/no-interpolation-in-snapshots.test.ts new file mode 100644 index 0000000..fe994e8 --- /dev/null +++ b/tests/no-interpolation-in-snapshots.test.ts @@ -0,0 +1,75 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-interpolation-in-snapshots' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect("something").toEqual("else");', + 'expect(something).toMatchInlineSnapshot();', + 'expect(something).toMatchInlineSnapshot(`No interpolation`);', + 'expect(something).toMatchInlineSnapshot({}, `No interpolation`);', + 'expect(something);', + 'expect(something).not;', + 'expect.toHaveAssertions();', + // eslint-disable-next-line no-template-curly-in-string + 'myObjectWants.toMatchInlineSnapshot({}, `${interpolated}`);', + // eslint-disable-next-line no-template-curly-in-string + 'myObjectWants.toMatchInlineSnapshot({}, `${interpolated1} ${interpolated2}`);', + // eslint-disable-next-line no-template-curly-in-string + 'toMatchInlineSnapshot({}, `${interpolated}`);', + // eslint-disable-next-line no-template-curly-in-string + 'toMatchInlineSnapshot({}, `${interpolated1} ${interpolated2}`);', + 'expect(something).toThrowErrorMatchingInlineSnapshot();', + 'expect(something).toThrowErrorMatchingInlineSnapshot(`No interpolation`);' + ], + invalid: [ + { + // eslint-disable-next-line no-template-curly-in-string + code: 'expect(something).toMatchInlineSnapshot(`${interpolated}`);', + errors: [ + { + messageId: 'noInterpolationInSnapshots', + column: 41, + line: 1 + } + ] + }, + { + // eslint-disable-next-line no-template-curly-in-string + code: 'expect(something).not.toMatchInlineSnapshot(`${interpolated}`);', + errors: [ + { + messageId: 'noInterpolationInSnapshots', + column: 45, + line: 1 + } + ] + }, + { + // eslint-disable-next-line no-template-curly-in-string + code: 'expect(something).toThrowErrorMatchingInlineSnapshot(`${interpolated}`);', + errors: [ + { + endColumn: 71, + column: 54, + messageId: 'noInterpolationInSnapshots' + } + ] + }, + { + // eslint-disable-next-line no-template-curly-in-string + code: 'expect(something).not.toThrowErrorMatchingInlineSnapshot(`${interpolated}`);', + errors: [ + { + endColumn: 75, + column: 58, + messageId: 'noInterpolationInSnapshots' + } + ] + } + ] + }) + }) +}) diff --git a/tests/no-large-snapshots.test.ts b/tests/no-large-snapshots.test.ts new file mode 100644 index 0000000..8fa589a --- /dev/null +++ b/tests/no-large-snapshots.test.ts @@ -0,0 +1,156 @@ +import { TSESLint } from '@typescript-eslint/utils' +import { describe, expect, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-large-snapshots' +import { ruleTester } from './ruleTester' + +const generateSnaShotLines = (lines: number) => + `\`\n${'line\n'.repeat(lines)}\`` + +const generateExportsSnapshotString = ( + lines: number, + title = 'a big component 1' +) => `exports[\`${title}\`] = ${generateSnaShotLines(lines - 1)};` + +const generateExpectInlineSnapsCode = ( + lines: number, + matcher: 'toMatchInlineSnapshot' | 'toThrowErrorMatchingInlineSnapshot' +) => `expect(something).${matcher}(${generateSnaShotLines(lines)});` + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect(something)', + 'expect(something).toBe(1)', + 'expect(something).toMatchInlineSnapshot', + 'expect(something).toMatchInlineSnapshot()', + { + filename: 'mock.js', + code: generateExpectInlineSnapsCode(2, 'toMatchInlineSnapshot') + }, + { + filename: 'mock.jsx', + code: generateExpectInlineSnapsCode(20, 'toMatchInlineSnapshot'), + options: [ + { + maxSize: 19, + inlineMaxSize: 21 + } + ] + }, + { + filename: 'mock.jsx', + code: generateExpectInlineSnapsCode(60, 'toMatchInlineSnapshot'), + options: [ + { + maxSize: 61 + } + ] + }, + { + // "it should not report snapshots that are allowed to be large" + filename: '/mock-component.jsx.snap', + code: generateExportsSnapshotString(58), + options: [ + { + allowedSnapshots: { + '/mock-component.jsx.snap': ['a big component 1'] + } + } + ] + } + ], + invalid: [ + { + filename: 'mock.js', + code: generateExpectInlineSnapsCode(50, 'toMatchInlineSnapshot'), + errors: [ + { + messageId: 'tooLongSnapShot', + data: { lineLimit: 50, lineCount: 51 } + } + ] + }, + { + filename: 'mock.js', + code: generateExpectInlineSnapsCode( + 50, + 'toThrowErrorMatchingInlineSnapshot' + ), + errors: [ + { + messageId: 'tooLongSnapShot', + data: { lineLimit: 50, lineCount: 51 } + } + ] + }, + { + filename: 'mock.js', + code: generateExpectInlineSnapsCode( + 50, + 'toThrowErrorMatchingInlineSnapshot' + ), + options: [{ maxSize: 51, inlineMaxSize: 50 }], + errors: [ + { + messageId: 'tooLongSnapShot', + data: { lineLimit: 50, lineCount: 51 } + } + ] + }, + { + // "should not report allowed large snapshots based on regexp" + filename: '/mock-component.jsx.snap', + code: [ + generateExportsSnapshotString(58, 'a big component w/ text'), + generateExportsSnapshotString(58, 'a big component 2') + ].join('\n\n'), + options: [ + { + allowedSnapshots: { + '/mock-component.jsx.snap': [/a big component \d+/u] + } + } + ], + errors: [ + { + messageId: 'tooLongSnapShot', + data: { lineLimit: 50, lineCount: 58 } + } + ] + } + ] + }) + }) +}) + +describe(RULE_NAME, () => { + describe('when "allowedSnapshots" options contains relative paths', () => { + it('should throw an exception', () => { + expect(() => { + const linter = new TSESLint.Linter() + + linter.defineRule(RULE_NAME, rule) + + linter.verify( + 'console.log()', + { + rules: { + 'no-large-snapshots': [ + 'error', + { + allowedSnapshots: { + './mock-component.jsx.snap': [/a big component \d+/u] + } + } + ] + } + }, + 'mock-component.jsx.snap' + ) + }).toThrow( + 'All paths for allowedSnapshots must be absolute. You can use JS config and `path.resolve`' + ) + }) + }) +}) diff --git a/tests/no-mocks-import.test.ts b/tests/no-mocks-import.test.ts new file mode 100644 index 0000000..04130a6 --- /dev/null +++ b/tests/no-mocks-import.test.ts @@ -0,0 +1,53 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-mocks-import' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'import something from "something"', + 'require("somethingElse")', + 'require("./__mocks__.js")', + 'require("./__mocks__x")', + 'require("./__mocks__x/x")', + 'require("./x__mocks__")', + 'require("./x__mocks__/x")', + 'require()', + 'var path = "./__mocks__.js"; require(path)', + 'entirelyDifferent(fn)' + ], + invalid: [ + { + code: 'require("./__mocks__")', + errors: [{ endColumn: 22, column: 9, messageId: 'noMocksImport' }] + }, + { + code: 'require("./__mocks__/")', + errors: [{ endColumn: 23, column: 9, messageId: 'noMocksImport' }] + }, + { + code: 'require("./__mocks__/index")', + errors: [{ endColumn: 28, column: 9, messageId: 'noMocksImport' }] + }, + { + code: 'require("__mocks__")', + errors: [{ endColumn: 20, column: 9, messageId: 'noMocksImport' }] + }, + { + code: 'require("__mocks__/")', + errors: [{ endColumn: 21, column: 9, messageId: 'noMocksImport' }] + }, + { + code: 'require("__mocks__/index")', + errors: [{ endColumn: 26, column: 9, messageId: 'noMocksImport' }] + }, + { + code: 'import thing from "./__mocks__/index"', + parserOptions: { sourceType: 'module' }, + errors: [{ endColumn: 38, column: 1, messageId: 'noMocksImport' }] + } + ] + }) + }) +}) diff --git a/tests/no-restricted-matchers.test.ts b/tests/no-restricted-matchers.test.ts new file mode 100644 index 0000000..5ee35b5 --- /dev/null +++ b/tests/no-restricted-matchers.test.ts @@ -0,0 +1,210 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-restricted-matchers' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect(a).toHaveBeenCalled()', + 'expect(a).not.toHaveBeenCalled()', + 'expect(a).toHaveBeenCalledTimes()', + 'expect(a).toHaveBeenCalledWith()', + 'expect(a).toHaveBeenLastCalledWith()', + 'expect(a).toHaveBeenNthCalledWith()', + 'expect(a).toHaveReturned()', + 'expect(a).toHaveReturnedTimes()', + 'expect(a).toHaveReturnedWith()', + 'expect(a).toHaveLastReturnedWith()', + 'expect(a).toHaveNthReturnedWith()', + 'expect(a).toThrow()', + 'expect(a).rejects;', + 'expect(a);', + { + code: 'expect(a).resolves', + options: [{ not: null }] + }, + { + code: 'expect(a).toBe(b)', + options: [{ 'not.toBe': null }] + }, + { + code: 'expect(a).toBeUndefined(b)', + options: [{ toBe: null }] + }, + { + code: 'expect(a)["toBe"](b)', + options: [{ 'not.toBe': null }] + }, + { + code: 'expect(a).resolves.not.toBe(b)', + options: [{ not: null }] + }, + { + code: 'expect(a).resolves.not.toBe(b)', + options: [{ 'not.toBe': null }] + } + ], + invalid: [ + { + code: 'expect(a).not.toBe(b)', + options: [{ not: null }], + errors: [ + { + messageId: 'restrictedChain', + data: { + message: null, + restriction: 'not' + }, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).resolves.toBe(b)', + options: [{ resolves: null }], + errors: [ + { + messageId: 'restrictedChain', + data: { + message: null, + restriction: 'resolves' + }, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).resolves.not.toBe(b)', + options: [{ resolves: null }], + errors: [ + { + messageId: 'restrictedChain', + data: { + message: null, + restriction: 'resolves' + }, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).resolves.not.toBe(b)', + options: [{ 'resolves.not': null }], + errors: [ + { + messageId: 'restrictedChain', + data: { + message: null, + restriction: 'resolves.not' + }, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).not.toBe(b)', + options: [{ 'not.toBe': null }], + errors: [ + { + messageId: 'restrictedChain', + data: { + message: null, + restriction: 'not.toBe' + }, + endColumn: 19, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).resolves.not.toBe(b)', + options: [{ 'resolves.not.toBe': null }], + errors: [ + { + messageId: 'restrictedChain', + data: { + message: null, + restriction: 'resolves.not.toBe' + }, + endColumn: 28, + column: 11, + line: 1 + } + ] + }, + { + code: 'expect(a).toBe(b)', + options: [{ toBe: 'Prefer `toStrictEqual` instead' }], + errors: [ + { + messageId: 'restrictedChainWithMessage', + data: { + message: 'Prefer `toStrictEqual` instead', + restriction: 'toBe' + }, + column: 11, + line: 1 + } + ] + }, + { + code: ` + test('some test', async () => { + await expect(Promise.resolve(1)).resolves.toBe(1); + }); + `, + options: [{ resolves: 'Use `expect(await promise)` instead.' }], + errors: [ + { + messageId: 'restrictedChainWithMessage', + data: { + message: 'Use `expect(await promise)` instead.', + restriction: 'resolves' + }, + endColumn: 53, + column: 40 + } + ] + }, + { + code: 'expect(Promise.resolve({})).rejects.toBeFalsy()', + options: [{ 'rejects.toBeFalsy': null }], + errors: [ + { + messageId: 'restrictedChain', + data: { + message: null, + restriction: 'rejects.toBeFalsy' + }, + endColumn: 46, + column: 29 + } + ] + }, + { + code: 'expect(uploadFileMock).not.toHaveBeenCalledWith(\'file.name\')', + options: [ + { 'not.toHaveBeenCalledWith': 'Use not.toHaveBeenCalled instead' } + ], + errors: [ + { + messageId: 'restrictedChainWithMessage', + data: { + message: 'Use not.toHaveBeenCalled instead', + restriction: 'not.toHaveBeenCalledWith' + }, + endColumn: 48, + column: 24 + } + ] + } + ] + }) + }) +}) diff --git a/tests/no-restricted-vi-methods.test.ts b/tests/no-restricted-vi-methods.test.ts new file mode 100644 index 0000000..f10e91a --- /dev/null +++ b/tests/no-restricted-vi-methods.test.ts @@ -0,0 +1,89 @@ +import { it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/no-restricted-vi-methods' +import { ruleTester } from './ruleTester' + +it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'vi', + 'vi()', + 'vi.mock()', + 'expect(a).rejects;', + 'expect(a);', + { + code: ` + import { vi } from 'vitest'; + vi; + `, + parserOptions: { sourceType: 'module' } + } + ], + + invalid: [ + { + code: 'vi.fn()', + options: [{ fn: null }], + errors: [ + { + messageId: 'restrictedViMethod', + data: { + message: null, + restriction: 'fn' + }, + column: 4, + line: 1 + } + ] + }, + { + code: 'vi.mock()', + options: [{ mock: 'Do not use mocks' }], + errors: [ + { + messageId: 'restrictedViMethodWithMessage', + data: { + message: 'Do not use mocks', + restriction: 'mock' + }, + column: 4, + line: 1 + } + ] + }, + { + code: ` + import { vi } from 'vitest'; + vi.advanceTimersByTime(); + `, + options: [{ advanceTimersByTime: null }], + parserOptions: { sourceType: 'module' }, + errors: [ + { + messageId: 'restrictedViMethod', + data: { + message: null, + restriction: 'advanceTimersByTime' + }, + column: 9, + line: 3 + } + ] + }, + { + code: 'vi["fn"]()', + options: [{ fn: null }], + errors: [ + { + messageId: 'restrictedViMethod', + data: { + message: null, + restriction: 'fn' + }, + column: 4, + line: 1 + } + ] + } + ] + }) +}) diff --git a/src/rules/no-standalone-expect.test.ts b/tests/no-standalone-expect.test.ts similarity index 93% rename from src/rules/no-standalone-expect.test.ts rename to tests/no-standalone-expect.test.ts index 944c8f6..890b0a5 100644 --- a/src/rules/no-standalone-expect.test.ts +++ b/tests/no-standalone-expect.test.ts @@ -1,10 +1,6 @@ -import { TSESLint } from '@typescript-eslint/utils' import { describe, it } from 'vitest' -import rule, { RULE_NAME } from './no-standalone-expect' - -const ruleTester = new TSESLint.RuleTester({ - parser: require.resolve('@typescript-eslint/parser') -}) +import rule, { RULE_NAME } from '../src/rules/no-standalone-expect' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { it(RULE_NAME, () => { diff --git a/src/rules/no-test-prefixes.test.ts b/tests/no-test-prefixes.test.ts similarity index 98% rename from src/rules/no-test-prefixes.test.ts rename to tests/no-test-prefixes.test.ts index a6400b0..d309d04 100644 --- a/src/rules/no-test-prefixes.test.ts +++ b/tests/no-test-prefixes.test.ts @@ -1,6 +1,6 @@ import { TSESLint } from '@typescript-eslint/utils' import { describe, test } from 'vitest' -import rule, { RULE_NAME } from './no-test-prefixes' +import rule, { RULE_NAME } from '../src/rules/no-test-prefixes' const ruleTester = new TSESLint.RuleTester({ parser: require.resolve('@typescript-eslint/parser') diff --git a/src/rules/no-test-return-statement.test.ts b/tests/no-test-return-statement.test.ts similarity index 95% rename from src/rules/no-test-return-statement.test.ts rename to tests/no-test-return-statement.test.ts index 5a30802..c1188b3 100644 --- a/src/rules/no-test-return-statement.test.ts +++ b/tests/no-test-return-statement.test.ts @@ -1,6 +1,6 @@ import { TSESLint } from '@typescript-eslint/utils' import { describe, it } from 'vitest' -import rule, { RULE_NAME } from './no-test-return-statement' +import rule, { RULE_NAME } from '../src/rules/no-test-return-statement' const ruleTester = new TSESLint.RuleTester({ parser: require.resolve('@typescript-eslint/parser') diff --git a/src/rules/prefer-called-with.test.ts b/tests/prefer-called-with.test.ts similarity index 89% rename from src/rules/prefer-called-with.test.ts rename to tests/prefer-called-with.test.ts index eef55f8..6d31dfd 100644 --- a/src/rules/prefer-called-with.test.ts +++ b/tests/prefer-called-with.test.ts @@ -1,10 +1,6 @@ -import { TSESLint } from '@typescript-eslint/utils' import { describe, test } from 'vitest' -import rule, { RULE_NAME } from './prefer-called-with' - -const ruleTester = new TSESLint.RuleTester({ - parser: require.resolve('@typescript-eslint/parser') -}) +import rule, { RULE_NAME } from '../src/rules/prefer-called-with' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/prefer-comparison-matcher.test.ts b/tests/prefer-comparison-matcher.test.ts similarity index 94% rename from src/rules/prefer-comparison-matcher.test.ts rename to tests/prefer-comparison-matcher.test.ts index 2e29cd2..1a956fc 100644 --- a/src/rules/prefer-comparison-matcher.test.ts +++ b/tests/prefer-comparison-matcher.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-comparison-matcher' +import rule, { RULE_NAME } from '../src/rules/prefer-comparison-matcher' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/prefer-each.test.ts b/tests/prefer-each.test.ts similarity index 98% rename from src/rules/prefer-each.test.ts rename to tests/prefer-each.test.ts index 96612a0..d07b409 100644 --- a/src/rules/prefer-each.test.ts +++ b/tests/prefer-each.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-each' +import rule, { RULE_NAME } from '../src/rules/prefer-each' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/prefer-equality-matcher.test.ts b/tests/prefer-equality-matcher.test.ts similarity index 98% rename from src/rules/prefer-equality-matcher.test.ts rename to tests/prefer-equality-matcher.test.ts index a1e4261..f4bffcc 100644 --- a/src/rules/prefer-equality-matcher.test.ts +++ b/tests/prefer-equality-matcher.test.ts @@ -1,7 +1,7 @@ import { TSESLint } from '@typescript-eslint/utils' import { test, describe } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-equality-matcher' +import rule, { RULE_NAME } from '../src/rules/prefer-equality-matcher' +import { ruleTester } from './ruleTester' type RuleMessages> = TRuleModule extends TSESLint.RuleModule diff --git a/src/rules/prefer-expect-resolves.test.ts b/tests/prefer-expect-resolves.test.ts similarity index 92% rename from src/rules/prefer-expect-resolves.test.ts rename to tests/prefer-expect-resolves.test.ts index 05ecb7a..d870bdd 100644 --- a/src/rules/prefer-expect-resolves.test.ts +++ b/tests/prefer-expect-resolves.test.ts @@ -1,6 +1,6 @@ import { it, describe } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-expect-resolves' +import rule, { RULE_NAME } from '../src/rules/prefer-expect-resolves' +import { ruleTester } from './ruleTester' const messageId = 'expectResolves' diff --git a/src/rules/prefer-hooks-in-order.test.ts b/tests/prefer-hooks-in-order.test.ts similarity index 99% rename from src/rules/prefer-hooks-in-order.test.ts rename to tests/prefer-hooks-in-order.test.ts index a5ecda4..fef3cab 100644 --- a/src/rules/prefer-hooks-in-order.test.ts +++ b/tests/prefer-hooks-in-order.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-hooks-in-order' +import rule, { RULE_NAME } from '../src/rules/prefer-hooks-in-order' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { it(RULE_NAME, () => { diff --git a/src/rules/prefer-hooks-on-top.test.ts b/tests/prefer-hooks-on-top.test.ts similarity index 97% rename from src/rules/prefer-hooks-on-top.test.ts rename to tests/prefer-hooks-on-top.test.ts index 11070cc..ef2cc01 100644 --- a/src/rules/prefer-hooks-on-top.test.ts +++ b/tests/prefer-hooks-on-top.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-hooks-on-top' +import rule, { RULE_NAME } from '../src/rules/prefer-hooks-on-top' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/tests/prefer-lowercase-title.test.ts b/tests/prefer-lowercase-title.test.ts new file mode 100644 index 0000000..b4e99dd --- /dev/null +++ b/tests/prefer-lowercase-title.test.ts @@ -0,0 +1,62 @@ +import { describe, it } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/prefer-lowercase-title' +import { TestCaseName } from '../src/utils/types' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(RULE_NAME, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'it.each()', + 'it.each()(1)', + 'it.todo();', + 'describe("oo", function () {})', + 'test("foo", function () {})', + 'test(`123`, function () {})' + ], + invalid: [ + { + code: 'it("Foo MM mm", function () {})', + output: 'it("foo MM mm", function () {})', + errors: [ + { + messageId: 'lowerCaseTitle', + data: { + method: TestCaseName.it + } + } + ] + }, + { + code: 'test(`Foo MM mm`, function () {})', + output: 'test(`foo MM mm`, function () {})', + errors: [ + { + messageId: 'lowerCaseTitle', + data: { + method: TestCaseName.test + } + } + ] + }, + { + code: 'test(`SFC Compile`, function () {})', + output: 'test(`sfc compile`, function () {})', + errors: [ + { + messageId: 'lowerCaseTitle', + data: { + method: TestCaseName.test + } + } + ], + options: [ + { + lowercaseFirstCharacterOnly: false + } + ] + } + ] + }) + }) +}) diff --git a/src/rules/prefer-mock-promise-shorthand.test.ts b/tests/prefer-mock-promise-shorthand.test.ts similarity index 98% rename from src/rules/prefer-mock-promise-shorthand.test.ts rename to tests/prefer-mock-promise-shorthand.test.ts index 4192c0c..9458f15 100644 --- a/src/rules/prefer-mock-promise-shorthand.test.ts +++ b/tests/prefer-mock-promise-shorthand.test.ts @@ -1,10 +1,10 @@ import { describe, test } from 'vitest' -import tester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-mock-promise-shorthand' +import rule, { RULE_NAME } from '../src/rules/prefer-mock-promise-shorthand' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { - tester.run(RULE_NAME, rule, { + ruleTester.run(RULE_NAME, rule, { valid: [ 'describe()', 'it()', diff --git a/src/rules/prefer-snapshot-hint.test.ts b/tests/prefer-snapshot-hint.test.ts similarity index 99% rename from src/rules/prefer-snapshot-hint.test.ts rename to tests/prefer-snapshot-hint.test.ts index 77b9d85..d2a5e7e 100644 --- a/src/rules/prefer-snapshot-hint.test.ts +++ b/tests/prefer-snapshot-hint.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-snapshot-hint' +import rule, { RULE_NAME } from '../src/rules/prefer-snapshot-hint' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { it(`${RULE_NAME} (always)`, () => { diff --git a/src/rules/prefer-spy-on.test.ts b/tests/prefer-spy-on.test.ts similarity index 97% rename from src/rules/prefer-spy-on.test.ts rename to tests/prefer-spy-on.test.ts index b25eb27..1442628 100644 --- a/src/rules/prefer-spy-on.test.ts +++ b/tests/prefer-spy-on.test.ts @@ -1,7 +1,7 @@ import { describe, test } from 'vitest' import { AST_NODE_TYPES } from '@typescript-eslint/utils' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-spy-on' +import rule, { RULE_NAME } from '../src/rules/prefer-spy-on' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/prefer-strict-equal.test.ts b/tests/prefer-strict-equal.test.ts similarity index 92% rename from src/rules/prefer-strict-equal.test.ts rename to tests/prefer-strict-equal.test.ts index e7be216..0bd8920 100644 --- a/src/rules/prefer-strict-equal.test.ts +++ b/tests/prefer-strict-equal.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-strict-equal' +import rule, { RULE_NAME } from '../src/rules/prefer-strict-equal' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { it(RULE_NAME, () => { diff --git a/src/rules/prefer-to-be-falsy.test.ts b/tests/prefer-to-be-falsy.test.ts similarity index 94% rename from src/rules/prefer-to-be-falsy.test.ts rename to tests/prefer-to-be-falsy.test.ts index 8ce8585..c263f38 100644 --- a/src/rules/prefer-to-be-falsy.test.ts +++ b/tests/prefer-to-be-falsy.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-to-be-falsy' +import rule, { RULE_NAME } from '../src/rules/prefer-to-be-falsy' +import { ruleTester } from './ruleTester' const messageId = 'preferToBeFalsy' diff --git a/src/rules/prefer-to-be-object.test.ts b/tests/prefer-to-be-object.test.ts similarity index 95% rename from src/rules/prefer-to-be-object.test.ts rename to tests/prefer-to-be-object.test.ts index 10a0b77..aedb2e9 100644 --- a/src/rules/prefer-to-be-object.test.ts +++ b/tests/prefer-to-be-object.test.ts @@ -1,6 +1,6 @@ import { test, describe } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-to-be-object' +import rule, { RULE_NAME } from '../src/rules/prefer-to-be-object' +import { ruleTester } from './ruleTester' const messageId = 'preferToBeObject' diff --git a/src/rules/prefer-to-be-truthy.test.ts b/tests/prefer-to-be-truthy.test.ts similarity index 95% rename from src/rules/prefer-to-be-truthy.test.ts rename to tests/prefer-to-be-truthy.test.ts index fa9edaa..b23fff4 100644 --- a/src/rules/prefer-to-be-truthy.test.ts +++ b/tests/prefer-to-be-truthy.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-to-be-truthy' +import rule, { RULE_NAME } from '../src/rules/prefer-to-be-truthy' +import { ruleTester } from './ruleTester' const messageId = 'preferToBeTruthy' diff --git a/tests/prefer-to-be.test.ts b/tests/prefer-to-be.test.ts new file mode 100644 index 0000000..f84a153 --- /dev/null +++ b/tests/prefer-to-be.test.ts @@ -0,0 +1,118 @@ +import { it, describe } from 'vitest' +import rule, { RULE_NAME } from '../src/rules/prefer-to-be' +import { ruleTester } from './ruleTester' + +describe(RULE_NAME, () => { + it(`${RULE_NAME} toBe`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect(null).toBeNull();', + 'expect(null).not.toBeNull();', + 'expect(null).toBe(1);', + 'expect(null).toBe(-1);', + 'expect(null).toBe(1);', + 'expect(obj).toStrictEqual([ x, 1 ]);', + 'expect(obj).toStrictEqual({ x: 1 });', + 'expect(obj).not.toStrictEqual({ x: 1 });', + 'expect(value).toMatchSnapshot();', + 'expect(catchError()).toStrictEqual({ message: \'oh noes!\' })', + 'expect("something");', + 'expect(token).toStrictEqual(/[abc]+/g);', + 'expect(token).toStrictEqual(new RegExp(\'[abc]+\', \'g\'));', + 'expect(0.1 + 0.2).toEqual(0.3);' + ], + invalid: [ + { + code: 'expect(value).toEqual("my string");', + output: 'expect(value).toBe("my string");', + errors: [{ messageId: 'useToBe' }] + }, + { + code: 'expect("a string").not.toEqual(null);', + output: 'expect("a string").not.toBeNull();', + errors: [{ messageId: 'useToBeNull', column: 24, line: 1 }] + }, + { + code: 'expect("a string").not.toStrictEqual(null);', + output: 'expect("a string").not.toBeNull();', + errors: [{ messageId: 'useToBeNull', column: 24, line: 1 }] + } + ] + }) + }) + + it(`${RULE_NAME} NaN`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect(NaN).toBeNaN();', + 'expect(true).not.toBeNaN();', + 'expect({}).toEqual({});', + 'expect(something).toBe()', + 'expect(something).toBe(somethingElse)', + 'expect(something).toEqual(somethingElse)', + 'expect(something).not.toBe(somethingElse)', + 'expect(something).not.toEqual(somethingElse)', + 'expect(undefined).toBe', + 'expect("something");' + ], + invalid: [ + { + code: 'expect(NaN).toBe(NaN);', + output: 'expect(NaN).toBeNaN();', + errors: [{ messageId: 'useToBeNaN', column: 13, line: 1 }] + }, + { + code: 'expect("a string").not.toBe(NaN);', + output: 'expect("a string").not.toBeNaN();', + errors: [{ messageId: 'useToBeNaN', column: 24, line: 1 }] + }, + { + code: 'expect("a string").not.toStrictEqual(NaN);', + output: 'expect("a string").not.toBeNaN();', + errors: [{ messageId: 'useToBeNaN', column: 24, line: 1 }] + } + ] + }) + }) + + it(`${RULE_NAME} null`, () => { + ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect(null).toBeNull();', + 'expect(null).not.toBeNull();', + 'expect(null).toBe(1);', + 'expect(obj).toStrictEqual([ x, 1 ]);', + 'expect(obj).toStrictEqual({ x: 1 });', + 'expect(obj).not.toStrictEqual({ x: 1 });' + ], + invalid: [ + { + code: 'expect(null).toBe(null);', + output: 'expect(null).toBeNull();', + errors: [{ messageId: 'useToBeNull', column: 14, line: 1 }] + }, + { + code: 'expect(null).toEqual(null);', + output: 'expect(null).toBeNull();', + parserOptions: { ecmaVersion: 2017 }, + errors: [{ messageId: 'useToBeNull', column: 14, line: 1 }] + }, + { + code: 'expect("a string").not.toEqual(null as number);', + output: 'expect("a string").not.toBeNull();', + errors: [{ messageId: 'useToBeNull', column: 24, line: 1 }] + }, + { + code: 'expect(undefined).toBe(undefined as unknown as string as any);', + output: 'expect(undefined).toBeUndefined();', + errors: [{ messageId: 'useToBeUndefined', column: 19, line: 1 }] + }, + { + code: 'expect("a string").toEqual(undefined as number);', + output: 'expect("a string").toBeUndefined();', + errors: [{ messageId: 'useToBeUndefined', column: 20, line: 1 }] + } + ] + }) + }) +}) diff --git a/src/rules/prefer-to-contain.test.ts b/tests/prefer-to-contain.test.ts similarity index 98% rename from src/rules/prefer-to-contain.test.ts rename to tests/prefer-to-contain.test.ts index 03b62ae..c7acc83 100644 --- a/src/rules/prefer-to-contain.test.ts +++ b/tests/prefer-to-contain.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-to-contain' +import rule, { RULE_NAME } from '../src/rules/prefer-to-contain' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/prefer-to-have-length.test.ts b/tests/prefer-to-have-length.test.ts similarity index 95% rename from src/rules/prefer-to-have-length.test.ts rename to tests/prefer-to-have-length.test.ts index 64eace5..902f1ef 100644 --- a/src/rules/prefer-to-have-length.test.ts +++ b/tests/prefer-to-have-length.test.ts @@ -1,6 +1,6 @@ import { test, describe } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-to-have-length' +import rule, { RULE_NAME } from '../src/rules/prefer-to-have-length' +import { ruleTester } from './ruleTester' const messageId = 'preferToHaveLength' diff --git a/src/rules/prefer-todo.test.ts b/tests/prefer-todo.test.ts similarity index 95% rename from src/rules/prefer-todo.test.ts rename to tests/prefer-todo.test.ts index 266e4da..27e216b 100644 --- a/src/rules/prefer-todo.test.ts +++ b/tests/prefer-todo.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './prefer-todo' +import rule, { RULE_NAME } from '../src/rules/prefer-todo' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/require-hook.test.ts b/tests/require-hook.test.ts similarity index 98% rename from src/rules/require-hook.test.ts rename to tests/require-hook.test.ts index 207def3..7fca68f 100644 --- a/src/rules/require-hook.test.ts +++ b/tests/require-hook.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './require-hook' +import rule, { RULE_NAME } from '../src/rules/require-hook' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/require-to-throw-message.test.ts b/tests/require-to-throw-message.test.ts similarity index 96% rename from src/rules/require-to-throw-message.test.ts rename to tests/require-to-throw-message.test.ts index 9518eec..4eb0bd1 100644 --- a/src/rules/require-to-throw-message.test.ts +++ b/tests/require-to-throw-message.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './require-to-throw-message' +import rule, { RULE_NAME } from '../src/rules/require-to-throw-message' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/rules/require-top-level-describe.test.ts b/tests/require-top-level-describe.test.ts similarity index 97% rename from src/rules/require-top-level-describe.test.ts rename to tests/require-top-level-describe.test.ts index 6728a9b..20296b1 100644 --- a/src/rules/require-top-level-describe.test.ts +++ b/tests/require-top-level-describe.test.ts @@ -1,6 +1,6 @@ import { describe, test } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './require-top-level-describe' +import rule, { RULE_NAME } from '../src/rules/require-top-level-describe' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { test(RULE_NAME, () => { diff --git a/src/utils/test.ts b/tests/ruleTester.ts similarity index 86% rename from src/utils/test.ts rename to tests/ruleTester.ts index 3e845c0..8e01410 100644 --- a/src/utils/test.ts +++ b/tests/ruleTester.ts @@ -6,5 +6,5 @@ RuleTester.describe = describe RuleTester.it = it export const ruleTester: RuleTester = new RuleTester({ - parser: '@typescript-eslint/parser' + parser: '@typescript-eslint/parser' }) diff --git a/src/rules/valid-describe-callback.test.ts b/tests/valid-describe-callback.test.ts similarity index 98% rename from src/rules/valid-describe-callback.test.ts rename to tests/valid-describe-callback.test.ts index 32c4c14..c08c77a 100644 --- a/src/rules/valid-describe-callback.test.ts +++ b/tests/valid-describe-callback.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './valid-describe-callback' +import rule, { RULE_NAME } from '../src/rules/valid-describe-callback' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { it(RULE_NAME, () => { diff --git a/tests/valid-expect.test.ts b/tests/valid-expect.test.ts new file mode 100644 index 0000000..0d91702 --- /dev/null +++ b/tests/valid-expect.test.ts @@ -0,0 +1,852 @@ +import rule, { RULE_NAME } from '../src/rules/valid-expect' +import { ruleTester } from './ruleTester' + +// describe(RULE_NAME, () => { +// test(RULE_NAME + ' in promise', () => { +ruleTester.run(RULE_NAME, rule, { + valid: [ + 'expect.hasAssertions', + 'expect.hasAssertions()', + 'expect("something").toEqual("else");', + 'expect(true).toBeDefined();', + 'expect([1, 2, 3]).toEqual([1, 2, 3]);', + 'expect(undefined).not.toBeDefined();', + 'test("valid-expect", () => { return expect(Promise.resolve(2)).resolves.toBeDefined(); });', + 'test("valid-expect", () => { return expect(Promise.reject(2)).rejects.toBeDefined(); });', + 'test("valid-expect", () => { return expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', + 'test("valid-expect", () => { return expect(Promise.resolve(2)).rejects.not.toBeDefined(); });', + 'test("valid-expect", function () { return expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', + 'test("valid-expect", function () { return expect(Promise.resolve(2)).rejects.not.toBeDefined(); });', + 'test("valid-expect", function () { return Promise.resolve(expect(Promise.resolve(2)).resolves.not.toBeDefined()); });', + 'test("valid-expect", function () { return Promise.resolve(expect(Promise.resolve(2)).rejects.not.toBeDefined()); });', + 'test("valid-expect", () => expect(Promise.resolve(2)).resolves.toBeDefined());', + 'test("valid-expect", () => expect(Promise.resolve(2)).resolves.toBeDefined());', + 'test("valid-expect", () => expect(Promise.reject(2)).rejects.toBeDefined());', + 'test("valid-expect", () => expect(Promise.reject(2)).resolves.not.toBeDefined());', + 'test("valid-expect", () => expect(Promise.reject(2)).rejects.not.toBeDefined());', + 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined(); });', + 'test("valid-expect", async () => { await expect(Promise.reject(2)).rejects.not.toBeDefined(); });', + 'test("valid-expect", async function () { await expect(Promise.reject(2)).resolves.not.toBeDefined(); });', + 'test("valid-expect", async function () { await expect(Promise.reject(2)).rejects.not.toBeDefined(); });', + 'test("valid-expect", async () => { await Promise.resolve(expect(Promise.reject(2)).rejects.not.toBeDefined()); });', + 'test("valid-expect", async () => { await Promise.reject(expect(Promise.reject(2)).rejects.not.toBeDefined()); });', + 'test("valid-expect", async () => { await Promise.all([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', + 'test("valid-expect", async () => { await Promise.race([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', + 'test("valid-expect", async () => { await Promise.allSettled([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', + 'test("valid-expect", async () => { await Promise.any([expect(Promise.reject(2)).rejects.not.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });', + 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")); });', + 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).then(() => console.log("another valid case")); });', + 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().catch(() => console.log("valid-case")); });', + 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).catch(() => console.log("another valid case")); });', + 'test("valid-expect", async () => { return expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => { expect(someMock).toHaveBeenCalledTimes(1); }); });', + 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")); });', + 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).then(() => console.log("another valid case")); });', + 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().catch(() => console.log("valid-case")); });', + 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => console.log("valid-case")).catch(() => console.log("another valid case")); });', + 'test("valid-expect", async () => { await expect(Promise.reject(2)).resolves.not.toBeDefined().then(() => { expect(someMock).toHaveBeenCalledTimes(1); }); });', + ` test("valid-expect", () => { + return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => { + return expect(Promise.resolve(2)).resolves.toBe(1); + }); + }); + `, + ` test("valid-expect", () => { + return expect(functionReturningAPromise()).resolves.toEqual(1).then(async () => { + await expect(Promise.resolve(2)).resolves.toBe(1); + }); + }); + `, + ` test("valid-expect", () => { + return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => expect(Promise.resolve(2)).resolves.toBe(1)); + }); + `, + ` expect.extend({ + toResolve(obj) { + return this.isNot + ? expect(obj).toBe(true) + : expect(obj).resolves.not.toThrow(); + } + }); + `, + ` expect.extend({ + toResolve(obj) { + return this.isNot + ? expect(obj).resolves.not.toThrow() + : expect(obj).toBe(true); + } + }); + `, + ` expect.extend({ + toResolve(obj) { + return this.isNot + ? expect(obj).toBe(true) + : anotherCondition + ? expect(obj).resolves.not.toThrow() + : expect(obj).toBe(false) + } + }); + `, + { + code: 'expect(1).toBe(2);', + options: [{ maxArgs: 2 }] + }, + { + code: 'expect(1, "1 !== 2").toBe(2);', + options: [{ maxArgs: 2 }] + }, + { + code: 'test("valid-expect", () => { expect(2).not.toBe(2); });', + options: [{ asyncMatchers: ['toRejectWith'] }] + }, + { + code: 'test("valid-expect", () => { expect(Promise.reject(2)).toRejectWith(2); });', + options: [{ asyncMatchers: ['toResolveWith'] }] + }, + { + code: 'test("valid-expect", async () => { await expect(Promise.resolve(2)).toResolve(); });', + options: [{ asyncMatchers: ['toResolveWith'] }] + }, + { + code: 'test("valid-expect", async () => { expect(Promise.resolve(2)).toResolve(); });', + options: [{ asyncMatchers: ['toResolveWith'] }] + } + ], + invalid: [ + { + code: 'expect().toBe(2);', + options: [{ minArgs: undefined, maxArgs: undefined }], + errors: [ + { + messageId: 'notEnoughArgs', + data: { + s: '', + amount: 1 + } + } + ] + }, + { + code: 'expect().toBe(true);', + errors: [ + { + endColumn: 8, + column: 7, + messageId: 'notEnoughArgs', + data: { + s: '', + amount: 1 + } + } + ] + }, + { + code: 'expect().toEqual("something");', + errors: [ + { + endColumn: 8, + column: 7, + messageId: 'notEnoughArgs', + data: { + s: '', + amount: 1 + } + } + ] + }, + { + code: 'expect("something", "else").toEqual("something");', + errors: [ + { + endColumn: 28, + column: 21, + messageId: 'tooManyArgs', + data: { + s: '', + amount: 1 + } + } + ] + }, + { + code: 'expect("something", "else", "entirely").toEqual("something");', + options: [{ maxArgs: 2 }], + errors: [ + { + endColumn: 40, + column: 29, + messageId: 'tooManyArgs', + data: { + s: 's', + amount: 2 + } + } + ] + }, + { + code: 'expect("something", "else", "entirely").toEqual("something");', + options: [{ maxArgs: 2, minArgs: 2 }], + errors: [ + { + endColumn: 40, + column: 29, + messageId: 'tooManyArgs', + data: { + s: 's', + amount: 2 + } + } + ] + }, + { + code: 'expect("something", "else", "entirely").toEqual("something");', + options: [{ maxArgs: 2, minArgs: 1 }], + errors: [ + { + endColumn: 40, + column: 29, + messageId: 'tooManyArgs', + data: { + s: 's', + amount: 2 + } + } + ] + }, + { + code: 'expect("something").toEqual("something");', + options: [{ minArgs: 2 }], + errors: [ + { + endColumn: 8, + column: 7, + messageId: 'notEnoughArgs', + data: { + s: 's', + amount: 2 + } + } + ] + }, + { + code: 'expect("something", "else").toEqual("something");', + options: [{ maxArgs: 1, minArgs: 3 }], + errors: [ + { + endColumn: 8, + column: 7, + messageId: 'notEnoughArgs', + data: { + s: 's', + amount: 3 + } + }, + { + endColumn: 28, + column: 21, + messageId: 'tooManyArgs', + data: { + s: '', + amount: 1 + } + } + ] + }, + { + code: 'expect("something");', + errors: [{ endColumn: 20, column: 1, messageId: 'matcherNotFound' }] + }, + { + code: 'expect();', + errors: [{ endColumn: 9, column: 1, messageId: 'matcherNotFound' }] + }, + { + code: 'expect(true).toBeDefined;', + errors: [ + { + endColumn: 25, + column: 14, + messageId: 'matcherNotCalled' + } + ] + }, + { + code: 'expect(true).not.toBeDefined;', + errors: [ + { + endColumn: 29, + column: 18, + messageId: 'matcherNotCalled' + } + ] + }, + { + code: 'expect(true).nope.toBeDefined;', + errors: [ + { + endColumn: 30, + column: 19, + messageId: 'matcherNotCalled' + } + ] + }, + { + code: 'expect(true).nope.toBeDefined();', + errors: [ + { + endColumn: 32, + column: 1, + messageId: 'modifierUnknown' + } + ] + }, + { + code: 'expect(true).not.resolves.toBeDefined();', + errors: [ + { + endColumn: 40, + column: 1, + messageId: 'modifierUnknown' + } + ] + }, + { + code: 'expect(true).not.not.toBeDefined();', + errors: [ + { + endColumn: 35, + column: 1, + messageId: 'modifierUnknown' + } + ] + }, + { + code: 'expect(true).resolves.not.exactly.toBeDefined();', + errors: [ + { + endColumn: 48, + column: 1, + messageId: 'modifierUnknown' + } + ] + }, + { + code: 'expect(true).resolves;', + errors: [ + { + endColumn: 22, + column: 14, + messageId: 'matcherNotFound' + } + ] + }, + { + code: 'expect(true).rejects;', + errors: [ + { + endColumn: 21, + column: 14, + messageId: 'matcherNotFound' + } + ] + }, + { + code: 'expect(true).not;', + errors: [ + { + endColumn: 17, + column: 14, + messageId: 'matcherNotFound' + } + ] + }, + { + code: 'expect(Promise.resolve(2)).resolves.toBeDefined();', + errors: [ + { + column: 1, + endColumn: 50, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'expect(Promise.resolve(2)).rejects.toBeDefined();', + errors: [ + { + column: 1, + endColumn: 49, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'expect(Promise.resolve(2)).resolves.toBeDefined();', + options: [{ alwaysAwait: true }], + errors: [ + { + column: 1, + endColumn: 50, + messageId: 'asyncMustBeAwaited' + } + ] + }, + { + code: ` + expect.extend({ + toResolve(obj) { + this.isNot + ? expect(obj).toBe(true) + : expect(obj).resolves.not.toThrow(); + } + }); + `, + errors: [ + { + column: 11, + endColumn: 45, + messageId: 'asyncMustBeAwaited' + } + ] + }, + { + code: ` + expect.extend({ + toResolve(obj) { + this.isNot + ? expect(obj).resolves.not.toThrow() + : expect(obj).toBe(true); + } + }); + `, + errors: [ + { + column: 11, + endColumn: 45, + messageId: 'asyncMustBeAwaited' + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).resolves.toBeDefined(); });', + errors: [ + { + column: 30, + endColumn: 79, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).toResolve(); });', + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 30, + line: 1 + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).toResolve(); });', + options: [{ asyncMatchers: undefined }], + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 30, + line: 1 + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).toReject(); });', + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 30, + line: 1 + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).not.toReject(); });', + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 30, + line: 1 + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', + errors: [ + { + column: 30, + endColumn: 83, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).rejects.toBeDefined(); });', + errors: [ + { + column: 30, + endColumn: 78, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.resolve(2)).rejects.not.toBeDefined(); });', + errors: [ + { + column: 30, + endColumn: 82, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'test("valid-expect", async () => { expect(Promise.resolve(2)).resolves.toBeDefined(); });', + errors: [ + { + column: 36, + endColumn: 85, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'test("valid-expect", async () => { expect(Promise.resolve(2)).resolves.not.toBeDefined(); });', + errors: [ + { + column: 36, + endColumn: 89, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.reject(2)).toRejectWith(2); });', + options: [{ asyncMatchers: ['toRejectWith'] }], + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 30 + } + ] + }, + { + code: 'test("valid-expect", () => { expect(Promise.reject(2)).rejects.toBe(2); });', + options: [{ asyncMatchers: ['toRejectWith'] }], + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 30 + } + ] + }, + { + code: ` + test("valid-expect", async () => { + expect(Promise.resolve(2)).resolves.not.toBeDefined(); + expect(Promise.resolve(1)).rejects.toBeDefined(); + }); + `, + errors: [ + { + line: 3, + column: 7, + endColumn: 60, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + }, + { + line: 4, + column: 7, + endColumn: 55, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", async () => { + await expect(Promise.resolve(2)).resolves.not.toBeDefined(); + expect(Promise.resolve(1)).rejects.toBeDefined(); + }); + `, + errors: [ + { + line: 4, + column: 7, + endColumn: 55, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", async () => { + expect(Promise.resolve(2)).resolves.not.toBeDefined(); + return expect(Promise.resolve(1)).rejects.toBeDefined(); + }); + `, + options: [{ alwaysAwait: true }], + errors: [ + { + line: 3, + column: 7, + endColumn: 60, + messageId: 'asyncMustBeAwaited' + }, + { + line: 4, + column: 14, + endColumn: 62, + messageId: 'asyncMustBeAwaited' + } + ] + }, + { + code: ` + test("valid-expect", async () => { + expect(Promise.resolve(2)).resolves.not.toBeDefined(); + return expect(Promise.resolve(1)).rejects.toBeDefined(); + }); + `, + errors: [ + { + line: 3, + column: 7, + endColumn: 60, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", () => { + Promise.x(expect(Promise.resolve(2)).resolves.not.toBeDefined()); + }); + `, + errors: [ + { + line: 3, + column: 7, + endColumn: 71, + messageId: 'promisesWithAsyncAssertionsMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", () => { + Promise.resolve(expect(Promise.resolve(2)).resolves.not.toBeDefined()); + }); + `, + options: [{ alwaysAwait: true }], + errors: [ + { + line: 3, + column: 8, + endColumn: 78, + messageId: 'promisesWithAsyncAssertionsMustBeAwaited' + } + ] + }, + { + code: ` + test("valid-expect", () => { + Promise.all([ + expect(Promise.resolve(2)).resolves.not.toBeDefined(), + expect(Promise.resolve(3)).resolves.not.toBeDefined(), + ]); + }); + `, + errors: [ + { + line: 3, + column: 7, + endLine: 6, + endColumn: 9, + messageId: 'promisesWithAsyncAssertionsMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", () => { + Promise.x([ + expect(Promise.resolve(2)).resolves.not.toBeDefined(), + expect(Promise.resolve(3)).resolves.not.toBeDefined(), + ]); + });`, + errors: [ + { + line: 3, + column: 7, + endLine: 6, + endColumn: 9, + messageId: 'promisesWithAsyncAssertionsMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", () => { + const assertions = [ + expect(Promise.resolve(2)).resolves.not.toBeDefined(), + expect(Promise.resolve(3)).resolves.not.toBeDefined(), + ] + }); + `, + errors: [ + { + line: 4, + column: 9, + endLine: 4, + endColumn: 62, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + }, + { + line: 5, + column: 9, + endLine: 5, + endColumn: 62, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", () => { + const assertions = [ + expect(Promise.resolve(2)).toResolve(), + expect(Promise.resolve(3)).toReject(), + ] + }); + `, + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 7, + line: 4 + }, + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 7, + line: 5 + } + ] + }, + { + code: ` + test("valid-expect", () => { + const assertions = [ + expect(Promise.resolve(2)).not.toResolve(), + expect(Promise.resolve(3)).resolves.toReject(), + ] + }); + `, + errors: [ + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 9, + line: 4 + }, + { + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' }, + column: 9, + line: 5 + } + ] + }, + { + code: 'expect(Promise.resolve(2)).resolves.toBe;', + errors: [ + { + column: 37, + endColumn: 41, + messageId: 'matcherNotCalled' + } + ] + }, + { + code: ` + test("valid-expect", () => { + return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => { + expect(Promise.resolve(2)).resolves.toBe(1); + }); + }); + `, + errors: [ + { + line: 4, + column: 9, + endLine: 4, + endColumn: 52, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", () => { + return expect(functionReturningAPromise()).resolves.toEqual(1).then(async () => { + await expect(Promise.resolve(2)).resolves.toBe(1); + expect(Promise.resolve(4)).resolves.toBe(4); + }); + }); + `, + errors: [ + { + line: 5, + column: 9, + endLine: 5, + endColumn: 52, + messageId: 'asyncMustBeAwaited', + data: { orReturned: ' or returned' } + } + ] + }, + { + code: ` + test("valid-expect", async () => { + await expect(Promise.resolve(1)); + }); + `, + errors: [{ endColumn: 39, column: 13, messageId: 'matcherNotFound' }] + } + ] +}) +// }) +// }) diff --git a/src/rules/valid-title.test.ts b/tests/valid-title.test.ts similarity index 99% rename from src/rules/valid-title.test.ts rename to tests/valid-title.test.ts index b836b99..373cccc 100644 --- a/src/rules/valid-title.test.ts +++ b/tests/valid-title.test.ts @@ -1,6 +1,6 @@ import { describe, it } from 'vitest' -import ruleTester from '../utils/tester' -import rule, { RULE_NAME } from './valid-title' +import rule, { RULE_NAME } from '../src/rules/valid-title' +import { ruleTester } from './ruleTester' describe(RULE_NAME, () => { it(`${RULE_NAME} - disallowed option`, () => { diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..221e9ed --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig, configDefaults } from 'vitest/config' + +export default defineConfig({ + test: { + include: ['tests/*.test.ts'], + exclude: [...configDefaults.exclude] + } +})