diff --git a/globals.ts b/globals.ts index 6f3efcdbb..477d758f8 100644 --- a/globals.ts +++ b/globals.ts @@ -1,28 +1,21 @@ import { - Browser, + ProtractorBrowser, ElementArrayFinder, ElementFinder, ElementHelper, ProtractorBy, - ProtractorExpectedConditions + ProtractorExpectedConditions, + Ptor } from 'protractor'; -export interface Protractor { - browser: Browser; - element: ElementHelper; - by: ProtractorBy; - By: ProtractorBy; - $: (search: string) => ElementFinder; - $$: (search: string) => ElementArrayFinder; - ExpectedConditions: ProtractorExpectedConditions; -} -interface global {}; -export var protractor: Protractor = global['protractor']; -export var browser: Browser = global['protractor']['browser']; -export var element: ElementHelper = global['protractor']['element']; -export var by: ProtractorBy = global['protractor']['by']; -export var By: ProtractorBy = global['protractor']['By']; -export var $: (search: string) => ElementFinder = global['protractor']['$']; -export var $$: (search: string) => ElementArrayFinder = global['protractor']['$$']; -export var ExpectedConditions: ProtractorExpectedConditions = - global['protractor']['ExpectedConditions']; +export let protractor: Ptor = global['protractor']; +export let browser: ProtractorBrowser = protractor.browser; +export let $: (search: string) => ElementFinder = protractor.$; +export let $$: (search: string) => ElementArrayFinder = protractor.$$; +export let element: ElementHelper = protractor.element; +export let By: ProtractorBy = protractor.By; +export let by: ProtractorBy = protractor.by; +export let wrapDriver: + (webdriver: any, baseUrl?: string, rootElement?: string, + untrackOutstandingTimeouts?: boolean) => ProtractorBrowser = protractor.wrapDriver; +export let ExpectedConditions: ProtractorExpectedConditions = protractor.ExpectedConditions; diff --git a/gulpfile.js b/gulpfile.js index e93d13a56..7f703a911 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -43,7 +43,8 @@ gulp.task('webdriver:update', function(done) { gulp.task('jshint', function(done) { runSpawn(done, 'node', ['node_modules/jshint/bin/jshint', 'lib', 'spec', 'scripts', - '--exclude=lib/selenium-webdriver/**/*.js,spec/dependencyTest/*.js']); + '--exclude=lib/selenium-webdriver/**/*.js,spec/dependencyTest/*.js,' + + 'spec/install/**/*.js']); }); gulp.task('format:enforce', () => { @@ -89,7 +90,7 @@ gulp.task('default',['prepublish']); gulp.task('types', function(done) { var folder = 'built'; var files = ['browser', 'element', 'locators', 'expectedConditions', - 'config', 'plugins']; + 'config', 'plugins', 'ptor']; var outputFile = path.resolve(folder, 'index.d.ts'); var contents = ''; files.forEach(file => { diff --git a/lib/browser.ts b/lib/browser.ts index b810b26f2..d76c92977 100644 --- a/lib/browser.ts +++ b/lib/browser.ts @@ -80,7 +80,7 @@ export interface ElementHelper extends Function { * @param {Browser} browser A browser instance. * @returns {function(webdriver.Locator): ElementFinder} */ -function buildElementHelper(browser: Browser): ElementHelper { +function buildElementHelper(browser: ProtractorBrowser): ElementHelper { let element: ElementHelper = (locator: Locator) => { return new ElementArrayFinder(browser).all(locator).toElementFinder_(); }; @@ -104,7 +104,7 @@ function buildElementHelper(browser: Browser): ElementHelper { * @param {boolean=} opt_untrackOutstandingTimeouts Whether Protractor should * stop tracking outstanding $timeouts. */ -export class Browser extends Webdriver { +export class ProtractorBrowser extends Webdriver { /** * @type {ProtractorBy} */ @@ -329,7 +329,8 @@ export class Browser extends Webdriver { * @returns {Browser} A browser instance. */ forkNewDriverInstance( - opt_useSameUrl?: boolean, opt_copyMockModules?: boolean): Browser { + opt_useSameUrl?: boolean, + opt_copyMockModules?: boolean): ProtractorBrowser { return null; } @@ -1242,8 +1243,8 @@ export class Browser extends Webdriver { */ static wrapDriver( webdriver: webdriver.WebDriver, baseUrl?: string, rootElement?: string, - untrackOutstandingTimeouts?: boolean): Browser { - return new Browser( + untrackOutstandingTimeouts?: boolean): ProtractorBrowser { + return new ProtractorBrowser( webdriver, baseUrl, rootElement, untrackOutstandingTimeouts); } } diff --git a/lib/element.ts b/lib/element.ts index caebdc648..d5d33b44a 100644 --- a/lib/element.ts +++ b/lib/element.ts @@ -2,7 +2,7 @@ let webdriver = require('selenium-webdriver'); let clientSideScripts = require('./clientsidescripts'); import {Logger} from './logger'; -import {Browser} from './browser'; +import {ProtractorBrowser} from './browser'; import {Locator} from './locators'; let logger = new Logger('element'); @@ -83,7 +83,7 @@ export class WebdriverWebElement { * }); * * @constructor - * @param {Browser} browser A browser instance. + * @param {ProtractorBrowser} browser A browser instance. * @param {function(): Array.} getWebElements A function * that returns a list of the underlying Web Elements. * @param {webdriver.Locator} locator The most relevant locator. It is only @@ -97,7 +97,7 @@ export class ElementArrayFinder extends WebdriverWebElement { getWebElements: Function; constructor( - public browser_: Browser, getWebElements?: Function, + public browser_: ProtractorBrowser, getWebElements?: Function, public locator_?: any, public actionResults_: webdriver.promise.Promise = null) { super(); @@ -703,7 +703,7 @@ export class ElementArrayFinder extends WebdriverWebElement { * * @constructor * @extends {webdriver.WebElement} - * @param {Browser} browser_ A browser instance. + * @param {ProtractorBrowser} browser_ A browser instance. * @param {ElementArrayFinder} elementArrayFinder The ElementArrayFinder * that this is branched from. * @returns {ElementFinder} @@ -716,7 +716,8 @@ export class ElementFinder extends WebdriverWebElement { errorFn: Function) => webdriver.promise.Promise = null; constructor( - public browser_: Browser, elementArrayFinder: ElementArrayFinder) { + public browser_: ProtractorBrowser, + elementArrayFinder: ElementArrayFinder) { super(); if (!elementArrayFinder) { throw new Error('BUG: elementArrayFinder cannot be empty'); @@ -785,7 +786,7 @@ export class ElementFinder extends WebdriverWebElement { } static fromWebElement_( - browser: Browser, webElem: webdriver.WebElement, + browser: ProtractorBrowser, webElem: webdriver.WebElement, locator: Locator): ElementFinder { let getWebElements = () => { return webdriver.promise.fulfilled([webElem]); }; diff --git a/lib/main.ts b/lib/main.ts index 281c0f2ad..a23085155 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -3,4 +3,4 @@ * namespace. */ -export = require('./ptor').protractor +export = require('./ptor').protractor; diff --git a/lib/ptor.ts b/lib/ptor.ts index 5cc6fffcb..63b4b57c1 100644 --- a/lib/ptor.ts +++ b/lib/ptor.ts @@ -1,36 +1,56 @@ -import {Browser, ElementHelper} from './browser'; +import {ElementHelper, ProtractorBrowser} from './browser'; import {ElementArrayFinder, ElementFinder} from './element'; import {ProtractorExpectedConditions} from './expectedConditions'; import {ProtractorBy} from './locators'; let webdriver = require('selenium-webdriver'); -export namespace protractor { +export class Ptor { // Variables tied to the global namespace. - export let browser: Browser; - export let $ = function(search: string): ElementFinder { return null;}; - export let $$ = function(search: string): ElementArrayFinder { return null;}; - export let element: ElementHelper; - export let By: ProtractorBy; - export let by: ProtractorBy; - export let wrapDriver: + browser: ProtractorBrowser; + $ = function(search: string): ElementFinder { return null; }; + $$ = function(search: string): ElementArrayFinder { return null; }; + element: ElementHelper; + By: ProtractorBy; + by: ProtractorBy; + wrapDriver: (webdriver: webdriver.WebDriver, baseUrl?: string, rootElement?: string, - untrackOutstandingTimeouts?: boolean) => Browser; - export let ExpectedConditions: ProtractorExpectedConditions; + untrackOutstandingTimeouts?: boolean) => ProtractorBrowser; + ExpectedConditions: ProtractorExpectedConditions; // Export protractor classes. - export let Browser = require('./browser').Browser; - export let ElementFinder = require('./element').ElementFinder; - export let ElementArrayFinder = require('./element').ElementArrayFinder; - export let ProtractorBy = require('./locators').ProtractorBy; - export let ProtractorExpectedConditions = + ProtractorBrowser = require('./browser').ProtractorBrowser; + ElementFinder = require('./element').ElementFinder; + ElementArrayFinder = require('./element').ElementArrayFinder; + ProtractorBy = require('./locators').ProtractorBy; + ProtractorExpectedConditions = require('./expectedConditions').ProtractorExpectedConditions; // Export selenium webdriver. - export let promise = webdriver.promise; - export let WebElement = webdriver.WebElement; - export let ActionSequence = webdriver.ActionSequence; - export let Key = webdriver.Key; - export let Command = require('selenium-webdriver/lib/command').Command; - export let CommandName = require('selenium-webdriver/lib/command').Name; + ActionSequence = webdriver.ActionSequence; + Browser = webdriver.Browser; + Builder = webdriver.Builder; + Button = webdriver.Button; + Capabilities = webdriver.Capabilities; + Capability = webdriver.Capability; + EventEmitter = webdriver.EventEmitter; + FileDetector = webdriver.FileDetector; + Key = webdriver.Key; + Session = webdriver.Session; + WebDriver = webdriver.WebDriver; + WebElement = webdriver.WebElement; + WebElementPromise = webdriver.WebElementPromise; + error = webdriver.error; + logging = webdriver.logging; + promise = webdriver.promise; + until = webdriver.until; + Command = require('selenium-webdriver/lib/command').Command; + CommandName = require('selenium-webdriver/lib/command').Name; + utils = { + firefox: require('selenium-webdriver/firefox'), + http: require('selenium-webdriver/http'), + remote: require('selenium-webdriver/remote') + } } + +export var protractor = new Ptor(); diff --git a/lib/runner.ts b/lib/runner.ts index 2a5a109c2..ac040c341 100644 --- a/lib/runner.ts +++ b/lib/runner.ts @@ -2,7 +2,7 @@ import {EventEmitter} from 'events'; import * as q from 'q'; import * as util from 'util'; -import {Browser} from './browser'; +import {ProtractorBrowser} from './browser'; import {Config} from './config'; import {AttachSession, BrowserStack, Direct, Hosted, Local, Mock, Sauce} from './driverProviders'; import {DriverProvider} from './driverProviders'; @@ -151,15 +151,15 @@ export class Runner extends EventEmitter { * Sets up convenience globals for test specs * @private */ - setupGlobals_(browser_: Browser) { + setupGlobals_(browser_: ProtractorBrowser) { // Keep $, $$, element, and by/By under the global protractor namespace protractor.browser = browser_; protractor.$ = browser_.$; protractor.$$ = browser_.$$; protractor.element = browser_.element; - protractor.by = protractor.By = Browser.By; - protractor.wrapDriver = Browser.wrapDriver; - protractor.ExpectedConditions = Browser.ExpectedConditions; + protractor.by = protractor.By = ProtractorBrowser.By; + protractor.wrapDriver = ProtractorBrowser.wrapDriver; + protractor.ExpectedConditions = ProtractorBrowser.ExpectedConditions; if (!this.config_.noGlobals) { // Export protractor to the global namespace to be used in tests. @@ -197,7 +197,7 @@ export class Runner extends EventEmitter { var config = this.config_; var driver = this.driverprovider_.getNewDriver(); - var browser_ = Browser.wrapDriver( + var browser_ = ProtractorBrowser.wrapDriver( driver, config.baseUrl, config.rootElement, config.untrackOutstandingTimeouts); diff --git a/scripts/test.js b/scripts/test.js index 237754652..26d280088 100755 --- a/scripts/test.js +++ b/scripts/test.js @@ -41,8 +41,9 @@ var passingTests = [ // Unit tests 'node node_modules/jasmine/bin/jasmine.js JASMINE_CONFIG_PATH=scripts/unit_test.json', // Dependency tests - 'node node_modules/jasmine/bin/jasmine.js JASMINE_CONFIG_PATH=scripts/dependency_test.json' + 'node node_modules/jasmine/bin/jasmine.js JASMINE_CONFIG_PATH=scripts/dependency_test.json', // Typings tests + 'node spec/install/test.js' // FIX THIS: 'node scripts/typings_tests/test_typings.js' ]; diff --git a/spec/dependencyTest/protractor_spec.js b/spec/dependencyTest/protractor_spec.js index 18d7335d2..8335f4c4a 100644 --- a/spec/dependencyTest/protractor_spec.js +++ b/spec/dependencyTest/protractor_spec.js @@ -8,25 +8,39 @@ describe('require(\'protractor\')', () => { describe('exported protractor classes', () => { it('should be defined', () => { - var protractorClasses = ['Browser', 'ElementFinder', 'ElementArrayFinder', + var protractorClasses = ['ProtractorBrowser', 'ElementFinder', 'ElementArrayFinder', 'ProtractorBy', 'ProtractorExpectedConditions']; for (var pos in protractorClasses) { var property = protractorClasses[pos]; expect(typeof protractor[property]).toEqual('function'); } }); + var seleniumClasses = ['ActionSequence', 'Browser', 'Builder', 'Button', + 'Capabilities', 'Capability', 'EventEmitter', 'FileDetector', 'Key', + 'Session', 'WebDriver', 'WebElement', 'WebElementPromise', 'Command', + 'CommandName']; + for (var pos in seleniumClasses) { + var propertyObj = seleniumClasses[pos]; + it('should have selenium-webdriver defined: ' + propertyObj, () => { + expect(typeof protractor[propertyObj]).toEqual('object'); + }); + } + + it('should have selenium-webdriver promise.Promise', function() { + expect(typeof protractor['promise']['Promise']).toEqual('function'); + }); describe('browser class', () => { it('should have static method defined', () => { var staticMethod = 'wrapDriver'; - expect(typeof protractor.Browser['wrapDriver']).toEqual('function'); + expect(typeof protractor.ProtractorBrowser['wrapDriver']).toEqual('function'); }); it('should have static variables defined', () => { var staticVariables = ['By', 'ExpectedConditions']; for (var pos in staticVariables) { var property = staticVariables[pos]; - expect(typeof protractor.Browser[property]).toEqual('object'); + expect(typeof protractor.ProtractorBrowser[property]).toEqual('object'); } }); }); diff --git a/spec/install/.gitignore b/spec/install/.gitignore new file mode 100644 index 000000000..ae5794927 --- /dev/null +++ b/spec/install/.gitignore @@ -0,0 +1,4 @@ +node_modules +typings +conf.js +typescript_spec.js diff --git a/spec/install/conf.ts b/spec/install/conf.ts new file mode 100644 index 000000000..e6c1c049f --- /dev/null +++ b/spec/install/conf.ts @@ -0,0 +1,7 @@ +import {Config} from 'protractor'; + +export let config: Config = { + mockSelenium: true, + specs: ['*_spec.js'], + framework: 'jasmine' +} diff --git a/spec/install/javascript_spec.js b/spec/install/javascript_spec.js new file mode 100644 index 000000000..cbcfcdc66 --- /dev/null +++ b/spec/install/javascript_spec.js @@ -0,0 +1,43 @@ +describe('javascript', function () { + it('should have global objects that match the protractor namespace', function () { + expect(protractor.browser === browser).toBeTruthy(); + expect(protractor.by === by).toBeTruthy(); + expect(protractor.By === By).toBeTruthy(); + expect(protractor.$ === $).toBeTruthy(); + expect(protractor.$$ === $$).toBeTruthy(); + expect(protractor.ExpectedConditions === ExpectedConditions).toBeTruthy(); + }); + it('should have selenium-webdriver components for the protractor namespace', function () { + expect(typeof protractor.promise.all).toEqual('function'); + expect(typeof protractor.promise.defer).toEqual('function'); + expect(typeof protractor.promise.Promise).toEqual('function'); + expect(typeof protractor.ActionSequence).toEqual('function'); + expect(typeof protractor.Browser).toEqual('object'); + expect(typeof protractor.Builder).toEqual('function'); + expect(typeof protractor.Capabilities).toEqual('function'); + expect(typeof protractor.Capability).toEqual('object'); + expect(typeof protractor.EventEmitter).toEqual('function'); + expect(typeof protractor.FileDetector).toEqual('function'); + expect(typeof protractor.Key).toEqual('object'); + expect(typeof protractor.Session).toEqual('function'); + expect(typeof protractor.WebDriver).toEqual('function'); + expect(typeof protractor.WebElement).toEqual('function'); + expect(typeof protractor.WebElementPromise).toEqual('function'); + expect(typeof protractor.error).toEqual('object'); + expect(typeof protractor.logging).toEqual('object'); + expect(typeof protractor.promise).toEqual('object'); + expect(typeof protractor.until).toEqual('object'); + expect(typeof protractor.Command).toEqual('function'); + expect(typeof protractor.CommandName).toEqual('object'); + expect(typeof protractor.utils.firefox).toEqual('object'); + expect(typeof protractor.utils.http).toEqual('object'); + expect(typeof protractor.utils.remote).toEqual('object'); + }); + it('should have protractor class definitions', function () { + expect(typeof protractor.ProtractorBrowser).toBe('function'); + expect(typeof protractor.ElementFinder).toBe('function'); + expect(typeof protractor.ElementArrayFinder).toBe('function'); + expect(typeof protractor.ProtractorBy).toBe('function'); + expect(typeof protractor.ProtractorExpectedConditions).toBe('function'); + }); +}); diff --git a/spec/install/package.json b/spec/install/package.json new file mode 100644 index 000000000..d26ad9837 --- /dev/null +++ b/spec/install/package.json @@ -0,0 +1,18 @@ +{ + "name": "protractor-install", + "version": "1.0.0", + "description": "e2e typescript => javascript => running", + "main": "index.js", + "scripts": { + "postinstall": "npm run typings", + "typings": "typings install", + "tsc": "tsc", + "test": "protractor conf.js" + }, + "author": "", + "license": "MIT", + "dependencies": { + "protractor": "file:../../", + "rimraf": "^2.5.4" + } +} diff --git a/spec/install/test.js b/spec/install/test.js new file mode 100644 index 000000000..c3f5681ad --- /dev/null +++ b/spec/install/test.js @@ -0,0 +1,63 @@ +"use strict"; +var path = require('path'); +var child_process = require('child_process'); +var rimraf = require('rimraf'); +var spawnSync = child_process.spawnSync; + +class TestUtils { + static runCommand(task, args, options) { + var child = spawnSync(task, args, options); + return child.output; + }; +}; + +function install() { + rimraf.sync(path.resolve(__dirname, 'node_modules')); + var options = {cwd: __dirname}; + var output = TestUtils.runCommand('npm', ['install'], options); + if (output && output[1]) { + console.log(output[1].toString()); + } else { + throw new Error('Something went wrong in function install.') + } +} + +function tsc() { + var options = {cwd: __dirname}; + var output = TestUtils.runCommand('npm', ['run', 'tsc'], options); + if (output && output[1]) { + var options = {cwd: path.resolve('.')}; + console.log(output[1].toString()); + if (output[1].toString().indexOf('error') >= 0) { + throw new Error('tsc failed.'); + } + } else { + throw new Error('Something went wrong in function tsc.') + } +} + +function test() { + var options = {cwd: __dirname}; + var output = TestUtils.runCommand('node', + ['node_modules/protractor/bin/protractor','conf.js'], + options); + if (output && output[1]) { + console.log(output[1].toString()); + var lines = output[1].toString().split('\n'); + for (var pos in lines) { + var line = lines[pos]; + if (line.indexOf(' specs, ') >= 0) { + var failures = line.split(' specs, ')[1].charAt(0); + if (failures !== '0') { + throw new Error('Failed with ' + failures + ' failure(s).'); + } + } + } + } else { + throw new Error('Something went wrong in function test.') + } +} + +install(); +tsc(); +test(); diff --git a/spec/install/tsconfig.json b/spec/install/tsconfig.json new file mode 100644 index 000000000..7a8b29376 --- /dev/null +++ b/spec/install/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": false, + "declaration": false, + "noImplicitAny": false + }, + "exclude": [ + "node_modules", + "typings/globals" + ] +} diff --git a/spec/install/typescript_spec.ts b/spec/install/typescript_spec.ts new file mode 100644 index 000000000..f1f479739 --- /dev/null +++ b/spec/install/typescript_spec.ts @@ -0,0 +1,46 @@ +import {browser, by, By, element, $, $$, ExpectedConditions, protractor} from 'protractor/globals'; +import {ProtractorBrowser} from 'protractor'; +describe('typescript imports', () => { + it('should have global objects that match the protractor namespace', () => { + expect(protractor.browser === browser).toBeTruthy(); + expect(protractor.by === by).toBeTruthy(); + expect(protractor.By === By).toBeTruthy(); + expect(protractor.$ === $).toBeTruthy(); + expect(protractor.$$ === $$).toBeTruthy(); + expect(protractor.ExpectedConditions === ExpectedConditions).toBeTruthy(); + expect(typeof protractor.wrapDriver).toEqual('function'); + }); + it('should have selenium-webdriver components for the protractor namespace', () => { + expect(typeof protractor.promise.all).toEqual('function'); + expect(typeof protractor.promise.defer).toEqual('function'); + expect(typeof protractor.promise.Promise).toEqual('function'); + expect(typeof protractor.ActionSequence).toEqual('function'); + expect(typeof protractor.Browser).toEqual('object'); + expect(typeof protractor.Builder).toEqual('function'); + expect(typeof protractor.Capabilities).toEqual('function'); + expect(typeof protractor.Capability).toEqual('object'); + expect(typeof protractor.EventEmitter).toEqual('function'); + expect(typeof protractor.FileDetector).toEqual('function'); + expect(typeof protractor.Key).toEqual('object'); + expect(typeof protractor.Session).toEqual('function'); + expect(typeof protractor.WebDriver).toEqual('function'); + expect(typeof protractor.WebElement).toEqual('function'); + expect(typeof protractor.WebElementPromise).toEqual('function'); + expect(typeof protractor.error).toEqual('object'); + expect(typeof protractor.logging).toEqual('object'); + expect(typeof protractor.promise).toEqual('object'); + expect(typeof protractor.until).toEqual('object'); + expect(typeof protractor.Command).toEqual('function'); + expect(typeof protractor.CommandName).toEqual('object'); + expect(typeof protractor.utils.firefox).toEqual('object'); + expect(typeof protractor.utils.http).toEqual('object'); + expect(typeof protractor.utils.remote).toEqual('object'); + }); + it('should have protractor class definitions', () => { + expect(typeof protractor.ProtractorBrowser).toBe('function'); + expect(typeof protractor.ElementFinder).toBe('function'); + expect(typeof protractor.ElementArrayFinder).toBe('function'); + expect(typeof protractor.ProtractorBy).toBe('function'); + expect(typeof protractor.ProtractorExpectedConditions).toBe('function'); + }); +}); diff --git a/spec/install/typings.json b/spec/install/typings.json new file mode 100644 index 000000000..47d414462 --- /dev/null +++ b/spec/install/typings.json @@ -0,0 +1,8 @@ +{ + "name": "protractor-install", + "dependencies": {}, + "globalDependencies": { + "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", + "node": "registry:dt/node#6.0.0+20160802155038" + } +} diff --git a/tsconfig.json b/tsconfig.json index 91ba8518e..bbb53b0d8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,7 @@ "typings/globals", "scripts", "globals.ts", - "exampleTypescript" + "exampleTypescript", + "spec" ] }