Skip to content

Commit

Permalink
Fixed #3989 – Unable to fetch elements with reference to a ShadowRoot
Browse files Browse the repository at this point in the history
  • Loading branch information
garg3133 committed Jan 24, 2024
1 parent 5670d57 commit e193d19
Show file tree
Hide file tree
Showing 4 changed files with 524 additions and 7 deletions.
14 changes: 10 additions & 4 deletions lib/api/web-element/scoped-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,15 @@ class ScopedWebElement {
const createLocateElement = () => {
return parentElement && parentElement.webElement ? function(locator) {
return new Condition('for at least one element to be located ' + locator, function (driver) {
return parentElement.webElement.findElements(locator).then(function (elements) {
return elements.length > 0 ? elements : null;
});
return parentElement.webElement
.then(function (webElement) {
// also takes into consideration if `webElement`
// resolves to a shadow root.
return webElement.findElements(locator);
})
.then(function (elements) {
return elements.length > 0 ? elements : null;
});
});
} : until.elementsLocated;
};
Expand All @@ -111,7 +117,7 @@ class ScopedWebElement {
while (allElements.length > 0) {
const nextElement = allElements.shift();
if (result) {
parentElement = {webElement: result};
parentElement = {webElement: Promise.resolve(result)};
}

const {condition, index} = ScopedElementLocator.create(nextElement, this.nightwatchInstance);
Expand Down
11 changes: 8 additions & 3 deletions lib/api/web-element/scoped-elements.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,14 @@ class ScopedElements {
}

async findElements({parentElement, selector, timeout, retryInterval}) {
const webElements = parentElement && parentElement.webElement
? await parentElement.webElement.findElements(selector)
: await this.nightwatchInstance.transport.driver.wait(until.elementsLocated(selector), timeout, null, retryInterval);
let webElements;

if (parentElement && parentElement.webElement) {
const parentWebElement = await parentElement.webElement;
webElements = await parentWebElement.findElements(selector);
} else {
webElements = await this.nightwatchInstance.transport.driver.wait(until.elementsLocated(selector), timeout, null, retryInterval);
}

return webElements;
}
Expand Down
190 changes: 190 additions & 0 deletions test/src/api/commands/web-element/testShadowFind.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
const assert = require('assert');
const {WebElement} = require('selenium-webdriver');
const {ShadowRoot} = require('selenium-webdriver/lib/webdriver.js');
const MockServer = require('../../../../lib/mockserver.js');
const CommandGlobals = require('../../../../lib/globals/commands-w3c.js');
const common = require('../../../../common.js');
const Element = common.require('element/index.js');

describe('element().shadow().find() commands', function () {
before(function (done) {
CommandGlobals.beforeEach.call(this, done);
});

after(function (done) {
CommandGlobals.afterEach.call(this, done);
});

it('test .element().shadow().find()', async function() {
MockServer
.addMock({
url: '/session/13521-10219-202/element/0/shadow',
method: 'GET',
response: JSON.stringify({
value: {'shadow-6066-11e4-a52e-4f735466cecf': '9'}
})
}, true)
.addMock({
url: '/session/13521-10219-202/shadow/9/elements',
postdata: {
using: 'css selector',
value: '#helpBtn'
},
method: 'POST',
response: JSON.stringify({
value: [{'element-6066-11e4-a52e-4f735466cecf': '5'}]
})
}, true);

const shadowRootEl = this.client.api.element('#signupSection').getShadowRoot();
assert.strictEqual(await shadowRootEl instanceof ShadowRoot, true);
assert.strictEqual(await shadowRootEl.getId(), '9');

const helpBtnElement = shadowRootEl.find('#helpBtn');
assert.strictEqual(helpBtnElement instanceof Element, true);
assert.strictEqual(await helpBtnElement.getId(), '5');

const helpBtnWebElement = await helpBtnElement;
assert.strictEqual(helpBtnWebElement instanceof WebElement, true);
assert.strictEqual(await helpBtnWebElement.getId(), '5');
});

it('test .element().shadow().get()', async function() {
MockServer
.addMock({
url: '/session/13521-10219-202/element/0/shadow',
method: 'GET',
response: JSON.stringify({
value: {'shadow-6066-11e4-a52e-4f735466cecf': '9'}
})
}, true)
.addMock({
url: '/session/13521-10219-202/shadow/9/elements',
postdata: {
using: 'css selector',
value: '#helpBtn'
},
method: 'POST',
response: JSON.stringify({
value: [{'element-6066-11e4-a52e-4f735466cecf': '5'}]
})
}, true);

const shadowRootEl = this.client.api.element('#signupSection').getShadowRoot();
assert.strictEqual(await shadowRootEl instanceof ShadowRoot, true);
assert.strictEqual(await shadowRootEl.getId(), '9');

const helpBtnElement = shadowRootEl.get('#helpBtn');
assert.strictEqual(helpBtnElement instanceof Element, true);
assert.strictEqual(await helpBtnElement.getId(), '5');

const helpBtnWebElement = await helpBtnElement;
assert.strictEqual(helpBtnWebElement instanceof WebElement, true);
assert.strictEqual(await helpBtnWebElement.getId(), '5');
});

it('test .element().shadow().findElement()', async function() {
MockServer
.addMock({
url: '/session/13521-10219-202/element/0/shadow',
method: 'GET',
response: JSON.stringify({
value: {'shadow-6066-11e4-a52e-4f735466cecf': '9'}
})
}, true)
.addMock({
url: '/session/13521-10219-202/shadow/9/elements',
postdata: {
using: 'css selector',
value: '#helpBtn'
},
method: 'POST',
response: JSON.stringify({
value: [{'element-6066-11e4-a52e-4f735466cecf': '5'}]
})
}, true);

const shadowRootEl = this.client.api.element('#signupSection').getShadowRoot();
assert.strictEqual(await shadowRootEl instanceof ShadowRoot, true);
assert.strictEqual(await shadowRootEl.getId(), '9');

const helpBtnElement = shadowRootEl.findElement('#helpBtn');
assert.strictEqual(helpBtnElement instanceof Element, true);
assert.strictEqual(await helpBtnElement.getId(), '5');

const helpBtnWebElement = await helpBtnElement;
assert.strictEqual(helpBtnWebElement instanceof WebElement, true);
assert.strictEqual(await helpBtnWebElement.getId(), '5');
});

it('test .element().shadow().find(selectorObject)', async function() {
MockServer
.addMock({
url: '/session/13521-10219-202/element/0/shadow',
method: 'GET',
response: JSON.stringify({
value: {'shadow-6066-11e4-a52e-4f735466cecf': '9'}
})
}, true)
.addMock({
url: '/session/13521-10219-202/shadow/9/elements',
postdata: {
using: 'xpath',
value: '//*[id="helpBtn"]'
},
method: 'POST',
response: JSON.stringify({
value: [{'element-6066-11e4-a52e-4f735466cecf': '2'}]
})
}, true);

const shadowRootEl = this.client.api.element('#signupSection').getShadowRoot();
assert.strictEqual(await shadowRootEl instanceof ShadowRoot, true);
assert.strictEqual(await shadowRootEl.getId(), '9');

const helpBtnElement = shadowRootEl.find({
locateStrategy: 'xpath', selector: '//*[id="helpBtn"]'});
assert.strictEqual(helpBtnElement instanceof Element, true);
assert.strictEqual(await helpBtnElement.getId(), '2');

const helpBtnWebElement = await helpBtnElement;
assert.strictEqual(helpBtnWebElement instanceof WebElement, true);
assert.strictEqual(await helpBtnWebElement.getId(), '2');
});

it('test .element().shadow().find().getText()', async function() {
MockServer
.addMock({
url: '/session/13521-10219-202/element/0/shadow',
method: 'GET',
response: JSON.stringify({
value: {'shadow-6066-11e4-a52e-4f735466cecf': '9'}
})
}, true)
.addMock({
url: '/session/13521-10219-202/shadow/9/elements',
postdata: {
using: 'css selector',
value: '#helpBtn'
},
method: 'POST',
response: JSON.stringify({
value: [{'element-6066-11e4-a52e-4f735466cecf': '55'}]
})
}, true)
.addMock({
url: '/session/13521-10219-202/element/55/text',
method: 'GET',
response: JSON.stringify({
value: 'Help'
})
}, true);

const shadowRootEl = this.client.api.element('#signupSection').getShadowRoot();
const helpBtnElement = shadowRootEl.find('#helpBtn');
const helpBtnTextPromise = helpBtnElement.getText();

assert.strictEqual(typeof helpBtnTextPromise.then, 'function');
assert.strictEqual(await helpBtnTextPromise, 'Help');
});
});
Loading

0 comments on commit e193d19

Please sign in to comment.