From 989759a45a8ef481eeaa0102982676cb51630f9b Mon Sep 17 00:00:00 2001 From: Craig Date: Tue, 20 Dec 2016 15:08:26 -0800 Subject: [PATCH] chore(tslint): add tslint to gulpfile (#3833) - add gulp task tslint and lint - update `**/*.ts` with tslint fixes - update circle.yml to run `gulp lint` - update `gulp pretest` to run both jshint and tslint --- circle.yml | 2 +- gulpfile.js | 20 ++++++++++---- lib/browser.ts | 9 +++---- lib/cli.ts | 8 +++--- lib/debugger.ts | 2 +- lib/driverProviders/attachSession.ts | 4 +-- lib/driverProviders/browserStack.ts | 4 +-- lib/driverProviders/sauce.ts | 4 +-- lib/element.ts | 3 +-- lib/expectedConditions.ts | 8 +++--- lib/launcher.ts | 4 +-- lib/locators.ts | 4 +-- lib/plugins.ts | 2 +- lib/ptor.ts | 4 +-- lib/runner.ts | 40 +++++++++++++--------------- lib/taskLogger.ts | 6 ++--- lib/taskScheduler.ts | 14 +++++----- package.json | 6 ++++- tslint.json | 15 +++++++++++ 19 files changed, 91 insertions(+), 68 deletions(-) create mode 100644 tslint.json diff --git a/circle.yml b/circle.yml index 8f3e1f63b..9ceca4bfd 100644 --- a/circle.yml +++ b/circle.yml @@ -12,7 +12,7 @@ dependencies: cache_directories: - testapp/node_modules post: - - ./node_modules/.bin/gulp format:enforce + - ./node_modules/.bin/gulp lint - ./node_modules/.bin/webdriver-manager update - ./node_modules/.bin/webdriver-manager start: background: true diff --git a/gulpfile.js b/gulpfile.js index d2f136ac0..55054cf41 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -6,6 +6,7 @@ var gulpFormat = require('gulp-clang-format'); var runSequence = require('run-sequence'); var spawn = require('child_process').spawn; var spawnSync = require('child_process').spawnSync; +var tslint = require('gulp-tslint'); var fs = require('fs'); var path = require('path'); var glob = require('glob'); @@ -34,6 +35,15 @@ var runSpawn = function(done, task, opt_arg, opt_io) { }); }; +gulp.task('tslint', function() { + return gulp.src(['lib/**/*.ts', 'spec/**/*.ts', '!spec/install/**/*.ts']) + .pipe(tslint()).pipe(tslint.report()); +}); + +gulp.task('lint', function(done) { + runSequence('tslint', 'jshint', 'format:enforce', done); +}); + // prevent contributors from using the wrong version of node gulp.task('checkVersion', function(done) { // read minimum node on package.json @@ -44,8 +54,8 @@ gulp.task('checkVersion', function(done) { if (semver.satisfies(process.version, nodeVersion)) { done(); } else { - throw new Error('minimum node version for Protractor ' + protractorVersion + - ' is node ' + nodeVersion); + throw new Error('minimum node version for Protractor ' + + protractorVersion + ' is node ' + nodeVersion); } }); @@ -60,7 +70,8 @@ gulp.task('webdriver:update', function(done) { }); gulp.task('jshint', function(done) { - runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', '-c', '.jshintrc', 'lib', 'spec', 'scripts', + runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', '-c', + '.jshintrc', 'lib', 'spec', 'scripts', '--exclude=lib/selenium-webdriver/**/*.js,spec/dependencyTest/*.js,' + 'spec/install/**/*.js']); }); @@ -90,8 +101,7 @@ gulp.task('prepublish', function(done) { gulp.task('pretest', function(done) { runSequence('checkVersion', - ['webdriver:update', 'jshint', 'format'], 'tsc', - 'built:copy', done); + ['webdriver:update', 'jshint', 'tslint', 'format'], 'tsc', 'built:copy', done); }); gulp.task('default',['prepublish']); diff --git a/lib/browser.ts b/lib/browser.ts index 25e1da744..ca47fd075 100644 --- a/lib/browser.ts +++ b/lib/browser.ts @@ -74,7 +74,7 @@ export class Webdriver { */ function ptorMixin(to: any, from: any, fnName: string, setupFn?: Function) { to[fnName] = function() { - for (var i = 0; i < arguments.length; i++) { + for (let i = 0; i < arguments.length; i++) { if (arguments[i] instanceof ElementFinder) { arguments[i] = arguments[i].getWebElement(); } @@ -103,10 +103,9 @@ function buildElementHelper(browser: ProtractorBrowser): ElementHelper { return new ElementArrayFinder(browser).all(locator).toElementFinder_(); }) as ElementHelper; - element.all = - (locator: Locator) => { - return new ElementArrayFinder(browser).all(locator); - } + element.all = (locator: Locator) => { + return new ElementArrayFinder(browser).all(locator); + }; return element; }; diff --git a/lib/cli.ts b/lib/cli.ts index 6e1831828..c3eb2cde4 100644 --- a/lib/cli.ts +++ b/lib/cli.ts @@ -9,10 +9,10 @@ import * as path from 'path'; * Values from command line options override values from the config. */ -var args: Array = []; +let args: Array = []; process.argv.slice(2).forEach(function(arg: string) { - var flag: string = arg.split('=')[0]; + let flag: string = arg.split('=')[0]; switch (flag) { case 'debug': @@ -72,7 +72,7 @@ optimist } }); -var argv: any = optimist.parse(args); +let argv: any = optimist.parse(args); if (argv.help) { optimist.showHelp(); @@ -105,7 +105,7 @@ if (argv.exclude) { } // Use default configuration, if it exists. -var configFile: string = argv._[0]; +let configFile: string = argv._[0]; if (!configFile) { if (fs.existsSync('./protractor.conf.js')) { configFile = './protractor.conf.js'; diff --git a/lib/debugger.ts b/lib/debugger.ts index f2d152d69..cb7f55d2f 100644 --- a/lib/debugger.ts +++ b/lib/debugger.ts @@ -1,6 +1,6 @@ import * as net from 'net'; import {promise as wdpromise, WebElement} from 'selenium-webdriver'; -import * as util from 'util' +import * as util from 'util'; import {ProtractorBrowser} from './browser'; import {Locator} from './locators'; diff --git a/lib/driverProviders/attachSession.ts b/lib/driverProviders/attachSession.ts index 29af052ae..58f4e4e35 100644 --- a/lib/driverProviders/attachSession.ts +++ b/lib/driverProviders/attachSession.ts @@ -38,8 +38,8 @@ export class AttachSession extends DriverProvider { * @return {WebDriver} webdriver instance */ getNewDriver(): WebDriver { - var executor = executors.createExecutor(this.config_.seleniumAddress); - var newDriver = WebDriver.attachToSession(executor, this.config_.seleniumSessionId); + let executor = executors.createExecutor(this.config_.seleniumAddress); + let newDriver = WebDriver.attachToSession(executor, this.config_.seleniumSessionId); this.drivers_.push(newDriver); return newDriver; } diff --git a/lib/driverProviders/browserStack.ts b/lib/driverProviders/browserStack.ts index 8e7d7edde..d6c91a43b 100644 --- a/lib/driverProviders/browserStack.ts +++ b/lib/driverProviders/browserStack.ts @@ -47,7 +47,7 @@ export class BrowserStack extends DriverProvider { let req = https.request(options, (res) => { res.on('data', (data: Buffer) => { - var info = JSON.parse(data.toString()); + let info = JSON.parse(data.toString()); if (info && info.automation_session && info.automation_session.browser_url) { logger.info( 'BrowserStack results available at ' + info.automation_session.browser_url); @@ -95,7 +95,7 @@ export class BrowserStack extends DriverProvider { * ready to test. */ setupEnv(): q.Promise { - var deferred = q.defer(); + let deferred = q.defer(); this.config_.capabilities['browserstack.user'] = this.config_.browserstackUser; this.config_.capabilities['browserstack.key'] = this.config_.browserstackKey; this.config_.seleniumAddress = 'http://hub.browserstack.com/wd/hub'; diff --git a/lib/driverProviders/sauce.ts b/lib/driverProviders/sauce.ts index a3db08a90..c93e7f71c 100644 --- a/lib/driverProviders/sauce.ts +++ b/lib/driverProviders/sauce.ts @@ -30,8 +30,8 @@ export class Sauce extends DriverProvider { * @return {q.promise} A promise that will resolve when the update is complete. */ updateJob(update: any): q.Promise { - var deferredArray = this.drivers_.map((driver: WebDriver) => { - var deferred = q.defer(); + let deferredArray = this.drivers_.map((driver: WebDriver) => { + let deferred = q.defer(); driver.getSession().then((session: Session) => { logger.info('SauceLabs results available at http://saucelabs.com/jobs/' + session.getId()); this.sauceServer_.updateJob(session.getId(), update, (err: Error) => { diff --git a/lib/element.ts b/lib/element.ts index 06b658fcf..0455603ca 100644 --- a/lib/element.ts +++ b/lib/element.ts @@ -1,7 +1,6 @@ import {By, error, ILocation, ISize, promise as wdpromise, WebDriver, WebElement, WebElementPromise} from 'selenium-webdriver'; -import {ElementHelper} from './browser'; -import {ProtractorBrowser} from './browser'; +import {ElementHelper, ProtractorBrowser} from './browser'; import {IError} from './exitCodes'; import {Locator} from './locators'; import {Logger} from './logger'; diff --git a/lib/expectedConditions.ts b/lib/expectedConditions.ts index 3cfef1a8b..87242ec70 100644 --- a/lib/expectedConditions.ts +++ b/lib/expectedConditions.ts @@ -3,8 +3,6 @@ import {ElementFinder} from './element'; const webdriver = require('selenium-webdriver'); -declare var global: any; - /** * Represents a library of canned expected conditions that are useful for * protractor, especially when dealing with non-angular apps. @@ -88,7 +86,7 @@ export class ProtractorExpectedConditions { if (fns.length === 0) { return defaultRet; } - var fn = fns[0]; + let fn = fns[0]; return fn().then((bool: boolean): boolean => { if (bool === defaultRet) { return self.logicalChain_(defaultRet, fns.slice(1))(); @@ -208,7 +206,7 @@ export class ProtractorExpectedConditions { * representing whether the text is present in the element. */ textToBePresentInElement(elementFinder: ElementFinder, text: string): Function { - var hasText = () => { + let hasText = () => { return elementFinder.getText().then((actualText: string): boolean => { // MSEdge does not properly remove newlines, which causes false // negatives @@ -235,7 +233,7 @@ export class ProtractorExpectedConditions { * representing whether the text is present in the element's value. */ textToBePresentInElementValue(elementFinder: ElementFinder, text: string): Function { - var hasText = () => { + let hasText = () => { return elementFinder.getAttribute('value').then((actualText: string): boolean => { return actualText.indexOf(text) > -1; }); diff --git a/lib/launcher.ts b/lib/launcher.ts index 4bcbb8891..9ecc0a310 100644 --- a/lib/launcher.ts +++ b/lib/launcher.ts @@ -238,7 +238,7 @@ let initFn = function(configFile: string, additionalConfig: Config) { let deferred = q.defer(); // Resolved when all tasks are completed let createNextTaskRunner = () => { - var task = scheduler.nextTask(); + let task = scheduler.nextTask(); if (task) { let taskRunner = new TaskRunner(configFile, additionalConfig, task, forkProcess); taskRunner.run() @@ -267,7 +267,7 @@ let initFn = function(configFile: string, additionalConfig: Config) { // the beginning. As a worker finishes a task, it will pick up the next // task // from the scheduler's queue until all tasks are gone. - for (var i = 0; i < scheduler.maxConcurrentTasks(); ++i) { + for (let i = 0; i < scheduler.maxConcurrentTasks(); ++i) { createNextTaskRunner(); } logger.info('Running ' + scheduler.countActiveTasks() + ' instances of WebDriver'); diff --git a/lib/locators.ts b/lib/locators.ts index 1b8e25017..9f97fd486 100644 --- a/lib/locators.ts +++ b/lib/locators.ts @@ -72,7 +72,7 @@ export class ProtractorBy extends WebdriverBy { */ addLocator(name: string, script: Function|string) { this[name] = (...args: any[]): Locator => { - var locatorArguments = args; + let locatorArguments = args; return { findElementsOverride: (driver: WebDriver, using: WebElement, rootSelector: string): wdpromise.Promise => { @@ -247,7 +247,7 @@ export class ProtractorBy extends WebdriverBy { // Generate either by.repeater or by.exactRepeater private byRepeaterInner(exact: boolean, repeatDescriptor: string): Locator { - var name = 'by.' + (exact ? 'exactR' : 'r') + 'epeater'; + let name = 'by.' + (exact ? 'exactR' : 'r') + 'epeater'; return { findElementsOverride: (driver: WebDriver, using: WebElement, rootSelector: string): wdpromise.Promise => { diff --git a/lib/plugins.ts b/lib/plugins.ts index 8734bc743..eca057a61 100644 --- a/lib/plugins.ts +++ b/lib/plugins.ts @@ -488,7 +488,7 @@ export class Plugins { export interface SpecResult { description: string; - assertions: AssertionResult[] + assertions: AssertionResult[]; } export interface AssertionResult { diff --git a/lib/ptor.ts b/lib/ptor.ts index d0ab492d4..69f85cbae 100644 --- a/lib/ptor.ts +++ b/lib/ptor.ts @@ -58,7 +58,7 @@ export class Ptor { firefox: require('selenium-webdriver/firefox'), http: require('selenium-webdriver/http'), remote: require('selenium-webdriver/remote') - } + }; } -export var protractor = new Ptor(); +export let protractor = new Ptor(); diff --git a/lib/runner.ts b/lib/runner.ts index d5ebcfc28..8aaac4a83 100644 --- a/lib/runner.ts +++ b/lib/runner.ts @@ -5,17 +5,16 @@ import * as util from 'util'; import {ProtractorBrowser} from './browser'; import {Config} from './config'; -import {AttachSession, BrowserStack, Direct, Hosted, Local, Mock, Sauce} from './driverProviders'; -import {DriverProvider} from './driverProviders'; +import {AttachSession, BrowserStack, Direct, DriverProvider, Hosted, Local, Mock, Sauce} from './driverProviders'; import {Logger} from './logger'; import {Plugins} from './plugins'; import {protractor} from './ptor'; import * as helper from './util'; -declare var global: any; -declare var process: any; +declare let global: any; +declare let process: any; -var webdriver = require('selenium-webdriver'); +const webdriver = require('selenium-webdriver'); let logger = new Logger('runner'); /* * Runner is responsible for starting the execution of a test run and triggering @@ -127,17 +126,16 @@ export class Runner extends EventEmitter { * @private * @param {int} Standard unix exit code */ - exit_ = function(exitCode: number): - any { - return helper.runFilenameOrFn_(this.config_.configDir, this.config_.onCleanUp, [exitCode]) - .then((returned): number | any => { - if (typeof returned === 'number') { - return returned; - } else { - return exitCode; - } - }); - } + exit_ = function(exitCode: number): any { + return helper.runFilenameOrFn_(this.config_.configDir, this.config_.onCleanUp, [exitCode]) + .then((returned): number | any => { + if (typeof returned === 'number') { + return returned; + } else { + return exitCode; + } + }); + }; /** * Getter for the Runner config object @@ -205,10 +203,10 @@ export class Runner extends EventEmitter { * @public */ createBrowser(plugins: any): any { - var config = this.config_; - var driver = this.driverprovider_.getNewDriver(); + let config = this.config_; + let driver = this.driverprovider_.getNewDriver(); - var browser_ = ProtractorBrowser.wrapDriver( + let browser_ = ProtractorBrowser.wrapDriver( driver, config.baseUrl, config.rootElement, config.untrackOutstandingTimeouts); browser_.params = config.params; @@ -341,7 +339,7 @@ export class Runner extends EventEmitter { } if (this.config_.restartBrowserBetweenTests) { - var restartDriver = () => { + let restartDriver = () => { browser_.restart(); }; this.on('testPass', restartDriver); @@ -393,7 +391,7 @@ export class Runner extends EventEmitter { // 9) Exit process }) .then(() => { - var exitCode = testPassed ? 0 : 1; + let exitCode = testPassed ? 0 : 1; return this.exit_(exitCode); }) .fin(() => { diff --git a/lib/taskLogger.ts b/lib/taskLogger.ts index baeea7f19..2031d9182 100644 --- a/lib/taskLogger.ts +++ b/lib/taskLogger.ts @@ -62,8 +62,8 @@ export class TaskLogger { * @param {string} data */ public log(data: string): void { - var tag = '['; - var capabilities = this.task.capabilities; + let tag = '['; + let capabilities = this.task.capabilities; tag += (capabilities.logName) ? capabilities.logName : (capabilities.browserName) ? capabilities.browserName : ''; tag += (capabilities.version) ? (' ' + capabilities.version) : ''; @@ -72,7 +72,7 @@ export class TaskLogger { tag += '] '; data = data.toString(); - for (var i = 0; i < data.length; i++) { + for (let i = 0; i < data.length; i++) { if (this.insertTag) { this.insertTag = false; // This ensures that the '\x1B[0m' appears before the tag, so that diff --git a/lib/taskScheduler.ts b/lib/taskScheduler.ts index fe3419d29..420c51dd0 100644 --- a/lib/taskScheduler.ts +++ b/lib/taskScheduler.ts @@ -77,7 +77,7 @@ export class TaskScheduler { capabilities.count = capabilities.count || 1; - for (var i = 0; i < capabilities.count; ++i) { + for (let i = 0; i < capabilities.count; ++i) { taskQueues.push(new TaskQueue(capabilities, specLists)); } }); @@ -92,9 +92,9 @@ export class TaskScheduler { * done: function()}} */ public nextTask(): Task { - for (var i = 0; i < this.taskQueues.length; ++i) { - var rotatedIndex = ((i + this.rotationIndex) % this.taskQueues.length); - var queue = this.taskQueues[rotatedIndex]; + for (let i = 0; i < this.taskQueues.length; ++i) { + let rotatedIndex = ((i + this.rotationIndex) % this.taskQueues.length); + let queue = this.taskQueues[rotatedIndex]; if (queue.numRunningInstances < queue.maxInstance && queue.specsIndex < queue.specLists.length) { this.rotationIndex = rotatedIndex + 1; @@ -125,7 +125,7 @@ export class TaskScheduler { * @return {number} */ public numTasksOutstanding(): number { - var count = 0; + let count = 0; this.taskQueues.forEach((queue) => { count += queue.numRunningInstances + (queue.specLists.length - queue.specsIndex); }); @@ -141,7 +141,7 @@ export class TaskScheduler { if (this.config.maxSessions && this.config.maxSessions > 0) { return this.config.maxSessions; } else { - var count = 0; + let count = 0; this.taskQueues.forEach((queue) => { count += Math.min(queue.maxInstance, queue.specLists.length); }); @@ -155,7 +155,7 @@ export class TaskScheduler { * @return {number} */ public countActiveTasks() { - var count = 0; + let count = 0; this.taskQueues.forEach((queue) => { count += queue.numRunningInstances; }); diff --git a/package.json b/package.json index f578da8b0..e36aa317c 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "express": "~4.14.0", "gulp": "^3.9.1", "gulp-clang-format": "^1.0.23", + "gulp-tslint": "^7.0.1", "jshint": "^2.9.2", "lodash": "^4.5.1", "marked": "^0.3.3", @@ -49,7 +50,10 @@ "rimraf": "~2.5.3", "run-sequence": "^1.1.5", "semver": "^5.3.0", - "typescript": "^2.0.0" + "tslint": "^4.1.0", + "tslint-eslint-rules": "^3.2.0", + "typescript": "^2.0.0", + "vrsource-tslint-rules": "^0.14.1" }, "repository": { "type": "git", diff --git a/tslint.json b/tslint.json new file mode 100644 index 000000000..5935ad95e --- /dev/null +++ b/tslint.json @@ -0,0 +1,15 @@ +{ + "rulesDirectory": [ + "node_modules/vrsource-tslint-rules/rules", + "node_modules/tslint-eslint-rules/dist/rules" + ], + "rules": { + "no-duplicate-imports": true, + "no-duplicate-variable": true, + "no-jasmine-focus": true, + "no-var-keyword": true, + "semicolon": [true], + "variable-name": [true, "ban-keywords"], + "no-inner-declarations": [true, "function"] + } +}