如何动态地将部分添加到 SitePrism 页面对象? [英] How to add a section to a SitePrism page object dynamically?

查看:17
本文介绍了如何动态地将部分添加到 SitePrism 页面对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 SitePrism 测试我的 Web 应用程序.我有许多扩展 SitePrism::Page 的类,并且许多常用的 HTML 片段由扩展 SitePrism::Section

I'm using SitePrism to test my web application. I have a number of classes that extend SitePrism::Page and a number of often-used HTML snippets are represented by matching classes extending SitePrism::Section

class Login < SitePrism::Section
  element :username, "#username"
  element :password, "#password"
  element :sign_in, "button"
end

class Home < SitePrism::Page
  section :login, Login, "div.login"
end

问题是,我正在开发的应用程序是基于 CMS,其中可以通过基于预定义内容选择 模板 来组装页面,然后拖放 -将任意数量的可用组件拖放到页面上.

The problem is, the application I'm working on is based on a CMS, in which a page can be assembled by selecting a Template based on pre-defined content and then drag-and-dropping any number of available components onto the page.

最初的开发者创建了一个页面对象来镜像每个可用的模板.这很好,只要测试数量少,并且我们必须在功能文件中测试的页面变体不多.

The initial developers created a Page Object to mirror every available Template. This was fine as long as the number of tests was low and there weren't too many variants of pages that we had to test in our feature files.

随着多个测试用例的增加,页面对象开始以惊人的速度增长.

With the addition of multiple test cases, the page objects started growing at an alarming rate.

虽然我们可以通过为 CMS 中的每个可用组件定义 Sections 并在 Page Objects 中重用它们来轻松减少代码重复,但只有很多属性很少得到用过.

While we can easily mitigate code duplication by defining Sections for every component available in the CMS and reusing them across Page Objects, there's just a lot of properties that rarely get used.

class BlogPost < SitePrism::Page

    section :logo, MySite::Components::Logo, '.logo'    
    section :navigation, MySite::Components::Navigation, '.primary-navigation'
    section :header, MySite::Components::BlogHeader, '.header'
    section :introduction, MySite::Components::Text, '.text .intro'
    # and so on, a lot of dynamic staff that could potentially be dropped onto the page
    # but does not neccessarily be there, going in dozens of lines
end

SitePrism 中是否有一种方法可以将部分动态添加到 页面对象 的实例中,而不是整个类?

Is there a way in SitePrism to dynamically add a section to an instance of a Page Object as opposed to a whole class?

Then(/^Some step$/) do
    @blog = PageObjects::BlogPost.new()
    @blog.load("some url")
    @blog.somehow_add_a_section_here_dynamically
    expect (@blog.some_added_section).to be_visible
end

我还担心,这样做可能会导致 CSS 选择器泄漏到步骤定义中,这通常是一种不好的做法.

It also worries me that doing something like this would potentially cause CSS selectors to leak into the step definitions, which is generally a bad practice.

解决此问题的另一种方法是为特定的页面示例构建页面对象,而不是通用模板.模板页面对象 可以只包含嵌入到模板中的任何内容,并由镜像特定页面的其他页面对象 扩展,以处理差异.这听起来像是一种更简洁的方法,所以我可能会以这种方式编写测试

Another way to work around this would be to build Page Objects for specific examples of pages as opposed to the versatile templates. The Template Page Objects could just contain whatever's baked into the templates and be extended by other Page Objects that mirror specific pages, taking care of the differences. It sounds like a much cleaner approach so I'm probably going to write my tests this way

无论如何,问题的技术部分仍然存在.不管它是好是坏,我怎样才能动态地扩展一个带有附加部分的页面对象?我只是好奇.

Anyway, the technical part of the question stands. Regardless of how good or bad an idea it is, how could I dynamically extend a page object with an additional section? I'm just curious.

推荐答案

出于几乎相同的原因,我曾一度想做您所说的事情.我们的页面可以拖入新的内容部分;使它们非常有活力.我尝试了多种方法来做到这一点,但从未找到我特别喜欢的方法.

I had at one point wanted to do what you're talking about for pretty much the same reason. We had pages that could have new content-sections dragged into them; making them very dynamic. I experimented with ways to do this and never found any that I particularly liked.

site-prism 中的 elementsections 等方法分别为该类定义了许多方法.您可以在测试中调用 MyPage.section 或添加调用 self.class.section 的方法并使用它来添加新部分.但是这些将存在于该页面的所有实例中;可能不是你想要的.

Methods like element and sections in site-prism each define a number of methods for the class. You could call MyPage.section in your test or add a method that calls self.class.section and use that to add on new sections. But those will exist for all instances of that page; probably not what you want.

您也可以通过 singleton_class 附加它们:

You could alternatively tack them on to through the singleton_class:

my_page = MyPage.new
my_page.singleton_class.section(:new_section, NewSection, '#foo')

但这在你的测试中有点难看,对吧?

But that's getting a bit ugly to toss into your tests, right?

我一直认为 Sections 应该有一个 default_locator(但很难让补丁被接受)
有了这个,我们可以概括一下:

I've long thought that Sections should have a default_locator (but tough to get patches accepted)
With that we could generalize this a bit:

class DynamicSection < SitePrism::Section
  def self.set_default_locator(locator)
    @default_locator = locator
  end
  def self.default_locator
    @default_locator
  end
end      

class DynamicPage < SitePrism::Page
  # add sections (and related methods) to this instance of the page
  def include_sections(*syms)
    syms.each do |sym|
      klass = sym.to_s.camelize.constantize
      self.singleton_class.section(sym, klass, klass.default_locator)
    end
  end
end

然后您可以将这些用作父母.

And then you can use these as the parents.

class FooSection < DynamicSection
  set_default_locator '#foo'
  element :username, "#username"
end

class BlogPostPage < DynamicPage
  # elements that exist on every BlogPost
end

在测试中:

@page = BlogPostPage.new
@page.include_sections(:foo_section, :bar_section)
expect(@page.foo_section).to be_visible

另一方面,创建一些不同的页面对象变体用于测试可能更容易.(你真的要测试这么多变体吗?也许……也许不是.)

On the other-hand it really might be easier to just create a few different variations of the page-object for use in tests. (Are you really going to test that many variations? Maybe..maybe not.)

这篇关于如何动态地将部分添加到 SitePrism 页面对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆