Description
Current behavior:
Testing a code who used event instanceof KeyboardEvent
, I've seen some strange behavior, digging up, it seems that there is some strange inconsistencies between the events triggered and also into the way they are sent to the eventListener
.
Desired behavior:
Consistent behavior:
.type
.trigger({..., type: 'keydown'})
.get('#element').then(element.dispatchEvent(new KeyboardEvent('keydown', ...)))
Should all send a KeyboardEvent type event.
And the eventListener:
element.addEventListener('keydown', (event) => (event instanceof KeyboardEvent));
Should always return true.
Steps to reproduce: (app code and test code)
I've tested three different methods: cy.type
, cy.trigger
, cy.get('#element').then( element.dispatchEvent)
.
And two different eventListener
for each test:
- One directly into a <script> inside the html page itself
- One created into the test itself using
cy.get -> addEventListener
You can find MWE here: https://github.com/avallete/cypress-test-tiny-event-bug
Simply run:
npm install
npm run cypress:open
# Then run the test and check the console.log inside the debuging tools.
# Each test is a specific case the 2 first show that event is type Event instead of KeyboardEvent.
# The third test show the inconsistency of the same eventListener if it's declared inside the test or outside (into the html <script>).
Versions
3.6.1, Linux, Chromium 78 / Electron 73
Activity
avallete commentedon Nov 9, 2019
The issue also seem to concern 'mousedown' and MouseEvent, except that
.click
seem to send MouseEvent to one of the two listener. But.trigger
doesn't.I've added the tests for the MouseEvent to the MWE repo.
jennifer-shehane commentedon Nov 13, 2019
Hey @avallete, I'm trying to narrow down exactly what the issue is from what you provided. Does the below summarize the totality of the issue?
When using
.type()
,.trigger()
or dispatching an event directly from an element returned from a Cypress command:mousedown
event that is triggered not aninstanceof MouseEvent
keydown
event that is triggered in Cypress not aninstanceof KeyboardEvent
Please clarify if I have missed something else. Thanks.
avallete commentedon Nov 13, 2019
I'll just add from my last comment that:
When using the
.click()
Cypress command, the event that is triggered is not aninstanceof MouseEvent
.And also the strange behavior is that between
eventListener
in different places into the code (directly put into cypressit(){...}
or into<script>...</script>
) seem to receive not the same values andinstanceof
seem to behave in different ways between these two scopes.But yeah @jennifer-shehane , you have summarized it way better than I did, thank's.
avallete commentedon Nov 21, 2019
Investigating a little bit on this issue, I've been able to found what seem to be the root of the behaviour I describe on this issue:
cypress/packages/driver/src/cy/keyboard.ts
Line 892 in 6749a0e
Replacing the
win['Event']
bywin['KeyboardEvent']
on this line, make the.type
function to properly send an event which isinstanceof KeyboardEvent
into the tests.But looking on the comment on top of this line, this fix may lead to some regression on Chrome < 63.
sainthkh commentedon Aug 7, 2020
I tried it with Cypress 4.12.1 +
'Event'
=>'KeyboardEvent'
. But something interesting happened.console.log
says it's aKeyboardEvent
, but theinstanceof KeyboardEvent
is false.Here are the screenshots.
Something similar happens to
MouseEvent
.It's a bit hard to figure out what made the difference.
avallete commentedon Aug 7, 2020
I had opened this issue so long ago that I had completely forgot about it.
Related to your comment @sainthkh I've refactored my MEW to:
instanceof
(inside the running test, inside the html web page script)instanceof
is not true in any of the context (since it's the attended behaviour)If you don't want to clone the MWE repository, here is the videos of the running tests to see what's wrong.
KeyboardEvent tests:
MouseEvent tests:
FYI, the expected behaviour for both KeyboardEvent and MouseEvent can be summarize into three assertions who are the following ones:
instanceof
(MouseEvent or KeyboardEvent, depending on the test).<script>
tag of the page, should see an event which is 'instanceof' (MouseEvent or KeyboardEvent, depending on the test). And so, set the text 'isKeyboardEvent|isMouseEvent' to true inside the '#result' div..click()
,.trigger()
,.type()
,.get(element).then(elem => elem.dispatchEvent())
) the behaviour should be consistent between all the raised events.I hope this addition may help to understand more clearly what's going on here.
sainthkh commentedon Aug 10, 2020
Finally, I understood what's going on.
You provided us 9 tests for each event. I read them and learned that the last 3 are duplicates of the above 6. So, all we have to check was those 6.
When we run the tests as-is with 4.12.0, only the test no. 3 passes. Other 5 fail. With the change to 'Event' to 'KeyboardEvent' you mentioned above, the test no.4 passes.
Now, we have 4 tests to fix.
When I saw the console log, the thing made me curious was this:
instanceof KeyboardEvent
isfalse
. But the object isKeyboardEvent
.This problem happens with the test no. 1 and 6. And I finally learned why.
It's because they use different
KeyboardEvent
.To run the test application, Cypress uses iframe. When we write test code with
KeyboardEvent
,KeyboardEvent
itself came from the test runner. Whileevent
object is the instance of the "application(inside iframe)"KeyboardEvent
.So, the test 1 and 6 should be written like below:
Check that I used
cy.window()
to bring iframeKeyboardEvent
.Finally, tests 2 and 4 are not fixed. The problem is here:
cypress/packages/driver/src/cy/commands/actions/trigger.js
Lines 8 to 16 in 1690d41
cy.trigger
doesn't take the type of event class into account.sainthkh commentedon Aug 10, 2020
Before I go fix
cy.trigger()
, I want to ask this question. When does this consistency necessary? Can I get some real world use cases?I'm asking this because to solve this problem, we need to add a big table of event name and event object types based on this.
avallete commentedon Aug 10, 2020
Hi there,
As you mentioned, the last 3 tests are effectively a combination of the check in both (html script and tests runner) contexts. Which as you say, if all the above tests work, should also work. I do realize know that it may be confusing, sorry for that.
Nice spot about the iframe and the use of win['KeyboardEvent']. It may be worthy to add this trick somewhere into the documentation since this problem should occurs for any
instanceof
or===
checks on window instantiated objects.On the question about 'why it is necessary ?':
.type
and.click
wasn'tinstanceof
the proper event. I do believe that the.trigger
issue may even be handled in another issue..trigger('keydown')
or.type
should produce the same kind of event, and that, according to the MDN, those events should have to proper types (as the ones who would be normally triggered by an user of the tested application.).32 remaining items