init
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# Shadow DOM & Web Components Testing
|
||||
|
||||
## Challenges
|
||||
|
||||
- CSS encapsulation breaks selectors
|
||||
- Elements hidden from DOM queries
|
||||
- XPath doesn't penetrate shadow boundaries
|
||||
|
||||
## Tool Support
|
||||
|
||||
| Tool | Support | Method |
|
||||
|------|---------|--------|
|
||||
| Playwright | Native | `>>` piercing selector |
|
||||
| Cypress | Good | `.shadow()` command |
|
||||
| Selenium | Limited | JS execution |
|
||||
| Axe | v5.7+ | API support |
|
||||
|
||||
## Playwright Shadow Piercing
|
||||
|
||||
```javascript
|
||||
const input = page.locator('my-component >> .internal-input');
|
||||
const button = page.locator('comp-a >> comp-b >> button');
|
||||
const el = page.locator('custom-element >> button:has-text("Click me")');
|
||||
```
|
||||
|
||||
## Cypress Shadow DOM
|
||||
|
||||
```javascript
|
||||
cy.get('my-component').shadow().find('.internal-button').click();
|
||||
|
||||
// Enable globally: { includeShadowDom: true }
|
||||
```
|
||||
|
||||
## Selenium Workaround
|
||||
|
||||
```javascript
|
||||
const shadowHost = driver.findElement(By.css('my-component'));
|
||||
const shadowRoot = driver.executeScript('return arguments[0].shadowRoot', shadowHost);
|
||||
const button = shadowRoot.findElement(By.css('button'));
|
||||
```
|
||||
|
||||
## Page Object Pattern
|
||||
|
||||
```typescript
|
||||
export class MyComponentPO {
|
||||
constructor(private page: Page) {}
|
||||
|
||||
async fillEmail(email: string) {
|
||||
await this.page.locator('my-form >> input[type="email"]').fill(email);
|
||||
}
|
||||
|
||||
async submit() {
|
||||
await this.page.locator('my-form >> button[type="submit"]').click();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Request `open` shadow roots when possible
|
||||
2. Encapsulate shadow traversal in page objects
|
||||
3. Avoid deep nesting (increases complexity)
|
||||
|
||||
## Debugging
|
||||
|
||||
```javascript
|
||||
const contents = await page.evaluate(() => {
|
||||
return document.querySelector('my-component').shadowRoot.innerHTML;
|
||||
});
|
||||
```
|
||||
Reference in New Issue
Block a user