Read more

Capybara: Pretending to interact with the document

Henning Koch
March 10, 2021Software engineer at makandra GmbH

Browsers blocks abusable JavaScript API calls until the user has interacted with the document. Examples would be opening new tab or start playing video or audio.

Illustration web development

Do you need DevOps-experts?

Your development team has a full backlog? No time for infrastructure architecture? Our DevOps team is ready to support you!

  • We build reliable cloud solutions with Infrastructure as code
  • We are experts in security, Linux and databases
  • We support your dev team to perform
Read more Show archive.org snapshot

E.g. if you attempt to call video.play() in a test, the call will reject with a message like this:

NotAllowedError: play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD

Workaround

To pretend document interaction in a test you can create an element, click on it, and remove the element again. This unblocks the entire JavaScript API for the current page.

You can include the following module in your test to get a method interact_with_page that does just that:

module InteractWithPage

  def interact_with_page
    create_empty_interaction_stub
    click_empty_interaction_stub
  ensure
    remove_empty_interaction_stub
  end

  private

  def create_empty_interaction_stub
    page.execute_script(<<~JS)
      let stub = document.createElement('div')
      stub.classList.add('empty-interaction')

      // Stop the click from bubbling up and closing any overlays
      stub.addEventListener('click', function(event) {
        event.stopImmediatePropagation()
        event.preventDefault()
      })

      // Make sure the stub has a clickable area
      stub.style.width = '1px'
      stub.style.height = '1px'
      stub.style.backgroundColor = 'blue'

      // Make sure the stub is positioned over any overlays to be clickable
      stub.style.position = 'fixed'
      stub.style.bottom = '0'
      stub.style.right = '0'
      stub.style.zIndex = '9999999999999999'

      document.body.appendChild(stub)
    JS
  end

  def click_empty_interaction_stub
    page.find('.empty-interaction').click
  end

  def remove_empty_interaction_stub
    page.execute_script(<<~JS)
      let stub = document.querySelector('.empty-interaction')
      if (stub) {
        stub.remove()
      }
    JS
  end

end

To use it in Cucumber:

World(InteractWithPage)

When 'I have interacted with the page' do
  interact_with_page
end
Henning Koch
March 10, 2021Software engineer at makandra GmbH
Posted by Henning Koch to makandra dev (2021-03-10 11:04)