From 73b9cbf660b13fd4de467f0f4de44dee0f186fdd Mon Sep 17 00:00:00 2001
From: Grzegorz Bizon <grzesiek.bizon@gmail.com>
Date: Fri, 22 Dec 2017 13:01:12 +0100
Subject: [PATCH] Add domain specific language to define QA page elements

---
 qa/qa/page/base.rb        | 21 +++++++++++++++++++++
 qa/qa/page/element.rb     | 26 ++++++++++++++++++++++++++
 qa/qa/page/view.rb        |  6 ++++++
 qa/spec/page/base_spec.rb | 35 +++++++++++++++++++++++++++++++++++
 4 files changed, 88 insertions(+)
 create mode 100644 qa/spec/page/base_spec.rb

diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 99eba02b6e3..4f79f24a629 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -5,6 +5,9 @@ module QA
     class Base
       include Capybara::DSL
       include Scenario::Actable
+      extend SingleForwardable
+
+      def_delegators :evaluator, :view, :views
 
       def refresh
         visit current_url
@@ -40,6 +43,24 @@ module QA
       def self.path
         raise NotImplementedError
       end
+
+      def self.evaluator
+        @evaluator ||= Page::Base::DSL.new
+      end
+
+      class DSL
+        attr_reader :views
+
+        def initialize
+          @views = []
+        end
+
+        def view(path, &block)
+          Page::Element.evaluate(&block).tap do |elements|
+            @views.push(Page::View.new(path, elements))
+          end
+        end
+      end
     end
   end
 end
diff --git a/qa/qa/page/element.rb b/qa/qa/page/element.rb
index c634e834c96..e8e537070cb 100644
--- a/qa/qa/page/element.rb
+++ b/qa/qa/page/element.rb
@@ -1,6 +1,32 @@
 module QA
   module Page
     class Element
+      attr_reader :name
+
+      def initialize(name, pattern)
+        @name = name
+        @pattern = pattern
+      end
+
+      def self.evaluate(&block)
+        Page::Element::DSL.new.tap do |evaluator|
+          evaluator.instance_exec(&block)
+
+          return evaluator.elements
+        end
+      end
+
+      class DSL
+        attr_reader :elements
+
+        def initialize
+          @elements = []
+        end
+
+        def element(name, pattern)
+          @elements.push(Page::Element.new(name, pattern))
+        end
+      end
     end
   end
 end
diff --git a/qa/qa/page/view.rb b/qa/qa/page/view.rb
index 076e4b8061b..c54a0d738bc 100644
--- a/qa/qa/page/view.rb
+++ b/qa/qa/page/view.rb
@@ -1,6 +1,12 @@
 module QA
   module Page
     class View
+      attr_reader :path, :elements
+
+      def initialize(path, elements)
+        @path = path
+        @elements = elements
+      end
     end
   end
 end
diff --git a/qa/spec/page/base_spec.rb b/qa/spec/page/base_spec.rb
new file mode 100644
index 00000000000..31ff9e258a1
--- /dev/null
+++ b/qa/spec/page/base_spec.rb
@@ -0,0 +1,35 @@
+describe QA::Page::Base do
+  describe 'page helpers' do
+    it 'exposes helpful page helpers' do
+      expect(subject).to respond_to :refresh, :wait, :scroll_to
+    end
+  end
+
+  describe 'DSL for defining view partials', '.view' do
+    subject do
+      Class.new(described_class) do
+        view 'path/to/some/view.html.haml' do
+          element :something, 'string pattern'
+          element :something_else, /regexp pattern/
+        end
+
+        view 'path/to/some/_partial.html.haml' do
+          element :something, 'string pattern'
+        end
+      end
+    end
+
+    it 'makes it possible to define page views' do
+      expect(subject.views.size).to eq 2
+      expect(subject.views).to all(be_an_instance_of QA::Page::View)
+    end
+
+    it 'populates views objects with data about elements' do
+      subject.views.first.elements.tap do |elements|
+        expect(elements.size).to eq 2
+        expect(elements).to all(be_an_instance_of QA::Page::Element)
+        expect(elements.map(&:name)).to eq [:something, :something_else]
+      end
+    end
+  end
+end
-- 
2.30.9