I have an iframe inside an angular component, into which I am injecting a component X dynamically using component factory (appending the native element to the iframe's body). The reason I am doing this is because I need media queries to function in the component. Without ViewEncapsulation.ShadowDom the component injected inside the frame will be 'style-less'.
Until now everything is fine and dandy and the feature works exactly as I want. However, during e2e testing I am not able to access any elements inside the shadow-root, I have tried multiple methods like document.querySelector('component-id').shadowRoot.querySelector('element-id') and even libraries and work arounds that are mentioned here.
Everything results in the same error
StaleElementReferenceError: stale element reference: stale element not found
To summarize,
- An angular component with Shadow Dom encapsulation is being injected into an iframe
- Cannot access the elements inside the shadowroot of the injected component using all the available methods
I realize this answer might not address your particular question, and that I am running the risk of losing rep due to downvotes, but I would like to suggest a change in architecture, based on my comments to the question above.
Since you have full control over the content of the
iframeI would suggest setting up Angular routing in such a way as to allow you to specify a route for theiframethat would display your simple component, while keeping the rest of the application's routes intact.Abstract
So assuming you have your app's routes set up normally, with a top level component (usually
app.component) which hosts the<router-outlet>tag, I would create a new top level component (let's call itapp-plain.component) which contains only<router-outlet></router-outlet>in its template, and nothing else. I would set up the app to use this component as the bootstrap component (instead ofapp.component), then I would change the route configuration to move all existing routes as children of a new blank path route ('') with the oldapp.componentas its component.Finally I would set up a new route with some path (say
iframe) that would use the component you wish to display in the iframe as its component (let's call itiframe.component).This would allow you to put an element such as this
<iframe src="/iframe"></iframe>anywhere in your components, and have it display just youriframe.component.Implementation
Assuming your existing route configuration looks like this:
I would modify the route configuration as follows:
As mentioned, I would create a new plain top level component called
app-plain.componentwith just a<router-outlet>in its template, and set it up as the module's bootstrap component:NOTE: Since the bootstrap component has changed, you have to specify its selector in your
index.htmltoo (instead ofapp-rootwhich it is by default)Demo/Sample
I've created a github repo with this solution concept.
I could not make a StackBlitz, because the
iframenever finishes loading when I try, here's my failed attempt.