From c025ddbe617b977908db509f365cc882924b196f Mon Sep 17 00:00:00 2001 From: Jeremy Morony & Tommy Fisher Date: Mon, 7 Oct 2013 15:52:50 -0700 Subject: [PATCH] feat(findElements): $ & $$ shortcuts. Introducing the $ shortcut method for finding a single element by css without having to call protractor.By.css. Additionally $$ for finding all elements by css. Examples: - ptor.$('.some .selector') - ptor.$$('.some .selector') --- lib/protractor.js | 50 ++++++++++++ spec/findelements_spec.js | 166 +++++++++++++++++++++++++++----------- 2 files changed, 167 insertions(+), 49 deletions(-) diff --git a/lib/protractor.js b/lib/protractor.js index a68b229fc..77a0bb046 100644 --- a/lib/protractor.js +++ b/lib/protractor.js @@ -146,6 +146,18 @@ Protractor.prototype.wrapWebElement = function(element) { var originalFindElements = element.findElements; var originalIsElementPresent = element.isElementPresent; + /** + * Shortcut for querying the document directly with css. + * + * @param {string} selector a css selector + * @see webdriver.WebElement.findElement + * @return {!webdriver.WebElement} + */ + element.$ = function(selector) { + var locator = protractor.By.css(selector); + return this.findElement(locator); + } + /** * @see webdriver.WebElement.findElement * @return {!webdriver.WebElement} @@ -163,6 +175,19 @@ Protractor.prototype.wrapWebElement = function(element) { return thisPtor.wrapWebElement(found); }; + /** + * Shortcut for querying the document directly with css. + * + * @param {string} selector a css selector + * @see webdriver.WebElement.findElements + * @return {!webdriver.promise.Promise} A promise that will be resolved to an + * array of the located {@link webdriver.WebElement}s. + */ + element.$$ = function(selector) { + var locator = protractor.By.css(selector); + return this.findElements(locator); + } + /** * @see webdriver.WebElement.findElements * @return {!webdriver.promise.Promise} A promise that will be resolved to an @@ -222,6 +247,18 @@ Protractor.prototype.wrapWebElement = function(element) { return element; }; +/** + * Shortcut for querying the document directly with css. + * + * @param {string} selector a css selector + * @see webdriver.WebDriver.findElement + * @return {!webdriver.WebElement} + */ +Protractor.prototype.$ = function(selector) { + var locator = protractor.By.css(selector); + return this.findElement(locator); +}; + /** * Waits for Angular to finish rendering before searching for elements. * @see webdriver.WebDriver.findElement @@ -240,6 +277,19 @@ Protractor.prototype.findElement = function(locator, varArgs) { return this.wrapWebElement(found); }; +/** + * Shortcut for querying the document directly with css. + * + * @param {string} selector a css selector + * @see webdriver.WebDriver.findElements + * @return {!webdriver.promise.Promise} A promise that will be resolved to an + * array of the located {@link webdriver.WebElement}s. + */ +Protractor.prototype.$$ = function(selector) { + var locator = protractor.By.css(selector); + return this.findElements(locator); +}; + /** * Waits for Angular to finish rendering before searching for elements. * @see webdriver.WebDriver.findElements diff --git a/spec/findelements_spec.js b/spec/findelements_spec.js index e907e68a6..f7c5e8718 100644 --- a/spec/findelements_spec.js +++ b/spec/findelements_spec.js @@ -278,24 +278,120 @@ describe('finding elements', function() { // Make sure it works with a promise expectation. expect(element.evaluate('planet.radius')).toEqual(1516); }); + }); + + describe('finding an element by css', function() { + beforeEach(function() { + ptor.get('app/index.html#/bindings'); + }); + + describe('via the driver', function() { + it('should return the same results as web driver', function() { + ptor.findElement(protractor.By.css('.planet-info')).getText().then(function(textFromLongForm) { + var textFromShortcut = ptor.$('.planet-info').getText(); + expect(textFromShortcut).toEqual(textFromLongForm); + }); + }); + }); + + describe('via a web element', function() { + var select; + + beforeEach(function() { + select = ptor.findElement(protractor.By.css('select')); + }); + + it('should return the same results as web driver', function() { + select.findElement(protractor.By.css('option[value="4"]')).getText().then(function(textFromLongForm) { + var textFromShortcut = select.$('option[value="4"]').getText(); + expect(textFromShortcut).toEqual(textFromLongForm); + }); + }); + }); + }); + + describe('finding elements by css', function() { + beforeEach(function() { + ptor.get('app/index.html#/bindings'); + }); + + describe('via the driver', function() { + it('should return the same results as web driver', function() { + ptor.findElements(protractor.By.css('option')).then(function(optionsFromLongForm) { + ptor.$$('option').then(function(optionsFromShortcut) { + expect(optionsFromShortcut.length).toEqual(optionsFromLongForm.length); + + optionsFromLongForm.forEach(function(option, i) { + option.getText().then(function(textFromLongForm) { + expect(optionsFromShortcut[i].getText()).toEqual(textFromLongForm); + }); + }); + }); + }); + }); + }); + + describe('via a web element', function() { + var select; + + beforeEach(function() { + select = ptor.findElement(protractor.By.css('select')); + }); - describe('when wrapping all elements', function() { - describe('when querying using a locator that specifies an override', function() { + it('should return the same results as web driver', function() { + select.findElements(protractor.By.css('option')).then(function(optionsFromLongForm) { + select.$$('option').then(function(optionsFromShortcut) { + expect(optionsFromShortcut.length).toEqual(optionsFromLongForm.length); + + optionsFromLongForm.forEach(function(option, i) { + option.getText().then(function(textFromLongForm) { + expect(optionsFromShortcut[i].getText()).toEqual(textFromLongForm); + }); + }); + }); + }); + }); + }); + }); + + describe('wrapping web driver elements', function() { + var verifyMethodsAdded = function(result) { + expect(typeof result.evaluate).toBe('function'); + expect(typeof result.$).toBe('function'); + expect(typeof result.$$).toBe('function'); + } + + beforeEach(function() { + ptor.get('app/index.html#/bindings'); + }); + + describe('when found via #findElement', function() { + describe('when using a locator that specifies an override', function() { + it('should wrap the result', function() { + ptor.findElement(protractor.By.binding('planet.name')).then(verifyMethodsAdded); + }); + }); + + describe('when using a locator that does not specify an override', function() { + it('should wrap the result', function() { + ptor.findElement(protractor.By.css('option[value="4"]')).then(verifyMethodsAdded); + }); + }); + }); + + describe('when found via #findElements', function() { + describe('when using a locator that specifies an override', function() { it('should wrap the results', function() { - ptor.findElements(protractor.By.binding('planet.name')).then(function(elements) { - for (var i = 0; i < elements.length; i++) { - expect(typeof elements[i].evaluate).toBe('function'); - } + ptor.findElements(protractor.By.binding('planet.name')).then(function(results) { + results.forEach(verifyMethodsAdded); }); }); }); - describe('when querying using a locator that does not specify an override', function() { + describe('when using a locator that does not specify an override', function() { it('should wrap the results', function() { - ptor.findElements(protractor.By.css('option[value="4"]')).then(function(elements) { - for (var i = 0; i < elements.length; i++) { - expect(typeof elements[i].evaluate).toBe('function'); - } + ptor.findElements(protractor.By.css('option[value="4"]')).then(function(results) { + results.forEach(verifyMethodsAdded); }); }); }); @@ -308,61 +404,33 @@ describe('finding elements', function() { info = ptor.findElement(protractor.By.css('.planet-info')); }); - describe('when querying for a single element', function() { - describe('when ng using a locator that specifies an override', function() { - var planetName; - - beforeEach(function() { - planetName = info.findElement(protractor.By.binding('planet.name')); - }); - + describe('when found via #findElement', function() { + describe('when using a locator that specifies an override', function() { it('should wrap the result', function() { - expect(typeof planetName.evaluate).toBe("function") + info.findElement(protractor.By.binding('planet.name')).then(verifyMethodsAdded); }); }); - describe('when querying using a locator that does not specify an override', function() { - var moons; - - beforeEach(function() { - moons = info.findElement(protractor.By.css('div:last-child')); - }); - + describe('when using a locator that does not specify an override', function() { it('should wrap the result', function() { - expect(typeof moons.evaluate).toBe("function") + info.findElement(protractor.By.css('div:last-child')).then(verifyMethodsAdded); }); }); }); describe('when querying for many elements', function() { describe('when using a locator that specifies an override', function() { - var planetName; - - beforeEach(function() { - planetName = info.findElements(protractor.By.binding('planet.name')); - }); - it('should wrap the result', function() { - planetName.then(function(result) { - for (var i = 0; i < result.length; ++i) { - expect(typeof result[i].evaluate).toBe("function"); - } + info.findElements(protractor.By.binding('planet.name')).then(function(results) { + results.forEach(verifyMethodsAdded); }); }); }); - describe('when querying using a locator that does not specify an override', function() { - var moons; - - beforeEach(function() { - moons = info.findElements(protractor.By.css('div:last-child')); - }); - + describe('when using a locator that does not specify an override', function() { it('should wrap the result', function() { - moons.then(function(result) { - for (var i = 0; i < result.length; ++i) { - expect(typeof result[i].evaluate).toBe("function"); - } + info.findElements(protractor.By.css('div:last-child')).then(function(results) { + results.forEach(verifyMethodsAdded); }); }); });