ShadowDOM ์ง์์ด ์์ง ๋๋ฝ๋ ๊ฒ ๊ฐ์ต๋๋ค.
์ ๋ ShadowDOM v1 ์ฌ์์ ๊ตฌํํ๋ ์ผ๋ถ Polymer 2 ๊ตฌ์ฑ ์์๋ก ์์
์ค์ด๋ฉฐ e2e ํ
์คํธ๋ฅผ ์คํํ๋ ค๋ฉด shadowRoot
๋ด๋ถ์ ์์๋ฅผ ์ ํํด์ผ ํฉ๋๋ค. deepCss
๊ฐ ํด๊ฒฐ์ฑ
์ด ๋ ์ ์์ง๋ง ์ ์๊ฒ๋ ํจ๊ณผ๊ฐ ์์ต๋๋ค. ๋ด๊ฐ ๋ณผ ์์๋ ํ by.deepCss
๋ by.css
์ ํน๋ณํ ์ฐจ์ด๊ฐ ์์ง๋ง ์ฃผ์ด์ง CSS ์ ํ๊ธฐ์ ์์ ๋ถ๋ถ์ * /deep/
๋ฅผ ์ถ๊ฐํ์ง๋ง /deep/
๋ ๋ธ๋ผ์ฐ์ ์์ ๋ ์ด์ ์ฌ์ฉ๋์ง ์์ต๋๋ค.
๋ค์ ๋ฒ์ ์ผ๋ก ์์ ํ๊ณ ์์ต๋๋ค.
v6.10.3
v5.1.2
v4.2.4
Chrome
Ubuntu v16.04.2 AMD64 LTS Xenial
๋ค์์ ํฌํจํ์ฌ ๋ชจ๋ ๊ด๋ จ ๊ธฐ์ฌ๋ฅผ ํ์ธํ์ง๋ง ๋ง์กฑ์ค๋ฌ์ด ๋ต๋ณ์ ์ป์ง ๋ชปํ ๊ฒ ๊ฐ์ต๋๋ค.
์ด์จ๋ ์ฌ์ฉ์ ์ง์ ๋ก์ผ์ดํฐ๋ฅผ ์ถ๊ฐํ์ฌ ShadowDOM ์์์ ๋ด๋ถ ์์๋ฅผ ์ ํํ ์ ์์ต๋๋ค. ๋ด ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
/**
* Usage:
* O element(by.css_sr('#parentElement #innerElement')) <=> $('#parentElement #innerElement')
* O element(by.css_sr('#parentElement::sr #innerElement')) <=> $('#parentElement').shadowRoot.$('#innerElement')
* O element.all(by.css_sr('#parentElement .inner-element')) <=> $$('#parentElement .inner-element')
* O element.all(by.css_sr('#parentElement::sr .inner-element')) <=> $$('#parentElement').shadowRoot.$$('.inner-element')
* O parentElement.element(by.css_sr('#innerElement')) <=> parentElement.$('#innerElement')
* O parentElement.element(by.css_sr('::sr #innerElement')) <=> parentElement.shadowRoot.$('#innerElement')
* O parentElement.all(by.css_sr('.inner-element')) <=> parentElement.$$('.inner-element')
* O parentElement.all(by.css_sr('::sr .inner-element')) <=> parentElement.shadowRoot.$$('.inner-element')
*/
by.addLocator('css_sr', (cssSelector: string, opt_parentElement, opt_rootSelector) => {
let selectors = cssSelector.split('::sr');
if (selectors.length === 0) {
return [];
}
let shadowDomInUse = (document.head.createShadowRoot || document.head.attachShadow);
let getShadowRoot = (el) => ((el && shadowDomInUse) ? el.shadowRoot : el);
let findAllMatches = (selector: string, targets: any[], firstTry: boolean) => {
let using, i, matches = [];
for (i = 0; i < targets.length; ++i) {
using = (firstTry) ? targets[i] : getShadowRoot(targets[i]);
if (using) {
if (selector === '') {
matches.push(using);
} else {
Array.prototype.push.apply(matches, using.querySelectorAll(selector));
}
}
}
return matches;
};
let matches = findAllMatches(selectors.shift().trim(), [opt_parentElement || document], true);
while (selectors.length > 0 && matches.length > 0) {
matches = findAllMatches(selectors.shift().trim(), matches, false);
}
return matches;
});
ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ด ์ชฝ์์ ์๋ํ๋ฏ๋ก ์ง๋ฌธํฉ๋๋ค~ ๋ด๊ฐ ๋์น ๊ฒ์ด ์๊ฑฐ๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์์ ๊ฐ๋๊ธฐ์ ๋ฐฐ๊ฒฝ ์๋ฆฌ๋ฅผ ์ค์ฉํ๋์? ์ ์คํ๊ฒ ๋ง์๋๋ฆฌ์ง๋ง ... ๊ทํ์ ํน์ ๊ท์น์ ๋๋ฌด ๋ง์ด ์๋ฐํ์ง ์๋๋ค๋ฉด ๋ค์ Protractor ์ ๋ฐ์ดํธ์ ShadowDOM ์ง์์ ์ถ๊ฐํ ์ ์์ต๋๊น?
๊ฐ์ฌํฉ๋๋ค.
@first87
์ด๊ฒ์ ๊ณต์ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค. ๋ณด๊ธฐ ์ข๊ณ ์ข์ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋๋ค.
์ต์ ๋ฒ์ ์ ๊ฐ๋๊ธฐ์์ ์ด๊ฒ์ ๋ณด๋ ค๋ฉด element(by. shadowRoot('#parentElement #innerElement'))
์ ๊ฐ์ ์ ๋ก์ผ์ดํฐ๋ก PR์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
@wwebcreation ์ข์, ์ข์. PR์ ์ถ๊ฐํ๊ฒ ์ต๋๋ค.
ํ์ง๋ง ์ด๋ํ๊ธฐ ์ ์ ํ ๊ฐ์ง๋ฅผ ๋ง๋ค๊ณ ์ถ์ด : ๋น์ ์ ์ ํ์์ด ์คํ์ผ ๊ด์ฐฎ #parentElement::sr #innerElement
ํ์ํ๋ ์์ #innerElement
์ ๊ทธ๋ฆผ์ ๋๋ฌด ๋ด๋ถ #parentElement
?
@first87
์์๊ฒผ์ด์๐
๋๋ PR์ ๋ํด ๊ฒฐ์ ํ๋ (์ ์ผํ) ์ฌ๋์ด ์๋๋๋ค. PR๋ ๊ฒํ ํ ํต์ฌ ๊ตฌ์ฑ์์ด ๊ฒฐ๊ตญ ๊ฒฐ์ ํฉ๋๋ค.
ํ๋ฅญํ ์ถ๊ฐ์ ๋ช ํํ ๊ธฐ๋ก์ด ๋ ๊ฒ ๊ฐ์ผ๋ ์ด์ ๊ฐ๋ณด์ธ์ ๐
@wwebcreation ๋ด ์ปค๋ฐ์ ํธ์
์๋ ํ์ธ์ @first87๋ ,
์ด ๋ฌธ์๋ฅผ ๋ณธ ์ ์ด ์์ต๋๊น? ๊ทธ๊ฒ์ ๋น์ ์ด ์ทจํ๋ ๋ฐ ํ์ํ ๋ชจ๋ ๋จ๊ณ๋ฅผ ๋ด๊ณ ์์ต๋๋ค.
@wswebcreation ์, DEVELOPER.md
๋ฅผ ํ์ธํ์ง๋ง ํธ์ ๊ฐ์ด๋๋ฅผ ์ฐพ์ง ๋ชปํ์ต๋๋ค. ๋ด๊ฐ ๊ฐ ๋จ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
git clone [email protected]:angular/protractor.git
cd protractor/
git remote add upstream https://github.com/angular/protractor.git
git checkout -b feature/shadow-root-locator master
๋ด ์์ ์ ์ง์ ๋ง๋ค๊ธฐnpm install
gulp lint
- ์ฝ๋ ํ์์ด ์ฌ๋ฐ๋ฅธ์ง ํ์ธnpm start
, webdriver-manager start
, npm test
๋ชจ๋ ํ
์คํธ ํต๊ณผ์ด์ ๋ค์์๋ ๋ฌด์์ ํด์ผ ํฉ๋๊น?
์๋ ํ์ธ์ @first87๋ ,
๊ทธ๊ฒ์ ํธ๋ฆญ์ํด์ผํฉ๋๋ค
@wswebcreation ๋ค , ์๋ดํด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
@wswebcreation ๋ฐฉ๊ธ PR #4392 ๋ฅผ ๋ง๋ค์์ต๋๋ค.
@first87 ํฐ์ค์์ค !!
์ด์ ๋ํ ์ํ๋ ๋ฌด์์ ๋๊น? by.shadowRoot ํจ์๋ฅผ ์ฌ์ฉํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๋๊ตฐ๊ฐ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐ ๋์์ด ๋๊ธธ ๋ฐ๋๋๋ค .
@first87 ๋ด e2e ํ ์คํธ์์ ์ ๋ก์ผ์ดํฐ๋ฅผ ์ฌ์ฉํด ๋ณด์์ต๋๋ค. ๋๋ ๊ทธ๋ฆผ์ ๋์์ ์์๋ฅผ ์ป์ ์ ์์ต๋๋ค.
ํ๊ฒฝ: ํด๋ฆฌ๋จธ ์น ๊ตฌ์ฑ ์์๊ฐ ์๋ Angular(v5) ์ ํ๋ฆฌ์ผ์ด์ . e2e ํ ์คํธ๋ฅผ ์คํํ๊ธฐ ์ํ ๊ฐ๋๊ธฐ.
๊ฐ๋ CLI: 1.6.4
๋
ธ๋: 6.10.0
๊ฐ๋: 5.2.0
@angular/cli: 1.6.4
ํ์ดํ์คํฌ๋ฆฝํธ: 2.5.3
์๋๋ ํฌ๋กฌ์์ ํ์ฅ๋ ํด๋ฆฌ๋จธ ์น ๊ตฌ์ฑ ์์ ์๋์ฐ ๋ฃจํธ์
๋๋ค. ์ด ์ฌ์ฉ์ ์ ์ ์์ ๋ด์์ ์
๋ ฅ ์ ํ = "ํ
์คํธ"๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
๊ฐ๋๊ธฐ by.css_sr์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ง์ ํด๋ฆฌ๋จธ ๊ตฌ์ฑ ์์ ๋ด๋ถ์ ์ ๋ ฅ ์์์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
var polymerFirstName = ์์(by.className('polyFName'));
var inputElement = polymerFirstName.element(by.css_sr('์
๋ ฅ')); // ์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์์ต๋๋ค.
"๋ก์ผ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์์๋ฅผ ์ฐพ์ ์ ์์: by.css_sr("input")" ์ค๋ฅ๋ก ์คํจํ์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ UI ์๋ํ ์์
์ ์ํํ ์ ์๋๋ก ๋ด๋ถ ์
๋ ฅ ์์์ ์ก์ธ์คํด์ผ ํฉ๋๋ค.
polymerFirstName.element(by.css_sr('์
๋ ฅ')).clear();
polymerFirstName.element(by.css_sr('input')).sendKeys('Ritchie');
๋ด๊ฐ ๋์น๊ณ ์๋ ๊ฒ์ด ์์ต๋๊น?
@msbasanth by.css_sr
๊ฐ ์์์ ์๋์ฐ ๋ฃจํธ์์ ์์๋ฅผ ์ฐพ๊ธฐ ์์ํ์ง ์๊ธฐ ๋๋ฌธ์ ::sr
๋์ณค์ต๋๋ค ~ ๊ฐ ::sr
๋ํ ๋ชจ๋ ์์์ ์๋์ฐ DOM ํธ๋ฆฌ๋ฅผ ํํค์น ๊ฒ์
๋๋ค
๋ฐ๋ผ์ ์
๋ ฅ ์์ ์ฐพ๊ธฐ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๊ฟ์ผ ํฉ๋๋ค.
var inputElement = polymerFirstName.element(by.css_sr('::sr input'));
@first87 ๋๋ถ ์ ๋งค๋ ฅ์ฒ๋ผ ์๋ํ์ต๋๋ค.
๊ณง ์ด shadow DOM ์ง์์ ๊ฐ๋๊ธฐ์์ ์ป์ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
์ด๊ฒ์ ์๋ํฉ๋๋ค! ๊ฐ์ฌํฉ๋๋ค! ํนํ ์ค์ฒฉ๋ ๊ทธ๋ฆผ์ ๋์ด ์๋ ๊ฒฝ์ฐ ์์๋ฅผ ์ฐพ๋ ๊ฒ์ด ๋งค์ฐ ์ด๋ ค์ธ ๊ฒ์ ๋๋ค. ์ฝ์์์ ๋ก์ผ์ดํฐ๋ฅผ ํ ์คํธํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ค์ ํ ๋ฒ ๊ฐ์ฌํฉ๋๋ค!
@firstor ์ ๋ง ๊ฐ์ฌํฉ๋๋ค! ์ด๊ฒ์ด ๊ณง ํตํฉ๋ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค....
๊ทธ๋๋ ์ด๊ฒ์ ๋ํด ๋น์ ์ ๋์์ ๋ฐ๊ธฐ๋ฅผ ๋ฐ๋์ต๋๋ค. ํ์์ ๋ฐ๋ผ ::sr์ ์ฌ์ฉํ์ฌ ์ฌ๋ฐ๋ฅธ ๊ฐ์ ์ป์ ์ ์์ง๋ง title.getText()
๋ฅผ ์ํํ๋ฉด "์๋ชป๋" ๊ฐ์ ์ป๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ค๋ธ์ ๋ก ๋ค๊ฐ์ค๋ ๊ฒ ๊ฐ์ต๋๋ค. ์๋์ ๋ค์ ์ถ๋ ฅ์ ์ฐธ์กฐํ์ญ์์ค.
[ 'Title' ]์(๋) 'Title'์ด์ด์ผ ํฉ๋๋ค.
ํด๋น ๊ฐ์ฒด/๋ฐฐ์ด์์ ๋ฌธ์์ด์ ๊ฐ์ ธ์ค๋ ๋ฐ ์ฑ๊ณตํ์ง ๋ชปํ๊ณ ์์ด๋์ด๊ฐ ์๋์ง ๊ถ๊ธํฉ๋๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ํด ๋ค์ ํ ๋ฒ ๊ฐ์ฌ๋๋ฆฝ๋๋ค!!
ํธ์ง: ๋ฌด์!! ์ด๊ฒ์ ์ฐธ์กฐํ๊ณ https://stackoverflow.com/questions/29478905/protractor-element-gettext-returns-an-object-and-not-string ํธ๋ฆญ์ ์ํํ์ต๋๋ค
@firstor / @msbasanth ๋ ์๋
ํ์ธ์, shadow-root DOM์ ์๋ ์์๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์์ ์ฝ๋๋ฅผ .ts ํ์ผ์ ๋ณต์ฌํ์ง๋ง ๋ผ์ธ ๋ฒํธ์์ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค. 6:
์ฝ๋: let shadowDomInUse = (document.head.createShadowRoot .......
์ค๋ฅ: 'HTMLHeadElement' ์ ํ์ 'createShadowRoot' ์์ฑ์ด ์์ต๋๋ค .
์์ฉ ํ๋ก๊ทธ๋จ: ๊ฐ๋ v7
๋
ธ๋JS: 6.9.0
ํ์ดํ์คํฌ๋ฆฝํธ: 2.3.3
๊ฐ๋๊ธฐ: 5.3.2
shadow-root ๋ด๋ถ์ ์
๋ ฅ ์์์ ์ผ๋ถ ํ
์คํธ๋ฅผ ์
๋ ฅํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์ธํ ์ค๋ช
ํด ์ฃผ์๊ฒ ์ต๋๊น?
๊ฐ์ฌ ํด์!
@firstor
๊ฐ์ฌํฉ๋๋ค. ์ด๋ ๊ฒ ์ฌ์ฉํ๋ ค๊ณ ํฉ๋๋ค.
var searchBar = ์์(by.css_sr('::sr ์
๋ ฅ'));
var searchButton = ์์(by.css_sr('::sr i'));
์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค
[11:36:06] E/๋ฐ์ฒ - TypeError: ์๋ชป๋ ๋ก์ผ์ดํฐ
๋ด๊ฐ ๋ญ ์๋ชปํ๊ณ ์์ฃ ?
๋์์ ์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. ๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
@firstor ์๋
ํ์ธ์, ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค)
๊ทธ๋ฌ๋ Protractor ๋ง์คํฐ ๋ธ๋์น์ ๋ณํฉ๋์ง ์๋ ํ ์ฐ๋ฆฌ ํ์์ ์์ ํ ์ฌ์ฉํ ์ ์์ต๋๋ค(์๊ฒฉ ๋
ธ๋์์ Protractor๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ํ
์คํธ๊ฐ ์คํ๋ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํญ์ ๋์ด์ต๋๋ค).
https://github.com/angular/protractor/pull/4786 ๋ณํฉ์ ์ง์ ์ด ์์ต๋๊น?
์ด์ ๋ํ ์ ๋ฐ์ดํธ๊ฐ ์์ต๋๊น?
๋ชจ๋ ์ ๋ฐ์ดํธ? ์ด๊ฒ์ ์ต๊ทผ์ ๋ง์ ์ฌ์์ ๋ํ ์ฐจ๋จ๊ธฐ์ ๋๋ค(
์๋ ํ์ธ์ @firstor๋
์์ฉ ํ๋ก๊ทธ๋จ: Angular 8
๋
ธ๋JS : 12.13.1
ํ์ดํ์คํฌ๋ฆฝํธ: 3.5.3
๊ฐ๋๊ธฐ : 5.4.0
ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์๋ ค์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
ShadowRoot์์ ์์๋ฅผ ์ฐพ์ผ๋ ค๊ณ ํฉ๋๋ค. ํ๋ก ํธ์๋ ์ํคํ ์ฒ์๋ 3๊ฐ์ง ๊น์ด ์์ค์ด ์์ต๋๋ค.
์ฒซ ๋ฒ์งธ ๋ฐ ๋ ๋ฒ์งธ shadowRoot ์์ค์ ์ก์ธ์คํ ์ ์์ง๋ง ๋ง์ง๋ง ์์ค์ ์๋๋๋ค.
์ฝ๋ ์์ค ์ถ์ถ:
await expect(element(by.tagName('page-affaire')).isDisplayed());
await browser.driver.sleep(3000);
console.log('Page affaire chargรฉe');
var el1 = element(by.tagName('page-affaire'));
var el2 = el1.element(by.css_sr('::sr rac-card'));
console.log('rac-card found');
var el3 = el1.element(by.css_sr('::sr rac-option'));
console.log('rac-option found');
var el4 = el1.element(by.css_sr('::sr mat-select'));
console.log('rac-card select');
๊ฒฐ๊ณผ ๋ก๊ทธ:
Jasmine` started
Page affaire chargรฉe
rac-card found
rac-option found
rac-card select
Sรฉlection du type de demande
crรฉer Affaire
ร Select type demande
- NoSuchElementError: No element found using locator: by.css_sr("::sr mat-select")
๋ค๋ฅธ ์๋ฃจ์ ์ผ๋ก ์๋ํฉ๋๋ค( https://stackoverflow.com/questions/57979981/how-to-check-in-protractor-javescript-in-shadow-dom-if-the-button-is-enabled-o ). ๋์ผํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
await browser.executeScript("return document.querySelector(\"page-affaire\");").then(function () {
console.log('page affaire found');
// browser.sleep(5000);
});
await browser.executeScript("return document.querySelector(\"page-affaire\").shadowRoot.querySelector(\"rac-card\");").then(function () {
console.log('rac card found');
// browser.sleep(5000);
});
await browser.executeScript("return document.querySelector(\"page-affaire\").shadowRoot.querySelector(\"rac-card\").shadowRoot.querySelector(\"rac-option\");").then(function () {
console.log('rac option found');
// browser.sleep(5000);
});
await browser.executeScript("return document.querySelector(\"page-affaire\").shadowRoot.querySelector(\"rac-card\").shadowRoot.querySelector(\"rac-option\").shadowRoot.querySelector(\"mat-select\").click();").then(function () {
console.log('Type de Demande cliquรฉ');
browser.sleep(5000);
});
๊ฒฐ๊ณผ :
Jasmine started
Page affaire chargรฉe
rac-card found
rac-option found
rac-card select
Sรฉlection du type de demande
crรฉer Affaire
ร Select type demande
- NoSuchElementError: No element found using locator: by.css_sr("::sr mat-select")
shadowRoot ๊น์ด ์ ํ ์ก์ธ์ค์ ๋ํ ์ ํ์ด ์์ต๋๊น?
์ง์ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
V1nc3kr0
์๋ ํ์ธ์ @firstor๋
์์ฉ ํ๋ก๊ทธ๋จ: Angular 8
๋ ธ๋JS : 12.13.1
ํ์ดํ์คํฌ๋ฆฝํธ: 3.5.3
๊ฐ๋๊ธฐ : 5.4.0ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์๋ ค์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
ShadowRoot์์ ์์๋ฅผ ์ฐพ์ผ๋ ค๊ณ ํฉ๋๋ค. ํ๋ก ํธ์๋ ์ํคํ ์ฒ์๋ 3๊ฐ์ง ๊น์ด ์์ค์ด ์์ต๋๋ค.
- 1๋จ๊ณ : ๋ง์ดํฌ๋ก ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์
- ๋ ๋ฒ์งธ ์์ค: ๋ง์ดํฌ๋ก ํ๋ก ํธ์๋ ๊ตฌ์ฑ ์์
- ์ธ ๋ฒ์งธ ์์ค : Angular ์ฌ๋ฃ ๊ตฌ์ฑ ์์
์ฒซ ๋ฒ์งธ ๋ฐ ๋ ๋ฒ์งธ shadowRoot ์์ค์ ์ก์ธ์คํ ์ ์์ง๋ง ๋ง์ง๋ง ์์ค์ ์๋๋๋ค.
์ฝ๋ ์์ค ์ถ์ถ:
await expect(element(by.tagName('page-affaire')).isDisplayed()); await browser.driver.sleep(3000); console.log('Page affaire chargรฉe'); var el1 = element(by.tagName('page-affaire')); var el2 = el1.element(by.css_sr('::sr rac-card')); console.log('rac-card found'); var el3 = el1.element(by.css_sr('::sr rac-option')); console.log('rac-option found'); var el4 = el1.element(by.css_sr('::sr mat-select')); console.log('rac-card select');
๊ฒฐ๊ณผ ๋ก๊ทธ:
Jasmine` started Page affaire chargรฉe rac-card found rac-option found rac-card select Sรฉlection du type de demande crรฉer Affaire ร Select type demande - NoSuchElementError: No element found using locator: by.css_sr("::sr mat-select")
๋ค๋ฅธ ์๋ฃจ์ ์ผ๋ก ์๋ํฉ๋๋ค( https://stackoverflow.com/questions/57979981/how-to-check-in-protractor-javescript-in-shadow-dom-if-the-button-is-enabled-o ). ๋์ผํ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
await browser.executeScript("return document.querySelector(\"page-affaire\");").then(function () { console.log('page affaire found'); // browser.sleep(5000); }); await browser.executeScript("return document.querySelector(\"page-affaire\").shadowRoot.querySelector(\"rac-card\");").then(function () { console.log('rac card found'); // browser.sleep(5000); }); await browser.executeScript("return document.querySelector(\"page-affaire\").shadowRoot.querySelector(\"rac-card\").shadowRoot.querySelector(\"rac-option\");").then(function () { console.log('rac option found'); // browser.sleep(5000); }); await browser.executeScript("return document.querySelector(\"page-affaire\").shadowRoot.querySelector(\"rac-card\").shadowRoot.querySelector(\"rac-option\").shadowRoot.querySelector(\"mat-select\").click();").then(function () { console.log('Type de Demande cliquรฉ'); browser.sleep(5000); });
๊ฒฐ๊ณผ :
Jasmine started Page affaire chargรฉe rac-card found rac-option found rac-card select Sรฉlection du type de demande crรฉer Affaire ร Select type demande - NoSuchElementError: No element found using locator: by.css_sr("::sr mat-select")
shadowRoot ๊น์ด ์ ํ ์ก์ธ์ค์ ๋ํ ์ ํ์ด ์์ต๋๊น?
์ง์ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
V1nc3kr0
๋ค์๊ณผ ๊ฐ์ด ์๋ํ์ญ์์ค.
var el4 = el3 .element(by.css_sr('::sr ๋งคํธ ์ ํ'));
@firstor
๋ด ์น ์ ํ๋ฆฌ์ผ์ด์
์ 10๊ฐ ๋ ๋ฒจ์ ์๋์ฐ ๋ฃจํธ๊ฐ ์๋ Polymer.js๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
๊ฐ๋ณ ์๋์ฐ ๋ฃจํธ๋ฅผ ํ์ํ๋ ๋์ ์ต์์ ๋
ธ๋์์ ๋ง์ง๋ง ์๋์ฐ ๋ฃจํธ ์์๋ฅผ ํธ์ถํ ์ ์์ต๋๊น?
์ง์ํด ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค.
์๋
ํ์ธ์ ์ฌ๋ฌ๋ถ ,
์ ๋ ๊ฐ๋๊ธฐ๋ฅผ ์ฒ์ ์ฌ์ฉํ๊ณ ์ด ๋ก์ผ์ดํฐ ์คํฌ๋ฆฝํธ(shadowDOM)๋ฅผ ๊ฐ๋๊ธฐ์ ํฌํจ์ํค๋ ๋ฐฉ๋ฒ์ ๋ํ ๋์์ ๋ฐ์ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๋๋ ํด๋ฆฌ๋จธ ์น ๊ตฌ์ฑ ์์, ๊ฐ๋๊ธฐ ๋ฒ์ : 5.4.2 ๋ฐ ๋
ธ๋ v12.13์ ๋ํ ๋ช ๊ฐ์ง UI ํ
์คํธ๋ฅผ ํ๊ณ ์์ต๋๋ค.
์๋ฌด๋ ๊ทธ ์คํฌ๋ฆฝํธ๋ฅผ ํฌํจํ ์์น๋ฅผ ๋งํด ์ค ์ ์์ต๋๊น? @firstor , @alagappan-qa
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
@rugaba
onPrepare() ๋ฉ์๋ ์๋์ Configuration.js ํ์ผ์ ์คํฌ๋ฆฝํธ๋ฅผ ํฌํจํฉ๋๋ค.
thx @ alagappan-qa, ์ฑ๊ณตํ์ต๋๋ค!!
์๋ ,
์ด ์คํฌ๋ฆฝํธ๋ฅผ ๋ณ๋์ js ํ์ผ์ ํฌํจํ๊ณ protractor.conf ํ์ผ์ ๊ฐ์ ธ์์ onPrepare() ๋ฉ์๋์ ํฌํจํ ์ ์์ต๋๊น? ๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํฉ๋๊น?
๊ฐ์ฌ ํด์,
๋ฝ์๋ฏธ
๋๊ตฐ๊ฐ ์ง๊ธ ์ด๊ฒ์ ํ์๋ก ํ๋ ๊ฒฝ์ฐ https://github.com/angular/protractor/pull/4786#issuecomment -607204672 ๋ฐ https://github.com/angular/protractor/pull/4786#issuecomment -607224145๋ฅผ ์ฐธ์กฐ ํ์ญ์์ค.
https://github.com/angular/protractor/pull/4786.patch ๋๋ https://github.com/angular/protractor/pull/4786.diff๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
์๋ ,
์ด ์คํฌ๋ฆฝํธ๋ฅผ ๋ณ๋์ js ํ์ผ์ ํฌํจํ๊ณ protractor.conf ํ์ผ์ ๊ฐ์ ธ์์ onPrepare() ๋ฉ์๋์ ํฌํจํ ์ ์์ต๋๊น? ๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํฉ๋๊น?
๊ฐ์ฌ ํด์,
๋ฝ์๋ฏธ
@Lakhs02
๋ค๋ฅธ ํ์ผ์์ ์ด ๋ก์ผ์ดํฐ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ ์ธํ์ญ์์ค.
exports.addShadowRootLocator = function () {
by.addLocator('css_sr', function (
.
.
.
return matches;
});
};
๊ทธ๋ฐ ๋ค์ onPrepare() ๋ฉ์๋์์
onPrepare: function () {
// register the shadow root locator, to use it globally
require('./path/to/file').addShadowRootLocator();
}
>
@firstor
๋ด ์น ์ ํ๋ฆฌ์ผ์ด์ ์ 10๊ฐ ๋ ๋ฒจ์ ์๋์ฐ ๋ฃจํธ๊ฐ ์๋ Polymer.js๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
๊ฐ๋ณ ์๋์ฐ ๋ฃจํธ๋ฅผ ํ์ํ๋ ๋์ ์ต์์ ๋ ธ๋์์ ๋ง์ง๋ง ์๋์ฐ ๋ฃจํธ ์์๋ฅผ ํธ์ถํ ์ ์์ต๋๊น?
์ง์ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
@firstor ๋๋ ๋น์ ์ ํ๋กํ์์ ๋น์ ์ด shadow DOM์ ๋ํด ๊ฒฝํํ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ค์ฒฉ๋ Shadow DOM์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์น์ ํ๊ฒ ์๋ฅผ ๋ค์ด ์ฃผ์๊ฒ ์ต๋๊น? ์ง๊ธ 2์ฃผ ๋์ ์ด๋ ค์์ ๊ฒช๊ณ ์์ง๋ง ์ฌ์ ํ ์ผ๋ถ ์์์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ๋ด ์์
๋๋ค. ๊ฐ์กฐ ํ์๋ div ์์์ ์ก์ธ์คํด์ผ ํฉ๋๋ค. div.a-choosen-text:
๋๋ ์๋์ ๋ก์ผ์ดํฐ(๋ฐ ๋ค๋ฅธ ๋ง์ ๊ฒ๋ค)๋ฅผ ์๋ํ์ง๋ง ์ฑ๊ณตํ์ง ๋ชปํ์ต๋๋ค:
nameOnTheProjectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)::sr appkit-panel::sr app-assignee- dropdown::sr appkit-dropdown::sr div.a-choosen-text'));
๋๋๊ฒ๋ app-project์ ๋ก์ผ์ดํฐ๋ ์ ์๋ํ์ง๋ง ๋ ๊น์ด ๋ค์ด๊ฐ๋ฉด ๋ฌด์์ ์๋ํ๋ ์๋ํ์ง ์์ต๋๋ค.
์ ์๋ํฉ๋๋ค: static projectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)'));
๋ด๊ฐ ๋ญ ์๋ชปํ๊ณ ์๋์ง ์์?
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
๋ง๊ทธ๋ค
>
@firstor
๋ด ์น ์ ํ๋ฆฌ์ผ์ด์ ์ 10๊ฐ ๋ ๋ฒจ์ ์๋์ฐ ๋ฃจํธ๊ฐ ์๋ Polymer.js๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
๊ฐ๋ณ ์๋์ฐ ๋ฃจํธ๋ฅผ ํ์ํ๋ ๋์ ์ต์์ ๋ ธ๋์์ ๋ง์ง๋ง ์๋์ฐ ๋ฃจํธ ์์๋ฅผ ํธ์ถํ ์ ์์ต๋๊น?
์ง์ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.@firstor ๋๋ ๋น์ ์ ํ๋กํ์์ ๋น์ ์ด shadow DOM์ ๋ํด ๊ฒฝํํ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ค์ฒฉ๋ Shadow DOM์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์น์ ํ๊ฒ ์๋ฅผ ๋ค์ด ์ฃผ์๊ฒ ์ต๋๊น? ์ง๊ธ 2์ฃผ ๋์ ์ด๋ ค์์ ๊ฒช๊ณ ์์ง๋ง ์ฌ์ ํ ์ผ๋ถ ์์์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ๋ด ์์ ๋๋ค. ๊ฐ์กฐ ํ์๋ div ์์์ ์ก์ธ์คํด์ผ ํฉ๋๋ค. div.a-choosen-text:๋๋ ์๋์ ๋ก์ผ์ดํฐ(๋ฐ ๋ค๋ฅธ ๋ง์ ๊ฒ๋ค)๋ฅผ ์๋ํ์ง๋ง ์ฑ๊ณตํ์ง ๋ชปํ์ต๋๋ค:
nameOnTheProjectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)::sr appkit-panel::sr app-assignee- dropdown::sr appkit-dropdown::sr div.a-choosen-text'));๋๋๊ฒ๋ app-project์ ๋ก์ผ์ดํฐ๋ ์ ์๋ํ์ง๋ง ๋ ๊น์ด ๋ค์ด๊ฐ๋ฉด ๋ฌด์์ ์๋ํ๋ ์๋ํ์ง ์์ต๋๋ค.
์ ์๋ํฉ๋๋ค: static projectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)'));๋ด๊ฐ ๋ญ ์๋ชปํ๊ณ ์๋์ง ์์?
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
๋ง๊ทธ๋ค
์๋
ํ์ธ์ ๋ง๊ทธ๋ค๋
๊ทํ์ ๊ฒฝ์ฐ WebElement appkit-panel ์๋์ ์๋์ฐ ๋ฃจํธ๋ ์์๋ฅผ ์ฐพ๊ธฐ ์ํด ํ์ฅ๋์ง ์์ต๋๋ค.
๊ทธ๋ฌ๋ nameOnTheProjectTab ์์์์ ํ์ฅ๋์ด ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
์๋ ์์ ๋ก์ผ์ดํฐ๋ฅผ ์ฌ์ฉํด๋ณด์ญ์์ค.
nameOnTheProjectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)::sr app-assignee-dropdown::sr appkit- dropdown::sr div.a-chosen-text'));
OMG, ์ด์ ์ป์๊ณ ํ์ํ ๋ชจ๋ ๋ก์ผ์ดํฐ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค!
๋์์ ์ฃผ์
์ ์ ๋ง ๊ฐ์ฌํฉ๋๋ค!
์น์ ํ๋,
๋ง๊ทธ๋ค
๋ณด๋ธ ์ฌ๋: alagappan-qa [email protected]
๋ณด๋: 2020๋
7์ 4์ผ ํ ์์ผ ์ค์ 4:34
๋ฐ๋ ์ฌ๋: ๊ฐ๋/๊ฐ๋๊ธฐ [email protected]
์ฐธ์กฐ: Bartkowiak-Jowsa, Magdalena [email protected] ; ๋๊ธ [email protected]
์ ๋ชฉ: Re: [๊ฐ๋/๊ฐ๋๊ธฐ] ShadowDOM ์ง์ ์์ฒญ(#4367)
@firstor https://github.com/firstor
๋ด ์น ์ ํ๋ฆฌ์ผ์ด์
์ 10๊ฐ ๋ ๋ฒจ์ ์๋์ฐ ๋ฃจํธ๊ฐ ์๋ Polymer.js๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
[๋ฐ์ ์๊ฐ ์ญ์ ํ ์ด๋ฏธ์ง์
๋๋ค. RJvlf] https://user-images.githubusercontent.com/57852329/72205775-de7d6300-34ac-11ea-93f7-37917052ce90.png
๊ฐ๋ณ ์๋์ฐ ๋ฃจํธ๋ฅผ ํ์ํ๋ ๋์ ์ต์์ ๋
ธ๋์์ ๋ง์ง๋ง ์๋์ฐ ๋ฃจํธ ์์๋ฅผ ํธ์ถํ ์ ์์ต๋๊น?
์ง์ํด ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค.
@firstor https://github.com/firstor ํ๋กํ์์ Shadow DOM์ ๋ํ ๊ฒฝํ์ด ์์์ ์ ์ ์์ต๋๋ค. ์ค์ฒฉ๋ Shadow DOM์ ์ก์ธ์คํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์น์ ํ๊ฒ ์๋ฅผ ๋ค์ด ์ฃผ์๊ฒ ์ต๋๊น? ์ง๊ธ 2์ฃผ ๋์ ์ด๋ ค์์ ๊ฒช๊ณ ์์ง๋ง ์ฌ์ ํ ์ผ๋ถ ์์์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
์ด๊ฒ์ ๋ด ์์
๋๋ค. ๊ฐ์กฐ ํ์๋ div ์์์ ์ก์ธ์คํด์ผ ํฉ๋๋ค. div.a-choosen-text:
[๋ฐ์ ์๊ฐ ์ญ์ ํ ์ด๋ฏธ์ง์
๋๋ค. ์ด๋ฏธ์ง] https://user-images.githubusercontent.com/50359393/86498151-c532e080-bd84-11ea-867c-337085b96087.png
๋๋ ์๋์ ๋ก์ผ์ดํฐ(๋ฐ ๋ค๋ฅธ ๋ง์ ๊ฒ๋ค)๋ฅผ ์๋ํ์ง๋ง ์ฑ๊ณตํ์ง ๋ชปํ์ต๋๋ค:
nameOnTheProjectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)::sr appkit-panel::sr app-assignee- dropdown::sr appkit-dropdown::sr div.a-choosen-text'));
๋๋๊ฒ๋ app-project์ ๋ก์ผ์ดํฐ๋ ์ ์๋ํ์ง๋ง ๋ ๊น์ด ๋ค์ด๊ฐ๋ฉด ๋ฌด์์ ์๋ํ๋ ์๋ํ์ง ์์ต๋๋ค.
์ ์๋ํฉ๋๋ค: static projectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)'));
๋ด๊ฐ ๋ญ ์๋ชปํ๊ณ ์๋์ง ์์?
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
๋ง๊ทธ๋ค
์๋
ํ์ธ์ ๋ง๊ทธ๋ค๋
๊ทํ์ ๊ฒฝ์ฐ WebElement appkit-panel ์๋์ ์๋์ฐ ๋ฃจํธ๋ ์์๋ฅผ ์ฐพ๊ธฐ ์ํด ํ์ฅ๋์ง ์์ต๋๋ค.
๊ทธ๋ฌ๋ nameOnTheProjectTab ์์์์ ํ์ฅ๋์ด ์ด ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
์๋ ์์ ๋ก์ผ์ดํฐ๋ฅผ ์ฌ์ฉํด๋ณด์ญ์์ค.
nameOnTheProjectTab = element(by.css_sr('app-dumbledore::sr lit-route::sr app-dashboard::sr app -project:nth-child (1)::sr app-assignee-dropdown::sr appkit- dropdown::sr div.a-chosen-text'));
โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์
๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub https://github.com/angular/protractor/issues/4367#issuecomment-653710546 ์์ ํ์ธํ๊ฑฐ๋ https://github.com/notifications/unsubscribe-auth/AMAGYYOPZMDJCRSHT5XI45TRZ2ILDANCNFSM4DR44ABQ ๊ตฌ๋
์ ์ทจ์
์บก์ ๋ฏธ๋ ํด์ค์นด Sp. ์ฆ์ฐ,
์ธ. ลปwirki i Wigury 16a 02-092 Warszawa,
S?d Rejonowy dla M.ST. Warszawy, XII Wydzia? Gospodarczy Rejestrowy, nr KRS: 0000040605,
NIP: 526-11-84-467,
์์์ฝ?? kapita?u zak?adowego: 16.403.320,00z?.
์ด ๋ฉ์์ง์๋ ๊ถํ์ด ์๊ฑฐ๋ ๊ธฐ๋ฐ์ผ ์ ์๋ ์ ๋ณด๊ฐ ํฌํจ๋์ด ์์ผ๋ฉฐ Capgemini Group์ ์์ฐ์
๋๋ค. ๊ทธ๊ฒ์ ์ฃผ์๊ฐ ์ง์ ๋ ์ฌ๋๋ง์ ์ํ ๊ฒ์
๋๋ค. ๊ทํ๊ฐ ์๋ํ ์์ ์๊ฐ ์๋ ๊ฒฝ์ฐ ์ด ๋ฉ์์ง ๋๋ ๊ทธ ์ผ๋ถ๋ฅผ ์ฝ๊ฑฐ๋, ์ธ์ํ๊ฑฐ๋, ๋ณด๊ดํ๊ฑฐ๋, ๋ณต์ฌํ๊ฑฐ๋, ๋ฐฐํฌํ๊ฑฐ๋, ์ฌ์ฉํ ๊ถํ์ด ์์ต๋๋ค. ์ด ๋ฉ์์ง๋ฅผ ์๋ชป ์์ ํ ๊ฒฝ์ฐ ๋ฐ์ ์์๊ฒ ์ฆ์ ์๋ฆฌ๊ณ ์ด ๋ฉ์์ง์ ๋ชจ๋ ์ฌ๋ณธ์ ์ญ์ ํ์ญ์์ค.
์๋
ํ์ธ์ ์ฌ๋ฌ๋ถ, ๊น์ ์์ค์์ ๊ทธ๋ฆผ์ ๋ฃจํธ ๋ด๋ถ์ ๊ทธ๋ฆผ์ ์์๋ฅผ ์ฐพ๋ ์๋ฃจ์
์ ์ฐพ์์ต๋๋ค.
๋
ธ๋ ๋ชจ๋ "query-selector-shadow-dom"์ ๋์์ผ๋ก Shadow DOM์ ์น ์์๋ฅผ ์ฝ๊ฒ ์๋ณํ ์ ์์ต๋๋ค. ๋ชจ๋ ๊ทธ๋ฆผ์ ๋ฃจํธ๋ฅผ ํต๊ณผํ ํ์๊ฐ ์์ต๋๋ค.
element(by.shadowDomCss('
์๋
ํ์ธ์ Alagappan๋
์๋ฅผ ๋ค์ด ์ข ๋ ์์ธํ ์ค๋ช
ํด ์ฃผ์๊ฒ ์ต๋๊น? ๊ฐ์ฌํฉ๋๋ค.
2020๋
8์ 19์ผ ์์์ผ ์ค์ 7:52 alagappan-annamalai <
[email protected]>์ ๋ค์๊ณผ ๊ฐ์ด ์ผ์ต๋๋ค.
์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ, ๋ด๋ถ์ ๊ทธ๋ฆผ์ ์์๋ฅผ ์ฐพ๋ ์๋ฃจ์ ์ ์ฐพ์์ต๋๋ค.
๋ชจ๋ ๊น์ ์์ค์ ๊ทธ๋ฆผ์ ๋ฃจํธ.
๋ ธ๋ ๋ชจ๋ "query-selector-shadow-dom"์ ๋์์ผ๋ก ์ฐ๋ฆฌ๋
Shadow DOM์์ ์น ์์๋ฅผ ์ฝ๊ฒ ์๋ณํฉ๋๋ค. ํก๋จํ ํ์ ์์
๋ชจ๋ ๊ทธ๋ฆผ์ ๋ฟ๋ฆฌ๋ฅผ ํตํด.
element(by.shadowDomCss(''))๋ฅผ ์ฌ์ฉํ์ฌ ๋ด๋ถ์ ์น ์์๋ฅผ ๊ฐ๋ฆฌํฌ ์ ์์ต๋๋ค.
๋ชจ๋ ์์ค์์ ๊ทธ๋ฆผ์ ๋ฃจํธ.โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์ ๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ณ GitHub์์ ํ์ธํ์ธ์.
https://github.com/angular/protractor/issues/4367#issuecomment-676304234 ,
๋๋ ๊ตฌ๋ ์ทจ์
https://github.com/notifications/unsubscribe-auth/AK2OQDTZK2ZVJTICP3VGS3DSBPDJVANCNFSM4DR44ABQ
.
์๋ ํ์ธ์ Alagappan๋, ์๋ฅผ ๋ค์ด ์ข ๋ ์์ธํ ์ค๋ช ํด ์ฃผ์๊ฒ ์ต๋๊น?๊ฐ์ฌํฉ๋๋ค.
โฆ
2020๋ 8์ 19์ผ ์์์ผ ์ค์ 7:52 alagappan-annamalai < @ . * > ์์ฑ: ์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ, ๋ชจ๋ ๋ฅ ๋ ๋ฒจ์์ Shadow Root ๋ด๋ถ์ Shadow Elements๋ฅผ ์ฐพ๋ ์๋ฃจ์ ์ ์ฐพ์์ต๋๋ค. ๋ ธ๋ ๋ชจ๋ "query-selector-shadow-dom"์ ๋์์ผ๋ก Shadow DOM์ ์น ์์๋ฅผ ์ฝ๊ฒ ์๋ณํ ์ ์์ต๋๋ค. ๋ชจ๋ ๊ทธ๋ฆผ์ ๋ฃจํธ๋ฅผ ํต๊ณผํ ํ์๊ฐ ์์ต๋๋ค. element(by.shadowDomCss(''))๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ ์์ค์์ Shadow Root ๋ด๋ถ์ Web ์์๋ฅผ ๊ฐ๋ฆฌํฌ ์ ์์ต๋๋ค. โ ๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๊ฒ ๋ฉ๋๋ค. ์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub < #4367 (comment) >์์ ํ์ธํ๊ฑฐ๋ https://github.com/notifications/unsubscribe-auth/AK2OQDTZK2ZVJTICP3VGS3DSBPDJVANCNFSM4DR44ABQ ๊ตฌ๋ ์ ์ทจ์
์์ ์คํฌ๋ฆฐ์ท์์ id=container์ธ ํ๊ทธ paper-input-container๋ 6+ ์๋์ฐ ๋ฃจํธ ๋ ์ด์ด์ ์์ต๋๋ค. ์ด webElement๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด element(by.shadowDomCss('paper-input#textbox paper-input-container#container')); ์ด ์งง์ ์์ ์๋ณ์๋ WebElement์์ ์๋ํฉ๋๋ค.
@firstor / @msbasanth ๋ ์๋ ํ์ธ์, shadow-root DOM์ ์๋ ์์๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์์ ์ฝ๋๋ฅผ .ts ํ์ผ์ ๋ณต์ฌํ์ง๋ง ๋ผ์ธ ๋ฒํธ์์ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค. 6:
์ฝ๋: let shadowDomInUse = (document.head.createShadowRoot .......
์ค๋ฅ: 'HTMLHeadElement' ์ ํ์ 'createShadowRoot' ์์ฑ์ด ์์ต๋๋ค .
๋ํ ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ์ผ๋ฉฐ ํด๊ฒฐ์ฑ
์ createShadowRoot
๋ฅผ attachShadow
๋ก ๋ฐ๊พธ๋ ๊ฒ์
๋๋ค. ์๋ํ๋ฉด createShadowRoot() ๋ฉ์๋๊ฐ attachShadow()๋ฅผ ์ํด ๋ ์ด์ ์ฌ์ฉ๋์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ฐธ์กฐ ์ฐธ์กฐ:
https://developer.mozilla.org/en-US/docs/Web/API/Element/createShadowRoot
๊ทธ๊ฑด ๊ทธ๋ ๊ณ @firstor , ์ด ๊ณตํ์ ๊ฐ์ฌ๋๋ฆฝ๋๋ค! ์ง๊ธ๊น์ง ํ๋ฅญํ๊ฒ ์๋ํ์ต๋๋ค. ๋๋๋ ค๊ณ ๋๋ฌด ๋ง์ ์๊ฐ์ ๋ญ๋น by.deepCss
๋๋ ์ต๊ทผ์ ๋ด ์ฝ๋ (10 ๊ฐ) ๊ตฌ์ฑ ์์์ ๊ธฐ๋ณธ shadowDom ์บก์ํ๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ๋ค ๊ฐ๋๊ธฐ์ ๊ฐ๋ (10)์ ์ผ์ encapsulation: ViewEncapsulation.ShadowDom
๋ด๊ฐ ์ฌ๋ํ์ง๋ง ํ๋ณต I๋์ง ์์ e2e ํ
์คํธ ์ค์ ์ค์ฒฉ๋ shadowDom ์์์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ๊ณ ๋ง๊ฒ๋ ์ด ์ฝ๋๋ฅผ ์ฐพ์์ต๋๋ค!
@Rob4226
https://www.npmjs.com/package/query-selector-shadow-dom ํจํค์ง๋ฅผ ์ดํด๋ณด์ญ์์ค.
์ ๋งํด ๋ณด์ธ๋ค.
@msbasanth @Rob4226 ์ ๋ ๊ฐ๋๊ธฐ๋ฅผ ์ฒ์ ์ฌ์ฉํฉ๋๋ค. ํฌ๋กฌ ๋ค์ด๋ก๋ ํ์ด์ง์ '๋ค์ด๋ก๋' ํ
์คํธ์ ์ก์ธ์คํ๋ ค๊ณ ํฉ๋๋ค.
๋ด ์ฝ๋ :
๋๋ ๋ํ ์๋ํ๋ค var x = await element.element(by.css_sr('h1')).getText(); ์๋ํ์ง ์์ต๋๋ค.
์๋ ์ค๋ฅ ๋ฉ์์ง๊ฐ ๋ํ๋ฉ๋๋ค.
์ด ๊ฐ์ฌํฉ๋๋ค!
์์ ํ์ต๋๋ค. ๋ชจ๋ ์ค์ฒฉ๋ ์๋ ๋ฃจํธ ์์์ ๋ํด ๋ณ๋์ ์์ ๋ณ์๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
@firstor ์ด ์ฝ๋์ ๋ํด ๋๋จํ ๊ฐ์ฌํฉ๋๋ค. ๋ง์ ๊ฐ์ฌํฉ๋๋ค ๐
์๋ ํ์ธ์ ์ ๋ ํ์ฌ shadow dom์ ์ ํํ๋ tr์ ๋๋ค. ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๋ ๋ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
Logg: { StaleElementReferenceError: stale element reference: stale element not found
(Session info: chrome=87.0.4280.66)
์ฉ๋ฒ:
const parent = element(by.css_sr('my-wrapper > div > div::sr my-data'));
const domElement = parent.element(by.css('my-checkbox input'));
console.log('Displayed', await domElement.isDisplayed());
<my-data>
<my-checkbox>
<input>
<my-checkbox>
</my-data>
.....
๋ด๊ฐ ๋ญ ์๋ชปํ๊ณ ์์ฃ ?
์๋ ํ์ธ์ ์ ๋ ํ์ฌ shadow dom์ ์ ํํ๋ tr์ ๋๋ค. ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ๋ ๋ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
Logg: { StaleElementReferenceError: stale element reference: stale element not found (Session info: chrome=87.0.4280.66)
์ฉ๋ฒ:
const parent = element(by.css_sr('my-wrapper > div > div::sr my-data')); const domElement = parent.element(by.css('my-checkbox input')); console.log('Displayed', await domElement.isDisplayed());
<my-data> <my-checkbox> <input> <my-checkbox> </my-data> .....
๋ด๊ฐ ๋ญ ์๋ชปํ๊ณ ์์ฃ ?
@wasoek๋ , ์๋์ฐ ๋ฃจํธ์์ ์ด ์์์ ๋ํ Chrome ๊ฐ๋ฐ์ ๋๊ตฌ > ์์ ๊ฒ์ฌ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๊น? ๊ทธ๋ฌ๋ฉด ์ด ๋ฌธ์ ์ ๋ํด ๋ ์์ธํ ์ ์ ์์ต๋๋ค.
์๋ ,
์ด๊ฒ์ ์๋ 2๊ฐ์ง ๋ฐฉ๋ฒ ์ค ํ๋๋ฅผ ์ฌ์ฉํ์ฌ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
element1 = element.all(by.css_shadowroot('downloads-manager::sr div')).get(1)
element2 = element1.element(by.css_shadowroot('::sr downloads-item::sr div::sr downloads-item')).getText();
๋๋
browser.element(by.css_shadowroot('downloads-manager::sr div[id=โmainContainerโ]::sr ๋ค์ด๋ก๋ ํญ๋ชฉ::sr div::sr ๋ค์ด๋ก๋ ํญ๋ชฉ')).getText();
[์ฌ๊ธฐ์ n๋ฒ์งธ ์์ ๋์ ์ ID๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์์์ ์ด์ ์ ๋ง์ถฅ๋๋ค.]
๊ฐ์ฌ ํด์,
์๋ผ๊ฐํ A
๋ณด๋ธ ์ฌ๋: shopmujahid [email protected]
๋ณด๋: 2020๋
12์ 3์ผ ๋ชฉ์์ผ ์ค์ 9:20
๋ฐ๋ ์ฌ๋: ๊ฐ๋/๊ฐ๋๊ธฐ [email protected]
์ฐธ์กฐ: Alagappan Annamalai [email protected] ; ๋๊ธ [email protected]
์ ๋ชฉ: Re: [๊ฐ๋/๊ฐ๋๊ธฐ] ShadowDOM ์ง์ ์์ฒญ(#4367)
Shadow dom(๊ฐ์กฐ ํ์๋จ)์ ๋ ๋ฒ์งธ div ์์ ์๋์ ์๋ ์์์ ์ก์ธ์คํ๋ ค๊ณ ํ์ง๋ง ํญ์ ์๋ ๋ฉ์์ง์ ํจ๊ป ์ฒซ ๋ฒ์งธ div ์์๋ฅผ ๊ฒ์ํฉ๋๋ค.
W/์์ - locator by.css_shadowroot("downloads-manager::sr div")์ ๋ํด ๋ ์ด์์ ์์๊ฐ ๋ฐ๊ฒฌ๋จ - ์ฒซ ๋ฒ์งธ ๊ฒฐ๊ณผ๊ฐ ์ฌ์ฉ๋ฉ๋๋ค.
์๋๋ ๋ด xpath์
๋๋ค.
browser.element(by.css_shadowroot('downloads-manager::sr div:nth-child (1)::sr ๋ค์ด๋ก๋ ํญ๋ชฉ::sr div::sr ๋ค์ด๋ก๋ ํญ๋ชฉ')).getText();
๋๊ตฐ๊ฐ๊ฐ ๋๋ฅผ ์๋ด ํ ์ ์์ต๋๊น? ๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค
[์ด๋ฏธ์ง] https://user-images.githubusercontent.com/58770415/100961235-336c0280-34df-11eb-9618-1f24ffcd62a0.png
โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์
๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ํ์ ํ๊ฑฐ๋ GitHub https://github.com/angular/protractor/issues/4367#issuecomment-737647758 ์์ ํ์ธํ๊ฑฐ๋ https://github.com/notifications/unsubscribe-auth/AORWPO6XNK7RUWPVHCWKBCTSS4DH5ANCNFSM4DR44ABQ ๊ตฌ๋
์ ์ทจ์
๋ด ๊ฒฝ์ฐ์๋ nth-child()์ type-of()๊ฐ ๋ชจ๋ ์๋ํ์ง ์๋ shadow dom ๋ด๋ถ์ div ์์ ์ค ํ๋์ ์ก์ธ์คํ๋ ค๊ณ ํฉ๋๋ค.
์ ์์ด ๋ฌธ์ ์ ์ง๋ฉด ํ ์ฌ๋์ด ์์ต๋๊น?
์๋๋ DOM ๊ตฌ์กฐ์ ๋ด xpath์
๋๋ค.
Browser.element(by.css_shadowroot('d2l-navigation::sr d2l-navigation-main- header:nth-type-of (3)'))๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค
์์๋ฅผ ์ฐพ์ ์ ์์ ์ค๋ฅ๊ฐ ์์ ๋ฉ๋๋ค.
์ด๋ค ๋์์ด๋ผ๋ ๋๋จํ ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. ๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
์๋ ,
์๋์ฐ ๋ฃจํธ ์ธ๋ถ์ ์์ผ๋ฏ๋ก ์์ ๋ก์ผ์ดํฐ์์ ::sr์ ์ ๊ฑฐํด ๋ณด์ธ์.
์ด 2๊ฐ์ ์์ ๋ก์ผ์ดํฐ ์ค ํ๋๋ฅผ ์ฌ์ฉํ์ฌ ์๋ํ๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํ์ญ์์ค.
Browser.element(by.css_shadowroot('d2l-navigation d2l-navigation-main- header:nth-type-of (3)'))๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค
๋๋
browser.element(by.css_shadowroot('d2l-navigation d2l-navigation-main-header div. d2l-navigation-header-right'))๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค.
๊ฐ์ฌ ํด์,
์๋ผ๊ฐํ A
๋ณด๋ธ ์ฌ๋: shopmujahid [email protected]
๋ณด๋: 2020๋
12์ 9์ผ ์์์ผ ์คํ 12:09
๋ฐ๋ ์ฌ๋: ๊ฐ๋/๊ฐ๋๊ธฐ [email protected]
์ฐธ์กฐ: Alagappan Annamalai [email protected] ; ๋๊ธ [email protected]
์ ๋ชฉ: Re: [๊ฐ๋/๊ฐ๋๊ธฐ] ShadowDOM ์ง์ ์์ฒญ(#4367)
๋ด ๊ฒฝ์ฐ์๋ nth-child()์ type-of()๊ฐ ๋ชจ๋ ์๋ํ์ง ์๋ shadow dom ๋ด๋ถ์ div ์์ ์ค ํ๋์ ์ก์ธ์คํ๋ ค๊ณ ํฉ๋๋ค.
์ ์์ด ๋ฌธ์ ์ ์ง๋ฉด ํ ์ฌ๋์ด ์์ต๋๊น?
์๋๋ DOM ๊ตฌ์กฐ์ ๋ด xpath์
๋๋ค.
[2134234] https://user-images.githubusercontent.com/58770415/101593797-cc9e8b80-39ad-11eb-8fd0-a7cd7541773f.jpg
Browser.element(by.css_shadowroot('d2l-navigation::sr d2l-navigation-main- header:nth-type-of (3)'))๋ฅผ ๊ธฐ๋ค๋ฆฝ๋๋ค
์์๋ฅผ ์ฐพ์ ์ ์์ ์ค๋ฅ๊ฐ ์์ ๋ฉ๋๋ค.
์ด๋ค ๋์์ด๋ผ๋ ๋๋จํ ๊ฐ์ฌํ๊ฒ ์ต๋๋ค. ๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
โ
๋น์ ์ด ๋๊ธ์ ๋ฌ์๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ๋ฐ๋ ๊ฒ์
๋๋ค.
์ด ์ด๋ฉ์ผ์ ์ง์ ๋ต์ฅํ๊ฑฐ๋ GitHub https://github.com/angular/protractor/issues/4367#issuecomment-741567009 ์์ ํ์ธํ๊ฑฐ๋ https://github.com/notifications/unsubscribe-auth/AORWPO7CSSI7P5GH37O74R3ST4LO5ANNCNFSM4DR44ABQ ๊ตฌ๋
์ ์ทจ์
@alagappan-annamalai ๊ฐ์ฌํฉ๋๋ค! ๐ ๋ ๋ฒ์งธ ์๋ฃจ์
์ ::sr์ ์ ๊ฑฐํ๊ณ tagname.classname์ ์ถ๊ฐํ์ฌ ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค. ๊ทธ๋ฌ๋ ์๋์ ์์ ์์์ ์ก์ธ์คํ์ง ๋ชปํ๋ ๋ค๋ฅธ ์ด์ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
์์ ๊ฐ์กฐ ํ์๋ ์์์ ์ก์ธ์คํด์ผ ํฉ๋๋ค.
์๋์ ๋ xpath๋ก ์๋ํ์ต๋๋ค.
browser.element(by.css_sr('d2l-navigation d2l-navigation-main-header div.d2l-navigation-header-right div d2l-dropdown d2l-dropdown-content div div div div ul:nth-child(2)' ))
๊ทธ๋ฆฌ๊ณ
Browser.element(by.css_sr('d2l-navigation d2l-navigation-main-header div.d2l-navigation-header-right div d2l-dropdown d2l-dropdown-content div div div div ul li._
์์๋ฅผ ์ฐพ์ ์ ์์ ์ค๋ฅ๊ฐ ์์ ๋ฉ๋๋ค.
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
@alagappan-annamalai ๊ฐ์ฌํฉ๋๋ค! ๐ ๋ ๋ฒ์งธ ์๋ฃจ์ ์ ::sr์ ์ ๊ฑฐํ๊ณ tagname.classname์ ์ถ๊ฐํ์ฌ ์ ์๊ฒ ํจ๊ณผ์ ์ด์์ต๋๋ค. ๊ทธ๋ฌ๋ ์๋์ ์์ ์์์ ์ก์ธ์คํ์ง ๋ชปํ๋ ๋ค๋ฅธ ์ด์ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
์์ ๊ฐ์กฐ ํ์๋ ์์์ ์ก์ธ์คํด์ผ ํฉ๋๋ค.
์๋์ ๋ xpath๋ก ์๋ํ์ต๋๋ค.
browser.element(by.css_sr('d2l-navigation d2l-navigation-main-header div.d2l-navigation-header-right div d2l-dropdown d2l-dropdown-content div div div div ul:nth-child(2)' ))๊ทธ๋ฆฌ๊ณ
Browser.element(by.css_sr('d2l-navigation d2l-navigation-main-header div.d2l-navigation-header-right div d2l-dropdown d2l-dropdown-content div div div div ul li._
_')) (li ํด๋์ค ์ด๋ฆ ์๋ก ๋ง์ฐ์ค๋ฅผ ๊ฐ์ ธ๊ฐ๋ฉด ์ผ๋ถ ํ ์คํธ๊ฐ ์ถ๊ฐ๋ฉ๋๋ค.)์์๋ฅผ ์ฐพ์ ์ ์์ ์ค๋ฅ๊ฐ ์์ ๋ฉ๋๋ค.
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
์ด๊ฒ์ css_sr ์์ด ๊ฐ๋จํ ๋ฐฉ๋ฒ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ ๋ช ๊ฐ์ง HTML ์น ์์๋ฅผ ์ ๊ณตํฉ๋๋ค.
browser.element.all(by.css('d2l-navigation d2l-navigation-main-header ul[class="d2l-datalist vui-list"] li')).get(1);
Bravo, ๋งค๋ ฅ์ฒ๋ผ ์ผํ์ต๋๋ค @lagappan-annamalai ๊ฐ์ฌํฉ๋๋ค! โ
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ด์ ๋ํ ์ํ๋ ๋ฌด์์ ๋๊น? by.shadowRoot ํจ์๋ฅผ ์ฌ์ฉํ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.