I'm getting a "NoMethodError" when I already have defined the method

204 Views Asked by At

Writing my Ruby-Watir-cucumber bdd test I get this:

NoMethodError: undefined method `msg=' for #<Watir::Browser:0x0000558fbcdc0cc0>
./features/support/pages/message_page.rb:27:in `escribir'
./features/step_definitions/message_steps.rb:14:in `/^I'm able to write and send a "([^"]*)" successfully$/'
./features/send_messages.feature:12:in `Then I'm able to write and send a "Robot message" successfully'
./features/send_messages.feature:9:in `Then I'm able to write and send a "<message>" successfully'
1 scenario (1 failed)
4 steps (1 failed, 3 passed)
0m12.939s

Process finished with exit code 1

When I have already defined the method:

class MessagePage
  include PageObject
  @@browser = Watir::Browser.new
  page_url 'https://www.linkedin.com/messaging/'
  text_field(:searchcontact, name: 'searchTerm')
  div(:txtmessage,:role => "textbox")
  button(:btnsend,:type => 'submit')
  div(:txtfield,:xpath =>"//div//div[@role='textbox']")
  text_field(:mensaje,:xpath =>"//div//div[@role='textbox']")
  div(:msg,:role => "textbox") /// HERE!!!

  def searchcontact contact
    self.searchcontact = contact
    #searchcontact(contact).send_keys(:enter)
    wait 5
  end

  def buscar contact
    wait_until do
      searchcontact_element.visible?
      self.searchcontact = contact
    end
    self.searchcontact = contact
  end

  def escribir (message)
    self.msg = message
    wait 5
  end

  def writemessage message
    wait_until do
      msg_element.visible?
      self.msg = message
    end
    self.msg = message
  end

  def sendmessage
    btnsend
  end



end
2

There are 2 best solutions below

3
Justin Ko On

The accessor div(:msg,:role => "textbox") does not generate a #msg= method. It only defines:

  • #msg - Gets the text of the div
  • #msg? - Check if the div is present
  • #msg_element - Get the PageObject::Elements::Element

You will need to either manually define the method or create a widget for content editable elements.

Manually Define Setter

Contenteditable elements can be be inputted using the #set method. You can use this to create a setter method:

class MessagePage
  include PageObject

  div(:msg, role: "textbox")

  def msg=(value)
    msg_element.set(value)
  end
end

page = MessagePage.new(browser)
page.msg = 'your text'
p page.msg
#=> "your text"

Define a Widget

If you have to deal with multiple contenteditable elements, you should create a widget to eliminate the need to manually create each of the setters.

class Contentedtiable < PageObject::Elements::Element
  def self.accessor_methods(widget, name)
    #
    # Set text
    #
    widget.send('define_method', "#{name}=") do |value|
      self.send("#{name}_element").set(value)
    end

    #
    # Get text
    #
    widget.send('define_method', "#{name}") do
      self.send("#{name}_element").text
    end
  end

  PageObject.register_widget :contenteditable, self, :element
end

class MyPage
  include PageObject

  contenteditable(:msg, tag_name: 'div', role: 'textbox')
end

page = MyPage.new(browser)
page.msg = 'your text'
p page.msg
#=> "your text"
1
Luke Hill On

Once you click on the textbox you could sendkeys to it. So something like

msg.click then msg.send_keys('blah')

Or maybe as it's a textbox you could operate directly with it depending on how your page is coded - So msg.send_keys('blah') May work directly.