From 9f43fbe51e05992f0a9c44bc1567141d8332472a Mon Sep 17 00:00:00 2001 From: James Henry Date: Sun, 10 Jun 2018 17:44:00 -0400 Subject: [PATCH] Chore: Powerful integration tests and improved README --- .eslintignore | 1 + .travis.yml | 9 +- README.md | 75 +- package.json | 4 +- tests/integration/.eslintrc.yml | 2 - .../.eslintrc.yml | 6 + .../Dockerfile | 22 + .../expected-lint-output.json | 214 ++++++ .../index.ts} | 0 .../package.json | 13 + tests/integration/docker-compose.yml | 52 ++ tests/integration/from-babel-eslint.spec.js | 710 ------------------ tests/integration/jest.config.js | 5 - .../jsdoc-indent-issues-344-422/.eslintrc.yml | 7 + .../jsdoc-indent-issues-344-422/Dockerfile | 22 + .../expected-lint-output.json | 1 + .../index.ts} | 0 .../jsdoc-indent-issues-344-422/package.json | 13 + .../method-overloads-issue-389/.eslintrc.yml | 11 + .../method-overloads-issue-389/Dockerfile | 22 + .../expected-lint-output.json | 1 + .../method-overloads-issue-389/index.ts | 7 + .../method-overloads-issue-389/package.json | 13 + .../.eslintrc.yml | 7 + .../Dockerfile | 22 + .../expected-lint-output.json | 1 + .../index.ts} | 0 .../package.json | 13 + .../.eslintrc.yml | 7 + .../range-error-indent-issue-333/Dockerfile | 22 + .../expected-lint-output.json | 1 + .../index.ts} | 0 .../range-error-indent-issue-333/package.json | 13 + tests/integration/typescript.spec.js | 210 ------ tests/integration/utils.js | 104 --- 35 files changed, 555 insertions(+), 1055 deletions(-) create mode 100644 .eslintignore delete mode 100644 tests/integration/.eslintrc.yml create mode 100644 tests/integration/declared-empty-body-functions-issue-162/.eslintrc.yml create mode 100644 tests/integration/declared-empty-body-functions-issue-162/Dockerfile create mode 100644 tests/integration/declared-empty-body-functions-issue-162/expected-lint-output.json rename tests/integration/{external-fixtures/declared-empty-body-functions.js => declared-empty-body-functions-issue-162/index.ts} (100%) create mode 100644 tests/integration/declared-empty-body-functions-issue-162/package.json create mode 100644 tests/integration/docker-compose.yml delete mode 100644 tests/integration/from-babel-eslint.spec.js delete mode 100644 tests/integration/jest.config.js create mode 100644 tests/integration/jsdoc-indent-issues-344-422/.eslintrc.yml create mode 100644 tests/integration/jsdoc-indent-issues-344-422/Dockerfile create mode 100644 tests/integration/jsdoc-indent-issues-344-422/expected-lint-output.json rename tests/integration/{external-fixtures/jsdoc-indent.js => jsdoc-indent-issues-344-422/index.ts} (100%) create mode 100644 tests/integration/jsdoc-indent-issues-344-422/package.json create mode 100644 tests/integration/method-overloads-issue-389/.eslintrc.yml create mode 100644 tests/integration/method-overloads-issue-389/Dockerfile create mode 100644 tests/integration/method-overloads-issue-389/expected-lint-output.json create mode 100644 tests/integration/method-overloads-issue-389/index.ts create mode 100644 tests/integration/method-overloads-issue-389/package.json create mode 100644 tests/integration/no-redeclare-overloaded-functions-issue-402/.eslintrc.yml create mode 100644 tests/integration/no-redeclare-overloaded-functions-issue-402/Dockerfile create mode 100644 tests/integration/no-redeclare-overloaded-functions-issue-402/expected-lint-output.json rename tests/integration/{external-fixtures/no-redeclare-overloaded-functions.js => no-redeclare-overloaded-functions-issue-402/index.ts} (100%) create mode 100644 tests/integration/no-redeclare-overloaded-functions-issue-402/package.json create mode 100644 tests/integration/range-error-indent-issue-333/.eslintrc.yml create mode 100644 tests/integration/range-error-indent-issue-333/Dockerfile create mode 100644 tests/integration/range-error-indent-issue-333/expected-lint-output.json rename tests/integration/{external-fixtures/range-error-indent.js => range-error-indent-issue-333/index.ts} (100%) create mode 100644 tests/integration/range-error-indent-issue-333/package.json delete mode 100644 tests/integration/typescript.spec.js delete mode 100644 tests/integration/utils.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..da86dd0 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +tests/integration/* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 4a6efad..c3bda60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,15 @@ +sudo: required + +services: + - docker + language: node_js -sudo: false + node_js: - "6" - "8" - "9" + - "10" + after_success: - npm run coveralls diff --git a/README.md b/README.md index 484da02..e4dce3c 100644 --- a/README.md +++ b/README.md @@ -2,54 +2,87 @@ A parser that converts TypeScript source code into an [ESTree](https://github.com/estree/estree)-compatible form. -**Important:** This parser is not fully compatible with all ESLint rules and plugins. Some rules will improperly mark source code as failing or not find problems where it should. +## Usage -## Supported TypeScript Version +This parser is actually somewhat generic and robust - it could be used to power any use-case which requires taking TypeScript source code and producing an ESTree-compatiable AST. -We will always endeavor to support the latest stable version of TypeScript. +In fact, that is exactly what it is used for in the popular open-source code formatter, [Prettier](https://prettier.io), to power its TypeScript support. -The version of TypeScript currently supported by this parser is `~2.9.1`. This is reflected in the `devDependency` requirement within the package.json file, and it is what the tests will be run against. We have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript. +Nevertheless, the parser does have a special appreciation for ESLint-specific use-cases built in, and can even produce a slightly different AST for ESLint if needed (using the special `parseForESLint()` method). -If you use a non-supported version of TypeScript, the parser will log a warning to the console. +The majority of users of this parser use it to enable them to use ESLint on their TypeScript source files, so they will not actually be interacting with the parser directly. Instead they will configure ESLint to use it instead of its default parser, [espree](https://github.com/eslint/espree), which does not understand TypeScript. -**Please ensure that you are using a supported version before submitting any issues/bug reports.** +## Usage with ESLint -## Known Issues +There is sometimes an incorrect assumption that the parser itself is what does everything necessary to facilitate the use of ESLint with TypeScript. In actuality, it is the combination of the parser _and_ one or more plugins which allow you to maximize your usage of ESLint with TypeScript. -The following ESLint rules will fail on acceptable code: - - no-undef [#416](https://github.com/eslint/typescript-eslint-parser/issues/416) - -The follow ESLint plugins have issues when used with this parser: - - eslint-plugin-import - - prefer-default-export - Will fail exports inside of Namespaces or Modules +For example, once this parser successfully produces an AST for the TypeScript source code, it might well contain some information which simply does not exist in a standard JavaScript context, such as the data for a TypeScript-specific construct, like an `interface`. -## Usage +The core rules built into ESLint, such as `indent` have no knowledge of such constructs, so it is impossible to expect them to work out of the box with them. + +Instead, you also need to make use of one more plugins which will add or extend rules with TypeScript-specific features. + +By far the most common case will be installing the [eslint-plugin-typescript](https://github.com/nzakas/eslint-plugin-typescript) plugin, but there are also other relevant options available such a [eslint-plugin-tslint](https://github.com/JamesHenry/eslint-plugin-tslint). Install: -``` -npm i typescript-eslint-parser --save-dev +```sh +npm install --save-dev typescript-eslint-parser ``` And in your ESLint configuration file: -``` +```json "parser": "typescript-eslint-parser" ``` +## Supported TypeScript Version + +We will always endeavor to support the latest stable version of TypeScript. + +The version of TypeScript currently supported by this parser is `~2.9.1`. This is reflected in the `devDependency` requirement within the package.json file, and it is what the tests will be run against. We have an open `peerDependency` requirement in order to allow for experimentation on newer/beta versions of TypeScript. + +If you use a non-supported version of TypeScript, the parser will log a warning to the console. + +**Please ensure that you are using a supported version before submitting any issues/bug reports.** + ## Help Wanted! If you're familiar with TypeScript and ESLint, and you'd like to see this project progress, please consider contributing. We need people with a good knowledge of TypeScript to ensure this parser is useful. -## Reporting Bugs +## Reporting Issues -Please check the current list of open and known issues and ensure the bug has not been reported before. When creating a new issue provide as much information about your environment as possible. This includes: +The vast majority of issues which are submitted here are not actually parsing bugs at all. They are integration issues with the ESLint ecosystem. + +This is not ideal, but users need a place to be able to report those things, so it has become accepted that that will also be done in this repo. + +Please check the current list of open and known issues and ensure the issue has not been reported before. When creating a new issue provide as much information about your environment as possible. This includes: - ESLint Version - TypeScript version - - TypeScript parser version + - The `typescript-eslint-parser` version - ESLint config or rules and plugins currently enabled -As well include a small code sample that can be used to reproduce the issue. +## Integration Tests + +We have a very flexible way of running integration tests which connects all of the moving parts of the usage of this parser in the ESLint ecosystem. + +We run each test within its own docker container, and so each one has complete autonomy over what dependencies/plugins are installed and what versions are used. This also has the benefit of not bloating the `package.json` and `node_modules` of the parser project itself. + +> If you are going to submit an issue related to the usage of this parser with ESLint, please consider creating a failing integration which clearly demonstrates the behavior. It's honestly super quick! + +You just need to duplicate on of the existing test sub-directories found in `tests/integration/`, tweak the dependencies and ESLint config to match what you need, and add a new entry to the docker-compose.yml file which matches the format of the existing ones. + +Then run: + +```sh +npm run integration-tests +``` + +If you ever need to change what gets installed when the docker images are built by docker-compose, you will first need to kill the existing containers by running: + +```sh +npm run kill-integration-test-containers +``` ## Contributing diff --git a/package.json b/package.json index 85649ee..999e8e7 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "devDependencies": { "babel-code-frame": "6.26.0", "babylon": "7.0.0-beta.39", - "dedent": "0.7.0", "eslint": "4.19.1", "eslint-config-eslint": "4.0.0", "eslint-plugin-node": "6.0.1", @@ -46,7 +45,8 @@ "test": "node Makefile.js test && npm run integration-tests && npm run ast-alignment-tests", "jest": "jest", "ast-alignment-tests": "jest --config=./tests/ast-alignment/jest.config.js", - "integration-tests": "jest --config=./tests/integration/jest.config.js", + "integration-tests": "docker-compose -f tests/integration/docker-compose.yml up", + "kill-integration-test-containers": "docker-compose -f tests/integration/docker-compose.yml down -v --rmi local", "lint": "node Makefile.js lint", "release": "eslint-release", "ci-release": "eslint-ci-release", diff --git a/tests/integration/.eslintrc.yml b/tests/integration/.eslintrc.yml deleted file mode 100644 index e19b2cf..0000000 --- a/tests/integration/.eslintrc.yml +++ /dev/null @@ -1,2 +0,0 @@ -env: - jest: true diff --git a/tests/integration/declared-empty-body-functions-issue-162/.eslintrc.yml b/tests/integration/declared-empty-body-functions-issue-162/.eslintrc.yml new file mode 100644 index 0000000..55c9336 --- /dev/null +++ b/tests/integration/declared-empty-body-functions-issue-162/.eslintrc.yml @@ -0,0 +1,6 @@ +root: true + +# typescript-eslint-parser +parser: /usr/parser/parser.js + +extends: eslint:all diff --git a/tests/integration/declared-empty-body-functions-issue-162/Dockerfile b/tests/integration/declared-empty-body-functions-issue-162/Dockerfile new file mode 100644 index 0000000..37142ae --- /dev/null +++ b/tests/integration/declared-empty-body-functions-issue-162/Dockerfile @@ -0,0 +1,22 @@ +FROM node:carbon + +# Copy the package.json into the container so that we can +# run the install. Every other file will be linked, rather +# than copied to allow for changes without rebuilds +WORKDIR /usr +COPY ./package.json /usr/ + +# Create file which will be executed by jest +# to assert that the lint output is what we expect +RUN echo "const expectedLintOutput = require('./linked/expected-lint-output.json');\n" \ + "const actualLintOutput = require('./lint-output.json');\n" \ + "\n" \ + "test('it should produce the expected lint ouput', () => {\n" \ + " expect(actualLintOutput).toEqual(expectedLintOutput);\n" \ + "});\n" > test.js + +# Install dependencies +RUN npm install + +# Run ESLint and assert that the output matches our expectations +CMD [ "npm", "start" ] diff --git a/tests/integration/declared-empty-body-functions-issue-162/expected-lint-output.json b/tests/integration/declared-empty-body-functions-issue-162/expected-lint-output.json new file mode 100644 index 0000000..39dd864 --- /dev/null +++ b/tests/integration/declared-empty-body-functions-issue-162/expected-lint-output.json @@ -0,0 +1,214 @@ +[{ + "filePath": "/usr/linked/index.ts", + "messages": [{ + "ruleId": "strict", + "severity": 2, + "message": "Use the function form of 'use strict'.", + "line": 1, + "column": 1, + "nodeType": "ExpressionStatement", + "source": "\"use strict\";", + "endLine": 1, + "endColumn": 14 + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'FF' is not defined.", + "line": 3, + "column": 19, + "nodeType": "Identifier", + "source": "declare namespace FF {", + "endLine": 3, + "endColumn": 21 + }, { + "ruleId": "no-unused-vars", + "severity": 2, + "message": "'Foo' is defined but never used.", + "line": 4, + "column": 11, + "nodeType": "Identifier", + "source": " class Foo extends Bar.Baz {", + "endLine": 4, + "endColumn": 14 + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'Bar' is not defined.", + "line": 4, + "column": 23, + "nodeType": "Identifier", + "source": " class Foo extends Bar.Baz {", + "endLine": 4, + "endColumn": 26 + }, { + "ruleId": "padded-blocks", + "severity": 2, + "message": "Block must be padded by blank lines.", + "line": 4, + "column": 31, + "nodeType": "ClassBody", + "source": " class Foo extends Bar.Baz {", + "fix": { + "range": [69, 69], + "text": "\n" + } + }, { + "ruleId": "padded-blocks", + "severity": 2, + "message": "Block must be padded by blank lines.", + "line": 6, + "column": 5, + "nodeType": "ClassBody", + "source": " }", + "fix": { + "range": [94, 94], + "text": "\n" + } + }, { + "ruleId": "no-redeclare", + "severity": 2, + "message": "'Foo' is already defined.", + "line": 10, + "column": 11, + "nodeType": "Identifier", + "source": " class Foo extends Bar.Baz {", + "endLine": 10, + "endColumn": 14 + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'Bar' is not defined.", + "line": 10, + "column": 23, + "nodeType": "Identifier", + "source": " class Foo extends Bar.Baz {", + "endLine": 10, + "endColumn": 26 + }, { + "ruleId": "padded-blocks", + "severity": 2, + "message": "Block must be padded by blank lines.", + "line": 10, + "column": 31, + "nodeType": "ClassBody", + "source": " class Foo extends Bar.Baz {", + "fix": { + "range": [152, 152], + "text": "\n" + } + }, { + "ruleId": "padded-blocks", + "severity": 2, + "message": "Block must be padded by blank lines.", + "line": 12, + "column": 5, + "nodeType": "ClassBody", + "source": " }", + "fix": { + "range": [177, 177], + "text": "\n" + } + }, { + "ruleId": "no-redeclare", + "severity": 2, + "message": "'Foo' is already defined.", + "line": 15, + "column": 15, + "nodeType": "Identifier", + "source": "declare class Foo extends Bar.Baz {", + "endLine": 15, + "endColumn": 18 + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'Bar' is not defined.", + "line": 15, + "column": 27, + "nodeType": "Identifier", + "source": "declare class Foo extends Bar.Baz {", + "endLine": 15, + "endColumn": 30 + }, { + "ruleId": "padded-blocks", + "severity": 2, + "message": "Block must be padded by blank lines.", + "line": 15, + "column": 35, + "nodeType": "ClassBody", + "source": "declare class Foo extends Bar.Baz {", + "fix": { + "range": [217, 217], + "text": "\n" + } + }, { + "ruleId": "padded-blocks", + "severity": 2, + "message": "Block must be padded by blank lines.", + "line": 17, + "column": 1, + "nodeType": "ClassBody", + "source": "}", + "fix": { + "range": [234, 234], + "text": "\n" + } + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'d3' is not defined.", + "line": 19, + "column": 19, + "nodeType": "Identifier", + "source": "declare namespace d3 {", + "endLine": 19, + "endColumn": 21 + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'select' is not defined.", + "line": 20, + "column": 21, + "nodeType": "Identifier", + "source": " export function select(selector: string): Selection;", + "endLine": 20, + "endColumn": 27 + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'selector' is not defined.", + "line": 20, + "column": 28, + "nodeType": "Identifier", + "source": " export function select(selector: string): Selection;", + "endLine": 20, + "endColumn": 44 + }, { + "ruleId": "no-undef", + "severity": 2, + "message": "'Selection' is not defined.", + "line": 20, + "column": 47, + "nodeType": "Identifier", + "source": " export function select(selector: string): Selection;", + "endLine": 20, + "endColumn": 56 + }, { + "ruleId": "eol-last", + "severity": 2, + "message": "Newline required at end of file but not found.", + "line": 21, + "column": 2, + "nodeType": "Program", + "source": "}", + "messageId": "missing", + "fix": { + "range": [323, 323], + "text": "\n" + } + }], + "errorCount": 19, + "warningCount": 0, + "fixableErrorCount": 7, + "fixableWarningCount": 0, + "source": "\"use strict\";\n\ndeclare namespace FF {\n class Foo extends Bar.Baz {\n far(): any;\n }\n}\n\ndeclare module \"FF\" {\n class Foo extends Bar.Baz {\n far(): any;\n }\n}\n\ndeclare class Foo extends Bar.Baz {\n far(): any;\n}\n\ndeclare namespace d3 {\n export function select(selector: string): Selection;\n}" +}] \ No newline at end of file diff --git a/tests/integration/external-fixtures/declared-empty-body-functions.js b/tests/integration/declared-empty-body-functions-issue-162/index.ts similarity index 100% rename from tests/integration/external-fixtures/declared-empty-body-functions.js rename to tests/integration/declared-empty-body-functions-issue-162/index.ts diff --git a/tests/integration/declared-empty-body-functions-issue-162/package.json b/tests/integration/declared-empty-body-functions-issue-162/package.json new file mode 100644 index 0000000..6881c73 --- /dev/null +++ b/tests/integration/declared-empty-body-functions-issue-162/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "scripts": { + "start": "npm run lint && npm run test", + "lint": "eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.ts || true", + "test": "jest ./test.js" + }, + "devDependencies": { + "eslint": "4.19.1", + "jest": "23.1.0", + "typescript": "~2.9.1" + } +} \ No newline at end of file diff --git a/tests/integration/docker-compose.yml b/tests/integration/docker-compose.yml new file mode 100644 index 0000000..e987e75 --- /dev/null +++ b/tests/integration/docker-compose.yml @@ -0,0 +1,52 @@ +version: '3' + +services: + range-error-indent-issue-333: + build: ./range-error-indent-issue-333 + container_name: "range-error-indent-issue-333" + volumes: + # link to all the integration test files, so that updates don't require a rebuild + - ./range-error-indent-issue-333:/usr/linked + # link to parser source, but "ignore" tests (by overriding it with an empty dir) + - ../../:/usr/parser + - /usr/parser/tests + + no-redeclare-overloaded-functions-issue-402: + build: ./no-redeclare-overloaded-functions-issue-402 + container_name: "no-redeclare-overloaded-functions-issue-402" + volumes: + # link to all the integration test files, so that updates don't require a rebuild + - ./no-redeclare-overloaded-functions-issue-402:/usr/linked + # link to parser source, but "ignore" tests (by overriding it with an empty dir) + - ../../:/usr/parser + - /usr/parser/tests + + declared-empty-body-functions-issue-162: + build: ./declared-empty-body-functions-issue-162 + container_name: "declared-empty-body-functions-issue-162" + volumes: + # link to all the integration test files, so that updates don't require a rebuild + - ./declared-empty-body-functions-issue-162:/usr/linked + # link to parser source, but "ignore" tests (by overriding it with an empty dir) + - ../../:/usr/parser + - /usr/parser/tests + + jsdoc-indent-issues-344-422: + build: ./jsdoc-indent-issues-344-422 + container_name: "jsdoc-indent-issues-344-422" + volumes: + # link to all the integration test files, so that updates don't require a rebuild + - ./jsdoc-indent-issues-344-422:/usr/linked + # link to parser source, but "ignore" tests (by overriding it with an empty dir) + - ../../:/usr/parser + - /usr/parser/tests + + method-overloads-issue-389: + build: ./method-overloads-issue-389 + container_name: "method-overloads-issue-389" + volumes: + # link to all the integration test files, so that updates don't require a rebuild + - ./method-overloads-issue-389:/usr/linked + # link to parser source, but "ignore" tests (by overriding it with an empty dir) + - ../../:/usr/parser + - /usr/parser/tests diff --git a/tests/integration/from-babel-eslint.spec.js b/tests/integration/from-babel-eslint.spec.js deleted file mode 100644 index 51449fa..0000000 --- a/tests/integration/from-babel-eslint.spec.js +++ /dev/null @@ -1,710 +0,0 @@ -/** - * LICENCE from babel-eslint - */ -// Copyright (c) 2014-2016 Sebastian McKenzie - -// MIT License - -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: - -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -"use strict"; - -const unpad = require("dedent"); - -const utils = require("./utils"); -const verifyAndAssertMessages = utils.verifyAndAssertMessages; - -describe("Non-regression tests from babel-eslint", () => { - it("arrow function support", () => { - verifyAndAssertMessages("describe('stuff', () => {});", {}, []); - }); - - it("EOL validation", () => { - verifyAndAssertMessages( - "module.exports = \"something\";", - { "eol-last": 1, semi: 1 }, - ["1:30 Newline required at end of file but not found. eol-last"] - ); - }); - - it("Modules support", () => { - verifyAndAssertMessages( - unpad(` - import Foo from 'foo'; - export default Foo; - export const c = 'c'; - export class Store {} - `), - {}, - [], - "module" - ); - }); - - it("Rest parameters", () => { - verifyAndAssertMessages( - "function foo(...args) { return args; }", - { "no-undef": 1 }, - [] - ); - }); - - it("Exported classes should be used", () => { - verifyAndAssertMessages( - "class Foo {} module.exports = Foo;", - { "no-unused-vars": 1 }, - [] - ); - }); - - it("super keyword in class", () => { - verifyAndAssertMessages( - "class Foo { constructor() { super() } }", - { "no-undef": 1 }, - [] - ); - }); - - it("Rest parameter in destructuring assignment", () => { - verifyAndAssertMessages( - "const [a, ...rest] = ['1', '2', '3']; module.exports = rest;", - { "no-undef": 1 }, - [], - "script", - { - envs: ["node"] - } - ); - }); - - it("JSX attribute names marked as variables", () => { - verifyAndAssertMessages( - "module.exports =
", - { "no-undef": 1 }, - [], - "script", - { - envs: ["node"] - } - ); - }); - - it("Multiple destructured assignment with compound properties", () => { - verifyAndAssertMessages( - "module.exports = { ...a.a, ...a.b };", - { "no-dupe-keys": 1 }, - [] - ); - }); - - it("Arrow function with non-block bodies", () => { - verifyAndAssertMessages( - "\"use strict\"; () => 1", - { strict: [1, "global"] }, - [], - "script" - ); - }); - - it("babel/babel-eslint#242", () => { - verifyAndAssertMessages( - "\"use strict\"; asdf;", - { "no-irregular-whitespace": 1 }, - [], - {} - ); - }); - - it("await keyword", () => { - verifyAndAssertMessages( - "async function foo() { await bar(); }", - { "no-unused-expressions": 1 }, - [] - ); - }); - - it("arrow functions", () => { - verifyAndAssertMessages( - "[1, 2, 3].map(i => i * 2);", - { "func-names": 1, "space-before-blocks": 1 }, - [] - ); - }); - - it("comment with padded-blocks", () => { - verifyAndAssertMessages( - unpad(` - if (a) { - // i'm a comment! - let b = c - } - `), - { "padded-blocks": [1, "never"] }, - [] - ); - }); - - it("class usage", () => { - verifyAndAssertMessages( - "class Lol {} module.exports = Lol;", - { "no-unused-vars": 1 }, - [] - ); - }); - - it("class definition: gaearon/redux#24", () => { - verifyAndAssertMessages( - unpad(` - export default function root(stores) { - return DecoratedComponent => class ReduxRootDecorator { - a() { DecoratedComponent; stores; } - }; - } - `), - { "no-undef": 1, "no-unused-vars": 1 }, - [] - ); - }); - - it("template strings", () => { - verifyAndAssertMessages( - "console.log(`${a}, b`);", - { "comma-spacing": 1 }, - [] - ); - }); - - it("template with destructuring", () => { - verifyAndAssertMessages( - unpad(` - module.exports = { - render() { - var {name} = this.props; - return Math.max(null, \`Name: \${name}, Name: \${name}\`); - } - }; - `), - { "comma-spacing": 1 }, - [] - ); - }); - - describe("decorators", () => { - // it("class declaration", () => { - // verifyAndAssertMessages( - // unpad(` - // import classDeclaration from 'decorator'; - // import decoratorParameter from 'decorator'; - // @classDeclaration((parameter) => parameter) - // @classDeclaration(decoratorParameter) - // @classDeclaration - // export class TextareaAutosize {} - // `), - // { "no-unused-vars": 1 }, - // [], - // "module" - // ); - // }); - - // it("method definition", () => { - // verifyAndAssertMessages( - // unpad(` - // import classMethodDeclarationA from 'decorator'; - // import decoratorParameter from 'decorator'; - // export class TextareaAutosize { - // @classMethodDeclarationA((parameter) => parameter) - // @classMethodDeclarationA(decoratorParameter) - // @classMethodDeclarationA - // methodDeclaration(e) { - // e(); - // } - // } - // `), - // { "no-unused-vars": 1 }, - // [] - // ); - // }); - - // it("method definition get/set", () => { - // verifyAndAssertMessages( - // unpad(` - // import classMethodDeclarationA from 'decorator'; - // import decoratorParameter from 'decorator'; - // export class TextareaAutosize { - // @classMethodDeclarationA((parameter) => parameter) - // @classMethodDeclarationA(decoratorParameter) - // @classMethodDeclarationA - // get bar() { } - // @classMethodDeclarationA((parameter) => parameter) - // @classMethodDeclarationA(decoratorParameter) - // @classMethodDeclarationA - // set bar(val) { val; } - // } - // `), - // { "no-unused-vars": 1 }, - // [] - // ); - // }); - - // it("object property", () => { - // verifyAndAssertMessages( - // unpad(` - // import classMethodDeclarationA from 'decorator'; - // import decoratorParameter from 'decorator'; - // var obj = { - // @classMethodDeclarationA((parameter) => parameter) - // @classMethodDeclarationA(decoratorParameter) - // @classMethodDeclarationA - // methodDeclaration(e) { - // e(); - // } - // }; - // obj; - // `), - // { "no-unused-vars": 1 }, - // [] - // ); - // }); - - // it("object property get/set", () => { - // verifyAndAssertMessages( - // unpad(` - // import classMethodDeclarationA from 'decorator'; - // import decoratorParameter from 'decorator'; - // var obj = { - // @classMethodDeclarationA((parameter) => parameter) - // @classMethodDeclarationA(decoratorParameter) - // @classMethodDeclarationA - // get bar() { }, - // @classMethodDeclarationA((parameter) => parameter) - // @classMethodDeclarationA(decoratorParameter) - // @classMethodDeclarationA - // set bar(val) { val; } - // }; - // obj; - // `), - // { "no-unused-vars": 1 }, - // [] - // ); - // }); - }); - - it("detects minimal no-unused-vars case", () => { - verifyAndAssertMessages("var unused;", { "no-unused-vars": 1 }, [ - "1:5 'unused' is defined but never used. no-unused-vars" - ]); - }); - - // This two tests are disabled, as the feature to visit properties when - // there is a spread/rest operator has been removed as it caused problems - // with other rules - it.skip("visits excluded properties left of spread", () => { - verifyAndAssertMessages( - "var originalObject = {}; var {field1, field2, ...clone} = originalObject;", - { "no-unused-vars": 1 }, - [] - ); - }); - - it.skip("visits excluded properties left of spread", () => { - verifyAndAssertMessages( - "const props = { yo: 'yo' }; const { ...otherProps } = props;", - { "no-unused-vars": 1 }, - [] - ); - }); - - it("does not mark spread variables false-positive", () => { - verifyAndAssertMessages( - "var originalObject = {}; var {field1, field2, ...clone} = originalObject;", - { "no-undef": 1, "no-redeclare": 1 }, - [] - ); - }); - - it("does not mark spread variables false-positive", () => { - verifyAndAssertMessages( - "const props = { yo: 'yo' }; const { ...otherProps } = props;", - { "no-undef": 1, "no-redeclare": 1 }, - [] - ); - }); - - it("does not mark spread variables as use-before-define", () => { - verifyAndAssertMessages( - "var originalObject = {}; var {field1, field2, ...clone} = originalObject;", - { "no-use-before-define": 1 }, - [] - ); - }); - - it("detects no-unused-vars with object destructuring", () => { - verifyAndAssertMessages( - "const {Bacona} = require('baconjs')", - { "no-undef": 1, "no-unused-vars": 1 }, - ["1:8 'Bacona' is assigned a value but never used. no-unused-vars"], - "script", - { - envs: ["node"] - } - ); - }); - - it("don't warn no-unused-vars with spread", () => { - verifyAndAssertMessages( - unpad(` - export default function test(data) { - return { - foo: 'bar', - ...data - }; - } - `), - { "no-undef": 1, "no-unused-vars": 1 }, - [] - ); - }); - - it("excludes comment tokens", () => { - verifyAndAssertMessages( - unpad(` - var a = [ - 1, - 2, // a trailing comment makes this line fail comma-dangle (always-multiline) - ]; - `), - { "comma-dangle": [2, "always-multiline"] }, - [] - ); - - verifyAndAssertMessages( - unpad(` - switch (a) { - // A comment here makes the above line fail brace-style - case 1: - console.log(a); - } - `), - { "brace-style": 2 }, - [] - ); - }); - - it("ternary and parens", () => { - verifyAndAssertMessages( - "true ? (true) : false;", - { "space-infix-ops": 1 }, - [] - ); - }); - - it("line comment space-in-parens", () => { - verifyAndAssertMessages( - unpad(` - React.createClass({ - render() { - // return ( - //
- // ); // <-- this is the line that is reported - } - }); - `), - { "space-in-parens": 1 }, - [] - ); - }); - - it("block comment space-in-parens", () => { - verifyAndAssertMessages( - unpad(` - React.createClass({ - render() { - /* - return ( -
- ); // <-- this is the line that is reported - */ - } - }); - `), - { "space-in-parens": 1 }, - [] - ); - }); - - it("no no-undef error with rest", () => { - verifyAndAssertMessages( - "const [a, ...rest] = ['1', '2', '3']; a; rest;", - { "no-undef": 1, "no-unused-vars": 1 }, - [] - ); - }); - - it("async function with space-before-function-paren", () => { - verifyAndAssertMessages( - "it('handles updates', async function() {});", - { "space-before-function-paren": [1, "never"] }, - [] - ); - }); - - it("no-use-before-define", () => { - verifyAndAssertMessages( - unpad(` - console.log(x); - var x = 1; - `), - { "no-use-before-define": 1 }, - ["1:13 'x' was used before it was defined. no-use-before-define"] - ); - }); - - it("jsx and stringliteral", () => { - verifyAndAssertMessages("
", {}, []); - }); - - it("getter/setter", () => { - verifyAndAssertMessages( - unpad(` - class Person { - set a (v) { } - } - `), - { - "space-before-function-paren": 1, - "keyword-spacing": [1, { before: true }], - indent: 1 - }, - [] - ); - }); - - it("getter/setter", () => { - verifyAndAssertMessages( - unpad(` - var B = { - get x () { - return this.ecks; - }, - set x (ecks) { - this.ecks = ecks; - } - }; - `), - { "no-dupe-keys": 1 }, - [] - ); - }); - - it("correctly detects redeclares if in script mode", () => { - verifyAndAssertMessages( - unpad(` - var a = 321; - var a = 123; - `), - { "no-redeclare": 1 }, - ["2:5 'a' is already defined. no-redeclare"], - "script" - ); - }); - - // it("correctly detects redeclares if in module mode", () => { - // verifyAndAssertMessages( - // unpad(` - // var a = 321; - // var a = 123; - // `), - // { "no-redeclare": 1 }, - // ["2:5 'a' is already defined. no-redeclare"], - // "module" - // ); - // }); - - it("no-implicit-globals in script", () => { - verifyAndAssertMessages( - "var leakedGlobal = 1;", - { "no-implicit-globals": 1 }, - [ - "1:5 Implicit global variable, assign as global property instead. no-implicit-globals" - ], - "script", - { - env: {}, - parserOptions: { ecmaVersion: 6, sourceType: "script" } - } - ); - }); - - // it("no-implicit-globals in module", () => { - // verifyAndAssertMessages( - // "var leakedGlobal = 1;", - // { "no-implicit-globals": 1 }, - // [], - // "module", - // { - // env: {}, - // parserOptions: { ecmaVersion: 6, sourceType: "module" } - // } - // ); - // }); - - // it("no-implicit-globals in default", () => { - // verifyAndAssertMessages( - // "var leakedGlobal = 1;", - // { "no-implicit-globals": 1 }, - // [], - // null, - // { - // env: {}, - // parserOptions: { ecmaVersion: 6 } - // } - // ); - // }); - - it("with does not crash parsing in script mode (strict off)", () => { - verifyAndAssertMessages("with (arguments) { length; }", {}, [], "script"); - }); - - // it("with does crash parsing in module mode (strict on)", () => { - // verifyAndAssertMessages("with (arguments) { length; }", {}, [ - // "1:1 Parsing error: 'with' in strict mode" - // ]); - // }); - - it("new.target is not reported as undef", () => { - verifyAndAssertMessages( - "function foo () { return new.target }", - { "no-undef": 1 }, - [] - ); - }); - - // it("decorator does not create TypeError", () => { - // verifyAndAssertMessages( - // unpad(` - // class A { - // @test - // f() {} - // } - // `), - // { "no-undef": 1 }, - // ["2:4 'test' is not defined. no-undef"] - // ); - // }); - - it("newline-before-return with comments", () => { - verifyAndAssertMessages( - unpad(` - function a() { - if (b) { - /* eslint-disable no-console */ - console.log('test'); - /* eslint-enable no-console */ - } - - return hasGlobal; - } - `), - { "newline-before-return": 1 }, - [] - ); - }); - - describe("Class Property Declarations", () => { - // it("no-redeclare false positive 1", () => { - // verifyAndAssertMessages( - // unpad(` - // class Group { - // static propTypes = {}; - // } - // class TypicalForm { - // static propTypes = {}; - // } - // `), - // { "no-redeclare": 1 }, - // [] - // ); - // }); - - // it("no-redeclare false positive 2", () => { - // verifyAndAssertMessages( - // unpad(` - // function validate() {} - // class MyComponent { - // static validate = validate; - // } - // `), - // { "no-redeclare": 1 }, - // [] - // ); - // }); - - // it("check references", () => { - // verifyAndAssertMessages( - // unpad(` - // var a; - // class A { - // prop1; - // prop2 = a; - // prop3 = b; - // } - // new A - // `), - // { "no-undef": 1, "no-unused-vars": 1, "no-redeclare": 1 }, - // ["5:11 'b' is not defined. no-undef"] - // ); - // }); - }); - - it("dynamic import support", () => { - verifyAndAssertMessages("import('test-module').then(() => {})", {}, []); - }); - - it("regex with es6 unicodeCodePointEscapes", () => { - verifyAndAssertMessages( - "string.replace(/[\u{0000A0}-\u{10FFFF}<>&]/gmiu, (char) => `&#x${char.codePointAt(0).toString(16)};`);", - {}, - [] - ); - }); - - it("works with dynamicImport", () => { - verifyAndAssertMessages( - unpad(` - import('a'); - `), - {}, - [] - ); - }); - - it("works with optionalCatchBinding", () => { - verifyAndAssertMessages( - unpad(` - try {} catch {} - try {} catch {} finally {} - `), - {}, - [] - ); - }); -}); - diff --git a/tests/integration/jest.config.js b/tests/integration/jest.config.js deleted file mode 100644 index 7670926..0000000 --- a/tests/integration/jest.config.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; - -module.exports = { - testRegex: ".*\\.spec\\.js$" -}; diff --git a/tests/integration/jsdoc-indent-issues-344-422/.eslintrc.yml b/tests/integration/jsdoc-indent-issues-344-422/.eslintrc.yml new file mode 100644 index 0000000..fdf3f24 --- /dev/null +++ b/tests/integration/jsdoc-indent-issues-344-422/.eslintrc.yml @@ -0,0 +1,7 @@ +root: true + +# typescript-eslint-parser +parser: /usr/parser/parser.js + +rules: + indent: 2 diff --git a/tests/integration/jsdoc-indent-issues-344-422/Dockerfile b/tests/integration/jsdoc-indent-issues-344-422/Dockerfile new file mode 100644 index 0000000..37142ae --- /dev/null +++ b/tests/integration/jsdoc-indent-issues-344-422/Dockerfile @@ -0,0 +1,22 @@ +FROM node:carbon + +# Copy the package.json into the container so that we can +# run the install. Every other file will be linked, rather +# than copied to allow for changes without rebuilds +WORKDIR /usr +COPY ./package.json /usr/ + +# Create file which will be executed by jest +# to assert that the lint output is what we expect +RUN echo "const expectedLintOutput = require('./linked/expected-lint-output.json');\n" \ + "const actualLintOutput = require('./lint-output.json');\n" \ + "\n" \ + "test('it should produce the expected lint ouput', () => {\n" \ + " expect(actualLintOutput).toEqual(expectedLintOutput);\n" \ + "});\n" > test.js + +# Install dependencies +RUN npm install + +# Run ESLint and assert that the output matches our expectations +CMD [ "npm", "start" ] diff --git a/tests/integration/jsdoc-indent-issues-344-422/expected-lint-output.json b/tests/integration/jsdoc-indent-issues-344-422/expected-lint-output.json new file mode 100644 index 0000000..f69db47 --- /dev/null +++ b/tests/integration/jsdoc-indent-issues-344-422/expected-lint-output.json @@ -0,0 +1 @@ +[{"filePath":"/usr/linked/index.ts","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0}] \ No newline at end of file diff --git a/tests/integration/external-fixtures/jsdoc-indent.js b/tests/integration/jsdoc-indent-issues-344-422/index.ts similarity index 100% rename from tests/integration/external-fixtures/jsdoc-indent.js rename to tests/integration/jsdoc-indent-issues-344-422/index.ts diff --git a/tests/integration/jsdoc-indent-issues-344-422/package.json b/tests/integration/jsdoc-indent-issues-344-422/package.json new file mode 100644 index 0000000..6881c73 --- /dev/null +++ b/tests/integration/jsdoc-indent-issues-344-422/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "scripts": { + "start": "npm run lint && npm run test", + "lint": "eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.ts || true", + "test": "jest ./test.js" + }, + "devDependencies": { + "eslint": "4.19.1", + "jest": "23.1.0", + "typescript": "~2.9.1" + } +} \ No newline at end of file diff --git a/tests/integration/method-overloads-issue-389/.eslintrc.yml b/tests/integration/method-overloads-issue-389/.eslintrc.yml new file mode 100644 index 0000000..0c55147 --- /dev/null +++ b/tests/integration/method-overloads-issue-389/.eslintrc.yml @@ -0,0 +1,11 @@ +root: true + +# typescript-eslint-parser +parser: /usr/parser/parser.js + +rules: + array-callback-return: 2 + getter-return: 2 + strict: 2 + lines-around-directive: 2 + no-empty-function: 2 diff --git a/tests/integration/method-overloads-issue-389/Dockerfile b/tests/integration/method-overloads-issue-389/Dockerfile new file mode 100644 index 0000000..37142ae --- /dev/null +++ b/tests/integration/method-overloads-issue-389/Dockerfile @@ -0,0 +1,22 @@ +FROM node:carbon + +# Copy the package.json into the container so that we can +# run the install. Every other file will be linked, rather +# than copied to allow for changes without rebuilds +WORKDIR /usr +COPY ./package.json /usr/ + +# Create file which will be executed by jest +# to assert that the lint output is what we expect +RUN echo "const expectedLintOutput = require('./linked/expected-lint-output.json');\n" \ + "const actualLintOutput = require('./lint-output.json');\n" \ + "\n" \ + "test('it should produce the expected lint ouput', () => {\n" \ + " expect(actualLintOutput).toEqual(expectedLintOutput);\n" \ + "});\n" > test.js + +# Install dependencies +RUN npm install + +# Run ESLint and assert that the output matches our expectations +CMD [ "npm", "start" ] diff --git a/tests/integration/method-overloads-issue-389/expected-lint-output.json b/tests/integration/method-overloads-issue-389/expected-lint-output.json new file mode 100644 index 0000000..f69db47 --- /dev/null +++ b/tests/integration/method-overloads-issue-389/expected-lint-output.json @@ -0,0 +1 @@ +[{"filePath":"/usr/linked/index.ts","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0}] \ No newline at end of file diff --git a/tests/integration/method-overloads-issue-389/index.ts b/tests/integration/method-overloads-issue-389/index.ts new file mode 100644 index 0000000..1d23c00 --- /dev/null +++ b/tests/integration/method-overloads-issue-389/index.ts @@ -0,0 +1,7 @@ +export class Test { + public test(param1: Number): Test; + public test(param1: Test): Test; + public test(param1: any): Test { + return new Test(); + } +} \ No newline at end of file diff --git a/tests/integration/method-overloads-issue-389/package.json b/tests/integration/method-overloads-issue-389/package.json new file mode 100644 index 0000000..6881c73 --- /dev/null +++ b/tests/integration/method-overloads-issue-389/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "scripts": { + "start": "npm run lint && npm run test", + "lint": "eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.ts || true", + "test": "jest ./test.js" + }, + "devDependencies": { + "eslint": "4.19.1", + "jest": "23.1.0", + "typescript": "~2.9.1" + } +} \ No newline at end of file diff --git a/tests/integration/no-redeclare-overloaded-functions-issue-402/.eslintrc.yml b/tests/integration/no-redeclare-overloaded-functions-issue-402/.eslintrc.yml new file mode 100644 index 0000000..3f2483c --- /dev/null +++ b/tests/integration/no-redeclare-overloaded-functions-issue-402/.eslintrc.yml @@ -0,0 +1,7 @@ +root: true + +# typescript-eslint-parser +parser: /usr/parser/parser.js + +rules: + no-redeclare: 2 diff --git a/tests/integration/no-redeclare-overloaded-functions-issue-402/Dockerfile b/tests/integration/no-redeclare-overloaded-functions-issue-402/Dockerfile new file mode 100644 index 0000000..37142ae --- /dev/null +++ b/tests/integration/no-redeclare-overloaded-functions-issue-402/Dockerfile @@ -0,0 +1,22 @@ +FROM node:carbon + +# Copy the package.json into the container so that we can +# run the install. Every other file will be linked, rather +# than copied to allow for changes without rebuilds +WORKDIR /usr +COPY ./package.json /usr/ + +# Create file which will be executed by jest +# to assert that the lint output is what we expect +RUN echo "const expectedLintOutput = require('./linked/expected-lint-output.json');\n" \ + "const actualLintOutput = require('./lint-output.json');\n" \ + "\n" \ + "test('it should produce the expected lint ouput', () => {\n" \ + " expect(actualLintOutput).toEqual(expectedLintOutput);\n" \ + "});\n" > test.js + +# Install dependencies +RUN npm install + +# Run ESLint and assert that the output matches our expectations +CMD [ "npm", "start" ] diff --git a/tests/integration/no-redeclare-overloaded-functions-issue-402/expected-lint-output.json b/tests/integration/no-redeclare-overloaded-functions-issue-402/expected-lint-output.json new file mode 100644 index 0000000..f69db47 --- /dev/null +++ b/tests/integration/no-redeclare-overloaded-functions-issue-402/expected-lint-output.json @@ -0,0 +1 @@ +[{"filePath":"/usr/linked/index.ts","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0}] \ No newline at end of file diff --git a/tests/integration/external-fixtures/no-redeclare-overloaded-functions.js b/tests/integration/no-redeclare-overloaded-functions-issue-402/index.ts similarity index 100% rename from tests/integration/external-fixtures/no-redeclare-overloaded-functions.js rename to tests/integration/no-redeclare-overloaded-functions-issue-402/index.ts diff --git a/tests/integration/no-redeclare-overloaded-functions-issue-402/package.json b/tests/integration/no-redeclare-overloaded-functions-issue-402/package.json new file mode 100644 index 0000000..6881c73 --- /dev/null +++ b/tests/integration/no-redeclare-overloaded-functions-issue-402/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "scripts": { + "start": "npm run lint && npm run test", + "lint": "eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.ts || true", + "test": "jest ./test.js" + }, + "devDependencies": { + "eslint": "4.19.1", + "jest": "23.1.0", + "typescript": "~2.9.1" + } +} \ No newline at end of file diff --git a/tests/integration/range-error-indent-issue-333/.eslintrc.yml b/tests/integration/range-error-indent-issue-333/.eslintrc.yml new file mode 100644 index 0000000..fdf3f24 --- /dev/null +++ b/tests/integration/range-error-indent-issue-333/.eslintrc.yml @@ -0,0 +1,7 @@ +root: true + +# typescript-eslint-parser +parser: /usr/parser/parser.js + +rules: + indent: 2 diff --git a/tests/integration/range-error-indent-issue-333/Dockerfile b/tests/integration/range-error-indent-issue-333/Dockerfile new file mode 100644 index 0000000..37142ae --- /dev/null +++ b/tests/integration/range-error-indent-issue-333/Dockerfile @@ -0,0 +1,22 @@ +FROM node:carbon + +# Copy the package.json into the container so that we can +# run the install. Every other file will be linked, rather +# than copied to allow for changes without rebuilds +WORKDIR /usr +COPY ./package.json /usr/ + +# Create file which will be executed by jest +# to assert that the lint output is what we expect +RUN echo "const expectedLintOutput = require('./linked/expected-lint-output.json');\n" \ + "const actualLintOutput = require('./lint-output.json');\n" \ + "\n" \ + "test('it should produce the expected lint ouput', () => {\n" \ + " expect(actualLintOutput).toEqual(expectedLintOutput);\n" \ + "});\n" > test.js + +# Install dependencies +RUN npm install + +# Run ESLint and assert that the output matches our expectations +CMD [ "npm", "start" ] diff --git a/tests/integration/range-error-indent-issue-333/expected-lint-output.json b/tests/integration/range-error-indent-issue-333/expected-lint-output.json new file mode 100644 index 0000000..f69db47 --- /dev/null +++ b/tests/integration/range-error-indent-issue-333/expected-lint-output.json @@ -0,0 +1 @@ +[{"filePath":"/usr/linked/index.ts","messages":[],"errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0}] \ No newline at end of file diff --git a/tests/integration/external-fixtures/range-error-indent.js b/tests/integration/range-error-indent-issue-333/index.ts similarity index 100% rename from tests/integration/external-fixtures/range-error-indent.js rename to tests/integration/range-error-indent-issue-333/index.ts diff --git a/tests/integration/range-error-indent-issue-333/package.json b/tests/integration/range-error-indent-issue-333/package.json new file mode 100644 index 0000000..6881c73 --- /dev/null +++ b/tests/integration/range-error-indent-issue-333/package.json @@ -0,0 +1,13 @@ +{ + "private": true, + "scripts": { + "start": "npm run lint && npm run test", + "lint": "eslint --format json --output-file /usr/lint-output.json --config /usr/linked/.eslintrc.yml /usr/linked/**/*.ts || true", + "test": "jest ./test.js" + }, + "devDependencies": { + "eslint": "4.19.1", + "jest": "23.1.0", + "typescript": "~2.9.1" + } +} \ No newline at end of file diff --git a/tests/integration/typescript.spec.js b/tests/integration/typescript.spec.js deleted file mode 100644 index c2a6f80..0000000 --- a/tests/integration/typescript.spec.js +++ /dev/null @@ -1,210 +0,0 @@ -"use strict"; - -const unpad = require("dedent"); - -const utils = require("./utils"); -const verifyAndAssertMessages = utils.verifyAndAssertMessages; -const loadExternalFixture = utils.loadExternalFixture; - -describe("TypeScript", () => { - it("should fundamentally work with `eslint:all`", () => { - verifyAndAssertMessages( - unpad(` - "use strict"; - const foo: string = "bar"; - `), - {}, - ["2:7 'foo' is assigned a value but never used. no-unused-vars"], - "script", - { - baseConfig: { - extends: ["eslint:all"], - rules: { - "eol-last": "off" - } - } - } - ); - }); - - it("should not cause a RangeError within the indent rule (#333)", () => { - verifyAndAssertMessages( - loadExternalFixture("range-error-indent"), - { - indent: "error" - }, - [] - ); - }); - - it("should not throw in any rules on method overloads (#389)", () => { - verifyAndAssertMessages( - unpad(` - export class Test { - public test(param1: Number): Test; - public test(param1: Test): Test; - public test(param1: any): Test { - return new Test(); - } - } - `), - { - "array-callback-return": "error", - "getter-return": "error", - strict: "error", - "lines-around-directive": "error", - "no-empty-function": "error" - }, - [] - ); - }); - - it("should not throw in any rules on abstract class methods (#400)", () => { - verifyAndAssertMessages( - unpad(` - export abstract class TestAbstract { - onCreated?(): Promise | any; - } - export abstract class AbstractSocket { - abstract createSocket(): Promise; - } - `), - { - "array-callback-return": "error", - "getter-return": "error", - strict: "error", - "lines-around-directive": "error", - "no-empty-function": "error" - }, - [] - ); - }); - - it("should not produce any lint errors on valid JSDoc indentation (#344 & #422)", () => { - verifyAndAssertMessages( - loadExternalFixture("jsdoc-indent"), - { - indent: "error" - }, - [] - ); - }); - - it("should not produce a parse error (#403)", () => { - verifyAndAssertMessages( - unpad(` - class X { - data() { - return { - form: { - startDate: undefined - } - }; - } - } - `), - {}, - [], - "script", - { - parserOptions: { - jsx: false - } - } - ); - }); - - it("should not produce any lint errors for no-declare on overloaded functions (#402)", () => { - verifyAndAssertMessages( - loadExternalFixture("no-redeclare-overloaded-functions"), - { - "no-redeclare": "error" - }, - [] - ); - }); - - it("should not throw any TypeErrors when parsing declared empty body functions using eslint:all (#162)", () => { - verifyAndAssertMessages( - loadExternalFixture("declared-empty-body-functions"), - {}, - [ - "3:19 'FF' is not defined. no-undef", - "4:11 'Foo' is defined but never used. no-unused-vars", - "4:23 'Bar' is not defined. no-undef", - "4:31 Block must be padded by blank lines. padded-blocks", - "6:5 Block must be padded by blank lines. padded-blocks", - "10:11 'Foo' is already defined. no-redeclare", - "10:23 'Bar' is not defined. no-undef", - "10:31 Block must be padded by blank lines. padded-blocks", - "12:5 Block must be padded by blank lines. padded-blocks", - "15:15 'Foo' is already defined. no-redeclare", - "15:27 'Bar' is not defined. no-undef", - "15:35 Block must be padded by blank lines. padded-blocks", - "17:1 Block must be padded by blank lines. padded-blocks", - "19:19 'd3' is not defined. no-undef", - "20:21 'select' is not defined. no-undef", - "20:28 'selector' is not defined. no-undef", - "20:47 'Selection' is not defined. no-undef", - "21:2 Newline required at end of file but not found. eol-last" - ], - "script", - { - baseConfig: { - extends: ["eslint:all"] - } - } - ); - }); - - it("should correctly apply no-unreachable on TS-constructs (#127)", () => { - verifyAndAssertMessages( - unpad(` - export namespace foo { - export function bar() { - return; - } - } - export type Qux = true; - `), - { - "no-unreachable": 2 - }, - [] - ); - }); - - // it("should not produce a false positive for no-restricted-globals rule (#350)", () => { - // verifyAndAssertMessages( - // unpad(` - // type foo = { - // location: any; - // }; - // `), - // { - // "no-restricted-globals": [2, "location"] - // }, - // [] - // ); - // }); - - // it("should not throw a TypeError in the indent rule for invalid code (#309)", () => { - // verifyAndAssertMessages( - // unpad(` - // const - // `), - // { - // indent: "error" - // }, - // [] - // ); - // }); - - // it("class properties and no-undef", () => { - // verifyAndAssertMessages( - // "class Lol { foo = 'bar'; }", - // { "no-undef": 1 }, - // [] - // ); - // }); -}); diff --git a/tests/integration/utils.js b/tests/integration/utils.js deleted file mode 100644 index f3cc76c..0000000 --- a/tests/integration/utils.js +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @fileoverview Utilities for running integration tests - * @author James Henry - * @copyright jQuery Foundation and other contributors, https://jquery.org/ - * MIT License - */ -"use strict"; - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ -const eslint = require("eslint"); -const unpad = require("dedent"); -const fs = require("fs"); -const path = require("path"); - -//------------------------------------------------------------------------------ -// Public -//------------------------------------------------------------------------------ - -/* eslint-disable no-use-before-define */ -module.exports = { - verifyAndAssertMessages, - loadExternalFixture -}; -/* eslint-enable no-use-before-define */ - -/** - * Loads an external fixture by name - * @param {string} fixtureName the name of the fixture file to load - * @returns {string} stringified file contents - */ -function loadExternalFixture(fixtureName) { - return fs.readFileSync( - path.join(__dirname, "external-fixtures", `${fixtureName}.js`) - ).toString(); -} - -/** - * A utility function to lint the given source code using typescript-eslint-parser - * and assert expectations around the linting feedback - * - * @param {string} code source code to lint - * @param {Object} rules ESLint rules configuration - * @param {string[]} expectedMessages Expected linting feedback - * @param {string} sourceType Either "module" or "script" - * @param {Obejct} overrideConfig Custom configuration options for the CLIEngine - * @returns {void} - */ -function verifyAndAssertMessages( - code, - rules, - expectedMessages, - sourceType, - overrideConfig -) { - const cliEngineConfig = { - useEslintrc: false, - parser: require.resolve("../../parser"), - rules, - parserOptions: { - ecmaVersion: 8, - ecmaFeatures: { - jsx: true, - experimentalObjectRestSpread: true, - globalReturn: true - }, - sourceType: sourceType || "script" - }, - cwd: __dirname - }; - - if (overrideConfig) { - Object.assign(cliEngineConfig, overrideConfig); - } - - const cli = new eslint.CLIEngine(cliEngineConfig); - const messages = cli.executeOnText(code, "fake-filename.js").results[0].messages; - - if (messages.length !== expectedMessages.length) { - throw new Error( - `Expected ${expectedMessages.length} message(s), got ${messages.length}\n${JSON.stringify( - messages, - null, - 2 - )}` - ); - } - - messages.forEach((message, i) => { - const formatedMessage = `${message.line}:${message.column} ${message.message}${message.ruleId - ? ` ${message.ruleId}` - : ""}`; - if (formatedMessage !== expectedMessages[i]) { - throw new Error( - unpad(` - Message ${i} does not match: - Expected: ${expectedMessages[i]} - Actual: ${formatedMessage} - `) - ); - } - }); -}