jamesshore / quixote

CSS unit and integration testing
Other
848 stars 45 forks source link

Support for cypress.io #55

Closed greyepoxy closed 4 years ago

greyepoxy commented 4 years ago

Thanks James for your great work on this library! Really appreciate that you are pushing the bounds of what people think is possible

Recently I have been using cypress.io to do my UI testing and have been greatly enjoying how it doesn't require arbitrary waits, allows you to visualize everything that occurred in your test during or after it runs, and also encourages writing fast tests.

I was curious on your thoughts for adding quixote support to cypress? I can think of a couple different ways of integrating,

Expose a way of creating QElement's from a dom node

Since cypress already hosts the UI under tests in an iFrame, there is no need for creating a corresponding QFrame. If a QElement from dom node constructor was exposed then after getting nodes in cypress could create the QElements and then assert as one would today (using descriptors) and cyrpess's should command https://docs.cypress.io/guides/references/assertions.html#Should-callback.

I believe this would be relatively straight forward, looking at the source https://github.com/jamesshore/quixote/blob/release/src/q_element.js#L13, I believe we just need to remove the frame from the constructor and everytime you want to access the document or body (like here https://github.com/jamesshore/quixote/blob/release/src/q_element.js#L47) use ownerDocument and then defaultView or parentView instead.

As a Custom Assertion library

I saw the discussion in the other thread https://github.com/jamesshore/quixote/issues/47 about updating the assertion library and one of the ideas called out was to create custom chai assertions. Assuming the object being asserted upon is create able from just dom nodes I believe this would be easy to use in cypress https://docs.cypress.io/guides/references/assertions.html#Adding-New-Assertions.

Can get a QFrame from a cypress test frame

Not sure you can get at the iFrame directly but cypress does expose commands to get the window or document https://docs.cypress.io/api/commands/window.html#Syntax.

As a Plugin

There are a bunch of classic visual testing tools integrated as plugins https://docs.cypress.io/plugins/#visual-testing. Not exactly sure if that makes sense with quixote, do not really know how the integration would work.

jamesshore commented 4 years ago

Thanks for your detailed suggestion. I'm not personally familiar with Cypress, but I'm open to changing Quixote to make it easier to support it.

It looks like the main thing we would need is the ability to make QElements. Currently, to make a QElement, we need two things: the DOM node (for obvious reasons) and the QFrame it lives in. You suggested that we remove the QFrame. Currently, we use the QFrame in these places:

  1. QElement, where it's used a) in getRawStyle() work around a Firefox bug; and b) in parent() to detect the body element so it won't be returned.

  2. ElementEdge, where it's used to detect if an element is rendered.

  3. ElementRenderedEdge, where it's used to find the page borders, so we can tell if an edge of an element is off-screen. (ElementRenderedEdge is in turn used by ElementRendered to see if the whole element is off-screen.)

I'm not convinced we can get rid of the QFrame requirement. If you see something I don't, let me know. I haven't studied it in depth.

Other than the QFrame issue, this seems fairly straightforward. We'd just need a QElement.fromDomElement() factory function to go along with our existing QElement.toDomElement() method. We could also make a corresponding QFrame.fromDomElement() factory.

greyepoxy commented 4 years ago

Thanks James, appreciate you taking a look. I opened a pull request demonstrating the removal of QFrame. Let me know what you think

jamesshore commented 4 years ago

What do you think about having a method such as quixote.frameFromDom(domElement) instead of having a separate QContentHost class? It would allow you to make a QFrame out of your Cypress iframe.

greyepoxy commented 4 years ago

hmmm I had not thought of that. I believe it would work but not ideal since cypress does not expose the frame as part of its api (just window and document ). So would have to figure out a way to get at it (maybe a little fragile?) or ask them to extend their api.

Would you like me to look into that?

jamesshore commented 4 years ago

No need, I'm working on it now. I think frameFromDom() would only work if we could somehow get the frame from an arbitrary element inside the frame, which may not be possible. Or if we don't need the actual iframe element, which might be. The main thing I want to avoid is having a separate QContentHost class--it makes the API more complicated and doesn't benefit the majority of users.

greyepoxy commented 4 years ago

Yeah I completely agree, curious to see what you figure out

jamesshore commented 4 years ago

Looking at it further, the only thing in QFrame that needs the actual iframe element is frame.resize(). As your code shows, everything else of interest can be done with nothing more than domElement.ownerDocument. (Or have I missed something? Let me know.)

So what I'm thinking is that I'll just modify QFrame so they can be constructed from an