Matthew

Fixing a bug in playwright-ruby-client

November 10, 2024

I fixed an issue with RSpec helpers provided by the very useful YusekeIwaki/playwright-ruby-client gem.

Rather than diving into the technical issues here, I wanted to write this to document my process working through the fix. The technical details of the fix are in my PR.

Investigation

A coworker of mine encountered this bug when expecting that an element gets removed from the page via expect(element).not_to be_visible:

Failures:
 
1) Playwright::LocatorAssertions#to_be_visible should work eventually when negated
    Failure/Error: @failure_message.gsub("expected to", "not expected to")
 
    NoMethodError:
      undefined method `gsub` for nil
    # ./lib/playwright/test.rb:60 in `failure_message_when_negated`
....

and asked to pair on it with me.

The first step was to ensure that the issue was not on our end by confirming that the element we are expecting not to be visible does eventually get removed from the page, but initially is present.

After confirming the issue was with the gem, and given that it was a nil error, I figured it might be an issue that we would be able to dive into the source code for and quickly fix.

So, we run bundle open playwright-ruby-client and add debugger statements in various code paths to see what the state of the @failure_message variable was for the normal and negated matchers. i.e.

it "is not visible" do
  expect(page.locator("span")).not_to be_visible
end
 
it "is visible" do
  expect(page.locator("span")).to be_visible
end

I timeboxed this investigation to a few minutes and decided to look at the docs one more time to see if there were other ways to assert that an element is not visible.

I found that there was a hidden matcher and a not_to_be_visible matcher (as opposed to not_to be_visible that uses RSpec negation logic) that worked for us.

Since the issue of testing the element's visibility was fixed, we ended the pairing session and I was determined to take a look at the fix on the playwright-ruby-client side on my own time.

Fixing the bug in the gem

I had a feeling that a working not_to_be_visible matcher meant that getting not_to be_visible to work would be possible if I could emulate not_to_be_visible via RSpec negation of be_visible. And that turned out to be the case!

Interestingly, the not_to_{matcher} matchers were generated via metaprogramming so it wasn't as straightforward as I was expecting.

But, fortunately, toggling an is_not parameter for expectations within the gem was all that was required to negate be_visible correctly.

The crux, then, was using the RSpec matcher's #does_not_match? method to provide the correct is_not param.

Contributing the fix

I went through the docs of playwright-ruby-client to set up the dev environment locally and looked through existing tests to see if there were any I could adapt to show what I fixed.

Once I was happy with the code, I wrote the PR description and made the pull request. Four days later it was approved and merged.