TC-FRAME-001Positive
Simple iframe button
Switch to a same-origin frame and click the nested action.
Do this: Locate the iframe by title and click the button inside it.
Expected: The nested result becomes visible in the parent status area.
frameLocator('iframe[title=Support]').getByRole('button', { name: 'Send' })TC-FRAME-002Positive
Nested frames and postMessage
Use two frame boundaries and verify a parent counter event.
Do this: Submit the nested support widget and observe the parent counter.
Expected: The parent receives one message and increments the counter once.
frameLocator('#parent-frame').frameLocator('#nested-frame').getByTestId('frame-submit')TC-FRAME-003Edge case
srcdoc and cross-origin boundary
Compare same-origin srcdoc access with a cross-origin document.
Do this: Attempt DOM access and document why the cross-origin frame is isolated.
Expected: The test uses frame context or an agreed postMessage/API contract; it does not bypass browser security.
page.frameLocator('iframe[title=External payment]')TC-FRAME-004Edge case
Dynamic frame lifecycle
Wait for a delayed frame, changing src, and replacement.
Do this: Recover from a Frame was detached event after a re-render.
Expected: The locator resolves the current frame and avoids stale frame handles.
page.frameLocator('[data-testid=dynamic-frame]').getByRole('button')TC-FRAME-005Positive
Frame selection and title
Compare id, name, title, index, and meaningful accessibility metadata.
Do this: Select the intended frame with a meaningful title.
Expected: The frame has a stable selector and an informative title attribute.
page.frameLocator('iframe[title=QA support widget]')TC-SHADOW-006Positive
Open Shadow DOM control
Interact with a button, input, counter, and list inside an open root.
Do this: Increment the counter inside the open component.
Expected: The count changes and the component remains keyboard reachable.
page.getByTestId('shadow-host').getByRole('button', { name: /Increment/ })TC-SHADOW-007Edge case
Nested Shadow DOM
Locate through a host containing another custom element with its own root.
Do this: Traverse both component boundaries and assert the nested label.
Expected: The locator resolves the nested component without document-wide selectors.
page.locator('qa-shell').locator('qa-card').getByRole('heading')TC-SHADOW-008Negative
Closed Shadow DOM
Understand why the root is inaccessible and choose a testability contract.
Do this: Confirm direct DOM traversal fails, then use an exposed API or host-level hook.
Expected: The test does not attempt to pierce a closed root with XPath.
page.getByTestId('closed-component')TC-SHADOW-009Edge case
Shadow inside iframe
Switch context first, then locate the web component inside the frame.
Do this: Find the open component after entering the iframe.
Expected: Frame and shadow boundaries are handled as separate steps.
frameLocator('#component-frame').locator('qa-player').getByRole('button')TC-SHADOW-010Positive
Web Component and slot
Distinguish light DOM slotted content from shadow-owned controls.
Do this: Assert slotted text and click the component’s internal action.
Expected: The test identifies which node belongs to light DOM and which belongs to shadow DOM.
page.locator('qa-card').getByText('Release quality')