Closed cognivator closed 8 years ago
At first glance, I'm in favor of the reload()
approach (option 2).
First, though, do you know why reset isn't working? Is it just a matter of events like DOMContentLoaded
not firing? If so, we can trigger those manually.
Or is it that inline scripts don't execute when we do replace innerHTML
?
I'm 99% certain it's the latter: inline scripts that need to run to bootstrap the framework.
Angular, for instance, has a dependency injection and service ecology that needs to initialize, followed by a compilation of the HTML content.
I'm less familiar with the inner workings of React, but it appeared from my sandbox project that the root React component wasn't properly attached to the DOM following the innerHTML
replacement. But React components aside, the rest of a React / Flux app would have a Flux Store that needs to be reset as well... more inline script issues, probably.
I can image a future state of Quixote that integrates with the frameworks in some deeper way, similar to how Protractor knows to wait for Angular to become ready before starting the Selenium Webdriver inspections.
But the short path for now feels like a page reload.
Any objections to me taking a pass at the reload
functionality? I have two sandbox apps to test with, one Angular and one React. Once we've ironed out how best to have the iframe reload its content, we can decide on a good place in the API... an enhancement to reset
or a new reload
method.
Nope, be my guest.
An easy way to check if the current frame.reset()
executes inline scripts would be to create a little web page that alert
s and see what happens when you call reset() on it.
Fair point, and an easy test.
Another question is if there's a way to re-read of scripts in the <head>
tag without doing a complete page reload.
Mmm, good point about the <head>
scripts. Hadn't considered those. It's possible reset
could reset the head as well as the body, though, if it works for the body.
BTW, I have an Ember app you can test at https://github.com/jamesshore/lab16_emberjs.
Pull request: #19.
Released in v0.11. Thanks @cognivator!
Problem
The existing
frame.reset()
method does a simple replacement ofbody.InnerHTML
with it's original contents. Certain (most?) client-side MV* frameworks -- AngularJS, ReactJS, etc. -- have a robust bootstrapping process that requires more than a simple reset ofbody.InnerHTML
.Workarounds
(there may be others)
Recreate the iframe
This workaround requires calling
frame.remove()
followed byquixote.createFrame(...)
in lieu offrame.reset()
. This solution comprises a complete reset of the iframe itself, and as such seems a little heavyweight... but it works. ProsCons
Custom messaging / events
Messages or events can be passed to a listener in the iframe page under test, and the listener can take the necessary reset action. The simple version of this solution uses the native
window.postMessage
to pass messages to and from the iframe content without running afoul of XSS security protections in the browser. Prosbody.InnerHTML
replacement!) are left to the SPA itselfCons
Proposed Solution(s)
Reload the iframe page source
Issue the equivalent of a browser refresh to reload the page source from the 'server.' This has the advantage of restarting an SPA the way it expects to be loaded, but without the overhead of recreating the iframe itself.
Implementation Option 1 - refactor existing
frame.reset()
method Add the reload possibilities as a configuration parameter toframe.reset()
Implementation Option 2 - add a new
frame.reload()
method Keep the reload separate from the reset.Optional functionality
window.postMessage
) during the reload lifecyle. Apps that need to can manage their cleanup and/or reset as necessary