Cypress Real Events Plugin

Solving the missing autocomplete popup using the cypress-real-events plugin by Dmitriy Kovalenko.

Recently a Cypress user asked in the online chat why an autocomplete popup does not appear when entering the search text. Previously I have written about testing autocomplete widgets using Cypress, so I have decided to investigate. Because the user has produced a repo with the test code, I could take a look. The test looked correct to me

1
2
3
4
5
6
7
8
9
10
cy.get('gm-search')
.shadow()
.find('div#search_dropdown')
.find('gm-text-field#searchfield')
.focus()
.trigger('dblclick')
.find('.vaadin-text-field-container')
.find('#gm-text-field-input-6').focused()
.find('input[placeholder=\'Typ een adres of plaats\']').trigger('focus')
.type('Haarzuilens', {delay: 100})

Tip: I would improve this test by adding assertions. Right now the test only has commands, thus it could run away from the application. See my guide to Cypress retry-ability for details.

The failing test is recorded below. Notice the Shadow DOM command, that might be relevant here.

The cy.type command does not seem to work

I have noticed that the autocomplete does work when typing into the same box myself.

Typing does work

Typically, a widget like this could take a little longer to bootstrap. Thus I tried adding a pause before typing.

1
2
3
.find('input[placeholder=\'Typ een adres of plaats\']').trigger('focus')
.wait(5000)
.type('Haarzuilens', {delay: 100})

It did not help. Then I increased the key event delay from 100ms to one second. Still nothing. Let's try something else. Cypress cy.type command sends synthetic JavaScript events to the input element. You can see the events by clicking on the TYPE command in the Command Log. The events show up in the DevTools console, but some of the fields are null. That is suspicious.

Inspecting the list of keyboards events Cypress sent to the element

Hmm, maybe synthetic keyboard events do not work correctly in this case, and it could possibly be related to the Shadow DOM page structure. Let's see if sending real browser events works better. When Cypress controls the browser, it opens a Chrome Debugger Protocol connection to perform some privileged operations. I have described this in my blog post Cypress vs Other Test Runners. Thus we can send real browser events when typing using the existing CDP connection, or by opening our own.

Which is what cypress-real-events from my former co-worker at Cypress Dmitriy Kovalenko does very nicely.

Note: Losing Dmitriy is Cypress' biggest mistake in my opinion. Not only he has helped me solve the component testing technical challenges, he absolutely rocks creating open source libraries that just work, like odiff for image comparison. You know Percy.io/Applitools/Happo and other visual testing services? Dmitriy could build a company like that during his lunch break, I think.

After installing the library and importing it from the Cypress support file, I switched the test.

1
2
- .type('Haarzuilens', {delay: 100})
+ .realType('Haarzuilens')

Boom, the application is working!

Real type is working

Glad the library cypress-real-events exists. In addition to cy.realType, it has cy.realClick, cy.realHover, cy.realPress, cy.realTouch, cy.realSwipe, cy.realMouseDown, and cy.realMouseUp. If you find an app mysteriously refusing to act, try using the real thing. In the future, I am sure Cypress will expose these event mode in its core, while leaving the synthetic events as an option.