Ruby 在元素声明中为id使用变量
我有一个超类Ruby 在元素声明中为id使用变量,ruby,metaprogramming,watir-webdriver,page-object-gem,Ruby,Metaprogramming,Watir Webdriver,Page Object Gem,我有一个超类DemoPage和几个子类SDemoPage,EDemoPage,等等。所有这些页面上都有相同的元素,SDemoPage上的id看起来像s-demo-test1上的相应id看起来像e-demo-test1。在我的DemoPage类中,我声明了所有元素,我需要一种方法来添加子类(调用类)的id。这就是我目前拥有的 class DemoPage include PageObject @@subclass_ids = {"SDemoPage" => "s-demo-",
DemoPage
和几个子类SDemoPage
,EDemoPage
,等等。所有这些页面上都有相同的元素,SDemoPage
上的id看起来像s-demo-test1
上的相应id看起来像e-demo-test1
。在我的DemoPage
类中,我声明了所有元素,我需要一种方法来添加子类(调用类)的id。这就是我目前拥有的
class DemoPage
include PageObject
@@subclass_ids = {"SDemoPage" => "s-demo-",
"EDemoPage" => "e-demo-"}
# class << self; attr_accessor :current_class_id; end
def initialize(browser, something)
initialize_elements
super(browser, something)
end
.........
def initialize_elements
self.instance_eval do
select_list(:facility, id: "#{@current_class_id}facility")
text_field(:account, id: "#{@current_class_id}account")
text_field(:service, id: "#{@current_class_id}service")
end
end
end
但这不允许我设置基于其他调用类的id
我还留下了一些其他尝试的代码,比如使用哈希查找,但在页面对象方法已经意识到变量/method@current_class_id不存在之后,这些仍然在initialize方法中设置实例变量
我不知道从这里到哪里去
编辑: 所以我终于找到了答案,但我不确定这是否是解决这个问题的最佳方法:
class DemoPage
include PageObject
include DataMagic
def initialize(browser, visit)
super(browser, visit)
instantiate_elements self.class
end
def instantiate_elements klass
klass.class_eval do
select_list(:facility, id: "#{@class_id}facility")
text_field(:account, id: "#{@class_id}account")
text_field(:service, id: "#{@class_id}service")
end
end
end
class-SDemoPage
这样做有什么不对吗?我确实需要对initialize方法进行修补,因为在这里我没有展示其中的其他内容。既然我已经需要这样做了,那么有什么理由不在SDemoPage
的上下文中而不是在实际的DemoPage
中“创建”元素呢?还是贾斯汀的回答完全是更好的做事方式
编辑2:
我接受了Justin的答案,因为在极少数情况下,我不需要在PageObject中对initialize方法进行猴子补丁,他的答案会减少重复和代码总量 我认为最简单的解决办法是:
class DemoPage
include PageObject
def self.common_demo_elements(class_id)
select_list(:facility, id: "#{class_id}facility")
text_field(:account, id: "#{class_id}account")
text_field(:service, id: "#{class_id}service")
end
end
class SDemoPage < DemoPage
common_demo_elements("s-demo-")
end
而子页面将是:
class DemoPage
include PageObject
def self.common_demo_elements(class_id)
select_list(:facility, id: "#{class_id}facility")
text_field(:account, id: "#{class_id}account")
text_field(:service, id: "#{class_id}service")
end
end
class SDemoPage < DemoPage
common_demo_elements("s-demo-")
end
class-SDemoPage
select\u list是哪一类的方法?页面对象模块hmm这是一个好方法。事实上,我不久前就知道了,但我正在测试以确保它能正常工作。我会试试你的方法,看看是否更好。我会发布我的方法,你能告诉我是否有任何理由让我不这样做吗?事实上我喜欢你的答案。如果我实际上不需要对initialize方法进行修补,那么您的答案会更好。谢谢你的帮助,我知道你会是那个回应并帮助我的人;)我看不出任何明显的理由说明你的方法行不通。虽然我想知道我们是不是把事情弄得更复杂了。为什么不对id使用regexs呢?例如select_list(:facility,id:/facility/)
?啊,因为我们使用的是GWT,GWT的一个副作用是整个html被加载到页面中。因此,即使某个“模块”不可见,也永远不会可见,html仍然存在。因此,id仍然存在,我们必须使用精确匹配。否则,watir webdriver可能会在遇到可见id之前找到一个不可见的id,然后会出现ElementNotClickable
错误或其他错误。
class SDemoPage < DemoPage
common_demo_elements("s-demo-")
end