diff --git a/docs/plugins.md b/docs/plugins.md index e38851a40..e05d5c734 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -12,11 +12,7 @@ The `plugins` folder contains default plugins for Protractor. ##In this document: * [Using Plugins](/docs/plugins.md#using-plugins) * [Writing Plugins](/docs/plugins.md#writing-plugins) -* Default Plugins - * [Accessibility Plugin](/docs/plugins.md#accessibility-plugin) - * [ngHint Plugin](/docs/plugins.md#nghint-plugin) - * [Timeline Plugin](/docs/plugins.md#timeline-plugin) - * [Console Plugin](/docs/plugins.md#console-plugin-chrome-only) +* [First Party Plugins](/docs/plugins.md#first-party-plugins) * [Community Plugins](/docs/plugins.md#community-plugins) Using Plugins @@ -290,145 +286,49 @@ exports.addWarning(message, options); If you specify any of these properties in your plugin file, they will be overwritten. -Accessibility Plugin --------------------- -Protractor comes with support for two accessibility testing options: - * Accessibility Developer Tools - * Tenon.io - -Protractor will run each set of audits (depending on your configuration) on your existing end-to-end -tests to ensure your site is free of obvious errors. In this kind of testing, there is no concept of -"warnings"–only pass or fail. In your configuration, you can decide whether warnings should -pass or fail your build. - -To understand how each of these tools can be used, see this support matrix: - -| Testing Library | Pricing | API Key | External Request | No. of Tests | Info | -|--------------------------------------|-------------------------------------------|---------|------------------|--------------|-------------------------------------------------------------------------| -| Chrome Accessibility Developer Tools | Free | No | No | 14 | [Github](https://github.com/GoogleChrome/accessibility-developer-tools) | -| Tenon.io | Free limited accounts, paid subscriptions | Yes | Yes | 63 | [Tenon.io](http://tenon.io/) | - -Protractor now supports the [Accessibility Developer Tools](https://github.com/GoogleChrome/accessibility-developer-tools), the same audit library used by the [Chrome browser extension](https://chrome.google.com/webstore/detail/accessibility-developer-t/fpkknkljclfencbdbgkenhalefipecmb?hl=en). Protractor -[runs an audit](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules) -locally by injecting the Dev Tools script into WebDriver pages, and it can diagnose issues including -missing labels, incorrect ARIA attributes and color contrast. This is a great starting point if -you can't send source code over the wire through an API. - -[Tenon.io](http://www.tenon.io) has a more robust set of tests to help you find -accessibility issues, but it requires [registering](http://tenon.io/register.php) for an API key -and making an external request for each test, which may not work for everyone. Some people use -Tenon with introspection services like ngrok or localtunnel to securely -test local web servers. Protractor takes the [options you provide](http://tenon.io/documentation/understanding-request-parameters.php) in the plugin configuration and sends them -with the page source to the Tenon API. One limitation of this approach is that all scripts must be reachable from the page source as a string, for example, by using a CDN. -For projects with an MIT license, Tenon is free but with a limited -daily API limit. Paid subscriptions are available for enterprise and commercial projects. - -Enable this plugin in your config file: -```js - // Chrome Accessibility Dev Tools only: - exports.config = { - ... - plugins: [{ - chromeA11YDevTools: { - treatWarningsAsFailures: true - }, - path: 'node_modules/protractor/plugins/accessibility' - }] - } -``` -```js - // Tenon.io only: - exports.config = { - ... - plugins: [{ - tenonIO: { - options: { - // See http://tenon.io/documentation/understanding-request-parameters.php - // options.src will be added by the test. - }, - printAll: false, // whether the plugin should log API response - }, - chromeA11YDevTools: true, - path: 'node_modules/protractor/plugins/accessibility' - }] - } -``` - -ngHint Plugin -------------- -ngHint adds run-time hinting to AngularJS projects. This plugin bubbles those hints up to the -command line so they can be used in automated testing. - -You enable this plugin in your config file: - ```js -exports.config = { - plugins: [{ - path: 'node_modules/protractor/plugins/ngHint', - - asTests: {Boolean}, - excludeURLs: {(String|RegExp)[]} - }] -}; -``` -`asTests` specifies if the plugin should generate passed/failed test results -based on the ngHint output or instead log the results to the console. -Defaults to true. - -`excludeURLs` specifies a list of URLs for which ngHint results should be -ignored. Defaults to [] - -Timeline Plugin ---------------- -This plugin gathers test timeline information from the protractor test process, the selenium -client logs (if available), and sauce labs (if available), and presents the output visually. -This improves understanding of where latency issues are in tests. +First Party Plugins +------------------- -To enable the Timeline plugin, set it up in your config file: -```js -exports.config = { - plugins: [{ - path: 'node_modules/protractor/plugins/timeline/index.js', +* Accessibility Plugin - // Output json and html will go in this folder. - outdir: 'timelines', + The accessibility plugin runs a set of accessibility audits on your webapp. + It is published at the npm module [`protractor-accessibility-plugin`] + (https://www.npmjs.com/package/protractor-accessibility-plugin) and stored at + the github repo [angular/protractor-accessibility-plugin] + (https://github.com/angular/protractor-accessibility-plugin). - // Optional - if sauceUser and sauceKey are specified, logs from - // SauceLabs will also be parsed after test invocation. - sauceUser: 'Jane', - sauceKey: 'abcdefg' - }], - // other configuration settings -}; -``` +* Timeline Plugin + The timeline plugin gathers test timeline information from various sources and + presents the output visually. This improves understanding of where latency + issues are in tests. It is published at the npm module + [`protractor-timeline-plugin`] + (https://www.npmjs.com/package/protractor-timeline-plugin) and stored at the + github repo [angular/protractor-timeline-plugin] + (https://github.com/angular/protractor-timeline-plugin). -Console Plugin (Chrome only) ----------------------------- +* ngHint Plugin -This plugin checks the browser log after each test for warnings and errors. It -can be configured to fail a test if either is detected. There is also an -optional exclude parameter which accepts both regex and strings. Any log -matching the exclude parameter will not fail the test or be logged to the -console. A false setting to logWarnings also overrides the failOnWarning setting. + The ngHint plugin uses [Angular Hint](https://github.com/angular/angular-hint) + to generate run-time hinting and then turns these hints into Protractor tests. + It is published at the npm module [`protractor-ng-hint-plugin`] + (https://www.npmjs.com/package/protractor-ng-hint-plugin) and stored at the + github repo [angular/protractor-ng-hint-plugin] + (https://github.com/angular/protractor-ng-hint-plugin). -```js -exports.config = { - plugins: [{ - path: 'node_modules/protractor/plugins/console', - failOnWarning: {Boolean} (Default - false), - failOnError: {Boolean} (Default - true), - logWarnings: {Boolean} (Default - true), - exclude: {Array of strings and regex} (Default - []) - }] -}; -``` +* Console Plugin (Chrome Only) -Note that this plugin's behavior is undefined on browsers other than Chrome. -Firefox users have reported flaky results. + The console plugin checks the browser log after each test for warnings and + errors. It is published at the npm module [`protractor-console-plugin`] + (https://www.npmjs.com/package/protractor-console-plugin) and stored at the + github repo [angular/protractor-console-plugin] + (https://github.com/angular/protractor-console-plugin). Community Plugins ----------------- -This list is here for reference and the plugins included are not developed or mantained by protractor's team by any means. If you find any issues with this plugins please report them to the corresponding plugin developer. +This list is here for reference and the plugins included are not developed or +mantained by protractor's team by any means. If you find any issues with this +plugins please report them to the corresponding plugin developer. * [Protractor testability plugin](https://github.com/alfonso-presa/protractor-testability-plugin): this plugins enables synchronous testing with protractor for features that are not developed using the services provided by AngularJS, preventing the need of additional waits coded in the tests. This happens for example if you have WebSockets communication with the server or for web applications built with frameworks different than AngularJS. diff --git a/plugins/README.md b/plugins/README.md deleted file mode 100644 index 496e32fc7..000000000 --- a/plugins/README.md +++ /dev/null @@ -1 +0,0 @@ -Please see [the plugin documentation](../docs/plugins.md) diff --git a/plugins/accessibility/index.js b/plugins/accessibility/index.js deleted file mode 100644 index 00ef4ca6d..000000000 --- a/plugins/accessibility/index.js +++ /dev/null @@ -1,232 +0,0 @@ -var q = require('q'), - fs = require('fs'), - path = require('path'), - _ = require('lodash'); - request = require('request'), - Entities = require('html-entities').XmlEntities; - -/** - * You can audit your website against the Chrome Accessibility Developer Tools, - * Tenon.io, or both by enabling this plugin in your config file: - * - * // Chrome Accessibility Developer Tools: - * exports.config = { - * ... - * plugins: [{ - * chromeA11YDevTools: { - * treatWarningsAsFailures: true - * }, - * path: 'node_modules/protractor.plugins/accessiblity' - * }] - * } - * - * // Tenon.io: - * - * // Read about the Tenon.io settings and API requirements: - * // -http://tenon.io/documentation/overview.php - * - * exports.config = { - * ... - * plugins: [{ - * tenonIO: { - * options: { - * // See http://tenon.io/documentation/understanding-request-parameters.php - * // options.src will be added by the test. - * }, - * printAll: false, // whether the plugin should log API response - * }, - * chromeA11YDevTools: false, - * path: 'node_modules/protractor/plugins/accessiblity' - * }] - * } - * - */ - -var AUDIT_FILE = require.resolve('accessibility-developer-tools/dist/js/axs_testing.js'); -var TENON_URL = 'http://www.tenon.io/api/'; - -/** - * Checks the information returned by the accessibility audit(s) and - * displays passed/failed results as console output. - * - * @this {Object} The plugin context object - * @return {q.Promise} A promise which resolves when all audits are finished - * @public - */ -function teardown() { - - var audits = []; - - if (this.config.chromeA11YDevTools) { - audits.push(runChromeDevTools(this)); - } - // check for Tenon config and an actual API key, not the placeholder - if (this.config.tenonIO && /[A-Za-z][0-9]/.test( - this.config.tenonIO.options.key)) { - audits.push(runTenonIO(this)); - } - return q.all(audits); -} - -var entities = new Entities(); - -/** - * Audits page source against the Tenon API, if configured. Requires an API key: - * more information about licensing and configuration available at - * http://tenon.io/documentation/overview.php. - * - * @param {Object} context The plugin context object - * @return {q.Promise} A promise which resolves when the audit is finished - * @private - */ -function runTenonIO(context) { - - return browser.driver.getPageSource().then(function(source) { - - var options = _.assign(context.config.tenonIO.options, {src: source}); - - // setup response as a deferred promise - var deferred = q.defer(); - request.post({ - url: TENON_URL, - form: options - }, - function(err, httpResponse, body) { - if (err) { return resolve.reject(new Error(err)); } - else { return deferred.resolve(JSON.parse(body)); } - }); - - return deferred.promise.then(function(response) { - return processTenonResults(response); - }); - }); - - function processTenonResults(response) { - - var testHeader = 'Tenon.io - '; - - if (!response.resultSet) { - if (response.code === 'daily_limit_reached') { - console.log(testHeader, 'Daily limit reached'); - console.log(response.moreInfo); - } - else { - console.log('Tenon.io error'); - } - return; - } - - var numResults = response.resultSet.length; - - if (numResults === 0) { - context.addSuccess(); - return; - } - - if (context.config.tenonIO.printAll) { - console.log('\x1b[32m', testHeader + 'API response', '\x1b[39m'); - console.log(response); - } - - return response.resultSet.forEach(function(result) { - var ref = (result.ref === null) ? '' : result.ref; - - context.addFailure(result.errorDescription + '\n\n' + - '\t\t' +entities.decode(result.errorSnippet) + - '\n\n\t\t' + ref, {specName: testHeader + result.errorTitle}); - }); - } -} - -/** - * Audits page source against the Chrome Accessibility Developer Tools, if configured. - * - * @param {Object} context The plugin context object - * @return {q.Promise} A promise which resolves when the audit is finished - * @private - */ -function runChromeDevTools(context) { - - var data = fs.readFileSync(AUDIT_FILE, 'utf-8'); - data = data + ' return axs.Audit.run();'; - - var elementPromises = [], - elementStringLength = 200; - - function trimText(text) { - if (text.length > elementStringLength) { - return text.substring(0, elementStringLength / 2) + ' ... ' - + text.substring(text.length - elementStringLength / 2); - } else { - return text; - } - } - - var testHeader = 'Chrome A11Y - '; - - return browser.executeScript_(data, 'a11y developer tool rules').then(function(results) { - - var audit = results.map(function(result) { - var DOMElements = result.elements; - if (DOMElements !== undefined) { - - DOMElements.forEach(function(elem) { - // get elements from WebDriver, add to promises array - elementPromises.push( - elem.getOuterHtml().then(function(text) { - return { - code: result.rule.code, - list: trimText(text) - }; - }, - function(reason){ - return { - code: result.rule.code, - list: reason - }; - }) - ); - }); - result.elementCount = DOMElements.length; - } - return result; - }); - - // Wait for element names to be fetched - return q.all(elementPromises).then(function(elementFailures) { - - return audit.forEach(function(result, index) { - if (result.result === 'FAIL') { - var label = result.elementCount === 1 ? ' element ' : ' elements '; - if (result.rule.severity !== 'Warning' - || context.config.chromeA11YDevTools.treatWarningsAsFailures) { - result.warning = false; - } else { - result.warning = true; - result.rule.heading = '\x1b[33m(WARNING) ' - + result.rule.heading + ' (' + result.elementCount - + label + 'failed)'; - } - result.output = '\n\t\t' + result.elementCount + label + 'failed:'; - - // match elements returned via promises - // by their failure codes - elementFailures.forEach(function(element, index) { - if (element.code === result.rule.code) { - result.output += '\n\t\t' + elementFailures[index].list; - } - }); - result.output += '\n\n\t\t' + result.rule.url; - (result.warning ? context.addWarning : context.addFailure)( - result.output, {specName: testHeader + result.rule.heading}); - } - else { - context.addSuccess({specName: testHeader + result.rule.heading}); - } - }); - }); - }); -} - -// Export -exports.teardown = teardown; diff --git a/plugins/accessibility/spec/fail_spec.js b/plugins/accessibility/spec/fail_spec.js deleted file mode 100644 index 2933c3f17..000000000 --- a/plugins/accessibility/spec/fail_spec.js +++ /dev/null @@ -1,5 +0,0 @@ -describe('check if accessibility plugin works on bad apps', function() { - it('should have accessibility problems on markup', function() { - browser.get('accessibility/badMarkup.html'); - }); -}); diff --git a/plugins/accessibility/spec/failureConfig.js b/plugins/accessibility/spec/failureConfig.js deleted file mode 100644 index 4ec69fb15..000000000 --- a/plugins/accessibility/spec/failureConfig.js +++ /dev/null @@ -1,21 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['fail_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - tenonIO: { - options: { - key: 'YOUR_API_KEY', // ADD YOUR API KEY HERE - level: 'AA' // WCAG AA OR AAA - }, - printAll: false - }, - chromeA11YDevTools: { - treatWarningsAsFailures: true - }, - path: '../index.js' - }] -}; diff --git a/plugins/accessibility/spec/successConfig.js b/plugins/accessibility/spec/successConfig.js deleted file mode 100644 index fa2757690..000000000 --- a/plugins/accessibility/spec/successConfig.js +++ /dev/null @@ -1,19 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['success_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - tenonIO: { - options: { - key: 'YOUR_API_KEY', // ADD YOUR API KEY HERE - level: 'AA' // WCAG AA OR AAA - }, - printAll: false - }, - chromeA11YDevTools: true, - path: "../index.js" - }] -}; diff --git a/plugins/accessibility/spec/success_spec.js b/plugins/accessibility/spec/success_spec.js deleted file mode 100644 index 0b20f15aa..000000000 --- a/plugins/accessibility/spec/success_spec.js +++ /dev/null @@ -1,9 +0,0 @@ -describe('accessibility', function() { - it('should get a file to test', function() { - browser.get('accessibility/index.html'); - - element.all(by.css('input')).then(function(inputs) { - expect(inputs.length).toEqual(2); - }); - }); -}); diff --git a/plugins/console/index.js b/plugins/console/index.js deleted file mode 100644 index 4e600326d..000000000 --- a/plugins/console/index.js +++ /dev/null @@ -1,117 +0,0 @@ -var q = require('q'); - -/** - * This plugin checks the browser log after each test for warnings and errors. - * It can be configured to fail a test if either is detected. There is also an - * optional exclude parameter which accepts both regex and strings. Any log - * matching the exclude parameter will not fail the test or be logged to the - * console. A false setting to logWarnings also overrides the failOnWarning setting. - * - * exports.config = { - * plugins: [{ - * path: 'node_modules/protractor/plugins/console', - * failOnWarning: {Boolean} (Default - false), - * failOnError: {Boolean} (Default - true), - * logWarnings: {Boolean} (Default - true), - * exclude: {Array of strings and regex} (Default - []) - * }] - * }; - */ -var ConsolePlugin = function() { -}; - -/** - * Gets the browser log. - * - * @return {webdriver.promise.Promise.>} - */ -ConsolePlugin.getBrowserLog = function() { - return browser.manage().logs().get('browser'); -}; - -/** - * Logs messages to the test outputl - * - * @param {Object} warnings The list of warnings detected by the browser log. - * @param {Object} errors The list of errors detected by the browser log. - * @param {boolean} failOnWarning Tests fail if a warning was detected - * @param {boolean} failOnError Tests fail if an error was detected - * @param {Object} context The plugin context object - */ -ConsolePlugin.logMessages = function(warnings, errors, - failOnWarning, failOnError, context) { - warnings.map(function(warning) { - (failOnWarning ? context.addFailure : context.addWarning)( - warning.level.name + ': ' + warning.message); - }); - errors.map(function(error) { - (failOnError ? context.addFailure : context.addWarning)( - error.level.name + ': ' + error.message); - }); -}; - -/** - * Determines if a log message is filtered out or not. This can be set at the - * config stage using the exclude parameter. The parameter accepts both strings - * and regex. - * - * @param {string} logMessage Current log message. - * @return {boolean} true iff the log should be included in the output - */ -ConsolePlugin.includeLog = function(logMessage) { - return ConsolePlugin.exclude.filter(function(e) { - return (e instanceof RegExp) ? logMessage.match(e) : - logMessage.indexOf(e) > -1; - }).length === 0; -}; - -/** - * Parses the log and decides whether to throw an error or not. - * - * @param {Object} context The plugin context object - * @return {!webdriver.promise.Promise.} A promise which resolves when the - * logs have been gathered - */ -ConsolePlugin.parseLog = function(context) { - var failOnWarning = (context.config.failOnWarning === undefined) ? false : - context.config.failOnWarning; - var failOnError = (context.config.failOnError === undefined) ? true : - context.config.failOnError; - var logWarnings = (context.config.logWarnings === undefined) ? true : - context.config.logWarnings; - ConsolePlugin.exclude = context.config.exclude || []; - - return ConsolePlugin.getBrowserLog().then(function(log) { - var warnings = []; - if (logWarnings) { - warnings = log.filter(function(node) { - return (node.level || {}).name === 'WARNING' && - ConsolePlugin.includeLog(node.message); - }); - } - - var errors = log.filter(function(node) { - return (node.level || {}).name === 'SEVERE' && - ConsolePlugin.includeLog(node.message); - }); - - ConsolePlugin.logMessages(warnings, errors, failOnWarning, failOnError, - context); - }); - -}; - -/** - * Gather the console logs and output them as test results. See the - * documentation of the teardown function in the protractor plugin API. - * - * @return {!webdriver.promise.Promise.} A promise which resolves to the - * test results generated by the console logs - */ -ConsolePlugin.prototype.teardown = function() { - return ConsolePlugin.parseLog(this); -}; - -var consolePlugin = new ConsolePlugin(); - -module.exports = consolePlugin; diff --git a/plugins/console/spec/consoleFailConfig.js b/plugins/console/spec/consoleFailConfig.js deleted file mode 100644 index 0787b841f..000000000 --- a/plugins/console/spec/consoleFailConfig.js +++ /dev/null @@ -1,13 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['fail_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - failOnWarning: true, - failOnError: true - }] -}; diff --git a/plugins/console/spec/consoleFailErrorConfig.js b/plugins/console/spec/consoleFailErrorConfig.js deleted file mode 100644 index 42ec16798..000000000 --- a/plugins/console/spec/consoleFailErrorConfig.js +++ /dev/null @@ -1,13 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['fail_error_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - failOnWarning: false, - failOnError: true - }] -}; diff --git a/plugins/console/spec/consoleFailFilterConfig.js b/plugins/console/spec/consoleFailFilterConfig.js deleted file mode 100644 index f5a6ed239..000000000 --- a/plugins/console/spec/consoleFailFilterConfig.js +++ /dev/null @@ -1,17 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['fail_error_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - failOnWarning: true, - failOnError: true, - exclude: [ - 'string', - /regex/ - ] - }] -}; diff --git a/plugins/console/spec/consoleFailLogWarnings.js b/plugins/console/spec/consoleFailLogWarnings.js deleted file mode 100644 index d531866a0..000000000 --- a/plugins/console/spec/consoleFailLogWarnings.js +++ /dev/null @@ -1,14 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['fail_warning_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - failOnWarning: true, - logWarnings: true, - failOnError: false - }] -}; diff --git a/plugins/console/spec/consoleFailWarningConfig.js b/plugins/console/spec/consoleFailWarningConfig.js deleted file mode 100644 index cbb39425a..000000000 --- a/plugins/console/spec/consoleFailWarningConfig.js +++ /dev/null @@ -1,13 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['fail_warning_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - failOnWarning: true, - failOnError: false - }] -}; diff --git a/plugins/console/spec/consolePassConfig.js b/plugins/console/spec/consolePassConfig.js deleted file mode 100644 index 4cfddee76..000000000 --- a/plugins/console/spec/consolePassConfig.js +++ /dev/null @@ -1,13 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['pass_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - failOnWarning: false, - failOnError: false - }] -}; diff --git a/plugins/console/spec/consolePassLogWarnings.js b/plugins/console/spec/consolePassLogWarnings.js deleted file mode 100644 index 84b6063f2..000000000 --- a/plugins/console/spec/consolePassLogWarnings.js +++ /dev/null @@ -1,14 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['pass_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - failOnWarning: true, - logWarnings: false, - failOnError: false - }] -}; diff --git a/plugins/console/spec/fail_error_spec.js b/plugins/console/spec/fail_error_spec.js deleted file mode 100644 index bb2099b69..000000000 --- a/plugins/console/spec/fail_error_spec.js +++ /dev/null @@ -1,15 +0,0 @@ -describe('console plugin', function() { - - var logMessageButton = element(by.id('log-message')); - var deleteMessageButton = element(by.id('simulate-error')); - - it('should fail on error message', function() { - browser.get('console/index.html'); - deleteMessageButton.click(); - }); - - it('should not fail on log and debug messages', function() { - browser.get('console/index.html'); - logMessageButton.click(); - }); -}); diff --git a/plugins/console/spec/fail_spec.js b/plugins/console/spec/fail_spec.js deleted file mode 100644 index d9b993bc2..000000000 --- a/plugins/console/spec/fail_spec.js +++ /dev/null @@ -1,21 +0,0 @@ -describe('console plugin', function() { - - var logMessageButton = element(by.id('log-message')); - var warningMessageButton = element(by.id('simulate-warning')); - var deleteMessageButton = element(by.id('simulate-error')); - - it('should fail on warning message', function() { - browser.get('console/index.html'); - warningMessageButton.click(); - }); - - it('should fail on error message', function() { - browser.get('console/index.html'); - deleteMessageButton.click(); - }); - - it('should not fail on log and debug messages', function() { - browser.get('console/index.html'); - logMessageButton.click(); - }); -}); diff --git a/plugins/console/spec/fail_warning_spec.js b/plugins/console/spec/fail_warning_spec.js deleted file mode 100644 index 11e2c3dce..000000000 --- a/plugins/console/spec/fail_warning_spec.js +++ /dev/null @@ -1,15 +0,0 @@ -describe('console plugin', function() { - - var logMessageButton = element(by.id('log-message')); - var warningMessageButton = element(by.id('simulate-warning')); - - it('should fail on warning message', function() { - browser.get('console/index.html'); - warningMessageButton.click(); - }); - - it('should not fail on log and debug messages', function() { - browser.get('console/index.html'); - logMessageButton.click(); - }); -}); diff --git a/plugins/console/spec/pass_spec.js b/plugins/console/spec/pass_spec.js deleted file mode 100644 index 6868e3b56..000000000 --- a/plugins/console/spec/pass_spec.js +++ /dev/null @@ -1,21 +0,0 @@ -describe('console plugin', function() { - - var logMessageButton = element(by.id('log-message')); - var warningMessageButton = element(by.id('simulate-warning')); - var deleteMessageButton = element(by.id('simulate-error')); - - it('should not fail on log and debug messages', function() { - browser.get('console/index.html'); - logMessageButton.click(); - }); - - it('should not fail on warning message', function() { - browser.get('console/index.html'); - warningMessageButton.click(); - }); - - it('should not fail on error message', function() { - browser.get('console/index.html'); - deleteMessageButton.click(); - }); -}); diff --git a/plugins/ngHint/index.js b/plugins/ngHint/index.js deleted file mode 100644 index 65451f6e6..000000000 --- a/plugins/ngHint/index.js +++ /dev/null @@ -1,199 +0,0 @@ -var q = require('q'), - fs = require('fs'), - _ = require('lodash'), - ngHintNames = { - ngHintControllers: 'Controllers', - ngHintDirectives: 'Directives', - ngHintDom: 'DOM', - ngHintEvents: 'Events', - ngHintInterpolation: 'Interpolation', - ngHintModules: 'Modules', - ngHintScopes: 'Scopes', - ngHintGeneral: 'General' - }; - -/** - * You enable this plugin in your config file: - * - * exports.config = { - * plugins: [{ - * path: 'node_modules/protractor/plugins/ngHint', - * - * asTests: {Boolean}, - * excludeURLs: {(String|RegExp)[]} - * }] - * }; - * - * asTests specifies if the plugin should generate passed/failed test results - * based on the ngHint output or instead log the results to the console. - * Defaults to true. - * - * excludeURLs specifies a list of URLs for which ngHint results should be - * ignored. Defaults to [] - */ - -/* - * The strategy for this plugin is as follows: - * - * During setup, install the ngHint code and listeners to capture its output. - * Store the output in the following format: - * {page URL} -> {module} -> {message} -> {message type} - * - * So, for instance, you might have: - * { - * 'google.com': { - * 'Controllers': { - * {'It is against Angular best practices to...': warning} - * }, - * 'Modules: { - * {'Module "Search" was loaded but does not exist': error} - * } - * } - * } - * - * We store the messages as keys in objects in order to avoid duplicates. - */ - -/** - * Configures the plugin to grab the output of ngHint - * - * @see docs/plugins.md - * @public - */ -function setup() { - // Intercept ngHint output - browser.addMockModule('protractorNgHintCaptureModule_', function() { - angular.module('protractorNgHintCaptureModule_', []); - var hintInstalled = true; - if (!angular.hint) { - hintInstalled = false; - angular.hint = {}; - } - /** override */ - angular.hint.onMessage = function(module, message, type) { - var ngHintLog = JSON.parse(localStorage.getItem( - 'ngHintLog_protractor') || '{}'); - var pageLog = ngHintLog[location] || {}; - var moduleLog = pageLog[module] || {}; - moduleLog[message] = type; - pageLog[module] = moduleLog; - ngHintLog[location] = pageLog; - localStorage.setItem('ngHintLog_protractor', - JSON.stringify(ngHintLog)); - }; - if (!hintInstalled) { - angular.hint.onMessage('General', 'ngHint plugin cannot be run as ' + - 'ngHint code was never included into the page', 'warning'); - } - }); -} - -/** - * Checks if a URL should not be examined by the ngHint plugin - * - * @param {String} url The URL to check for exclusion - * @param {Object} config The configuration file for the ngHint plugin - * @return {Boolean} true if the URL should not be examined by the ngHint plugin - * @private - */ -function isExcluded(url, config) { - var excludeURLs = config.excludeURLs || []; - for (var i = 0; i < excludeURLs.length; i++) { - if (typeof excludeURLs[i] == typeof '') { - if (url == excludeURLs[i]) { - return true; - } - } else { - if (excludeURLs[i].test(url)) { - return true; - } - } - } - return false; -} - -/** - * Checks if a warning message should be ignored by the ngHint plugin - * - * @param {String} message The message to check - * @return {Boolean} true if the message should be ignored - * @private - */ -function isMessageToIgnore(message) { - if (message == 'It is against Angular best practices to instantiate a ' + - 'controller on the window. This behavior is deprecated in Angular ' + - '1.3.0') { - return true; // An ngHint bug, see http://git.io/S3yySQ - } - - var module = /^Module "(\w*)" was created but never loaded\.$/.exec( - message); - if (module != null) { - module = module[1]; - if (ngHintNames[module] != null) { - return true; // An ngHint module - } - if ((module == 'protractorBaseModule_') || (module == - 'protractorNgHintCaptureModule_')) { - return true; // A protractor module - } - } - - return false; -} - -/** - * Checks the information which has been stored by the ngHint plugin and - * generates passed/failed tests and/or console output - * - * @see docs/plugins.md - * @return {q.Promise} A promise which resolves to the results of any passed or - * failed tests - * @public - */ -function teardown() { - var self = this; - // Get logged data - return browser.executeScript_(function() { - return localStorage.getItem('ngHintLog_protractor') || '{}'; - }, 'get ngHintLog').then(function(ngHintLog) { - ngHintLog = JSON.parse(ngHintLog); - - // Get a list of all the modules we tested against - var modulesUsed = _.union.apply(_, [_.values(ngHintNames)].concat( - _.values(ngHintLog).map(Object.keys))); - - // Check log - var testOut = {failedCount: 0, specResults: []}; - for (url in ngHintLog) { - if (!isExcluded(url, self.config)) { - for (var i = 0; i < modulesUsed.length; i++) { - var resultInfo = {specName: 'Angular Hint Test: ' + modulesUsed[i] + - ' (' + url + ')'}; - var passed = true; - - // Fill in the test details - var messages = ngHintLog[url][modulesUsed[i]]; - if (messages) { - for (var message in messages) { - if (!isMessageToIgnore(message)) { - (self.config.asTests !== false ? self.addFailure : - self.addWarning)(messages[message] + ' -- ' + message, - resultInfo); - passed = false; - } - } - } - - if (passed) { - self.addSuccess(resultInfo); - } - } - } - } - }); -} - -// Export -exports.setup = setup; -exports.teardown = teardown; diff --git a/plugins/ngHint/spec/fail_spec.js b/plugins/ngHint/spec/fail_spec.js deleted file mode 100644 index ca950c88d..000000000 --- a/plugins/ngHint/spec/fail_spec.js +++ /dev/null @@ -1,7 +0,0 @@ -describe('check if ngHint plugin works on bad apps', function() { - it('should have ngHint problems on bad apps', function() { - browser.get('ngHint/noNgHint.html'); - browser.get('ngHint/noTag.html'); - browser.get('ngHint/unused.html'); - }); -}); diff --git a/plugins/ngHint/spec/failureConfig.js b/plugins/ngHint/spec/failureConfig.js deleted file mode 100644 index dbe49f445..000000000 --- a/plugins/ngHint/spec/failureConfig.js +++ /dev/null @@ -1,11 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['fail_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js' - }] -}; diff --git a/plugins/ngHint/spec/successConfig.js b/plugins/ngHint/spec/successConfig.js deleted file mode 100644 index dfd6d9d93..000000000 --- a/plugins/ngHint/spec/successConfig.js +++ /dev/null @@ -1,11 +0,0 @@ -var env = require('../../../spec/environment.js'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - framework: 'jasmine', - specs: ['success_spec.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js' - }] -}; diff --git a/plugins/ngHint/spec/success_spec.js b/plugins/ngHint/spec/success_spec.js deleted file mode 100644 index 336bc1e8e..000000000 --- a/plugins/ngHint/spec/success_spec.js +++ /dev/null @@ -1,5 +0,0 @@ -describe('check if ngHint plugin works on good apps', function() { - it('should not have ngHint problems on a good app', function() { - browser.get('ngHint/index.html'); - }); -}); diff --git a/plugins/timeline/index.js b/plugins/timeline/index.js deleted file mode 100644 index d462f16a2..000000000 --- a/plugins/timeline/index.js +++ /dev/null @@ -1,340 +0,0 @@ -var q = require('q'), - fs = require('fs'), - path = require('path'), - SauceLabs = require('saucelabs'), - https = require('https'); - -var SAUCE_LOGS_WAIT = 5000; - -/** - * Outputs information about where your Protractor test is spending its time - * to the specified folder. A JSON data file and small index.html to view - * it will be created. The page uses Google Charts to show the timeline. - * - * You enable this plugin in your config file: - * - * exports.config = { - * plugins: [{ - * path: 'node_modules/protractor/plugins/timeline', - * - * // Output json and html will go in this folder. Relative - * // to current working directory of the process. - * // TODO - it would make more sense for this to be relative - * // to the config file - reconsider this setup - * outdir: 'timelines', - * - * // Optional - if sauceUser and sauceKey are specified, logs from - * // SauceLabs will also be parsed after test invocation. - * sauceUser: 'Jane', - * sauceKey: 'abcdefg' - * }] - * }; - * - * The plugin will create timeline entries from - * - The Protractor test process itself. - * - The WebDriver Selenium Server (these logs are unavailable for Internet - * Explorer and for Chrome test run over Sauce Labs). - * - Sauce Labs job logs, if sauceUser and sauceKey are specified. - * - * @constructor - */ -var TimelinePlugin = function() { - // Timelines are of the format: - // Array<{ - // source: string, - // id: number, - // command: string, - // start: number, - // end: number - // }> - this.timeline = []; - - this.clientLogAvailable = false; - this.outdir; - this.sessionId; - this.testProcessSetTimeoutTimestamp = 0; -}; - -/** - * Parse a selenium log in array form. For example, the logs returned - * from the selenium standalone server are returned as arrays. - * - * @param {Array} logArr The selenium server logs. - * @param {string} sourceName Descripton of source. - * @param {number} referenceStart Date in millis. - */ -TimelinePlugin.parseArrayLog = function(logArr, sourceName, referenceStart) { - return TimelinePlugin.parseLog(logArr, sourceName, { - isEventStart: function(event) { - return /Executing:/.test(event.message); - }, - isEventEnd: function(event) { - return /Done:/.test(event.message); - }, - extractCommand: function(event) { - // Messages from the Selenium Standalone server are of the form - // org...DriverServlet Executing: [command: details [params]] at URL /url/ - return /Executing: \[([^:^\]]*)/.exec(event.message)[1]; - }, - extractTimestamp: function(event) { - return event.timestamp; - } - }, referenceStart); -}; - -/** - * Parse a selenium log from a string. For example, the logs returned from - * Sauce Labs are available only as plain text. - * - * @param {string} text The text logs. - * @param {string} sourceName Descripton of source. - * @param {number} referenceStart Date in millis. - */ -TimelinePlugin.parseTextLog = function(text, sourceName, referenceStart) { - var logLines = text.split('\n'); - var actions; - - // Look for 'standalone server' in the first couple lines of the log. - if (/standalone server/.test(logLines.slice(0, 3).join(' '))) { - // This is a Selenium Standalone Server log. - actions = { - isEventStart: function(event) { - return /INFO - Executing:/.test(event); - }, - isEventEnd: function(event) { - return /INFO - Done:/.test(event); - }, - extractCommand: function(event) { - // Messages are of the form - // timestamp INFO - Executing: [command: details; [params]] - return /Executing: \[([^:^\]]*)/.exec(event)[1]; - }, - extractTimestamp: function(event) { - // Timestamps begin the line and are formatted as - // HH:MM:SS.SSS - // We don't care about the date so just set it to 0. - return Date.parse('01 Jan 1970 ' + event.slice(0, 12)); - } - }; - } else { - // This is a ChromeDriver log. - actions = { - isEventStart: function(event) { - return /: COMMAND/.test(event); - }, - isEventEnd: function(event) { - return /: RESPONSE/.test(event); - }, - extractCommand: function(event) { - return /: COMMAND ([^\s]*)/.exec(event)[1]; - }, - extractTimestamp: function(event) { - return parseFloat(/^\[?([^\]]*)/.exec(event)[1]) * 1000; - } - }; - } - - return TimelinePlugin.parseLog(logLines, sourceName, actions, referenceStart); -}; - - -/** - * Parse a selenium log. - * - * @param {Array} entries The list of entries. - * @param {string} sourceName Descripton of source. - * @param {isEventStart: function, - isEventEnd: function, - extractCommand: function, - extractTimestamp: function} actions Methods to interpret entries. - * @param {number} referenceStart Date in millis. - */ -TimelinePlugin.parseLog = - function(entries, sourceName, actions, referenceStart) { - var parsedTimeline = []; - var currentEvent = {}; - var index = 0; - var relativeStartTime = 0; - for (var j = 0; j < entries.length; ++j) { - var event = entries[j]; - if (actions.isEventStart(event)) { - currentEvent = { - source: sourceName, - id: index++, - command: actions.extractCommand(event), - start: actions.extractTimestamp(event) - }; - if (!relativeStartTime && - currentEvent.command.toString() == 'setScriptTimeout' || - currentEvent.command.toString() == 'set script timeout' || - // [sic], the timeoutt typo is present in the logs - currentEvent.command.toString() == 'set script timeoutt' || - currentEvent.command.toString() == 'SetScriptTimeout') { - relativeStartTime = currentEvent.start; - } - } else if (actions.isEventEnd(event)) { - currentEvent.end = actions.extractTimestamp(event); - currentEvent.duration = currentEvent.end - currentEvent.start; - parsedTimeline.push(currentEvent); - } - } - - // Make all the times relative to the first time log types is fetched. - for (var k = 0; k < parsedTimeline.length; ++k) { - parsedTimeline[k].start += (referenceStart - relativeStartTime); - parsedTimeline[k].end += (referenceStart - relativeStartTime); - } - - return parsedTimeline; -}; - -TimelinePlugin.prototype.outputResults = function(done) { - try { - fs.mkdirSync(this.outdir); - } catch (e) { - if (e.code != 'EEXIST') throw e; - } - var stream = fs.createReadStream( - path.join(__dirname, 'indextemplate.html')); - var outfile = path.join(this.outdir, 'timeline.json'); - fs.writeFileSync(outfile, JSON.stringify(this.timeline)); - stream.pipe(fs.createWriteStream(path.join(this.outdir, 'index.html'))); - stream.on('end', done); -}; - -/** - * @see docs/plugins.md - */ -TimelinePlugin.prototype.setup = function() { - var self = this; - var deferred = q.defer(); - self.outdir = path.resolve(process.cwd(), this.config.outdir); - var counter = 0; - - // Override executor so that we get information about commands starting - // and stopping. - var originalExecute = browser.driver.executor_.execute; - browser.driver.executor_.execute = function(command, callback) { - var timelineEvent = { - source: 'Test Process', - id: counter++, - command: command, - start: new Date().getTime(), - end: null - }; - if (!self.testProcessSetTimeoutTimestamp && - timelineEvent.command.name_ == 'setScriptTimeout') { - self.testProcessSetTimeoutTimestamp = timelineEvent.start; - } - self.timeline.push(timelineEvent); - var wrappedCallback = function(var_args) { - timelineEvent.end = new Date().getTime(); - callback.apply(this, arguments); - }; - originalExecute.apply(browser.driver.executor_, [command, wrappedCallback]); - }; - - // Clear the logs here. - browser.manage().logs().getAvailableLogTypes().then(function(result) { - // The Selenium standalone server stores its logs in the 'client' channel. - if (result.indexOf('client') !== -1) { - self.clientLogAvailable = true; - deferred.resolve(); - // browser.manage().logs().get('client').then(function() { - // deferred.resolve(); - // }); - } else { - deferred.resolve(); - } - }, function(error) { - // No logs are available - this will happen for Internet Explorer, which - // does not implement webdriver logs. See - // https://code.google.com/p/selenium/issues/detail?id=4925 - deferred.resolve(); - }); - return deferred.promise; -}; - -/** - * @see docs/plugins.md - */ -TimelinePlugin.prototype.teardown = function() { - var self = this; - var deferred = q.defer(); - // This will be needed later for grabbing data from Sauce Labs. - browser.getSession().then(function(session) { - self.sessionId = session.getId(); - }); - - // If running with a Selenium Standalone server, get the client logs. - if (self.clientLogAvailable) { - browser.manage().logs().get('client').then(function(result) { - var serverTimeline = TimelinePlugin.parseArrayLog( - result, 'Selenium Client', self.testProcessSetTimeoutTimestamp); - self.timeline = self.timeline.concat(serverTimeline); - deferred.resolve(); - }); - } else { - deferred.resolve(); - } - return deferred.promise; -}; - -/** - * @see docs/plugins.md - */ -TimelinePlugin.prototype.postResults = function() { - var self = this; - var deferred = q.defer(); - // We can't get Chrome or IE logs from Sauce Labs via the webdriver logs API - // because it does not expose them. - // TODO - if the feature request at - // https://support.saucelabs.com/entries/60070884-Enable-grabbing-server-logs-from-the-wire-protocol - // gets implemented, remove this hack. - if (this.config.sauceUser && this.config.sauceKey) { - // WARNING, HACK: we have a timeout to deal with the fact that there's a - // delay before Sauce Labs updates logs. - setTimeout(function() { - var sauceServer = new SauceLabs({ - username: this.config.sauceUser, - password: this.config.sauceKey - }); - - sauceServer.showJob(self.sessionId, function(err, job) { - var sauceLog = ''; - if (!job.log_url) { - console.log('WARNING - no Sauce Labs log url found'); - deferred.resolve(); - return; - } - https.get(job.log_url, function(res) { - res.on('data', function(data) { - sauceLog += data; - }); - - res.on('end', function() { - var sauceTimeline = - TimelinePlugin.parseTextLog( - sauceLog, - 'SauceLabs Server', - self.testProcessSetTimeoutTimestamp); - self.timeline = self.timeline.concat(sauceTimeline); - self.outputResults(deferred.resolve); - }); - - }).on('error', function(e) { - console.error(e); - }); - }); - }, SAUCE_LOGS_WAIT); - } else { - self.outputResults(deferred.resolve); - } - return deferred.promise; -}; - - -// Export - -module.exports = new TimelinePlugin(); -module.exports.TimelinePlugin = TimelinePlugin; diff --git a/plugins/timeline/indextemplate.html b/plugins/timeline/indextemplate.html deleted file mode 100644 index 76b23b44e..000000000 --- a/plugins/timeline/indextemplate.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - -
- - \ No newline at end of file diff --git a/plugins/timeline/spec/chromelog.txt b/plugins/timeline/spec/chromelog.txt deleted file mode 100644 index 5b28ca2e4..000000000 --- a/plugins/timeline/spec/chromelog.txt +++ /dev/null @@ -1,284 +0,0 @@ -[2.465][INFO]: COMMAND InitSession { - "desiredCapabilities": { - "browserName": "chrome", - "chromeOptions": { - "args": [ "start-maximized", "disable-webgl", "blacklist-webgl", "blacklist-accelerated-compositing", "disable-accelerated-2d-canvas", "disable-accelerated-compositing", "disable-accelerated-layers", "disable-accelerated-plugins", "disable-accelerated-video", "disable-accelerated-video-decode", "disable-gpu", "test-type", "disable-threaded-compositing" ], - "binary": "/Volumes/Sauce/Chrome/Chrome 35.app/Contents/MacOS/Google Chrome" - }, - "count": 1, - "debuggerAddress": "127.0.0.1:9222", - "proxy": { - "proxyAutoconfigUrl": "http://127.0.0.1:19876/proxy.pac", - "proxyType": "PAC" - }, - "webdriver.remote.quietExceptions": true - } -} -[2.466][INFO]: Populating Preferences file: { - "alternate_error_pages": { - "enabled": false - }, - "autofill": { - "enabled": false - }, - "browser": { - "check_default_browser": false - }, - "distribution": { - "import_bookmarks": false, - "import_history": false, - "import_search_engine": false, - "make_chrome_default_for_user": false, - "show_welcome_page": false, - "skip_first_run_ui": true - }, - "dns_prefetching": { - "enabled": false - }, - "profile": { - "content_settings": { - "pattern_pairs": { - "https://*,*": { - "media-stream": { - "audio": "Default", - "video": "Default" - } - } - } - }, - "default_content_settings": { - "geolocation": 1, - "mouselock": 1, - "notifications": 1, - "popups": 1, - "ppapi-broker": 1 - }, - "password_manager_enabled": false - }, - "safebrowsing": { - "enabled": false - }, - "search": { - "suggest_enabled": false - }, - "translate": { - "enabled": false - } -} -[2.467][INFO]: Populating Local State file: { - "background_mode": { - "enabled": false - }, - "ssl": { - "rev_checking": { - "enabled": false - } - } -} -[2.469][INFO]: Launching chrome: /Volumes/Sauce/Chrome/Chrome 35.app/Contents/MacOS/Google Chrome --blacklist-accelerated-compositing --blacklist-webgl --disable-accelerated-2d-canvas --disable-accelerated-compositing --disable-accelerated-layers --disable-accelerated-plugins --disable-accelerated-video --disable-accelerated-video-decode --disable-background-networking --disable-client-side-phishing-detection --disable-component-update --disable-default-apps --disable-gpu --disable-hang-monitor --disable-prompt-on-repost --disable-sync --disable-threaded-compositing --disable-web-resources --disable-webgl --enable-logging --ignore-certificate-errors --load-extension=/var/folders/bl/1800rz_j7blcqx8pthyrq59h0000gn/T/.org.chromium.Chromium.BZB35o/internal --logging-level=1 --metrics-recording-only --no-first-run --password-store=basic --proxy-pac-url=http://127.0.0.1:19876/proxy.pac --remote-debugging-port=12382 --safebrowsing-disable-auto-update --safebrowsing-disable-download-protection --start-maximized --test-type --use-mock-keychain --user-data-dir=/var/folders/bl/1800rz_j7blcqx8pthyrq59h0000gn/T/.org.chromium.Chromium.E1jTrM data:, -[4.246][INFO]: RESPONSE InitSession { - "acceptSslCerts": true, - "applicationCacheEnabled": false, - "browserConnectionEnabled": false, - "browserName": "chrome", - "chrome": { - "userDataDir": "/var/folders/bl/1800rz_j7blcqx8pthyrq59h0000gn/T/.org.chromium.Chromium.E1jTrM" - }, - "cssSelectorsEnabled": true, - "databaseEnabled": false, - "handlesAlerts": true, - "javascriptEnabled": true, - "locationContextEnabled": true, - "nativeEvents": true, - "platform": "Mac OS X", - "rotatable": false, - "takesHeapSnapshot": true, - "takesScreenshot": true, - "version": "35.0.1916.114", - "webStorageEnabled": true -} -[4.512][INFO]: COMMAND ExecuteScript { - "args": [ ], - "script": "return screen.width" -} -[4.746][INFO]: Waiting for pending navigations... -[4.763][INFO]: Done waiting for pending navigations -[4.812][INFO]: Waiting for pending navigations... -[4.812][INFO]: Done waiting for pending navigations -[4.812][INFO]: RESPONSE ExecuteScript 1280 -[4.815][INFO]: COMMAND ExecuteScript { - "args": [ ], - "script": "return screen.height" -} -[4.815][INFO]: Waiting for pending navigations... -[4.815][INFO]: Done waiting for pending navigations -[4.824][INFO]: Waiting for pending navigations... -[4.824][INFO]: Done waiting for pending navigations -[4.824][INFO]: RESPONSE ExecuteScript 800 -[4.827][INFO]: COMMAND SetWindowPosition { - "windowHandle": "current", - "x": 0, - "y": 0 -} -[4.832][INFO]: Waiting for pending navigations... -[4.843][INFO]: Done waiting for pending navigations -[5.001][INFO]: RESPONSE SetWindowPosition -[5.003][INFO]: COMMAND SetWindowSize { - "height": 800, - "width": 1280, - "windowHandle": "current" -} -[5.198][INFO]: RESPONSE SetWindowSize -[5.201][INFO]: COMMAND MaximizeWindow { - "windowHandle": "current" -} -[5.307][INFO]: RESPONSE MaximizeWindow -[5.310][INFO]: COMMAND GetWindows { - -} -[5.311][INFO]: RESPONSE GetWindows [ "CDwindow-64D838A1-3314-CD60-A5AB-D64369F3D241" ] -[5.397][INFO]: COMMAND SetScriptTimeout { - "ms": 11000 -} -[5.397][INFO]: RESPONSE SetScriptTimeout -[5.456][INFO]: COMMAND GetLogTypes { - -} -[5.456][INFO]: RESPONSE GetLogTypes [ "browser", "driver" ] -[5.598][INFO]: COMMAND Navigate { - "url": "data:text/html,\u003Chtml>\u003C/html>" -} -[5.598][INFO]: Waiting for pending navigations... -[5.598][INFO]: Done waiting for pending navigations -[5.667][INFO]: Waiting for pending navigations... -[5.667][INFO]: Done waiting for pending navigations -[5.667][INFO]: RESPONSE Navigate -[5.850][INFO]: COMMAND ExecuteScript { - "args": [ ], - "script": "window.name = \"NG_DEFER_BOOTSTRAP!\" + window.name;window.location.replace(\"http://localhost:8081/index.html#/async\");" -} -[5.850][INFO]: Waiting for pending navigations... -[5.850][INFO]: Done waiting for pending navigations -[5.859][INFO]: Waiting for pending navigations... -[6.112][INFO]: Done waiting for pending navigations -[6.112][INFO]: RESPONSE ExecuteScript null -[6.293][INFO]: COMMAND ExecuteScript { - "args": [ ], - "script": "return window.location.href;" -} -[6.293][INFO]: Waiting for pending navigations... -[6.293][INFO]: Done waiting for pending navigations -[6.296][INFO]: Waiting for pending navigations... -[6.296][INFO]: Done waiting for pending navigations -[6.296][INFO]: RESPONSE ExecuteScript "http://localhost:8081/index.html#/async" -[6.474][INFO]: COMMAND ExecuteAsyncScript { - "args": [ 10 ], - "script": "try { return (function (attempts, asyncCallback) {\n var callback = function(args) {\n setTimeout(function() {\n asyncCallback(args);\n }, 0);\n };\n var check = function(n) {\n try {\n ..." -} -[6.474][INFO]: Waiting for pending navigations... -[6.474][INFO]: Done waiting for pending navigations -[6.585][INFO]: Waiting for pending navigations... -[6.585][INFO]: Done waiting for pending navigations -[6.585][INFO]: RESPONSE ExecuteAsyncScript [ true, null ] -[6.658][INFO]: COMMAND ExecuteScript { - "args": [ ], - "script": "return (function () {\n angular.module('protractorBaseModule_', []).\n config(['$compileProvider', function($compileProvider) {\n if ($compileProvider.debugInfoEnabled) {\n ..." -} -[6.658][INFO]: Waiting for pending navigations... -[6.658][INFO]: Done waiting for pending navigations -[6.660][INFO]: Waiting for pending navigations... -[6.660][INFO]: Done waiting for pending navigations -[6.661][INFO]: RESPONSE ExecuteScript null -[6.824][INFO]: COMMAND ExecuteScript { - "args": [ [ "protractorBaseModule_" ] ], - "script": "angular.resumeBootstrap(arguments[0]);" -} -[6.824][INFO]: Waiting for pending navigations... -[6.824][INFO]: Done waiting for pending navigations -[6.868][INFO]: Waiting for pending navigations... -[6.868][INFO]: Done waiting for pending navigations -[6.868][INFO]: RESPONSE ExecuteScript null -[7.103][INFO]: COMMAND ExecuteAsyncScript { - "args": [ "body" ], - "script": "try { return (function (rootSelector, callback) {\n var el = document.querySelector(rootSelector);\n\n try {\n if (!window.angular) {\n throw new Error('angular could not be found on the windo..." -} -[7.103][INFO]: Waiting for pending navigations... -[7.103][INFO]: Done waiting for pending navigations -[7.312][INFO]: Waiting for pending navigations... -[7.312][INFO]: Done waiting for pending navigations -[7.312][INFO]: RESPONSE ExecuteAsyncScript null -[7.402][INFO]: COMMAND ExecuteScript { - "args": [ "slowHttpStatus", false, null, "body" ], - "script": "try { return (function (binding, exactMatch, using, rootSelector) {\n var root = document.querySelector(rootSelector || 'body');\n using = using || document;\n if (angular.getTestability) {\n ret..." -} -[7.402][INFO]: Waiting for pending navigations... -[7.402][INFO]: Done waiting for pending navigations -[7.405][INFO]: Waiting for pending navigations... -[7.405][INFO]: Done waiting for pending navigations -[7.405][INFO]: RESPONSE ExecuteScript [ { - "ELEMENT": "0.5319263362325728-1" -} ] -[7.610][INFO]: COMMAND GetElementText { - "id": "0.5319263362325728-1" -} -[7.610][INFO]: Waiting for pending navigations... -[7.610][INFO]: Done waiting for pending navigations -[7.626][INFO]: Waiting for pending navigations... -[7.626][INFO]: Done waiting for pending navigations -[7.626][INFO]: RESPONSE GetElementText "not started" -[7.731][INFO]: COMMAND ExecuteAsyncScript { - "args": [ "body" ], - "script": "try { return (function (rootSelector, callback) {\n var el = document.querySelector(rootSelector);\n\n try {\n if (!window.angular) {\n throw new Error('angular could not be found on the windo..." -} -[7.731][INFO]: Waiting for pending navigations... -[7.731][INFO]: Done waiting for pending navigations -[7.734][INFO]: Waiting for pending navigations... -[7.734][INFO]: Done waiting for pending navigations -[7.734][INFO]: RESPONSE ExecuteAsyncScript null -[7.793][INFO]: COMMAND FindElements { - "using": "css selector", - "value": "[ng-click=\"slowHttp()\"]" -} -[7.793][INFO]: Waiting for pending navigations... -[7.793][INFO]: Done waiting for pending navigations -[7.805][INFO]: Waiting for pending navigations... -[7.805][INFO]: Done waiting for pending navigations -[7.805][INFO]: RESPONSE FindElements [ { - "ELEMENT": "0.5319263362325728-2" -} ] -[7.888][INFO]: COMMAND ClickElement { - "id": "0.5319263362325728-2" -} -[7.888][INFO]: Waiting for pending navigations... -[7.888][INFO]: Done waiting for pending navigations -[7.932][INFO]: Waiting for pending navigations... -[7.932][INFO]: Done waiting for pending navigations -[7.932][INFO]: RESPONSE ClickElement -[8.138][INFO]: COMMAND ExecuteAsyncScript { - "args": [ "body" ], - "script": "try { return (function (rootSelector, callback) {\n var el = document.querySelector(rootSelector);\n\n try {\n if (!window.angular) {\n throw new Error('angular could not be found on the windo..." -} -[8.138][INFO]: Waiting for pending navigations... -[8.138][INFO]: Done waiting for pending navigations -[13.026][INFO]: Waiting for pending navigations... -[13.026][INFO]: Done waiting for pending navigations -[13.026][INFO]: RESPONSE ExecuteAsyncScript null -[13.100][INFO]: COMMAND ExecuteScript { - "args": [ "slowHttpStatus", false, null, "body" ], - "script": "try { return (function (binding, exactMatch, using, rootSelector) {\n var root = document.querySelector(rootSelector || 'body');\n using = using || document;\n if (angular.getTestability) {\n ret..." -} -[13.100][INFO]: Waiting for pending navigations... -[13.100][INFO]: Done waiting for pending navigations -[13.102][INFO]: Waiting for pending navigations... -[13.102][INFO]: Done waiting for pending navigations -[13.102][INFO]: RESPONSE ExecuteScript [ { - "ELEMENT": "0.5319263362325728-1" -} ] -[13.296][INFO]: COMMAND GetElementText { - "id": "0.5319263362325728-1" -} -[13.296][INFO]: Waiting for pending navigations... -[13.296][INFO]: Done waiting for pending navigations -[13.301][INFO]: Waiting for pending navigations... -[13.301][INFO]: Done waiting for pending navigations -[13.301][INFO]: RESPONSE GetElementText "done" \ No newline at end of file diff --git a/plugins/timeline/spec/conf.js b/plugins/timeline/spec/conf.js deleted file mode 100644 index c34cee8c2..000000000 --- a/plugins/timeline/spec/conf.js +++ /dev/null @@ -1,12 +0,0 @@ -var env = require('../../../spec/environment.js'); -var os = require('os'); - -exports.config = { - seleniumAddress: env.seleniumAddress, - specs: ['e2e.js'], - baseUrl: env.baseUrl, - plugins: [{ - path: '../index.js', - outdir: os.tmpdir() - }] -}; diff --git a/plugins/timeline/spec/e2e.js b/plugins/timeline/spec/e2e.js deleted file mode 100644 index 2a61b1748..000000000 --- a/plugins/timeline/spec/e2e.js +++ /dev/null @@ -1,14 +0,0 @@ -describe('timeline plugin', function() { - it('should do a couple basic commands', function() { - var usernameInput = element(by.model('username')); - var name = element(by.binding('username')); - - browser.get('index.html#/form'); - - expect(name.getText()).toEqual('Anon'); - - usernameInput.clear(); - usernameInput.sendKeys('Jane'); - expect(name.getText()).toEqual('Jane'); - }); -}); diff --git a/plugins/timeline/spec/standalonelog.txt b/plugins/timeline/spec/standalonelog.txt deleted file mode 100644 index 9ceaaad13..000000000 --- a/plugins/timeline/spec/standalonelog.txt +++ /dev/null @@ -1,261 +0,0 @@ -Dec 23, 2014 7:59:17 PM org.openqa.grid.selenium.GridLauncher main -INFO: Launching a standalone server -Setting system property webdriver.ie.driver to D:\selenium\IEDriverServer.exe -Setting system property webdriver.ie.driver.logfile to c:\log\iedriver.log -Setting system property webdriver.ie.driver.loglevel to DEBUG -Setting system property http.proxyHost to maki77193.miso -Setting system property http.proxyPort to 33128 -Setting system property http.nonProxyHosts to "localhost|127.0.0.1" -Setting system property https.proxyHost to maki77193.miso -Setting system property https.proxyPort to 33128 -Setting system property https.nonProxyHosts to "localhost|127.0.0.1" -19:59:17.466 INFO - Java: Oracle Corporation 24.60-b09 -19:59:17.472 INFO - OS: Windows Server 2008 R2 6.1 x86 -19:59:17.504 INFO - v2.40.0, with Core v2.40.0. Built from revision fbe29a9 -19:59:18.069 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4443/wd/hub -19:59:18.075 INFO - Version Jetty/5.1.x -19:59:18.079 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver] -19:59:18.080 INFO - Started HttpContext[/selenium-server,/selenium-server] -19:59:18.080 INFO - Started HttpContext[/,/] -19:59:18.210 INFO - Started org.openqa.jetty.jetty.servlet.ServletHandler@149959a -19:59:18.210 INFO - Started HttpContext[/wd,/wd] -19:59:18.220 INFO - Started SocketListener on 0.0.0.0:4443 -19:59:18.220 INFO - Started org.openqa.jetty.jetty.Server@150f0a7 -19:59:20.171 INFO - Executing: [new session: Capabilities [{count=1, browserName=internet explorer, webdriver.remote.quietExceptions=true}]] at URL: /session) -19:59:20.216 INFO - Creating a new session for Capabilities [{count=1, browserName=internet explorer, webdriver.remote.quietExceptions=true}] -Started InternetExplorerDriver server (32-bit) -2.42.0.0 -Listening on port 28134 -Log level is set to DEBUG -Log file is set to c:\log\iedriver.log -19:59:23.420 INFO - I/O exception (java.net.SocketException) caught when processing request: Software caused connection abort: recv failed -19:59:23.420 INFO - Retrying request -19:59:23.595 INFO - Done: /session -19:59:23.768 INFO - Executing: [execute script: return screen.width, []] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:23.855 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:23.863 INFO - Executing: [execute script: return screen.height, []] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:23.907 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:23.913 INFO - Executing: [set window position] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window/current/position) -19:59:23.940 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window/current/position -19:59:23.949 INFO - Executing: [set window size] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window/current/size) -19:59:23.999 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window/current/size -19:59:24.006 INFO - Executing: [maximise window] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window/current/maximize) -19:59:24.049 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window/current/maximize -19:59:24.056 INFO - Executing: [get window handles] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window_handles) -19:59:24.060 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/window_handles -19:59:24.163 INFO - Executing: [set script timeoutt: 11000] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/timeouts/async_script) -19:59:24.209 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/timeouts/async_script -19:59:24.326 INFO - Executing: [fetching available log types] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/log/types) -19:59:24.345 WARN - Exception thrown -org.openqa.selenium.WebDriverException: Command not found: GET /session/6944190b-14c8-4d68-9822-85718b9425ea/log/types -Command duration or timeout: 6 milliseconds -Build info: version: '2.40.0', revision: 'fbe29a9', time: '2014-02-19 20:54:28' -System info: host: 'WIN-8LIIH1BGM1D', ip: '172.20.33.134', os.name: 'Windows Server 2008 R2', os.arch: 'x86', os.version: '6.1', java.version: '1.7.0_60' -Session ID: 6944190b-14c8-4d68-9822-85718b9425ea -Driver info: org.openqa.selenium.ie.InternetExplorerDriver -Capabilities [{platform=WINDOWS, javascriptEnabled=true, elementScrollBehavior=0, ignoreZoomSetting=false, enablePersistentHover=true, ie.ensureCleanSession=false, browserName=internet explorer, enableElementCacheCleanup=true, unexpectedAlertBehaviour=dismiss, version=11, ie.usePerProcessProxy=false, cssSelectorsEnabled=true, ignoreProtectedModeSettings=false, requireWindowFocus=false, handlesAlerts=true, initialBrowserUrl=http://localhost:28134/, ie.forceCreateProcessApi=false, nativeEvents=true, browserAttachTimeout=0, ie.browserCommandLineSwitches=, takesScreenshot=true}] - at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) - at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) - at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) - at java.lang.reflect.Constructor.newInstance(Unknown Source) - at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:193) - at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:145) - at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:573) - at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:588) - at org.openqa.selenium.remote.RemoteExecuteMethod.execute(RemoteExecuteMethod.java:32) - at org.openqa.selenium.remote.RemoteLogs.getAvailableLogTypes(RemoteLogs.java:87) - at org.openqa.selenium.remote.server.handler.GetAvailableLogTypesHandler.call(GetAvailableLogTypesHandler.java:35) - at org.openqa.selenium.remote.server.handler.GetAvailableLogTypesHandler.call(GetAvailableLogTypesHandler.java:1) - at java.util.concurrent.FutureTask.run(Unknown Source) - at org.openqa.selenium.remote.server.DefaultSession$1.run(DefaultSession.java:170) - at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) - at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) - at java.lang.Thread.run(Unknown Source) -19:59:24.354 WARN - Exception: Command not found: GET /session/6944190b-14c8-4d68-9822-85718b9425ea/log/types -Command duration or timeout: 6 milliseconds -Build info: version: '2.40.0', revision: 'fbe29a9', time: '2014-02-19 20:54:28' -System info: host: 'WIN-8LIIH1BGM1D', ip: '172.20.33.134', os.name: 'Windows Server 2008 R2', os.arch: 'x86', os.version: '6.1', java.version: '1.7.0_60' -Session ID: 6944190b-14c8-4d68-9822-85718b9425ea -Driver info: org.openqa.selenium.ie.InternetExplorerDriver -Capabilities [{platform=WINDOWS, javascriptEnabled=true, elementScrollBehavior=0, ignoreZoomSetting=false, enablePersistentHover=true, ie.ensureCleanSession=false, browserName=internet explorer, enableElementCacheCleanup=true, unexpectedAlertBehaviour=dismiss, version=11, ie.usePerProcessProxy=false, cssSelectorsEnabled=true, ignoreProtectedModeSettings=false, requireWindowFocus=false, handlesAlerts=true, initialBrowserUrl=http://localhost:28134/, ie.forceCreateProcessApi=false, nativeEvents=true, browserAttachTimeout=0, ie.browserCommandLineSwitches=, takesScreenshot=true}] -19:59:24.599 INFO - Executing: [get: about:blank] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/url) -19:59:24.832 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/url -19:59:25.027 INFO - Executing: [execute script: window.name = "NG_DEFER_BOOTSTRAP!" + window.name;window.location.replace("http://localhost:8081/index.html#/async");, []] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:25.073 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:25.288 INFO - Executing: [execute script: return window.location.href;, []] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:25.327 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:25.541 INFO - Executing: [execute async script: try { return (function (attempts, asyncCallback) { - var callback = function(args) { - setTimeout(function() { - asyncCallback(args); - }, 0); - }; - var check = function(n) { - try { - if (window.angular && window.angular.resumeBootstrap) { - callback([true, null]); - } else if (n < 1) { - if (window.angular) { - callback([false, 'angular never provided resumeBootstrap']); - } else { - callback([false, 'retries looking for angular exceeded']); - } - } else { - window.setTimeout(function() {check(n - 1);}, 1000); - } - } catch (e) { - callback([false, e]); - } - }; - check(attempts); -}).apply(this, arguments); } -catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async) -19:59:25.613 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async -19:59:25.717 INFO - Executing: [execute script: return (function () { - angular.module('protractorBaseModule_', []). - config(['$compileProvider', function($compileProvider) { - if ($compileProvider.debugInfoEnabled) { - $compileProvider.debugInfoEnabled(true); - } - }]); - }).apply(null, arguments);, []] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:25.751 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:25.954 INFO - Executing: [execute script: angular.resumeBootstrap(arguments[0]);, [[protractorBaseModule_]]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:26.064 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:26.560 INFO - Executing: [execute async script: try { return (function (rootSelector, callback) { - var el = document.querySelector(rootSelector); - - try { - if (!window.angular) { - throw new Error('angular could not be found on the window'); - } - if (angular.getTestability) { - angular.getTestability(el).whenStable(callback); - } else { - if (!angular.element(el).injector()) { - throw new Error('root element (' + rootSelector + ') has no injector.' + - ' this may mean it is not inside ng-app.'); - } - angular.element(el).injector().get('$browser'). - notifyWhenNoOutstandingRequests(callback); - } - } catch (err) { - callback(err.message); - } -}).apply(this, arguments); } -catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async) -19:59:26.614 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async -19:59:26.734 INFO - Executing: [execute script: try { return (function (binding, exactMatch, using, rootSelector) { - var root = document.querySelector(rootSelector || 'body'); - using = using || document; - if (angular.getTestability) { - return angular.getTestability(root). - findBindings(using, binding, exactMatch); - } - var bindings = using.getElementsByClassName('ng-binding'); - var matches = []; - for (var i = 0; i < bindings.length; ++i) { - var dataBinding = angular.element(bindings[i]).data('$binding'); - if(dataBinding) { - var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding; - if (exactMatch) { - var matcher = new RegExp('({|\\s|^|\\|)' + binding + '(}|\\s|$|\\|)'); - if (matcher.test(bindingName)) { - matches.push(bindings[i]); - } - } else { - if (bindingName.indexOf(binding) != -1) { - matches.push(bindings[i]); - } - } - - } - } - return matches; /* Return the whole array for webdriver.findElements. */ -}).apply(this, arguments); } -catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [slowHttpStatus, false, null, body]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:26.780 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:26.987 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@55c8cc3e -> unknown locator]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/element/0/text) -19:59:27.047 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/element/0/text -19:59:27.207 INFO - Executing: [execute async script: try { return (function (rootSelector, callback) { - var el = document.querySelector(rootSelector); - - try { - if (!window.angular) { - throw new Error('angular could not be found on the window'); - } - if (angular.getTestability) { - angular.getTestability(el).whenStable(callback); - } else { - if (!angular.element(el).injector()) { - throw new Error('root element (' + rootSelector + ') has no injector.' + - ' this may mean it is not inside ng-app.'); - } - angular.element(el).injector().get('$browser'). - notifyWhenNoOutstandingRequests(callback); - } - } catch (err) { - callback(err.message); - } -}).apply(this, arguments); } -catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async) -19:59:27.263 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async -19:59:27.382 INFO - Executing: [find elements: By.selector: [ng-click="slowHttp()"]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/elements) -19:59:27.475 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/elements -19:59:27.588 INFO - Executing: [click: 1 [[InternetExplorerDriver: internet explorer on WINDOWS (6944190b-14c8-4d68-9822-85718b9425ea)] -> css selector: [ng-click="slowHttp()"]]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/element/1/click) -19:59:27.842 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/element/1/click -19:59:28.110 INFO - Executing: [execute async script: try { return (function (rootSelector, callback) { - var el = document.querySelector(rootSelector); - - try { - if (!window.angular) { - throw new Error('angular could not be found on the window'); - } - if (angular.getTestability) { - angular.getTestability(el).whenStable(callback); - } else { - if (!angular.element(el).injector()) { - throw new Error('root element (' + rootSelector + ') has no injector.' + - ' this may mean it is not inside ng-app.'); - } - angular.element(el).injector().get('$browser'). - notifyWhenNoOutstandingRequests(callback); - } - } catch (err) { - callback(err.message); - } -}).apply(this, arguments); } -catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async) -19:59:32.842 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute_async -19:59:32.997 INFO - Executing: [execute script: try { return (function (binding, exactMatch, using, rootSelector) { - var root = document.querySelector(rootSelector || 'body'); - using = using || document; - if (angular.getTestability) { - return angular.getTestability(root). - findBindings(using, binding, exactMatch); - } - var bindings = using.getElementsByClassName('ng-binding'); - var matches = []; - for (var i = 0; i < bindings.length; ++i) { - var dataBinding = angular.element(bindings[i]).data('$binding'); - if(dataBinding) { - var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding; - if (exactMatch) { - var matcher = new RegExp('({|\\s|^|\\|)' + binding + '(}|\\s|$|\\|)'); - if (matcher.test(bindingName)) { - matches.push(bindings[i]); - } - } else { - if (bindingName.indexOf(binding) != -1) { - matches.push(bindings[i]); - } - } - - } - } - return matches; /* Return the whole array for webdriver.findElements. */ -}).apply(this, arguments); } -catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [slowHttpStatus, false, null, body]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute) -19:59:33.035 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/execute -19:59:33.265 INFO - Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@55c8cc3e -> unknown locator]] at URL: /session/c163949d-96b2-44e0-9d06-653a863a4a90/element/0/text) -19:59:33.354 INFO - Done: /session/c163949d-96b2-44e0-9d06-653a863a4a90/element/0/text \ No newline at end of file diff --git a/plugins/timeline/spec/unit.js b/plugins/timeline/spec/unit.js deleted file mode 100644 index d1d42f8fc..000000000 --- a/plugins/timeline/spec/unit.js +++ /dev/null @@ -1,124 +0,0 @@ -var fs = require('fs'); -var path = require('path'); -var TimelinePlugin = require('../index.js').TimelinePlugin; - -describe('timeline plugin', function() { - it('should parse an example selenium standalone log', function() { - var timeline = TimelinePlugin.parseTextLog( - fs.readFileSync(path.join(__dirname, 'standalonelog.txt')).toString()); - - expect(timeline.length).toEqual(23); - expect(timeline[0].command).toEqual('new session'); - expect(timeline[0].duration).toEqual(3424); - }); - - it('should parse an example chromedriver log', function() { - var timeline = TimelinePlugin.parseTextLog( - fs.readFileSync(path.join(__dirname, 'chromelog.txt')).toString()); - - expect(timeline.length).toEqual(24); - expect(timeline[0].command).toEqual('InitSession'); - expect(timeline[0].duration).toEqual(1781); - }); - - it('should parse example selenium client logs', function() { - var clientLog = [{ - level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Executing: [click: 1 [[SafariDriver: safari on MAC (null)] -> css selector: [ng-click="slowHttp()"]]] at URL: /session/b057191b-6328-4c7b-bdd2-170ba79280af/element/1/click)', - timestamp: 1419031697443, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Done: /session/b057191b-6328-4c7b-bdd2-170ba79280af/element/1/click', - timestamp: 1419031697470, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Executing: [execute async script: try { return (function (rootSelector, callback) {\n var el = document.querySelector(rootSelector);\n\n try {\n if (!window.angular) {\n throw new Error(\'angular could not be found on the window\');\n }\n if (angular.getTestability) {\n angular.getTestability(el).whenStable(callback);\n } else {\n if (!angular.element(el).injector()) {\n throw new Error(\'root element (\' + rootSelector + \') has no injector.\' +\n \' this may mean it is not inside ng-app.\');\n }\n angular.element(el).injector().get(\'$browser\').\n notifyWhenNoOutstandingRequests(callback);\n }\n } catch (err) {\n callback(err.message);\n }\n}).apply(this, arguments); }\ncatch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]] at URL: /session/b057191b-6328-4c7b-bdd2-170ba79280af/execute_async)', - timestamp: 1419031697672, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Done: /session/b057191b-6328-4c7b-bdd2-170ba79280af/execute_async', - timestamp: 1419031702495, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Executing: [execute script: try { return (function (binding, exactMatch, using, rootSelector) {\n var root = document.querySelector(rootSelector || \'body\');\n using = using || document;\n if (angular.getTestability) {\n return angular.getTestability(root).\n findBindings(using, binding, exactMatch);\n }\n var bindings = using.getElementsByClassName(\'ng-binding\');\n var matches = [];\n for (var i = 0; i < bindings.length; ++i) {\n var dataBinding = angular.element(bindings[i]).data(\'$binding\');\n if(dataBinding) {\n var bindingName = dataBinding.exp || dataBinding[0].exp || dataBinding;\n if (exactMatch) {\n var matcher = new RegExp(\'({|\\\\s|^|\\\\|)\' + binding + \'(}|\\\\s|$|\\\\|)\');\n if (matcher.test(bindingName)) {\n matches.push(bindings[i]);\n }\n } else {\n if (bindingName.indexOf(binding) != -1) {\n matches.push(bindings[i]);\n }\n }\n \n }\n }\n return matches; /* Return the whole array for webdriver.findElements. */\n}).apply(this, arguments); }\ncatch(e) { throw (e instanceof Error) ? e : new Error(e); }, [slowHttpStatus, false, null, body]] at URL: /session/b057191b-6328-4c7b-bdd2-170ba79280af/execute)', - timestamp: 1419031702585, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Done: /session/b057191b-6328-4c7b-bdd2-170ba79280af/execute', - timestamp: 1419031702608, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Executing: [get text: 0 [org.openqa.selenium.remote.RemoteWebElement@2a868887 -> unknown locator]] at URL: /session/b057191b-6328-4c7b-bdd2-170ba79280af/element/0/text)', - timestamp: 1419031702795, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'org.openqa.selenium.remote.server.DriverServlet org.openqa.selenium.remote.server.rest.ResultConfig.handle Done: /session/b057191b-6328-4c7b-bdd2-170ba79280af/element/0/text', - timestamp: 1419031702812, - type: '' - }]; - var timeline = TimelinePlugin.parseArrayLog(clientLog); - - expect(timeline.length).toEqual(4); - expect(timeline[0].command).toEqual('click'); - expect(timeline[0].duration).toEqual(1419031697470 - 1419031697443); - }); - - it('should align chrome logs', function() { - var chromeLog = - '[1.000][INFO]: COMMAND SetScriptTimeout {\n' + - ' "ms": 11000\n' + - '}\n' + - '[1.000][INFO]: RESPONSE SetScriptTimeout\n' + - '[4.000][INFO]: COMMAND GetElementText {\n' + - ' "id": "0.5319263362325728-1"\n' + - '}\n' + - '[5.000][INFO]: RESPONSE GetElementText "not started"\n'; - var timeline = TimelinePlugin.parseTextLog(chromeLog, 'chrome logs', 90000); - expect(timeline.length).toEqual(2); - expect(timeline[1].source).toEqual('chrome logs'); - expect(timeline[1].start).toEqual(93000); - expect(timeline[1].end).toEqual(94000); - }); - - it('should align selenium standalone logs', function() { - var clientLog = - 'INFO: Launching a standalone server\n' + - '01:40:01.0000 INFO - Executing: [set script timeoutt: 5] at URL: /abc)\n' + - '01:40:02.0000 INFO - Done: /abc\n' + - '01:40:04.0000 INFO - Executing: [get text: 0 [elem -> unknown locator]] at URL: /abc)\n' + - '01:40:05.0000 INFO - Done: /abc\n'; - - var timeline = TimelinePlugin.parseTextLog(clientLog, 'standalone log', 90000); - expect(timeline.length).toEqual(2); - expect(timeline[1].source).toEqual('standalone log'); - expect(timeline[1].start).toEqual(93000); - expect(timeline[1].end).toEqual(94000); - }); - - it('should align selenium client logs', function() { - var clientLog = [{ - level: { value: 800, name: 'INFO' }, - message: 'foo.bar Executing: [set script timeout: 1]', - timestamp: 111000, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'foo.bar Done: [set script timeout: 1]', - timestamp: 112000, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'foo.bar Executing: [get text: 0 [elemid -> unknown locator]]', - timestamp: 114000, - type: '' - }, { level: { value: 800, name: 'INFO' }, - message: 'foo.bar Done: [get text: 0 [elemid -> unknown locator]]', - timestamp: 115000, - type: '' - }]; - var timeline = TimelinePlugin.parseArrayLog(clientLog, 'client log', 90000); - - expect(timeline.length).toEqual(2); - expect(timeline[1].source).toEqual('client log'); - expect(timeline[1].start).toEqual(93000); - expect(timeline[1].end).toEqual(94000); - }); -}); diff --git a/scripts/test.js b/scripts/test.js index d056ac8ce..3ae550d6b 100755 --- a/scripts/test.js +++ b/scripts/test.js @@ -37,12 +37,6 @@ var passingTests = [ 'node scripts/interactive_tests/with_base_url.js', // Unit tests 'node node_modules/.bin/jasmine JASMINE_CONFIG_PATH=scripts/unit_test.json', - // Plugins - 'node lib/cli.js plugins/timeline/spec/conf.js', - 'node lib/cli.js plugins/ngHint/spec/successConfig.js', - 'node lib/cli.js plugins/accessibility/spec/successConfig.js', - 'node lib/cli.js plugins/console/spec/consolePassConfig.js', - 'node lib/cli.js plugins/console/spec/consolePassLogWarnings.js' ]; var executor = new Executor(); @@ -133,73 +127,4 @@ executor.addCommandlineTest('node lib/cli.js spec/errorTest/slowHttpAndTimeoutCo {message: '^((?!The following tasks were pending).)*$'} ]); -// Check ngHint plugin - -executor.addCommandlineTest( - 'node lib/cli.js plugins/ngHint/spec/failureConfig.js') - .expectExitCode(1) - .expectErrors([{ - message: 'warning -- ngHint plugin cannot be run as ngHint code was ' + - 'never included into the page' - }, { - message: 'warning -- ngHint is included on the page, but is not active ' + - 'because there is no `ng-hint` attribute present' - }, { - message: 'warning -- Module "xApp" was created but never loaded.' - }]); - -// Check accessibility plugin - -executor.addCommandlineTest( - 'node lib/cli.js plugins/accessibility/spec/failureConfig.js') - .expectExitCode(1) - .expectErrors([{ - message: '3 elements failed:' - }, - { - message: '1 element failed:' - }]); - -// Check console plugin - -executor.addCommandlineTest( - 'node lib/cli.js plugins/console/spec/consoleFailConfig.js') - .expectExitCode(1) - .expectErrors([ - {message: 'This is a test warning'}, - {message: 'This is a test error'}, - {message: 'This should be filtered out by string'}, - {message: 'This should be filtered out by regex'} - ]); - -executor.addCommandlineTest( - 'node lib/cli.js plugins/console/spec/consoleFailErrorConfig.js') - .expectExitCode(1) - .expectErrors([ - {message: 'This is a test error'}, - {message: 'This should be filtered out by string'}, - {message: 'This should be filtered out by regex'} - ]); - -executor.addCommandlineTest( - 'node lib/cli.js plugins/console/spec/consoleFailWarningConfig.js') - .expectExitCode(1) - .expectErrors([ - {message: 'This is a test warning'} - ]); - -executor.addCommandlineTest( - 'node lib/cli.js plugins/console/spec/consoleFailFilterConfig.js') - .expectExitCode(1) - .expectErrors([ - {message: 'This is a test error'} - ]); - -executor.addCommandlineTest( - 'node lib/cli.js plugins/console/spec/consoleFailLogWarnings.js') - .expectExitCode(1) - .expectErrors([ - {message: 'This is a test warning'} - ]); - executor.execute(); diff --git a/scripts/unit_test.json b/scripts/unit_test.json index c3ff16f47..aa5e7bacd 100644 --- a/scripts/unit_test.json +++ b/scripts/unit_test.json @@ -2,7 +2,6 @@ "spec_dir": "", "spec_files": [ "spec/unit/*.js", - "website/docgen/spec/*.js", - "plugins/timeline/spec/unit.js" + "website/docgen/spec/*.js" ] } diff --git a/testapp/accessibility/badMarkup.html b/testapp/accessibility/badMarkup.html deleted file mode 100644 index b3df2808b..000000000 --- a/testapp/accessibility/badMarkup.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - Angular.js Example - - - - - - First name: -
- Last name: -
- Hello {{firstName}} {{lastName}} - - - - diff --git a/testapp/accessibility/index.html b/testapp/accessibility/index.html deleted file mode 100644 index 57fc37f03..000000000 --- a/testapp/accessibility/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - Angular.js Example - - - - - - - -
- - -
- Hello {{firstName}} {{lastName}} - Firstname Lastname - - diff --git a/testapp/console/index.html b/testapp/console/index.html deleted file mode 100644 index b5b71ef58..000000000 --- a/testapp/console/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - Angular.js Example - - - - - - - - - - diff --git a/testapp/ngHint/index.html b/testapp/ngHint/index.html deleted file mode 100644 index 4a4d02260..000000000 --- a/testapp/ngHint/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - Angular.js Example - - - - - - - First name: -
- Last name: -
- Hello {{firstName}} {{lastName}} - - diff --git a/testapp/ngHint/ngHint.js b/testapp/ngHint/ngHint.js deleted file mode 100644 index 0bc080a40..000000000 --- a/testapp/ngHint/ngHint.js +++ /dev/null @@ -1,2180 +0,0 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o -1) || - angular.hint.logMessage('General', 'Module ' + name + ' could not be found', SEVERITY_WARNING); - }); -} - -function hintModuleName(name) { - return 'ngHint' + title(name); -} - -function title(str) { - return str[0].toUpperCase() + str.substr(1); -} - -var LEVELS = [ - 'error', - 'warning', - 'suggestion' -]; - -function flush() { - var log = angular.hint.flush(), - groups = Object.keys(log); - - groups.forEach(function (groupName) { - var group = log[groupName]; - var header = 'Angular Hint: ' + groupName; - - console.groupCollapsed ? - console.groupCollapsed(header) : - console.log(header); - - LEVELS.forEach(function (level) { - group[level] && logGroup(group[level], title(level)); - }); - console.groupEnd && console.groupEnd(); - }); -} - -setInterval(flush, 2) - -angular.hint.onMessage = function () { - setTimeout(flush, 2); -}; - -function logGroup(group, type) { - console.group ? console.group(type) : console.log(type); - for(var i = 0, ii = group.length; i < ii; i++) { - console.log(group[i]); - } - console.group && console.groupEnd(); -} - -},{"angular-hint-controllers":2,"angular-hint-directives":3,"angular-hint-events":38,"angular-hint-log":47,"angular-hint-modules":48,"angular-hint-scopes":66}],2:[function(require,module,exports){ -'use strict'; - -var nameToControllerMatch = {}, - controllers = {}, - hintLog = angular.hint = require('angular-hint-log'), - MODULE_NAME = 'Controllers', - SEVERITY_ERROR = 1, - SEVERITY_WARNING = 2; - -/** -* Decorates $controller with a patching function to -* log a message if the controller is instantiated on the window -*/ -angular.module('ngHintControllers', []). - config(function ($provide) { - $provide.decorator('$controller', function($delegate) { - return function(ctrl, locals) { - //If the controller name is passed, find the controller than matches it - if(typeof ctrl === 'string') { - if(nameToControllerMatch[ctrl]) { - ctrl = nameToControllerMatch[ctrl]; - } else { - //If the controller function cannot be found, check for it on the window - checkUppercaseName(ctrl); - checkControllerInName(ctrl); - ctrl = window[ctrl] || ctrl; - if(typeof ctrl === 'string') { - throw new Error('The controller function for ' + ctrl + ' could not be found.' + - ' Is the function registered under that name?'); - } - } - } - locals = locals || {}; - //If the controller is not in the list of already registered controllers - //and it is not connected to the local scope, it must be instantiated on the window - if(!controllers[ctrl] && (!locals.$scope || !locals.$scope[ctrl]) && - ctrl.toString().indexOf('@name ngModel.NgModelController#$render') === -1 && - ctrl.toString().indexOf('@name form.FormController') === -1) { - if(angular.version.minor <= 2) { - hintLog.logMessage(MODULE_NAME, 'It is against Angular best practices to ' + - 'instantiate a controller on the window. This behavior is deprecated in Angular' + - ' 1.3.0', SEVERITY_WARNING); - } else { - hintLog.logMessage(MODULE_NAME, 'Global instantiation of controllers was deprecated' + - ' in Angular 1.3.0. Define the controller on a module.', SEVERITY_ERROR); - } - } - var ctrlInstance = $delegate.apply(this, [ctrl, locals]); - return ctrlInstance; - }; - }); -}); - -/** -* Save details of the controllers as they are instantiated -* for use in decoration. -* Hint about the best practices for naming controllers. -*/ -var originalModule = angular.module; - -function checkUppercaseName(controllerName) { - var firstLetter = controllerName.charAt(0); - if(firstLetter !== firstLetter.toUpperCase() && firstLetter === firstLetter.toLowerCase()) { - hintLog.logMessage(MODULE_NAME, 'The best practice is to name controllers with an' + - ' uppercase first letter. Check the name of \'' + controllerName + '\'.', SEVERITY_WARNING); - } -} - -function checkControllerInName(controllerName) { - var splitName = controllerName.split('Controller'); - if(splitName.length === 1 || splitName[splitName.length - 1] !== '') { - hintLog.logMessage(MODULE_NAME, 'The best practice is to name controllers ending with ' + - '\'Controller\'. Check the name of \'' + controllerName + '\'.', SEVERITY_WARNING); - } -} - -angular.module = function() { - var module = originalModule.apply(this, arguments), - originalController = module.controller; - module.controller = function(controllerName, controllerConstructor) { - nameToControllerMatch[controllerName] = controllerConstructor; - controllers[controllerConstructor] = controllerConstructor; - checkUppercaseName(controllerName); - checkControllerInName(controllerName); - return originalController.apply(this, arguments); - }; - return module; -}; - -},{"angular-hint-log":47}],3:[function(require,module,exports){ -'use strict'; - -var ddLibData = require('./lib/ddLib-data'); - -var RESTRICT_REGEXP = /restrict\s*:\s*['"](.+?)['"]/; -var customDirectives = []; -var dasherize = require('dasherize'); -var search = require('./lib/search'); -var checkPrelimErrors = require('./lib/checkPrelimErrors'); -var getKeysAndValues = require('./lib/getKeysAndValues'); -var defaultDirectives = ddLibData.directiveTypes['angular-default-directives'].directives; -var htmlDirectives = ddLibData.directiveTypes['html-directives'].directives; - -angular.module('ngHintDirectives', []) - .config(['$provide', function($provide) { - $provide.decorator('$compile', ['$delegate', function($delegate) { - return function(elem) { - elem = angular.element(elem); - for(var i = 0, length = elem.length; i < length; i+=2) { - if(elem[i].getElementsByTagName) { - var toSend = Array.prototype.slice.call(elem[i].getElementsByTagName('*')); - search(toSend, customDirectives); - } - } - return $delegate.apply(this, arguments); - }; - }]); - }]); - -function supportObject(directiveObject) { - if(typeof directiveObject === 'object') { - var keys = Object.keys(directiveObject); - for(var i = keys.length - 1; i >= 0; i--) { - if(typeof directiveObject[keys[i]] === 'function') { - return directiveObject[keys[i]]; - } - } - } - return function() {}; -} - -var originalAngularModule = angular.module; -angular.module = function() { - var module = originalAngularModule.apply(this, arguments); - var originalDirective = module.directive; - module.directive = function(directiveName, directiveFactory) { - directiveFactory = directiveFactory || supportObject(directiveName); - directiveName = typeof directiveName === 'string' ? directiveName : Object.keys(directiveName)[0]; - - var originalDirectiveFactory = typeof directiveFactory === 'function' ? directiveFactory : - directiveFactory[directiveFactory.length - 1]; - - var factoryStr = originalDirectiveFactory.toString(); - - checkPrelimErrors(directiveName, factoryStr); - - var pairs = getKeysAndValues(factoryStr); - pairs.map(function(pair) { - customDirectives.push(pair); - }); - - var matchRestrict = factoryStr.match(RESTRICT_REGEXP); - var restrict = (matchRestrict && matchRestrict[1]) || 'A'; - var directive = { - directiveName: directiveName, - restrict: restrict, - require: pairs - }; - - customDirectives.push(directive); - - return originalDirective.apply(this, arguments); - }; - return module; -}; - -},{"./lib/checkPrelimErrors":16,"./lib/ddLib-data":17,"./lib/getKeysAndValues":24,"./lib/search":32,"dasherize":34}],4:[function(require,module,exports){ -/** - *@param s: first string to compare - *@param t: second string to compare - * - *@description: - *Checks to see if two strings are similiar enough to even bother checking the Levenshtein Distance. - */ -module.exports = function(s, t) { - var strMap = {}, similarities = 0, STRICTNESS = 0.66; - if(Math.abs(s.length - t.length) > 3) { - return false; - } - s.split('').forEach(function(x){strMap[x] = x;}); - for (var i = t.length - 1; i >= 0; i--) { - similarities = strMap[t.charAt(i)] ? similarities + 1 : similarities; - } - return similarities >= t.length * STRICTNESS; -}; - -},{}],5:[function(require,module,exports){ -var ddLibData = require('./ddLib-data'); - -/** - *@param attribute: attribute name as string e.g. 'ng-click', 'width', 'src', etc. - *@param options: {} options object from beginSearch. - * - *@description attribute exsistance in the types of directives/attibutes (html, angular core, and - * angular custom) and checks the restrict property of values matches its use. - * - *@return {} with attribute exsistance and wrong use e.g. restrict property set to elements only. - **/ -module.exports = function(attribute, options) { - var anyTrue = false, - wrongUse = '', - directive, - restrictProp; - - options.directiveTypes.forEach(function(dirType) { - var isTag = attribute.charAt(0) === '*'; - var isCustomDir = dirType === 'angular-custom-directives'; - if(!isTag) { - directive = ddLibData.directiveTypes[dirType].directives[attribute] || ''; - restrictProp = directive.restrict || directive; - if(restrictProp) { - if(restrictProp.indexOf('E') > -1 && restrictProp.indexOf('A') < 0) { - wrongUse = 'element'; - } - if(restrictProp.indexOf('C') > -1 && restrictProp.indexOf('A') < 0) { - wrongUse = (wrongUse) ? 'element and class' : 'class'; - } - anyTrue = anyTrue || true; - } - } - else if(isTag && isCustomDir){ - directive = ddLibData.directiveTypes[dirType].directives[attribute.substring(1)] || ''; - restrictProp = directive.restrict || directive; - anyTrue = anyTrue || true; - if(restrictProp && restrictProp.indexOf('A') > -1 && restrictProp.indexOf('E') < 0) { - wrongUse = 'attribute'; - } - } - }); - var typeError = wrongUse? 'wronguse' : '' || !anyTrue ? 'nonexsisting' : '' || ''; - return {exsists: anyTrue, wrongUse: wrongUse, typeError: typeError}; -}; - -},{"./ddLib-data":17}],6:[function(require,module,exports){ -var ddLibData = require('./ddLib-data'), - SEVERITY_ERROR = 1; - -module.exports = function(info, id, type) { - var message = ddLibData.directiveTypes[info.directiveType].message + type + ' element' + id + '. '; - var error = info.error; - error = (error.charAt(0) === '*') ? error.substring(1): error; - message += 'Found deprecated directive "' + error + '". Use an alternative solution.'; - return [message, SEVERITY_ERROR]; -}; - -},{"./ddLib-data":17}],7:[function(require,module,exports){ -var SEVERITY_ERROR = 1; - -module.exports = function(info, id, type) { - var missingLength = info.missing.length; - var s = missingLength === 1 ? ' ' : 's '; - var waswere = missingLength === 1 ? 'is ' : 'are '; - var missing = ''; - info.missing.forEach(function(str){ - missing += '"' + str + '",'; - }); - missing = '[' + missing.substring(0, missing.length-1) + '] '; - var message = 'Attribute' + s + missing + waswere + 'missing in ' + type + ' element' + id + '.'; - return [message, SEVERITY_ERROR]; -}; - -},{}],8:[function(require,module,exports){ -var isMutExclusiveDir = require('./isMutExclusiveDir'), - SEVERITY_ERROR = 1; - -module.exports = function(info, id, type) { - var pair = isMutExclusiveDir(info.error); - var message = 'Angular attributes "'+info.error+'" and "'+pair+'" in '+type+ ' element'+id+ - ' should not be attributes together on the same HTML element'; - return [message, SEVERITY_ERROR]; -}; - -},{"./isMutExclusiveDir":29}],9:[function(require,module,exports){ -var hintLog = require('angular-hint-log'), - MODULE_NAME = 'Directives', - SEVERITY_SUGGESTION = 3; - -module.exports = function(directiveName) { - var message = 'Directive "'+directiveName+'" should have proper namespace try adding a prefix'+ - ' and/or using camelcase.'; - var domElement = '<'+directiveName+'> '; - hintLog.logMessage(MODULE_NAME, message, SEVERITY_SUGGESTION); -}; - -},{"angular-hint-log":47}],10:[function(require,module,exports){ -var SEVERITY_SUGGESTION = 3; - -module.exports = function(info, id, type) { - var ngDir = 'ng-' + info.error.substring(2), - message = 'Use Angular version of "' + info.error + '" in ' + type + ' element' + id + - '. Try: "' + ngDir + '"'; - return [message, SEVERITY_SUGGESTION]; -}; - -},{}],11:[function(require,module,exports){ -var SEVERITY_ERROR = 1; -module.exports = function(info, id, type) { - var message = 'ngRepeat in '+type+' element'+id+' was used incorrectly. '+info.suggestion; - return [message, SEVERITY_ERROR]; -}; - -},{}],12:[function(require,module,exports){ -var ddLibData = require('./ddLib-data'), - SEVERITY_ERROR = 1; - -module.exports = function(info, id, type) { - var message = ddLibData.directiveTypes[info.directiveType].message + type + ' element' + id + '. '; - var error = (info.error.charAt(0) === '*') ? info.error.substring(1): info.error; - message += 'Found incorrect attribute "' + error + '" try "' + info.match + '".'; - return [message, SEVERITY_ERROR]; -}; - -},{"./ddLib-data":17}],13:[function(require,module,exports){ -var hintLog = angular.hint = require('angular-hint-log'), - MODULE_NAME = 'Directives', - SEVERITY_ERROR = 1; - -module.exports = function(directiveName) { - var message = 'The use of "replace" in directive factories is deprecated,'+ - ' and it was found in "' + directiveName + '".'; - var domElement = '<' + directiveName + '> '; - hintLog.logMessage(MODULE_NAME, message, SEVERITY_ERROR); -}; - -},{"angular-hint-log":47}],14:[function(require,module,exports){ -var ddLibData = require('./ddLib-data'), - SEVERITY_ERROR = 1; - -module.exports = function(info, id, type) { - var message = ddLibData.directiveTypes[info.directiveType].message + type + ' element' + - id + '. ', - error = (info.error.charAt(0) === '*') ? info.error.substring(1): info.error, - aecmType = (info.wrongUse.indexOf('attribute') > -1)? 'Element' : 'Attribute'; - message += aecmType + ' name "' + error + '" is reserved for ' + info.wrongUse + ' names only.'; - return [message, SEVERITY_ERROR]; -}; - -},{"./ddLib-data":17}],15:[function(require,module,exports){ - -module.exports = function(attrVal){ - var suggestion, - error = false, - TRACK_REGEXP = /track\s+by\s+\S*/, - FILTER_REGEXP = /filter\s*:\s*\w+(?:\.\w+)*/; - var trackMatch = attrVal.match(TRACK_REGEXP); - var filterMatch = attrVal.match(FILTER_REGEXP); - var breakIndex = attrVal.indexOf('|') > -1 ? attrVal.indexOf('|') : Infinity; - - if(!trackMatch && filterMatch && breakIndex === Infinity) { - return 'Try: " | '+filterMatch[0]+'"'; - } - - if(trackMatch && filterMatch) { - var trackInd = attrVal.indexOf(trackMatch[0]); - var filterInd = attrVal.indexOf(filterMatch[0]); - if(!(breakIndex < filterInd && filterInd < trackInd)) { - return 'Try: " | '+filterMatch[0]+' '+trackMatch[0]+'"'; - } - } -} -},{}],16:[function(require,module,exports){ -var hasNameSpace = require('./hasNameSpace'); -var buildNameSpace = require('./buildNameSpace'); -var hasReplaceOption = require('./hasReplaceOption'); -var buildReplaceOption = require('./buildReplaceOption'); - -module.exports = function(dirName, dirFacStr) { - if (!hasNameSpace(dirName)) { - buildNameSpace(dirName); - } - if (hasReplaceOption(dirFacStr)) { - buildReplaceOption(dirName); - } -}; - -},{"./buildNameSpace":9,"./buildReplaceOption":13,"./hasNameSpace":27,"./hasReplaceOption":28}],17:[function(require,module,exports){ -module.exports = { - directiveTypes : { - 'html-directives': { - message: 'There was an HTML error in ', - directives: { - 'abbr' : 'A', - 'accept': 'A', - 'accesskey': 'A', - 'action': 'A', - 'align': 'A', - 'alt': 'A', - 'async': 'A', - 'background': 'A', - 'bgcolor': 'A', - 'border': 'A', - 'cellpadding': 'A', - 'char': 'A', - 'charoff': 'A', - 'charset': 'A', - 'checked': 'A', - 'cite': 'A', - 'class': 'A', - 'classid': 'A', - 'code': 'A', - 'codebase': 'A', - 'color': 'A', - 'cols': 'A', - 'colspan': 'A', - 'content': 'A', - 'data': 'A', - 'defer': 'A', - 'dir': 'A', - 'face': 'A', - 'for': 'A', - 'frame': 'A', - 'frameborder': 'A', - 'headers': 'A', - 'height': 'A', - 'http-equiv': 'A', - 'href': 'A', - 'id': 'A', - 'label': 'A', - 'lang': 'A', - 'language': 'A', - 'link': 'A', - 'marginheight': 'A', - 'marginwidth': 'A', - 'maxlength': 'A', - 'media': 'A', - 'multiple': 'A', - 'name': 'A', - 'object': '!A', - 'onblur': '!A', - 'onchange': '!A', - 'onclick': '!A', - 'onfocus': '!A', - 'onkeydown': '!A', - 'onkeypress': '!A', - 'onkeyup': '!A', - 'onload': '!A', - 'onmousedown': '!A', - 'onmousemove': '!A', - 'onmouseout': '!A', - 'onmouseover': '!A', - 'onmouseup': '!A', - 'onreset': '!A', - 'onselect': '!A', - 'onsubmit': '!A', - 'property': 'A', - 'readonly': 'A', - 'rel': 'A', - 'rev': 'A', - 'role': 'A', - 'rows': 'A', - 'rowspan': 'A', - 'size': 'A', - 'span': 'EA', - 'src': 'A', - 'start': 'A', - 'style': 'A', - 'text': 'A', - 'target': 'A', - 'title': 'A', - 'type': 'A', - 'value': 'A', - 'width': 'A' - } - }, - 'angular-default-directives': { - message: 'There was an AngularJS error in ', - directives: { - 'count': 'A', - 'min': 'A', - 'max': 'A', - 'ng-app': 'A', - 'ng-bind': 'A', - 'ng-bindhtml': 'A', - 'ng-bindtemplate': 'A', - 'ng-blur': 'A', - 'ng-change': 'A', - 'ng-checked': 'A', - 'ng-class': 'A', - 'ng-classeven': 'A', - 'ng-classodd': 'A', - 'ng-click': 'A', - 'ng-cloak': 'A', - 'ng-controller': 'A', - 'ng-copy': 'A', - 'ng-csp': 'A', - 'ng-cut': 'A', - 'ng-dblclick': 'A', - 'ng-disabled': 'A', - 'ng-dirty': 'A', - 'ng-focus': 'A', - 'ng-form': 'A', - 'ng-hide': 'A', - 'ng-hint': 'A', - 'ng-hint-exclude': 'A', - 'ng-hint-include': 'A', - 'ng-href': 'A', - 'ng-if': 'A', - 'ng-include': 'A', - 'ng-init': 'A', - 'ng-invalid': 'A', - 'ng-keydown': 'A', - 'ng-keypress': 'A', - 'ng-keyup': 'A', - 'ng-list': 'A', - 'ng-maxlength': 'A', - 'ng-minlength': 'A', - 'ng-model': 'A', - 'ng-model-options': 'A', - 'ng-mousedown': 'A', - 'ng-mouseenter': 'A', - 'ng-mouseleave': 'A', - 'ng-mousemove': 'A', - 'ng-mouseover': 'A', - 'ng-mouseup': 'A', - 'ng-nonbindable': 'A', - 'ng-open': 'A', - 'ng-options': 'A', - 'ng-paste': 'A', - 'ng-pattern': 'A', - 'ng-pluralize': 'A', - 'ng-pristine': 'A', - 'ng-readonly': 'A', - 'ng-repeat': 'A', - 'ng-repeat-start': 'A', - 'ng-repeat-end': 'A', - 'ng-required': 'A', - 'ng-selected': 'A', - 'ng-show': 'A', - 'ng-src': 'A', - 'ng-srcset': 'A', - 'ng-style': 'A', - 'ng-submit': 'A', - 'ng-switch': 'A', - 'ng-switch-when': 'A', - 'ng-transclude': 'A', - 'ng-true-value': 'A', - 'ng-trim': 'A', - 'ng-false-value': 'A', - 'ng-value': 'A', - 'ng-valid': 'A', - 'ng-view': 'A', - 'required': 'A', - 'when': 'A' - } - }, - 'angular-custom-directives': { - message: 'There was an AngularJS error in ', - directives: {} - }, - 'angular-deprecated-directives': { - message: 'There was an AngularJS error in ', - directives: { - 'ng-bind-html-unsafe': 'deprecated' - } - } - } -}; - -},{}],18:[function(require,module,exports){ -var areSimilarEnough = require('./areSimilarEnough'); -var levenshteinDistance = require('./levenshtein'); - -/** - *@param directiveTypeData: {} with list of directives/attributes and - *their respective restrict properties. - *@param attribute: attribute name as string e.g. 'ng-click', 'width', 'src', etc. - * - *@return {} with Levenshtein Distance and name of the closest match to given attribute. - **/ -module.exports = function(directiveTypeData, attribute) { - if(typeof attribute !== 'string') { - throw new Error('Function must be passed a string as second parameter.'); - } - if((directiveTypeData === null || directiveTypeData === undefined) || - typeof directiveTypeData !== 'object') { - throw new Error('Function must be passed a defined object as first parameter.'); - } - var min_levDist = Infinity, - closestMatch = ''; - - for(var directive in directiveTypeData){ - if(min_levDist !== 1 && areSimilarEnough(attribute,directive)) { - var currentlevDist = levenshteinDistance(attribute, directive); - closestMatch = (currentlevDist < min_levDist)? directive : closestMatch; - min_levDist = (currentlevDist < min_levDist)? currentlevDist : min_levDist; - } - } - return {min_levDist: min_levDist, match: closestMatch}; -}; - -},{"./areSimilarEnough":4,"./levenshtein":30}],19:[function(require,module,exports){ - -var getFailedAttributesOfElement = require('./getFailedAttributesOfElement'); - -module.exports = function(scopeElements, options) { - return scopeElements.map(getFailedAttributesOfElement.bind(null, options)) - .filter(function(x) {return x;}); -}; - -},{"./getFailedAttributesOfElement":23}],20:[function(require,module,exports){ -var ddLibData = require('./ddLib-data'); - -module.exports = function(dirName, attributes) { - attributes = attributes.map(function(x){return x.nodeName;}); - var directive = ddLibData.directiveTypes['angular-custom-directives'].directives[dirName]; - var missing = []; - if (directive && directive.require) { - for (var i = 0, length = directive.require.length; i < length; i++) { - var dirName = directive.require[i].directiveName; - if (attributes.indexOf(dirName) < 0) { - missing.push(dirName); - } - } - } - return missing; -}; - -},{"./ddLib-data":17}],21:[function(require,module,exports){ -var hintLog = angular.hint = require('angular-hint-log'), - MODULE_NAME = 'Directives'; - -var build = { - deprecated: require('./buildDeprecated'), - missingrequired: require('./buildMissingRequired'), - mutuallyexclusive: require('./buildMutuallyExclusive'), - ngevent: require('./buildNgEvent'), - ngrepeatformat: require('./buildNgRepeatFormat'), - nonexsisting: require('./buildNonExsisting'), - wronguse: require('./buildWrongUse') -}; - -/** - *@param failedElements: [] of {}s of all failed elements with their failed attributes and closest - *matches or restrict properties - * - *@return [] of failed messages. - **/ -module.exports = function(failedElements) { - failedElements.forEach(function(obj) { - obj.data.forEach(function(info) { - var id = (obj.domElement.id) ? ' with id: #' + obj.domElement.id : '', - type = obj.domElement.nodeName, - messageAndSeverity = build[info.typeError](info, id, type); - hintLog.logMessage(MODULE_NAME, messageAndSeverity[0], messageAndSeverity[1]); - }); - }); -}; - -},{"./buildDeprecated":6,"./buildMissingRequired":7,"./buildMutuallyExclusive":8,"./buildNgEvent":10,"./buildNgRepeatFormat":11,"./buildNonExsisting":12,"./buildWrongUse":14,"angular-hint-log":47}],22:[function(require,module,exports){ -var normalizeAttribute = require('./normalizeAttribute'); -var ddLibData = require('./ddLib-data'); -var isMutExclusiveDir = require('./isMutExclusiveDir'); -var hasMutExclusivePair = require('./hasMutExclusivePair'); -var attributeExsistsInTypes = require('./attributeExsistsInTypes'); -var getSuggestions = require('./getSuggestions'); -var checkNgRepeatFormat = require('./checkNgRepeatFormat'); - -/** - *@param attributes: [] of attributes from element (includes tag name of element, e.g. DIV, P, etc.) - *@param options: {} options object from beginSearch - * - *@return [] of failedAttributes with their respective suggestions and directiveTypes - **/ -module.exports = function(attributes, options) { - var failedAttrs = [], mutExPairFound = false; - for (var i = 0; i < attributes.length; i++) { - var attr = normalizeAttribute(attributes[i].nodeName); - var dirVal = ddLibData.directiveTypes['html-directives'].directives[attr] || - ddLibData.directiveTypes['angular-deprecated-directives'].directives[attr] || ''; - - if(dirVal === 'deprecated') { - failedAttrs.push({ - error: attr, - directiveType: 'angular-deprecated-directives', - typeError: 'deprecated' - }); - } - - //if attr is a event attr. Html event directives are prefixed with ! in ddLibData - if (dirVal.indexOf('!') > -1) { - failedAttrs.push({ - error: attr, - directiveType: 'html-directives', - typeError: 'ngevent' - }); - continue; - } - if (!mutExPairFound && isMutExclusiveDir(attr) && hasMutExclusivePair(attr, attributes)) { - failedAttrs.push({ - error: attr, - directiveType: 'angular-default-directives', - typeError: 'mutuallyexclusive' - }); - mutExPairFound = true; - continue; - } - var attrVal = attributes[i].value || ''; - if(attr === 'ng-repeat') { - var result = checkNgRepeatFormat(attrVal); - if(result) { - failedAttrs.push({ - error: attr, - suggestion: result, - directiveType: 'angular-default-directives', - typeError: 'ngrepeatformat' - }); - } - } - - var result = attributeExsistsInTypes(attr,options); - - var suggestion = result.typeError === 'nonexsisting' ? - getSuggestions(attr, options) : {match: ''}; - - if (result.typeError) { - failedAttrs.push({ - match: suggestion.match || '', - wrongUse: result.wrongUse || '', - error: attr, - directiveType: suggestion.directiveType || 'angular-custom-directives', - typeError: result.typeError - }); - } - } - return failedAttrs; -}; -},{"./attributeExsistsInTypes":5,"./checkNgRepeatFormat":15,"./ddLib-data":17,"./getSuggestions":25,"./hasMutExclusivePair":26,"./isMutExclusiveDir":29,"./normalizeAttribute":31}],23:[function(require,module,exports){ -var getFailedAttributes = require('./getFailedAttributes'); -var findMissingAttrs = require('./findMissingAttrs'); - - -/** - *@description - *Adds element tag name (DIV, P, SPAN) to list of attributes with '*' prepended - *for identification later. - * - *@param options: {} options object from beginSearch - *@param element: HTML element to check attributes of - * - *@return {} of html element and [] of failed attributes - **/ -module.exports = function(options, element) { - if(element.attributes.length) { - var eleName = element.nodeName.toLowerCase(); - var eleAttrs = Array.prototype.slice.call(element.attributes); - eleAttrs.push({ - nodeName: '*'+eleName - }); - var failedAttrs = getFailedAttributes(eleAttrs, options); - var missingRequired = findMissingAttrs(eleName, eleAttrs); - var missingLength = missingRequired.length; - - if(failedAttrs.length || missingLength) { - if(missingLength) { - failedAttrs.push({ - directiveType: 'angular-custom-directive', - missing: missingRequired, - typeError: 'missingrequired' - }); - } - return { - domElement: element, - data: failedAttrs - }; - } - } -}; - -},{"./findMissingAttrs":20,"./getFailedAttributes":22}],24:[function(require,module,exports){ -module.exports = function(str) { - var customDirectives = [], - pairs = [], - SCOPE_REGEXP = /scope\s*:\s*{\s*[^}]*['"]\s*}/, - PROPERTY_REGEXP = /\w+\s*:\s*['"][a-zA-Z=@&]+['"]/g, - KEYVAL_REGEXP = /(\w+)\s*:\s*['"](.+)['"]/; - var matchScope = str.replace(/\n/g,'').match(SCOPE_REGEXP); - var propertiesMatch = matchScope ? matchScope[0].match(PROPERTY_REGEXP) : undefined; - - if (matchScope && propertiesMatch) { - propertiesMatch.map(function(str){ - var temp = str.match(KEYVAL_REGEXP); - pairs.push({key: temp[1], value: temp[2]}); - }); - pairs.forEach(function(pair){ - var name = (['=', '@', '&'].indexOf(pair.value) !== -1)? pair.key : pair.value.substring(1); - customDirectives.push({directiveName: name , restrict:'A'}); - }); - } - return customDirectives; -}; - -},{}],25:[function(require,module,exports){ -var ddLibData = require('./ddLib-data'); -var findClosestMatchIn = require('./findClosestMatchIn'); - -/** - *@param attribute: attribute name as string e.g. 'ng-click', 'width', 'src', etc. - *@param options: {} options object from beginSearch. - * - *@return {} with closest match to attribute and the directive type it corresponds to. - **/ -module.exports = function(attribute, options) { - var min_levDist = Infinity, - match = '', - dirType = ''; - - options.directiveTypes.forEach(function(directiveType) { - var isTag = attribute.charAt(0) === '*'; - var isCustomDir = directiveType === 'angular-custom-directives'; - if (!isTag || (isTag && isCustomDir)) { - var directiveTypeData = ddLibData.directiveTypes[directiveType].directives; - var tempMatch = findClosestMatchIn(directiveTypeData, attribute); - if (tempMatch.min_levDist < options.tolerance && tempMatch.min_levDist < min_levDist) { - match = tempMatch.match; - dirType = directiveType; - min_levDist = tempMatch.min_levDist; - } - } - }); - return { - match: match, - directiveType: dirType - }; -}; - -},{"./ddLib-data":17,"./findClosestMatchIn":18}],26:[function(require,module,exports){ -var isMutExclusiveDir = require('./isMutExclusiveDir'); - -module.exports = function(attr, attributes) { - var pair = isMutExclusiveDir(attr); - - return attributes.some(function(otherAttr) { - return otherAttr.nodeName === pair; - }); -}; - -},{"./isMutExclusiveDir":29}],27:[function(require,module,exports){ -var dasherize = require('dasherize'); -var validate = require('validate-element-name'); - -module.exports = function(str) { - var dashStr = dasherize(str); - var validated = !validate(dashStr).message ? true : false; - //Check for message definition because validate-element-name returns true for things starting - //with ng-, polymer-, and data- but message is defined for those and errors. - return validated && str.toLowerCase() !== str; -}; - -},{"dasherize":34,"validate-element-name":35}],28:[function(require,module,exports){ -module.exports = function(facStr) { - return facStr.match(/replace\s*:/); -}; - -},{}],29:[function(require,module,exports){ -module.exports = function (dirName) { - var exclusiveDirHash = { - 'ng-show' : 'ng-hide', - 'ng-hide' : 'ng-show', - 'ng-switch-when' : 'ng-switch-default', - 'ng-switch-default' : 'ng-switch-when', - }; - return exclusiveDirHash[dirName]; -}; - -},{}],30:[function(require,module,exports){ -/** - *@param s: first string to compare for Levenshtein Distance. - *@param t: second string to compare for Levenshtein Distance. - * - *@description - *Calculates the minimum number of changes (insertion, deletion, transposition) to get from s to t. - * - *credit: http://stackoverflow.com/questions/11919065/sort-an-array-by-the-levenshtein-distance-with-best-performance-in-javascript - *http://www.merriampark.com/ld.htm, http://www.mgilleland.com/ld/ldjavascript.htm, Damerau–Levenshtein distance (Wikipedia) - **/ -module.exports = function(s, t) { - if(typeof s !== 'string' || typeof t !== 'string') { - throw new Error('Function must be passed two strings, given: '+typeof s+' and '+typeof t+'.'); - } - var d = []; - var n = s.length; - var m = t.length; - - if (n === 0) {return m;} - if (m === 0) {return n;} - - for (var ii = n; ii >= 0; ii--) { d[ii] = []; } - for (var ii = n; ii >= 0; ii--) { d[ii][0] = ii; } - for (var jj = m; jj >= 0; jj--) { d[0][jj] = jj; } - for (var i = 1; i <= n; i++) { - var s_i = s.charAt(i - 1); - - for (var j = 1; j <= m; j++) { - if (i == j && d[i][j] > 4) return n; - var t_j = t.charAt(j - 1); - var cost = (s_i == t_j) ? 0 : 1; - var mi = d[i - 1][j] + 1; - var b = d[i][j - 1] + 1; - var c = d[i - 1][j - 1] + cost; - if (b < mi) mi = b; - if (c < mi) mi = c; - d[i][j] = mi; - if (i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j) { - d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost); - } - } - } - return d[n][m]; -}; - -},{}],31:[function(require,module,exports){ -/** - *@param attribute: attribute name before normalization as string - * e.g. 'data-ng-click', 'width', 'x:ng:src', etc. - * - *@return normalized attribute name - **/ -module.exports = function(attribute) { - return attribute.replace(/^(?:data|x)[-_:]/,'').replace(/[:_]/g,'-'); -}; - -},{}],32:[function(require,module,exports){ - -var formatResults = require('./formatResults'); -var findFailedElements = require('./findFailedElements'); -var setCustomDirectives = require('./setCustomDirectives'); -var defaultTypes = [ - 'html-directives', - 'angular-default-directives', - 'angular-custom-directives', - 'angular-deprecated-directives' -]; - - -/** - * - *@param scopeElements: [] of HTML elements to be checked for incorrect attributes - *@param customDirectives: [] of custom directive objects from $compile decorator - *@param options: {} of options for app to run with: - * options.tolerance: Integer, maximum Levenshtein Distance to be allowed for misspellings - * options.directiveTypes: [] of which type of directives/attributes to search through - **/ -module.exports = function(scopeElements, customDirectives, options) { - if(!Array.isArray(scopeElements)) { - throw new Error('Function search must be passed an array.'); - } - options = options || {}; - options.directiveTypes = options.directiveTypes || defaultTypes; - options.tolerance = options.tolerance || 4; - if(customDirectives && customDirectives.length){ - setCustomDirectives(customDirectives); - } - var failedElements = findFailedElements(scopeElements, options); - formatResults(failedElements); -}; - -},{"./findFailedElements":19,"./formatResults":21,"./setCustomDirectives":33}],33:[function(require,module,exports){ -var ddLibData = require('../lib/ddLib-data'); - -module.exports = function(customDirectives) { - customDirectives.forEach(function(directive) { - var directiveName = directive.directiveName.replace(/([A-Z])/g, '-$1').toLowerCase(); - ddLibData.directiveTypes['angular-custom-directives'] - .directives[directiveName] = directive; - }); -}; - -},{"../lib/ddLib-data":17}],34:[function(require,module,exports){ -'use strict'; - -var isArray = Array.isArray || function (obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; -}; - -var isDate = function (obj) { - return Object.prototype.toString.call(obj) === '[object Date]'; -}; - -var isRegex = function (obj) { - return Object.prototype.toString.call(obj) === '[object RegExp]'; -}; - -var has = Object.prototype.hasOwnProperty; -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - return keys; -}; - -function dashCase(str) { - return str.replace(/([A-Z])/g, function ($1) { - return '-' + $1.toLowerCase(); - }); -} - -function map(xs, f) { - if (xs.map) { - return xs.map(f); - } - var res = []; - for (var i = 0; i < xs.length; i++) { - res.push(f(xs[i], i)); - } - return res; -} - -function reduce(xs, f, acc) { - if (xs.reduce) { - return xs.reduce(f, acc); - } - for (var i = 0; i < xs.length; i++) { - acc = f(acc, xs[i], i); - } - return acc; -} - -function walk(obj) { - if (!obj || typeof obj !== 'object') { - return obj; - } - if (isDate(obj) || isRegex(obj)) { - return obj; - } - if (isArray(obj)) { - return map(obj, walk); - } - return reduce(objectKeys(obj), function (acc, key) { - var camel = dashCase(key); - acc[camel] = walk(obj[key]); - return acc; - }, {}); -} - -module.exports = function (obj) { - if (typeof obj === 'string') { - return dashCase(obj); - } - return walk(obj); -}; - -},{}],35:[function(require,module,exports){ -'use strict'; -var ncname = require('ncname'); - -var reservedNames = [ - 'annotation-xml', - 'color-profile', - 'font-face', - 'font-face-src', - 'font-face-uri', - 'font-face-format', - 'font-face-name', - 'missing-glyph' -]; - -function hasError(name) { - if (!name) { - return 'Missing element name.'; - } - - if (/[A-Z]/.test(name)) { - return 'Custom element names must not contain uppercase ASCII characters.'; - } - - if (name.indexOf('-') === -1) { - return 'Custom element names must contain a hyphen. Example: unicorn-cake'; - } - - if (/^\d/i.test(name)) { - return 'Custom element names must not start with a digit.'; - } - - if (/^-/i.test(name)) { - return 'Custom element names must not start with a hyphen.'; - } - - // http://www.w3.org/TR/custom-elements/#concepts - if (!ncname.test(name)) { - return 'Invalid element name.'; - } - - if (reservedNames.indexOf(name) !== -1) { - return 'The supplied element name is reserved and can\'t be used.\nSee: http://www.w3.org/TR/custom-elements/#concepts'; - } -} - -function hasWarning(name) { - if (/^polymer-/i.test(name)) { - return 'Custom element names should not start with `polymer-`.\nSee: http://webcomponents.github.io/articles/how-should-i-name-my-element'; - } - - if (/^x-/i.test(name)) { - return 'Custom element names should not start with `x-`.\nSee: http://webcomponents.github.io/articles/how-should-i-name-my-element/'; - } - - if (/^ng-/i.test(name)) { - return 'Custom element names should not start with `ng-`.\nSee: http://docs.angularjs.org/guide/directive#creating-directives'; - } - - if (/^xml/i.test(name)) { - return 'Custom element names should not start with `xml`.'; - } - - if (/^[^a-z]/i.test(name)) { - return 'This element name is only valid in XHTML, not in HTML. First character should be in the range a-z.'; - } - - if (/[^a-z0-9]$/i.test(name)) { - return 'Custom element names should not end with a non-alpha character.'; - } - - if (/[\.]/.test(name)) { - return 'Custom element names should not contain a dot character as it would need to be escaped in a CSS selector.'; - } - - if (/[^\x20-\x7E]/.test(name)) { - return 'Custom element names should not contain non-ASCII characters.'; - } - - if (/--/.test(name)) { - return 'Custom element names should not contain consecutive hyphens.'; - } - - if (/[^a-z0-9]{2}/i.test(name)) { - return 'Custom element names should not contain consecutive non-alpha characters.'; - } -} - -module.exports = function (name) { - var errMsg = hasError(name); - - return { - isValid: !errMsg, - message: errMsg || hasWarning(name) - }; -}; - -},{"ncname":36}],36:[function(require,module,exports){ -'use strict'; -var xmlChars = require('xml-char-classes'); - -function getRange(re) { - return re.source.slice(1, -1); -} - -// http://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-NCName -module.exports = new RegExp('^[' + getRange(xmlChars.letter) + '_][' + getRange(xmlChars.letter) + getRange(xmlChars.digit) + '\\.\\-_' + getRange(xmlChars.combiningChar) + getRange(xmlChars.extender) + ']*$'); - -},{"xml-char-classes":37}],37:[function(require,module,exports){ -exports.baseChar = /[A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7\u04C8\u04CB\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B36-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60\u0D61\u0E01-\u0E2E\u0E30\u0E32\u0E33\u0E40-\u0E45\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD\u0EAE\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102\u1103\u1105-\u1107\u1109\u110B\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D\u116E\u1172\u1173\u1175\u119E\u11A8\u11AB\u11AE\u11AF\u11B7\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3]/; - -exports.ideographic = /[\u3007\u3021-\u3029\u4E00-\u9FA5]/; - -exports.letter = /[A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7\u04C8\u04CB\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B36-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60\u0D61\u0E01-\u0E2E\u0E30\u0E32\u0E33\u0E40-\u0E45\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD\u0EAE\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102\u1103\u1105-\u1107\u1109\u110B\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D\u116E\u1172\u1173\u1175\u119E\u11A8\u11AB\u11AE\u11AF\u11B7\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A\u212B\u212E\u2180-\u2182\u3007\u3021-\u3029\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\u4E00-\u9FA5\uAC00-\uD7A3]/; - -exports.combiningChar = /[\u0300-\u0345\u0360\u0361\u0483-\u0486\u0591-\u05A1\u05A3-\u05B9\u05BB-\u05BD\u05BF\u05C1\u05C2\u05C4\u064B-\u0652\u0670\u06D6-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0901-\u0903\u093C\u093E-\u094D\u0951-\u0954\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A02\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A70\u0A71\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0B01-\u0B03\u0B3C\u0B3E-\u0B43\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B82\u0B83\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C82\u0C83\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0D02\u0D03\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86-\u0F8B\u0F90-\u0F95\u0F97\u0F99-\u0FAD\u0FB1-\u0FB7\u0FB9\u20D0-\u20DC\u20E1\u302A-\u302F\u3099\u309A]/; - -exports.digit = /[0-9\u0660-\u0669\u06F0-\u06F9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE7-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29]/; - -exports.extender = /[\xB7\u02D0\u02D1\u0387\u0640\u0E46\u0EC6\u3005\u3031-\u3035\u309D\u309E\u30FC-\u30FE]/; -},{}],38:[function(require,module,exports){ -'use strict'; - -/** -* Load necessary functions from /lib into variables. -*/ -var ngEventDirectives = require('./lib/getEventDirectives')(), - getEventAttribute = require('./lib/getEventAttribute'), - getFunctionNames = require('./lib/getFunctionNames'), - formatResults = require('./lib/formatResults'); - -/** -* Decorate $provide in order to examine ng-event directives -* and hint about their effective use. -*/ -angular.module('ngHintEvents', []) - .config(['$provide', function($provide) { - - for(var directive in ngEventDirectives) { - var dirName = ngEventDirectives[directive]+'Directive'; - try{ - $provide.decorator(dirName, ['$delegate', '$timeout', '$parse', - function($delegate, $timeout, $parse) { - - var original = $delegate[0].compile, falseBinds = [], messages = []; - - $delegate[0].compile = function(element, attrs, transclude) { - var angularAttrs = attrs.$attr; - var eventAttrName = getEventAttribute(angularAttrs); - var fn = $parse(attrs[eventAttrName]); - var messages = []; - return function ngEventHandler(scope, element, attrs) { - for(var attr in angularAttrs) { - var boundFuncs = getFunctionNames(attrs[attr]); - boundFuncs.forEach(function(boundFn) { - if(ngEventDirectives[attr] && !(boundFn in scope)) { - messages.push({ - scope: scope, - element:element, - attrs: attrs, - boundFunc: boundFn - }); - } - }); - } - element.on(eventAttrName.substring(2).toLowerCase(), function(event) { - scope.$apply(function() { - fn(scope, {$event:event}); - }); - }); - formatResults(messages); - }; - }; - return $delegate; - }]); - } catch(e) {} - } - }]); -},{"./lib/formatResults":40,"./lib/getEventAttribute":41,"./lib/getEventDirectives":42,"./lib/getFunctionNames":43}],39:[function(require,module,exports){ -'use strict'; - -var getValidProps = require('./getValidProps'), - suggest = require('suggest-it'); - -module.exports = function addSuggestions(messages) { - messages.forEach(function(messageObj) { - var dictionary = getValidProps(messageObj.scope), - suggestion = suggest(dictionary)(messageObj.boundFunc); - messageObj['match'] = suggestion; - }); - return messages; -}; - -},{"./getValidProps":44,"suggest-it":46}],40:[function(require,module,exports){ -'use strict'; - -var hintLog = angular.hint = require('angular-hint-log'), - addSuggestions = require('./addSuggestions'), - MODULE_NAME = 'Events', - SEVERITY_ERROR = 1; - -module.exports = function formatResults(messages) { - messages = addSuggestions(messages); - if(messages.length) { - messages.forEach(function(obj) { - var id = (obj.element[0].id) ? ' with id: #' + obj.element[0].id : '', - type = obj.element[0].nodeName, - suggestion = obj.match ? ' (Try "' + obj.match + '").': '.', - message = 'Variable "' + obj.boundFunc + '" called on ' + type + ' element' + id + - ' does not exist in that scope' + suggestion + ' Event directive found on "' + - obj.element[0].outerHTML + '".'; - hintLog.logMessage(MODULE_NAME, message, SEVERITY_ERROR); - }); - } -}; - -},{"./addSuggestions":39,"angular-hint-log":47}],41:[function(require,module,exports){ -'use strict'; - -var ngEventDirectives = require('./getEventDirectives')(); - -module.exports = function getEventAttribute(attrs) { - for(var attr in attrs) { - if(ngEventDirectives[attr]) { - return attr; - } - } -}; - -},{"./getEventDirectives":42}],42:[function(require,module,exports){ -'use strict'; - -module.exports = function getEventDirectives() { - var list = 'click submit mouseenter mouseleave mousemove mousedown mouseover mouseup dblclick keyup keydown keypress blur focus submit cut copy paste'.split(' '); - var eventDirHash = {}; - list.forEach(function(dirName) { - dirName = 'ng'+dirName.charAt(0).toUpperCase()+dirName.substring(1); - eventDirHash[dirName] = dirName; - }); - return eventDirHash; -}; - -},{}],43:[function(require,module,exports){ -'use strict'; - -module.exports = function getFunctionNames(str) { - var results = str.replace(/\s+/g, '').split(/[\+\-\/\|\<\>\^=&!%~]/g).map(function(x) { - if(isNaN(+x)) { - if(x.match(/\w+\(.*\)$/)){ - return x.substring(0, x.indexOf('(')); - } - return x; - } - }).filter(function(x){return x;}); - return results; -}; - -},{}],44:[function(require,module,exports){ -'use strict'; - -module.exports = function getValidProps(obj) { - var props = []; - for(var prop in obj) { - if (prop.charAt(0) !== '$' && typeof obj[prop] === 'function') { - props.push(prop); - } - } - return props; -}; - -},{}],45:[function(require,module,exports){ -module.exports = distance; - -function distance(a, b) { - var table = []; - if (a.length === 0 || b.length === 0) return Math.max(a.length, b.length); - for (var ii = 0, ilen = a.length + 1; ii !== ilen; ++ii) { - table[ii] = []; - for (var jj = 0, jlen = b.length + 1; jj !== jlen; ++jj) { - if (ii === 0 || jj === 0) table[ii][jj] = Math.max(ii, jj); - else { - var diagPenalty = Number(a[ii-1] !== b[jj-1]); - var diag = table[ii - 1][jj - 1] + diagPenalty; - var top = table[ii - 1][jj] + 1; - var left = table[ii][jj - 1] + 1; - table[ii][jj] = Math.min(left, top, diag); - } - } - } - return table[a.length][b.length]; -} - - -},{}],46:[function(require,module,exports){ -module.exports = suggestDictionary; - -var distance = require('./levenstein_distance'); - -function suggestDictionary(dict, opts) { - opts = opts || {}; - var threshold = opts.threshold || 0.5; - return function suggest(word) { - var length = word.length; - return dict.reduce(function (result, dictEntry) { - var score = distance(dictEntry, word); - if (result.score > score && score / length < threshold) { - result.score = score; - result.word = dictEntry; - } - return result; - }, { score: Infinity }).word; - }; -} - -suggestDictionary.distance = distance; - -},{"./levenstein_distance":45}],47:[function(require,module,exports){ -/** -* HintLog creates a queue of messages logged by ngHint modules. This object -* has a key for each ngHint module that corresponds to the messages -* from that module. -*/ -var queuedMessages = {}, - MESSAGE_TYPES = [ - 'error', - 'warning', - 'suggestion' - ]; - -/** -* Add a message to the HintLog message queue. Messages are organized into categories -* according to their module name and severity. -**/ -function logMessage(moduleName, message, severity, category) { - // If no severity was provided, categorize the message as a `suggestion` - severity = severity || 3; - var messageType = MESSAGE_TYPES[severity - 1]; - - // If no ModuleName was found, categorize the message under `General` - moduleName = moduleName || 'General'; - - // If the category does not exist, initialize a new object - queuedMessages[moduleName] = queuedMessages[moduleName] || {}; - queuedMessages[moduleName][messageType] = queuedMessages[moduleName][messageType] || []; - - if (queuedMessages[moduleName][messageType].indexOf(message) < 0) { - queuedMessages[moduleName][messageType].push(message); - } - - module.exports.onMessage(moduleName, message, messageType, category); -} - -/** -* Return and empty the current queue of messages. -**/ -function flush() { - var flushMessages = queuedMessages; - queuedMessages = {}; - return flushMessages; -} - -module.exports.onMessage = function(message) {}; -module.exports.logMessage = logMessage; -module.exports.flush = flush; - -},{}],48:[function(require,module,exports){ -'use strict'; - -var storeDependencies = require('./lib/storeDependencies'), - getModule = require('./lib/getModule'), - start = require('./lib/start'), - storeNgAppAndView = require('./lib/storeNgAppAndView'), - storeUsedModules = require('./lib/storeUsedModules'), - hasNameSpace = require('./lib/hasNameSpace'), - modData = require('./lib/moduleData'); - -var doc = Array.prototype.slice.call(document.getElementsByTagName('*')), - originalAngularModule = angular.module, - modules = {}; - -storeNgAppAndView(doc); - -angular.module = function() { - var requiresOriginal = arguments[1], - module = originalAngularModule.apply(this, arguments), - name = module.name; - module.requiresOriginal = requiresOriginal; - modules[name] = module; - hasNameSpace(name); - var modToCheck = getModule(name, true); - - if(modToCheck && modToCheck.requiresOriginal !== module.requiresOriginal) { - if(!modData.createdMulti[name]) { - modData.createdMulti[name] = [getModule(name,true)]; - } - modData.createdMulti[name].push(module); - } - modData.createdModules[name] = module; - return module; -}; - -angular.module('ngHintModules', []).config(function() { - var ngAppMod = modules[modData.ngAppMod]; - storeUsedModules(ngAppMod, modules); - start(); -}); - -},{"./lib/getModule":51,"./lib/hasNameSpace":55,"./lib/moduleData":57,"./lib/start":60,"./lib/storeDependencies":61,"./lib/storeNgAppAndView":62,"./lib/storeUsedModules":63}],49:[function(require,module,exports){ -var hintLog = angular.hint = require('angular-hint-log'), - MODULE_NAME = 'Modules'; - -module.exports = function(modules) { - modules.forEach(function(module) { - hintLog.logMessage(MODULE_NAME, module.message, module.severity); - }); -}; - -},{"angular-hint-log":47}],50:[function(require,module,exports){ -var modData = require('./moduleData'); - MODULE_NAME = 'Modules', - SEVERITY_WARNING = 2; - -module.exports = function() { - var multiLoaded = []; - for(var modName in modData.createdMulti) { - var message = 'Multiple modules with name "' + modName + '" are being created and they will ' + - 'overwrite each other.'; - var multi = modData.createdMulti[modName]; - var multiLength = multi.length; - var details = { - existingModule: multi[multiLength - 1], - overwrittenModules: multi.slice(0, multiLength - 1) - }; - multiLoaded - .push({module: details, message: message, name: MODULE_NAME, severity: SEVERITY_WARNING}); - } - return multiLoaded; -}; - -},{"./moduleData":57}],51:[function(require,module,exports){ -var modData = require('./moduleData'); - -module.exports = function(moduleName, getCreated) { - return (getCreated)? modData.createdModules[moduleName] : modData.loadedModules[moduleName]; -}; - -},{"./moduleData":57}],52:[function(require,module,exports){ -var hintLog = angular.hint = require('angular-hint-log'), - MODULE_NAME = 'Modules', - SEVERITY_ERROR = 1; - module.exports = function(attrs, ngAppFound) { - if(attrs['ng-app'] && ngAppFound) { - hintLog.logMessage(MODULE_NAME, 'ng-app may only be included once. The module "' + - attrs['ng-app'].value + '" was not used to bootstrap because ng-app was already included.', - SEVERITY_ERROR); - } - return attrs['ng-app'] ? attrs['ng-app'].value : undefined; - }; - - - -},{"angular-hint-log":47}],53:[function(require,module,exports){ -var getModule = require('./getModule'), - dictionary = Object.keys(require('./moduleData').createdModules), - suggest = require('suggest-it')(dictionary), - SEVERITY_ERROR = 1; - -module.exports = function(loadedModules) { - var undeclaredModules = []; - for(var module in loadedModules) { - var cModule = getModule(module, true); - if(!cModule) { - var match = suggest(module), - suggestion = (match) ? '; Try: "'+match+'"' : '', - message = 'Module "'+module+'" was loaded but does not exist'+suggestion+'.'; - - undeclaredModules.push({module: null, message: message, severity: SEVERITY_ERROR}); - } - } - return undeclaredModules; -}; - -},{"./getModule":51,"./moduleData":57,"suggest-it":65}],54:[function(require,module,exports){ -var getModule = require('./getModule'), - IGNORED = ['ngHintControllers', 'ngHintDirectives', 'ngHintDOM', 'ngHintEvents', - 'ngHintInterpolation', 'ngHintModules']; - SEVERITY_WARNING = 2; - -module.exports = function(createdModules) { - var unusedModules = []; - for(var module in createdModules) { - if(!getModule(module)) { - var cModule = createdModules[module], - message = 'Module "' + cModule.name + '" was created but never loaded.'; - if(IGNORED.indexOf(cModule.name) === -1) { - unusedModules.push({module: cModule, message: message, severity: SEVERITY_WARNING}); - } - } - } - return unusedModules; -}; - -},{"./getModule":51}],55:[function(require,module,exports){ -var hintLog = angular.hint = require('angular-hint-log'), - MODULE_NAME = 'Modules', - SEVERITY_SUGGESTION = 3; -module.exports = function(str) { - if(str.toLowerCase() === str || str.charAt(0).toUpperCase() === str.charAt(0)) { - hintLog.logMessage(MODULE_NAME, 'The best practice for' + - ' module names is to use lowerCamelCase. Check the name of "' + str + '".', - SEVERITY_SUGGESTION); - return false; - } - return true; -}; - -},{"angular-hint-log":47}],56:[function(require,module,exports){ -var normalizeAttribute = require('./normalizeAttribute'); - -module.exports = function(attrs) { - for(var i = 0, length = attrs.length; i < length; i++) { - if(normalizeAttribute(attrs[i].nodeName) === 'ng-view' || - attrs[i].value.indexOf('ng-view') > -1) { - return true; - } - } -}; - -},{"./normalizeAttribute":59}],57:[function(require,module,exports){ -module.exports = { - createdModules: {}, - createdMulti: {}, - loadedModules: {} -}; - -},{}],58:[function(require,module,exports){ -var modData = require('./moduleData'), - getModule = require('./getModule'); - -module.exports = function() { - if(modData.ngViewExists && !getModule('ngRoute')) { - return {message: 'Directive "ngView" was used in the application however "ngRoute" was not loaded into any module.'}; - } -}; - -},{"./getModule":51,"./moduleData":57}],59:[function(require,module,exports){ -module.exports = function(attribute) { - return attribute.replace(/^(?:data|x)[-_:]/, '').replace(/[:_]/g, '-'); -}; - -},{}],60:[function(require,module,exports){ -var display = require('./display'), - formatMultiLoaded = require('./formatMultiLoaded'), - getUnusedModules = require('./getUnusedModules'), - getUndeclaredModules = require('./getUndeclaredModules'), - modData = require('./moduleData'), - ngViewNoNgRoute = require('./ngViewNoNgRoute'); - -module.exports = function() { - var unusedModules = getUnusedModules(modData.createdModules), - undeclaredModules = getUndeclaredModules(modData.loadedModules), - multiLoaded = formatMultiLoaded(), - noNgRoute = ngViewNoNgRoute(); - if(unusedModules.length || undeclaredModules.length || multiLoaded.length || noNgRoute) { - var toSend = unusedModules.concat(undeclaredModules) - .concat(multiLoaded); - if(noNgRoute) { - toSend = toSend.concat(noNgRoute); - } - display(toSend); - } -}; - -},{"./display":49,"./formatMultiLoaded":50,"./getUndeclaredModules":53,"./getUnusedModules":54,"./moduleData":57,"./ngViewNoNgRoute":58}],61:[function(require,module,exports){ -var modData = require('./moduleData'); - -module.exports = function(module, isNgAppMod) { - var name = module.name || module; - if(!isNgAppMod){ - module.requires.forEach(function(dependency){ - modData.loadedModules[dependency] = dependency; - }); - } - else { - modData.loadedModules[name] = name; - modData.ngAppMod = name; - } -}; - -},{"./moduleData":57}],62:[function(require,module,exports){ -var getNgAppMod = require('./getNgAppMod'), - inAttrsOrClasses = require('./inAttrsOrClasses'), - storeDependencies = require('./storeDependencies'), - modData = require('./moduleData'); - -module.exports = function(doms) { - var bothFound, - ngViewFound, - elem, - isElemName, - isInAttrsOrClasses, - ngAppMod; - - for(var i = 0; i < doms.length; i++) { - elem = doms[i]; - var attributes = elem.attributes; - isElemName = elem.nodeName.toLowerCase() === 'ng-view'; - isInAttrsOrClasses = inAttrsOrClasses(attributes); - - ngViewFound = isElemName || isInAttrsOrClasses; - - ngAppMod = getNgAppMod(attributes, modData.ngAppFound); - modData.ngAppFound = modData.ngAppFound || ngAppMod; - - if(ngAppMod) { - storeDependencies(ngAppMod, true); - } - modData.ngViewExists = ngViewFound ? true : modData.ngViewExists; - - if(bothFound) { - break; - } - } -}; - -},{"./getNgAppMod":52,"./inAttrsOrClasses":56,"./moduleData":57,"./storeDependencies":61}],63:[function(require,module,exports){ -var storeDependencies = require('./storeDependencies'); - -var storeUsedModules = module.exports = function(module, modules){ - if(module) { - storeDependencies(module); - module.requires.forEach(function(modName) { - var mod = modules[modName]; - storeUsedModules(mod, modules); - }); - } -}; -},{"./storeDependencies":61}],64:[function(require,module,exports){ -module.exports=require(45) -},{"/usr/local/google/home/sjelin/angular-hint/node_modules/angular-hint-events/node_modules/suggest-it/lib/levenstein_distance.js":45}],65:[function(require,module,exports){ -module.exports=require(46) -},{"./levenstein_distance":64,"/usr/local/google/home/sjelin/angular-hint/node_modules/angular-hint-events/node_modules/suggest-it/lib/suggest-it.js":46}],66:[function(require,module,exports){ -'use strict'; - -var summarize = require('./lib/summarize-model'); -var hint = angular.hint = require('angular-hint-log'); -var debounceOn = require('debounce-on'); - -hint.emit = function () {}; - -module.exports = angular.module('ngHintScopes', []).config(['$provide', function ($provide) { - $provide.decorator('$rootScope', ['$delegate', '$parse', decorateRootScope]); - $provide.decorator('$compile', ['$delegate', decorateDollaCompile]); -}]); - -function decorateRootScope($delegate, $parse) { - - var perf = window.performance || { now: function () { return 0; } }; - - var scopes = {}, - watching = {}; - - var debouncedEmitModelChange = debounceOn(emitModelChange, 10, byScopeId); - - hint.watch = function (scopeId, path) { - path = typeof path === 'string' ? path.split('.') : path; - - if (!watching[scopeId]) { - watching[scopeId] = {}; - } - - for (var i = 1, ii = path.length; i <= ii; i += 1) { - var partialPath = path.slice(0, i).join('.'); - if (watching[scopeId][partialPath]) { - continue; - } - var get = gettterer(scopeId, partialPath); - var value = summarize(get()); - watching[scopeId][partialPath] = { - get: get, - value: value - }; - hint.emit('model:change', { - id: scopeId, - path: partialPath, - value: value - }); - } - }; - - hint.unwatch = function (scopeId, unwatchPath) { - Object.keys(watching[scopeId]). - forEach(function (path) { - if (path.indexOf(unwatchPath) === 0) { - delete watching[scopeId][path]; - } - }); - }; - - var debouncedEmit = debounceOn(hint.emit, 10, function (params) { - return params.id + params.path; - }); - - - var scopePrototype = ('getPrototypeOf' in Object) ? - Object.getPrototypeOf($delegate) : $delegate.__proto__; - - var _watch = scopePrototype.$watch; - scopePrototype.$watch = function (watchExpression, reactionFunction) { - var watchStr = humanReadableWatchExpression(watchExpression); - var scopeId = this.$id; - if (typeof watchExpression === 'function') { - arguments[0] = function () { - var start = perf.now(); - var ret = watchExpression.apply(this, arguments); - var end = perf.now(); - hint.emit('scope:watch', { - id: scopeId, - watch: watchStr, - time: end - start - }); - return ret; - }; - } else { - var thatScope = this; - arguments[0] = function () { - var start = perf.now(); - var ret = thatScope.$eval(watchExpression); - var end = perf.now(); - hint.emit('scope:watch', { - id: scopeId, - watch: watchStr, - time: end - start - }); - return ret; - }; - } - - if (typeof reactionFunction === 'function') { - var applyStr = reactionFunction.toString(); - arguments[1] = function () { - var start = perf.now(); - var ret = reactionFunction.apply(this, arguments); - var end = perf.now(); - hint.emit('scope:reaction', { - id: this.$id, - watch: watchStr, - time: end - start - }); - return ret; - }; - } - - return _watch.apply(this, arguments); - }; - - - var _destroy = scopePrototype.$destroy; - scopePrototype.$destroy = function () { - var id = this.id; - - hint.emit('scope:destroy', { id: id }); - - delete scopes[id]; - delete watching[id]; - - return _destroy.apply(this, arguments); - }; - - - var _new = scopePrototype.$new; - scopePrototype.$new = function () { - var child = _new.apply(this, arguments); - - scopes[child.$id] = child; - watching[child.$id] = {}; - - hint.emit('scope:new', { parent: this.$id, child: child.$id }); - setTimeout(function () { - emitScopeElt(child); - }, 0); - return child; - }; - - function emitScopeElt (scope) { - var scopeId = scope.$id; - var elt = findElt(scopeId); - var descriptor = scopeDescriptor(elt, scope); - hint.emit('scope:link', { - id: scopeId, - descriptor: descriptor - }); - } - - function findElt (scopeId) { - var elts = document.querySelectorAll('.ng-scope'); - var elt, scope; - - for (var i = 0; i < elts.length; i++) { - elt = angular.element(elts[i]); - scope = elt.scope(); - if (scope.$id === scopeId) { - return elt; - } - } - } - - - var _digest = scopePrototype.$digest; - scopePrototype.$digest = function (fn) { - var start = perf.now(); - var ret = _digest.apply(this, arguments); - var end = perf.now(); - hint.emit('scope:digest', { id: this.$id, time: end - start }); - return ret; - }; - - - var _apply = scopePrototype.$apply; - scopePrototype.$apply = function (fn) { - var start = perf.now(); - var ret = _apply.apply(this, arguments); - var end = perf.now(); - hint.emit('scope:apply', { id: this.$id, time: end - start }); - debouncedEmitModelChange(this); - return ret; - }; - - - function gettterer (scopeId, path) { - if (path === '') { - return function () { - return scopes[scopeId]; - }; - } - var getter = $parse(path); - return function () { - return getter(scopes[scopeId]); - }; - } - - function emitModelChange (scope) { - var scopeId = scope.$id; - if (watching[scopeId]) { - Object.keys(watching[scopeId]).forEach(function (path) { - var model = watching[scopeId][path]; - var value = summarize(model.get()); - if (value !== model.value) { - hint.emit('model:change', { - id: scope.$id, - path: path, - oldValue: model.value, - value: value - }); - model.value = value; - } - }); - } - } - - hint.emit('scope:new', { - parent: null, - child: $delegate.$id - }); - scopes[$delegate.$id] = $delegate; - watching[$delegate.$id] = {}; - - return $delegate; -} - -function decorateDollaCompile ($delegate) { - return function () { - var link = $delegate.apply(this, arguments); - - return function (scope) { - var elt = link.apply(this, arguments); - var descriptor = scopeDescriptor(elt, scope); - hint.emit('scope:link', { - id: scope.$id, - descriptor: descriptor - }); - return elt; - } - } -} - -function scopeDescriptor (elt, scope) { - var val, - types = [ - 'ng-app', - 'ng-controller', - 'ng-repeat', - 'ng-include' - ], - theseTypes = [], - type; - - if (elt) { - for (var i = 0; i < types.length; i++) { - type = types[i]; - if (val = elt.attr(type)) { - theseTypes.push(type + '="' + val + '"'); - } - } - } - if (theseTypes.length === 0) { - return 'scope.$id=' + scope.$id; - } else { - return theseTypes.join(' '); - } -} - -function byScopeId (scope) { - return scope.$id; -} - -function humanReadableWatchExpression (fn) { - if (fn.exp) { - fn = fn.exp; - } else if (fn.name) { - fn = fn.name; - } - return fn.toString(); -} - -},{"./lib/summarize-model":67,"angular-hint-log":47,"debounce-on":68}],67:[function(require,module,exports){ - -module.exports = function summarizeModel (model) { - - if (model instanceof Array) { - return JSON.stringify(model.map(summarizeProperty)); - } else if (typeof model === 'object') { - return JSON.stringify(Object. - keys(model). - filter(isAngularPrivatePropertyName). - reduce(shallowSummary, {})); - } else { - return model; - } - - function shallowSummary (obj, prop) { - obj[prop] = summarizeProperty(model[prop]); - return obj; - } -}; - -function isAngularPrivatePropertyName (key) { - return !(key[0] === '$' && key[1] === '$') && key !== '$parent' && key !== '$root'; -} - -// TODO: handle DOM nodes, fns, etc better. -function summarizeProperty (obj) { - return obj instanceof Array ? - { '~array-length': obj.length } : - obj === null ? - null : - typeof obj === 'object' ? - { '~object': true } : - obj; -} - -},{}],68:[function(require,module,exports){ -module.exports = function debounceOn (fn, timeout, hash) { - var timeouts = {}; - - timeout = typeof timeout === 'number' ? timeout : (hash = timeout, 100); - hash = typeof hash === 'function' ? hash : defaultHash; - - return function () { - var key = hash.apply(null, arguments); - var args = arguments; - if (typeof timeouts[key] === 'undefined') { - timeouts[key] = setTimeout(function () { - delete timeouts[key]; - fn.apply(null, args); - }, timeout); - } - return function cancel () { - if (timeouts[key]) { - clearTimeout(timeouts[key]); - delete timeouts[key]; - return true; - } - return false; - }; - }; -}; - -function defaultHash () { - return Array.prototype.join.call(arguments, '::'); -} - -},{}]},{},[1]); diff --git a/testapp/ngHint/noNgHint.html b/testapp/ngHint/noNgHint.html deleted file mode 100644 index b15e05299..000000000 --- a/testapp/ngHint/noNgHint.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - Angular.js Example - - - - - - First name: -
- Last name: -
- Hello {{firstName}} {{lastName}} - - diff --git a/testapp/ngHint/noTag.html b/testapp/ngHint/noTag.html deleted file mode 100644 index 29aeed91a..000000000 --- a/testapp/ngHint/noTag.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - Angular.js Example - - - - - - - First name: -
- Last name: -
- Hello {{firstName}} {{lastName}} - - diff --git a/testapp/ngHint/unused.html b/testapp/ngHint/unused.html deleted file mode 100644 index 58475a888..000000000 --- a/testapp/ngHint/unused.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - Angular.js Example - - - - - - - First name: -
- Last name: -
- Hello {{firstName}} {{lastName}} - -