From b2eaa290bbd1d069fdaf8f25eee5eb3da611b589 Mon Sep 17 00:00:00 2001 From: Craig Date: Thu, 21 Jul 2016 13:02:03 -0700 Subject: [PATCH] fix(types): output plugin typings (#3389) * output plugin typings * change ProtractorPlugin to an interface * doc clean up closes #3365 --- docs/plugins.md | 26 ++--- exampleTypescript/plugins.ts | 16 +++ gulpfile.js | 3 +- lib/plugins.ts | 218 +++++++++++++++++++++++++++++++++-- 4 files changed, 241 insertions(+), 22 deletions(-) create mode 100644 exampleTypescript/plugins.ts diff --git a/docs/plugins.md b/docs/plugins.md index 36147ea25..2a22236c4 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -312,30 +312,28 @@ export function onPageLoad(): void { }; ``` -However, if you want your code more heavily typed, you can write your plugin as -an extension of the `ProtractorPlugin` class: +If you want your code more heavily typed, you can write your plugin with +the `ProtractorPlugin` interface: ```typescript -import {ProtractorPlugin} from 'protractor/built/plugins'; +import {ProtractorPlugin} from 'protractor'; -export class MyPlugin extends ProtractorPlugin { +// creating a "var module: any" will allow use of module.exports +declare var module: any; + +let myPlugin: ProtractorPlugin = { + addSuccess(info: {specName: string}) { + console.log('on success: ' + info.specName); + }, onPageLoad() { this.addSuccess({specName: 'Hello, World!'}); - }; + } }; -``` -Then, in a separate file, export an instance of that class using an assignment -export: +module.exports = myPlugin; -```typescript -import MyPlugin from './MyPlugin'; - -export = new MyPlugin(); ``` -This instance is what you should point to in your config file. - First Party Plugins ------------------- diff --git a/exampleTypescript/plugins.ts b/exampleTypescript/plugins.ts new file mode 100644 index 000000000..b32daaae7 --- /dev/null +++ b/exampleTypescript/plugins.ts @@ -0,0 +1,16 @@ +// a plugin example with the protractor plugin interface +import { ProtractorPlugin } from 'protractor'; + +// creating a "var module: any" will allow use of module.exports +declare var module: any; + +let myPlugin: ProtractorPlugin = { + addSuccess(info: {specName: string}) { + console.log('on success: ' + info.specName); + }, + onPageLoad() { + this.addSuccess({specName: 'Hello, World!'}); + } +}; + +module.exports = myPlugin; diff --git a/gulpfile.js b/gulpfile.js index 6ed22bf75..ed42768ca 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -78,7 +78,8 @@ gulp.task('default',['prepublish']); gulp.task('types', function(done) { var folder = 'built'; - var files = ['browser', 'element', 'locators', 'expectedConditions', 'config']; + var files = ['browser', 'element', 'locators', 'expectedConditions', + 'config', 'plugins']; var outputFile = path.resolve(folder, 'index.d.ts'); var contents = ''; files.forEach(file => { diff --git a/lib/plugins.ts b/lib/plugins.ts index e185b14ac..04e1e0cc2 100644 --- a/lib/plugins.ts +++ b/lib/plugins.ts @@ -18,16 +18,220 @@ export interface PluginConfig { [key: string]: any; } -export class ProtractorPlugin { - skipAngularStability: boolean; +export interface ProtractorPlugin { + /** + * Sets up plugins before tests are run. This is called after the WebDriver + * session has been started, but before the test framework has been set up. + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, a failed assertion is added to + * the test results. + * + * @return {q.Promise=} Can return a promise, in which case protractor will wait + * for the promise to resolve before continuing. If the promise is + * rejected, a failed assertion is added to the test results. + */ + setup?: () => q.Promise; + + /** + * This is called after the tests have been run, but before the WebDriver + * session has been terminated. + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, a failed assertion is added to + * the test results. + * + * @return {q.Promise=} Can return a promise, in which case protractor will wait + * for the promise to resolve before continuing. If the promise is + * rejected, a failed assertion is added to the test results. + */ + teardown?: () => q.Promise; + + /** + * Called after the test results have been finalized and any jobs have been + * updated (if applicable). + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, it is outputted to the console + * + * @return {q.Promise=} Can return a promise, in which case protractor will wait + * for the promise to resolve before continuing. If the promise is + * rejected, an error is logged to the console. + */ + postResults?: () => q.Promise; - name: string; - config: PluginConfig; - addFailure: + /** + * Called after each test block (in Jasmine, this means an `it` block) + * completes. + * + * @param {boolean} passed True if the test passed. + * @param {Object} testInfo information about the test which just ran. + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, a failed assertion is added to + * the test results. + * + * @return {q.Promise=} Can return a promise, in which case protractor will wait + * for the promise to resolve before outputting test results. Protractor + * will *not* wait before executing the next test, however. If the promise + * is rejected, a failed assertion is added to the test results. + */ + postTest?: (passed: boolean, testInfo: any) => q.Promise; + + /** + * This is called inside browser.get() directly after the page loads, and before + * angular bootstraps. + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, a failed assertion is added to + * the test results. + * + * @return {q.Promise=} Can return a promise, in which case protractor will wait + * for the promise to resolve before continuing. If the promise is + * rejected, a failed assertion is added to the test results. + */ + onPageLoad?: () => q.Promise; + + /** + * This is called inside browser.get() directly after angular is done + * bootstrapping/synchronizing. If browser.ignoreSynchronization is true, this + * will not be called. + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, a failed assertion is added to + * the test results. + * + * @return {q.Promise=} Can return a promise, in which case protractor will wait + * for the promise to resolve before continuing. If the promise is + * rejected, a failed assertion is added to the test results. + */ + onPageStable?: () => q.Promise; + + /** + * Between every webdriver action, Protractor calls browser.waitForAngular() to + * make sure that Angular has no outstanding $http or $timeout calls. + * You can use waitForPromise() to have Protractor additionally wait for your + * custom promise to be resolved inside of browser.waitForAngular(). + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, a failed assertion is added to + * the test results. + * + * @return {q.Promise=} Can return a promise, in which case protractor will wait + * for the promise to resolve before continuing. If the promise is + * rejected, a failed assertion is added to the test results, and protractor + * will continue onto the next command. If nothing is returned or something + * other than a promise is returned, protractor will continue onto the next + * command. + */ + waitForPromise?: () => q.Promise; + + /** + * Between every webdriver action, Protractor calls browser.waitForAngular() to + * make sure that Angular has no outstanding $http or $timeout calls. + * You can use waitForCondition() to have Protractor additionally wait for your + * custom condition to be truthy. + * + * @this {Object} bound to module.exports + * + * @throws {*} If this function throws an error, a failed assertion is added to + * the test results. + * + * @return {q.Promise|boolean} If truthy, Protractor will continue onto + * the next command. If falsy, webdriver will continuously re-run this + * function until it is truthy. If a rejected promise is returned, a failed + * assertion is added to the test results, and protractor will continue onto + * the next command. + */ + waitForCondition?: () => q.Promise; + + /** + * Used to turn off default checks for angular stability + * + * Normally Protractor waits for all $timeout and $http calls to be processed + * before executing the next command. This can be disabled using + * browser.ignoreSynchronization, but that will also disable any + * .waitForPromise or .waitForCondition checks. If you want + * to + * disable synchronization with angular, but leave in tact any custom plugin + * synchronization, this is the option for you. + * + * This is used by users who want to replace Protractor's synchronization code + * This is used by users who want to replace Protractor's synchronization code + * with their own. + * + * @type {boolean} + */ + skipAngularStability?: boolean; + + /** + * Used when reporting results. + * + * If you do not specify this property, it will be filled in with something + * reasonable (e.g. the plugin's path) + * + * @type {string} + */ + name?: string; + + /** + * The plugin configuration object. Note that this is not the entire + * Protractor config object, just the entry in the plugins array for this + * plugin. + * + * @type {Object} + */ + config?: PluginConfig; + + /** + * Adds a failed assertion to the test's results. Note: this is added by the + * Protractor API, not to be implemented by the plugin author. + * + * @param {string} message The error message for the failed assertion + * @param {specName: string, stackTrace: string} options Some optional extra + * information about the assertion: + * - specName The name of the spec which this assertion belongs to. + * Defaults to `PLUGIN_NAME + ' Plugin Tests'`. + * - stackTrace The stack trace for the failure. Defaults to undefined. + * Defaults to `{}`. + * + * @throws {Error} Throws an error if called after results have been reported + */ + addFailure?: (message?: string, info?: {specName?: string, stackTrace?: string}) => void; - addSuccess: (info?: {specName?: string}) => void; - addWarning: (message?: string, info?: {specName?: string}) => void; + + /** + * Adds a passed assertion to the test's results. Note: this is added by the + * Protractor API, not to be implemented by the plugin author. + * + * @param {specName: string} options Extra information about the assertion: + * - specName The name of the spec which this assertion belongs to. + * Defaults to `PLUGIN_NAME + ' Plugin Tests'`. + * Defaults to `{}`. + * + * @throws {Error} Throws an error if called after results have been reported + */ + addSuccess?: (info?: {specName?: string}) => void; + + /** + * Warns the user that something is problematic. Note: this is added by the + * Protractor API, not to be implemented by the plugin author. + * + * @param {string} message The message to warn the user about + * @param {specName: string} options Extra information about the assertion: + * - specName The name of the spec which this assertion belongs to. + * Defaults to `PLUGIN_NAME + ' Plugin Tests'`. + * Defaults to `{}`. + */ + addWarning?: (message?: string, info?: {specName?: string}) => void; } /**