Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Commit

Permalink
fix(element chaining): make element chaining work when the control fl…
Browse files Browse the repository at this point in the history
…ow is disabled (#4029)

Also added some tests to `spec/ts/noCF/smoke_spec.ts` double checking that the control flow is off
  • Loading branch information
sjelin authored Jan 30, 2017
1 parent 8d2fc07 commit a20c7a7
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 39 deletions.
36 changes: 24 additions & 12 deletions lib/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,18 +482,30 @@ export class ElementArrayFinder extends WebdriverWebElement {
let callerError = new Error();
let actionResults = this.getWebElements()
.then((arr: any) => wdpromise.all(arr.map(actionFn)))
.then(null, (e: IError | string) => {
let noSuchErr: any;
if (e instanceof Error) {
noSuchErr = e;
noSuchErr.stack = noSuchErr.stack + callerError.stack;
} else {
noSuchErr = new Error(e as string);
noSuchErr.stack = callerError.stack;
}
throw noSuchErr;
});
return new ElementArrayFinder(this.browser_, this.getWebElements, this.locator_, actionResults);
.then(
(value: any) => {
return {passed: true, value: value};
},
(error: any) => {
return {passed: false, value: error};
});
let getWebElements = () => actionResults.then(() => this.getWebElements());
actionResults = actionResults.then((result: {passed: boolean, value: any}) => {
if (result.passed) {
return result.value;
} else {
let noSuchErr: any;
if (result.value instanceof Error) {
noSuchErr = result.value;
noSuchErr.stack = noSuchErr.stack + callerError.stack;
} else {
noSuchErr = new Error(result.value as string);
noSuchErr.stack = callerError.stack;
}
throw noSuchErr;
}
});
return new ElementArrayFinder(this.browser_, getWebElements, this.locator_, actionResults);
}

/**
Expand Down
98 changes: 71 additions & 27 deletions spec/ts/noCF/smoke_spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
// Based off of spec/basic/elements_spec.js
import {promise as ppromise, browser, element, by, By, $, $$, ExpectedConditions, ElementFinder} from '../../..';
import * as q from 'q';

import {$, $$, browser, by, By, element, ElementArrayFinder, ElementFinder, ExpectedConditions, promise as ppromise, WebElement} from '../../..';

describe('verify control flow is off', function() {
it('should have set webdriver.promise.USE_PROMISE_MANAGER', () => {
expect((ppromise as any).USE_PROMISE_MANAGER).toBe(false);
});

it('should not wait on one command before starting another', async function() {
// Wait forever
browser.controlFlow().wait(
(browser.controlFlow() as any).promise((): void => undefined) as ppromise.Promise<void>);

// then return
await browser.controlFlow().execute(() => ppromise.when(null));
});
});

describe('ElementFinder', function() {
it('should return the same result as browser.findElement', async function() {
await browser.get('index.html#/form');
const nameByElement = element(by.binding('username'));

await expect(nameByElement.getText()).toEqual(
browser.findElement(by.binding('username')).getText());
await expect(nameByElement.getText())
.toEqual(browser.findElement(by.binding('username')).getText());
});

it('should wait to grab the WebElement until a method is called', async function() {
Expand All @@ -32,38 +49,65 @@ describe('ElementFinder', function() {

await expect(name.getText()).toEqual('Anon');

await ((usernameInput.clear() as any) as ElementFinder).sendKeys('Jane');
await((usernameInput.clear() as any) as ElementFinder).sendKeys('Jane');
await expect(name.getText()).toEqual('Jane');
});

it('chained call should wait to grab the WebElement until a method is called',
async function() {
it('should run chained element actions in sequence', function(done: any) {
// Testing private methods is bad :(
let els = new ElementArrayFinder(browser, () => {
return ppromise.when([null as WebElement]);
});
let applyAction_: (actionFn: (value: WebElement, index: number, array: WebElement[]) => any) =>
ElementArrayFinder = (ElementArrayFinder as any).prototype.applyAction_;
let order: string[] = [];

let deferredA = q.defer<void>();
els = applyAction_.call(els, () => {
return deferredA.promise.then(() => {
order.push('a');
});
});
let deferredB = q.defer<void>();
els = applyAction_.call(els, () => {
return deferredB.promise.then(() => {
order.push('b');
});
});

deferredB.resolve();
setTimeout(async function() {
deferredA.resolve();
await els;
expect(order).toEqual(['a', 'b']);
done();
}, 100);
});

it('chained call should wait to grab the WebElement until a method is called', async function() {
// These should throw no error before a page is loaded.
const reused = element(by.id('baz')).
element(by.binding('item.reusedBinding'));
const reused = element(by.id('baz')).element(by.binding('item.reusedBinding'));

await browser.get('index.html#/conflict');

await expect(reused.getText()).toEqual('Inner: inner');
await expect(reused.isPresent()).toBe(true);
});

it('should differentiate elements with the same binding by chaining',
async function() {
await browser.get('index.html#/conflict');
it('should differentiate elements with the same binding by chaining', async function() {
await browser.get('index.html#/conflict');

const outerReused = element(by.binding('item.reusedBinding'));
const innerReused =
element(by.id('baz')).element(by.binding('item.reusedBinding'));
const outerReused = element(by.binding('item.reusedBinding'));
const innerReused = element(by.id('baz')).element(by.binding('item.reusedBinding'));

await expect(outerReused.getText()).toEqual('Outer: outer');
await expect(innerReused.getText()).toEqual('Inner: inner');
});
await expect(outerReused.getText()).toEqual('Outer: outer');
await expect(innerReused.getText()).toEqual('Inner: inner');
});

it('should chain deeper than 2', async function() {
// These should throw no error before a page is loaded.
const reused = element(by.css('body')).element(by.id('baz')).
element(by.binding('item.reusedBinding'));
const reused =
element(by.css('body')).element(by.id('baz')).element(by.binding('item.reusedBinding'));

await browser.get('index.html#/conflict');

Expand Down Expand Up @@ -108,11 +152,13 @@ describe('ElementFinder', function() {
await browser.get('index.html#/form');

const invalidElement = element(by.binding('INVALID'));
const successful = invalidElement.getText().then(function() {
return true;
} as any as (() => ppromise.Promise<void>), function() {
return false;
} as any as (() => ppromise.Promise<void>));
const successful = invalidElement.getText().then(
function() {
return true;
} as any as (() => ppromise.Promise<void>),
function() {
return false;
} as any as (() => ppromise.Promise<void>));
await expect(successful).toEqual(false);
});

Expand All @@ -139,9 +185,7 @@ describe('ElementFinder', function() {
const name = element(by.binding('username'));

await expect(name.getText()).toEqual('Anon');
await expect(
name.getText().then(null, function() {})
).toEqual('Anon');
await expect(name.getText().then(null, function() {})).toEqual('Anon');

});

Expand Down

0 comments on commit a20c7a7

Please sign in to comment.