OSDN Git Service

add selenium test code.
authorAkira Saito <akrstjp@users.sourceforge.jp>
Sun, 31 May 2015 14:29:08 +0000 (23:29 +0900)
committerAkira Saito <akrstjp@users.sourceforge.jp>
Sun, 31 May 2015 14:29:08 +0000 (23:29 +0900)
26 files changed:
app/helpers/application_helper.rb
app/views/hooks/_quick_edit_context.html.erb
test/.rspec [new file with mode: 0644]
test/selenium/edit_core_field.rb [new file with mode: 0644]
test/selenium/edit_custom_field.rb [new file with mode: 0644]
test/selenium/pages/custom_field_new.rb [new file with mode: 0644]
test/selenium/pages/custom_fields.rb [new file with mode: 0644]
test/selenium/pages/issue_new.rb [new file with mode: 0644]
test/selenium/pages/issue_show.rb [new file with mode: 0644]
test/selenium/pages/issues.rb [new file with mode: 0644]
test/selenium/pages/mypage.rb [new file with mode: 0644]
test/selenium/pages/page.rb [new file with mode: 0644]
test/selenium/pages/project_new.rb [new file with mode: 0644]
test/selenium/pages/project_settings.rb [new file with mode: 0644]
test/selenium/pages/project_settings_members.rb [new file with mode: 0644]
test/selenium/pages/project_show.rb [new file with mode: 0644]
test/selenium/pages/projects.rb [new file with mode: 0644]
test/selenium/pages/start.rb [new file with mode: 0644]
test/selenium/pages/user_edit.rb [new file with mode: 0644]
test/selenium/pages/user_new.rb [new file with mode: 0644]
test/selenium/pages/users.rb [new file with mode: 0644]
test/selenium/pages/welcome.rb [new file with mode: 0644]
test/selenium/pages/workflow_edit.rb [new file with mode: 0644]
test/selenium/pages/workflow_permissions.rb [new file with mode: 0644]
test/selenium/setup.rb [new file with mode: 0644]
test/spec_helper.rb [new file with mode: 0644]

index a0a4b51..c92ba00 100644 (file)
@@ -34,11 +34,14 @@ module ApplicationHelper
 
      ajax_url = quick_edit_issues_edit_path(:ids => issue_ids, :target_specifier => target_specifier, :back_url => back_url)
 
-     sprintf('<li>%s</li>',
+     html_id = "quick_edit_context_#{attribute_name}"
+     html_id += "_#{additional_index}" unless additional_index.nil?
+
+     sprintf("<li id='#{html_id}'>%s</li>",
         context_menu_link(
            h(caption),
            ajax_url,
-           :class => 'icon-edit',
+           :class => 'quick_edit icon-edit',
            :disabled => disabled,
            :remote => true
         )
index 081c0d4..52d1671 100644 (file)
@@ -30,7 +30,7 @@
 
 %>
   <li class="folder">
-    <a href="#" class="submenu"><%= l(:button_quick_edit) %></a>
+    <a id="quick_edit_context" href="#" class="submenu"><%= l(:button_quick_edit) %></a>
     <ul>
       <%= quick_edit_link_to(@issue_ids, get_attribute_caption(:subject), :subject, nil, back_url, !editable(:subject,@can,readonly_fields)) %>
       <%= quick_edit_link_to(@issue_ids, get_attribute_caption(:description), :description, nil, back_url, !editable(:description,@can,readonly_fields)) %>
diff --git a/test/.rspec b/test/.rspec
new file mode 100644 (file)
index 0000000..e3b9f88
--- /dev/null
@@ -0,0 +1,3 @@
+--color
+--format d
+--require spec_helper
diff --git a/test/selenium/edit_core_field.rb b/test/selenium/edit_core_field.rb
new file mode 100644 (file)
index 0000000..fa24171
--- /dev/null
@@ -0,0 +1,131 @@
+# coding: utf-8
+
+require "json"
+require "selenium-webdriver"
+$: << File.expand_path('../../', __FILE__)
+require 'spec_helper'
+Dir[File.dirname(__FILE__) + '/pages/page.rb'].each {|file| require file }
+Dir[File.dirname(__FILE__) + '/pages/*.rb'].each {|file| require file }
+require "uri"
+require "net/http"
+include RSpec::Expectations
+
+describe "Edit" do
+
+  before(:each) do
+    profile = Selenium::WebDriver::Firefox::Profile.new
+    @driver = Selenium::WebDriver.for :firefox, :profile => profile
+    @driver.manage.window.maximize
+    @base_url = "http://localhost:3000/"
+    @accept_next_alert = true
+    @driver.manage.timeouts.implicit_wait = 10
+    @verification_errors = []
+    @default_project = "test"
+    @default_user = "admin"
+    @default_password = "dummy"
+    @issue_id = 1
+    start_page = QuickEdit::Test::Pages::StartPage.new(@driver, @base_url, @default_project)
+    first_page = start_page.login @default_user, @default_password
+    @issues_page = first_page.open_issues
+  end
+  
+  after(:each) do
+    @driver.quit
+    expect(@verification_errors).to match_array []
+  end
+  
+  it "subject can edit" do
+    new_value = 'dummy'
+    expect( edit(@issue_id, :subject, new_value) ).to eq new_value
+
+    new_value = 'subject: new_value'
+    expect( edit(@issue_id, :subject, new_value) ).to eq new_value
+
+    expect( edit_with_alert(@issue_id, :subject, "") ).to eq new_value
+  end
+
+  it "start_date can edit" do
+    new_value = '1900-01-01'
+    expect( edit(@issue_id, :start_date, new_value) ).to eq new_value
+
+    new_value = '1900-01-02'
+    expect( edit(@issue_id, :start_date, new_value) ).to eq new_value
+
+    expect( edit_with_alert(@issue_id, :start_date, "") ).to eq new_value
+  end
+
+  it "due_date can edit" do
+    new_value = '2000-01-01'
+    expect( edit(@issue_id, :due_date, new_value) ).to eq new_value
+
+    new_value = '2000-01-02'
+    expect( edit(@issue_id, :due_date, new_value) ).to eq new_value
+
+    expect( edit_with_alert(@issue_id, :due_date, "") ).to eq new_value
+  end
+
+  it "description can edit" do
+    new_value = 'dummy'
+    expect( edit(@issue_id, :description, new_value) ).to eq new_value
+
+    new_value = 'description: new_value'
+    expect( edit(@issue_id, :description, new_value) ).to eq new_value
+
+    expect( edit_with_alert(@issue_id, :description, "") ).to eq new_value
+  end
+
+  def edit(issue_id, attribute_name, new_value)
+    @issues_page.quick_edit_for_core_field issue_id, attribute_name, new_value
+
+    field_value = get_core_field(issue_id, attribute_name)
+    field_value
+  end
+
+  def edit_with_alert(issue_id, attribute_name, new_value)
+    @issues_page.quick_edit_for_core_field issue_id, attribute_name, new_value, true
+    @issues_page.alert.accept
+
+    field_value = get_core_field(issue_id, attribute_name)
+    field_value
+  end
+
+  def edit_custom_field(issue_id, custom_field_name, new_value)
+    cf = get_custom_field(issue_id, custom_field_name)
+    cf_id = cf["id"]
+
+    @issues_page.quick_edit_for_custom_field issue_id, cf_id, new_value
+
+    cf = get_custom_field(issue_id, custom_field_name)
+    cf["value"]
+  end
+
+  def get_core_field(issue_id, attribute_name)
+    json = get_json("issues/#{issue_id}.json")
+
+    json["issue"][attribute_name.to_s]
+  end
+
+  def get_custom_field(issue_id, custom_field_name)
+    cf_hash_list = get_custom_fields(issue_id)
+
+    cf_hash = cf_hash_list.select do |cf_hash|
+      cf_hash["name"] == custom_field_name.to_s
+    end
+
+    cf_hash.first
+  end
+
+  def get_custom_fields(issue_id)
+    json = get_json("issues/#{issue_id}.json")
+
+    json["issue"]["custom_fields"]
+  end
+
+  def get_json(path)
+    uri = URI::parse "#{@base_url}#{path}"
+    res = Net::HTTP::get_response(uri)
+    JSON.parse(res.body)
+  end
+  
+  
+end
diff --git a/test/selenium/edit_custom_field.rb b/test/selenium/edit_custom_field.rb
new file mode 100644 (file)
index 0000000..918ac11
--- /dev/null
@@ -0,0 +1,174 @@
+# coding: utf-8
+
+require "json"
+require "selenium-webdriver"
+$: << File.expand_path('../../', __FILE__)
+require 'spec_helper'
+Dir[File.dirname(__FILE__) + '/pages/page.rb'].each {|file| require file }
+Dir[File.dirname(__FILE__) + '/pages/*.rb'].each {|file| require file }
+require "uri"
+require "net/http"
+include RSpec::Expectations
+
+describe "Edit" do
+
+  before(:each) do
+    profile = Selenium::WebDriver::Firefox::Profile.new
+    @driver = Selenium::WebDriver.for :firefox, :profile => profile
+    @driver.manage.window.maximize
+    @base_url = "http://localhost:3000/"
+    @accept_next_alert = true
+    @driver.manage.timeouts.implicit_wait = 10
+    @verification_errors = []
+    @default_project = "test"
+    @default_user = "admin"
+    @default_password = "dummy"
+    @issue_id = 1
+    start_page = QuickEdit::Test::Pages::StartPage.new(@driver, @base_url, @default_project)
+    first_page = start_page.login @default_user, @default_password
+    @issues_page = first_page.open_issues
+  end
+  
+  after(:each) do
+    @driver.quit
+    expect(@verification_errors).to match_array []
+  end
+  
+  it "custom_text can edit" do
+    new_value = 'dummy'
+    expect( edit_custom_field(@issue_id, :custom_text, new_value) ).to eq new_value
+
+    new_value = 'custom_text: new_value'
+    expect( edit_custom_field(@issue_id, :custom_text, new_value) ).to eq new_value
+
+    invalid_value = ''
+    expect( edit_custom_field_with_alert(@issue_id, :custom_text, invalid_value) ).to eq new_value
+  end
+
+  it "custom_int can edit" do
+    new_value = '0'
+    expect( edit_custom_field(@issue_id, :custom_int, new_value) ).to eq new_value
+
+    new_value = '2147483647'
+    expect( edit_custom_field(@issue_id, :custom_int, new_value) ).to eq new_value
+
+    new_value = '+10'
+    expect( edit_custom_field(@issue_id, :custom_int, new_value).to_i ).to eq new_value.to_i
+
+    new_value = '-10'
+    expect( edit_custom_field(@issue_id, :custom_int, new_value).to_i ).to eq new_value.to_i
+
+    invalid_value = 'a'
+    expect( edit_custom_field_with_alert(@issue_id, :custom_int, invalid_value) ).to eq new_value
+
+    invalid_value = ''
+    expect( edit_custom_field_with_alert(@issue_id, :custom_int, "") ).to eq new_value
+  end
+
+  it "custom_date can edit" do
+    new_value = '1900-01-01'
+    expect( edit_custom_field(@issue_id, :custom_date, new_value) ).to eq new_value
+
+    new_value = '2015-01-01'
+    expect( edit_custom_field(@issue_id, :custom_date, new_value) ).to eq new_value
+
+    invalid_value = '2015-01-0a'
+    expect( edit_custom_field_with_alert(@issue_id, :custom_date, invalid_value) ).to eq new_value
+
+    invalid_value = ''
+    expect( edit_custom_field_with_alert(@issue_id, :custom_date, invalid_value) ).to eq new_value
+  end
+
+  it "custom_long can edit" do
+    new_value = 'dummy'
+    expect( edit_custom_field(@issue_id, :custom_long, new_value) ).to eq new_value
+
+    new_value = 'custom_long: new_value '
+    expect( edit_custom_field(@issue_id, :custom_long, new_value) ).to eq new_value
+
+    invalid_value = ''
+    expect( edit_custom_field_with_alert(@issue_id, :custom_long, invalid_value) ).to eq new_value
+  end
+
+  it "custom_float can edit" do
+    new_value = '0'
+    expect( edit_custom_field(@issue_id, :custom_float, new_value) ).to eq new_value
+
+    new_value = '0.1'
+    expect( edit_custom_field(@issue_id, :custom_float, new_value).to_f ).to eq new_value.to_f
+
+    new_value = '+0.1'
+    expect( edit_custom_field(@issue_id, :custom_float, new_value).to_f ).to eq new_value.to_f
+
+    new_value = '-0.1'
+    expect( edit_custom_field(@issue_id, :custom_float, new_value).to_f ).to eq new_value.to_f
+
+    new_value = '0.1e2'
+    expect( edit_custom_field(@issue_id, :custom_float, new_value).to_f ).to eq new_value.to_f
+
+    new_value = '0.1e-2'
+    expect( edit_custom_field(@issue_id, :custom_float, new_value).to_f ).to eq new_value.to_f
+
+    invalid_value = ''
+    expect( edit_custom_field_with_alert(@issue_id, :custom_float, invalid_value) ).to eq new_value
+  end
+
+  def edit(issue_id, attribute_name, new_value)
+    @issues_page.quick_edit issue_id, attribute_name, new_value
+
+    field_value = get_core_field(issue_id, attribute_name)
+    field_value
+  end
+
+  def edit_custom_field(issue_id, custom_field_name, new_value)
+    cf = get_custom_field(issue_id, custom_field_name)
+    cf_id = cf["id"]
+
+    @issues_page.quick_edit_for_custom_field issue_id, cf_id, new_value
+
+    cf = get_custom_field(issue_id, custom_field_name)
+    cf["value"]
+  end
+
+  def edit_custom_field_with_alert(issue_id, custom_field_name, new_value="")
+    cf = get_custom_field(issue_id, custom_field_name)
+    cf_id = cf["id"]
+
+    @issues_page.quick_edit_for_custom_field issue_id, cf_id, new_value, true
+    @issues_page.alert.accept
+
+    cf = get_custom_field(issue_id, custom_field_name)
+    cf["value"]
+  end
+
+
+  def get_core_field(issue_id, attribute_name)
+    json = get_json("issues/#{issue_id}.json")
+
+    json["issue"][attribute_name.to_s]
+  end
+
+  def get_custom_field(issue_id, custom_field_name)
+    cf_hash_list = get_custom_fields(issue_id)
+
+    cf_hash = cf_hash_list.select do |cf_hash|
+      cf_hash["name"] == custom_field_name.to_s
+    end
+
+    cf_hash.first
+  end
+
+  def get_custom_fields(issue_id)
+    json = get_json("issues/#{issue_id}.json")
+
+    json["issue"]["custom_fields"]
+  end
+
+  def get_json(path)
+    uri = URI::parse "#{@base_url}#{path}"
+    res = Net::HTTP::get_response(uri)
+    JSON.parse(res.body)
+  end
+  
+  
+end
diff --git a/test/selenium/pages/custom_field_new.rb b/test/selenium/pages/custom_field_new.rb
new file mode 100644 (file)
index 0000000..b2f8daf
--- /dev/null
@@ -0,0 +1,38 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class CustomFieldNewPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-custom_fields action-new']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/custom_fields/new?type=IssueCustomField"
+          CustomFieldNewPage.new driver, base_url, project
+        end
+
+        def create(name, format)
+          input_text :id, :custom_field_name, name
+          select :id, :custom_field_field_format, format
+
+          # check bug tracker
+          click :id, 'custom_field_tracker_ids_1'
+
+          # check for all projects
+          click :id, 'custom_field_is_for_all'
+
+          # submit
+          click :name, 'commit'
+
+          CustomFieldsPage.new @driver, @base_url, @project
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/custom_fields.rb b/test/selenium/pages/custom_fields.rb
new file mode 100644 (file)
index 0000000..92cba52
--- /dev/null
@@ -0,0 +1,39 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class CustomFieldsPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-custom_fields action-index']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/custom_fields/"
+          CustomFieldsPage.new driver, base_url, project
+        end
+
+        def open_new_page
+          CustomFieldNewPage.open @driver, @base_url, @project
+        end
+
+        def find_field(name)
+          elements = find_elements(:css, 'td > a')
+          elements = elements.select do |e|
+            e.text == name.to_s
+          end
+
+          if elements.empty?
+            return nil
+          else
+            /custom_fields\/(\d+)\// =~ elements[0].attribute('href')
+            Regexp.last_match(1)
+          end
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/issue_new.rb b/test/selenium/pages/issue_new.rb
new file mode 100644 (file)
index 0000000..691ffea
--- /dev/null
@@ -0,0 +1,33 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class IssueNewPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-issues action-new']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/projects/#{project}/issues/new"
+          IssueNewPage.new driver, base_url, project
+        end
+
+        def create(tracker, subject)
+          select_tracker tracker
+          input_text :id, :issue_subject, subject
+          click :name, :commit
+
+          IssueShowPage.new @driver, @base_url, @project
+        end
+
+        def select_tracker(tracker)
+          select :id, :issue_tracker_id, {:bug=>1, :feature=>2, :support=>3}[tracker.to_sym]
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/issue_show.rb b/test/selenium/pages/issue_show.rb
new file mode 100644 (file)
index 0000000..c1915e1
--- /dev/null
@@ -0,0 +1,43 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class IssueShowPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-issues action-show']"
+        end
+
+        def self.open(driver, base_url, project, issue_id)
+          driver.get "#{base_url}/projects/#{project}/issues/#{issue_id}"
+          IssueShowPage.new driver, base_url, project, issue_id
+        end
+
+        def id
+          title = @driver.getTitle()
+          /^(\w+) #(\d+)/ =~ title
+          Regexp.last_match(1)
+        end
+
+        def subject
+          find_element :css, "div.subject h3"
+        end
+
+        def start_date
+          find_element :css, "td.start-date"
+        end
+
+        def due_date
+          find_element :css, "td.due-date"
+        end
+        def description
+          find_element :css, "div.description > div.wiki > p"
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/issues.rb b/test/selenium/pages/issues.rb
new file mode 100644 (file)
index 0000000..cbecb25
--- /dev/null
@@ -0,0 +1,81 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class IssuesPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-issues action-index']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/projects/#{project}/issues/"
+          IssuesPage.new driver, base_url, project
+        end
+
+        def issue_ids_on_page
+          issue_elements = find_elements(:css, "tr.issue")
+          issue_ids = issue_elements.map do |e|
+            #p "find:" + e.attribute("id")
+            /issue-(\d+)/ =~ e.attribute("id")
+            Regexp.last_match(1)
+          end
+          issue_ids
+        end
+
+        def open_new_page()
+          IssueNewPage.open @driver, @base_url, @project
+        end
+
+        def open_context(issue_id)
+          wait
+
+          element = find_element(:css, "#issue-#{issue_id} > td.subject")
+          action.move_to(element).context_click(element).perform
+        end
+
+        def quick_edit(issue_id, menu_selector, new_value)
+          open_context issue_id
+
+          menu_element = find_element(:id, "quick_edit_context")
+          menu_item_element = find_element(:css, menu_selector)
+          action.move_to(menu_element).click(menu_item_element).perform
+
+          input_text :id, "new_value", new_value
+
+          buttons = find_elements(:css, "button > span")
+          submit_button = buttons.select {|button| button.text =~ /Submit/}
+          submit_button.first.click
+        end
+
+        def quick_edit_for_core_field(issue_id, attribute_name, new_value, desire_alerting = false)
+          menu_selector = "#quick_edit_context_#{attribute_name} > a"
+
+          quick_edit(issue_id, menu_selector, new_value)
+
+          IssuesPage.new @driver, @base_url, @project unless desire_alerting
+        end
+
+        def quick_edit_for_custom_field(issue_id, custom_field_id, new_value, desire_alerting = false)
+          open_context issue_id
+
+          menu_element = find_element(:id, "quick_edit_context")
+          menu_item_element = find_element(:css, "#quick_edit_context_custom_field_values_#{custom_field_id} > a")
+
+          action.move_to(menu_element).click(menu_item_element).perform
+
+          input_text :id, "new_value", new_value
+
+          buttons = find_elements(:css, "button > span")
+          submit_button = buttons.select {|button| button.text =~ /Submit/}
+          submit_button.first.click
+
+          IssuesPage.new @driver, @base_url, @project unless desire_alerting
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/mypage.rb b/test/selenium/pages/mypage.rb
new file mode 100644 (file)
index 0000000..a6ba5b5
--- /dev/null
@@ -0,0 +1,22 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class MyPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-my action-page']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/my/page"
+          MyPage.new driver, base_url, project
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/page.rb b/test/selenium/pages/page.rb
new file mode 100644 (file)
index 0000000..6506bfb
--- /dev/null
@@ -0,0 +1,112 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class Page
+        def initialize(driver, base_url, project)
+          @driver = driver
+          @base_url = base_url
+          @project = project
+          @default_wait = 0.2
+          @retry = 0
+          @retry_limit = 2
+        end
+
+        def get(url)
+          @driver.get url
+
+          wait
+        end
+
+        def wait(sec=nil)
+          sec = @default_wait if sec.nil?
+          sleep sec
+        end
+
+        def find_element(by, target)
+          @driver.find_element(by, target)
+        end
+
+        def find_elements(by, target)
+          @driver.find_elements(by, target)
+        end
+
+        def input_text(by, target, value)
+          wait
+
+          element = find_element(by, target)
+          element.clear
+          element.send_keys value.to_s unless value.nil? || value.empty?
+        end
+
+        def click(by, target)
+          wait
+
+          begin
+            element = find_element(by, target)
+            element.click
+            @retry = 0
+          rescue Selenium::WebDriver::Error::StaleElementReferenceError => e
+            if @retry < @retry_limit
+              @retry += 1
+              p "+++ retry for click(#{by},#{target})"
+              retry
+            else
+              raise e
+            end
+          end
+        end
+
+        def select(by, target, value)
+          wait
+
+          element = find_element(by, target)
+          select = Selenium::WebDriver::Support::Select.new(element)
+          select.select_by :value, value.to_s
+        end
+
+        def selected(by_or_element, target=nil)
+          if target.nil?
+            element = by_or_element
+          else
+            element = find_element(by, target)
+          end
+          select = Selenium::WebDriver::Support::Select.new(element)
+          select.selected_options
+        end
+
+        def action
+          @driver.action
+        end
+
+        def alert
+          wait 3
+
+          @driver.switch_to.alert
+        end
+
+        def open_projects
+          ProjectsPage.open @driver, @base_url, @project
+        end
+
+        def open_users
+          UsersPage.open @driver, @base_url, @project
+        end
+
+        def open_custom_fields
+          CustomFieldsPage.open @driver, @base_url, @project
+        end
+
+        def open_workflow_edit
+          WorkflowEditPage.open @driver, @base_url, @project
+        end
+
+        def open_issues
+          IssuesPage.open @driver, @base_url, @project
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/project_new.rb b/test/selenium/pages/project_new.rb
new file mode 100644 (file)
index 0000000..0e55268
--- /dev/null
@@ -0,0 +1,30 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class ProjectNewPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-projects action-new']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/projects/new"
+          ProjectNewPage.new driver, base_url, project
+        end
+
+        def create(id, name)
+          input_text :id, 'project_name', name
+          input_text :id, 'project_identifier', id
+          click :name, 'commit'
+
+          ProjectSettingsPage.new @driver, @base_url, @project
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/project_settings.rb b/test/selenium/pages/project_settings.rb
new file mode 100644 (file)
index 0000000..8a90616
--- /dev/null
@@ -0,0 +1,25 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class ProjectSettingsPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-projects action-settings']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/projects/#{project}/settings"
+          ProjectSettingsPage.new driver, base_url, project
+        end
+
+        def open_members
+          ProjectSettingsMembersPage.open @driver, @base_url, @project
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/project_settings_members.rb b/test/selenium/pages/project_settings_members.rb
new file mode 100644 (file)
index 0000000..f5493cd
--- /dev/null
@@ -0,0 +1,79 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class ProjectSettingsMembersPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-projects action-settings']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/projects/#{project}/settings/members"
+          ProjectSettingsMembersPage.new driver, base_url, project
+        end
+
+        def find_role(user_id)
+          begin
+            pnodata = find_element(:css, "p.nodata")
+            if pnodata.displayed?
+              return nil
+            end
+          rescue Selenium::WebDriver::Error::NoSuchElementError
+            # next
+          end
+
+          member_elements = find_elements(:css, "tr.member")
+          target_tr = member_elements.select do | element |
+            e = element.find_element(:css, "td.user > a.user")
+            href = e.attribute("href")
+            /\/users\/(\d+)/ =~ href
+            id = Regexp.last_match(1)
+
+            id.to_i == user_id.to_i
+          end
+
+          if target_tr.empty?
+            nil
+          else
+            target_tr.first.find_element(:css, "td.roles > span").text
+          end
+        end
+
+        def add(user_id, role_id)
+          membership_elements = find_elements(:css, 'input[name^=membership]')
+          userid_elements = membership_elements.select do |membership_element|
+            name = membership_element.attribute("name")
+            /membership\[user_ids\]\[\]/ =~ name
+          end
+
+          userid_element = userid_elements.select do |userid_element|
+            value = userid_element.attribute("value")
+            value.to_i() == user_id.to_i()
+          end
+
+          userid_element.first.click
+
+          roleid_elements = membership_elements.select do |membership_element|
+            name = membership_element.attribute("name")
+            /membership\[role_ids\]\[\]/ =~ name
+          end
+
+          roleid_element = roleid_elements.select do |roleid_element|
+            value = roleid_element.attribute("value")
+            value.to_i == role_id.to_i
+          end
+
+          roleid_element.first.click
+
+          click :id, "member-add-submit"
+
+          ProjectSettingsMembersPage.new @driver, @base_url, @project
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/project_show.rb b/test/selenium/pages/project_show.rb
new file mode 100644 (file)
index 0000000..ab44be1
--- /dev/null
@@ -0,0 +1,21 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class ProjectShowPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-projects action-show']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/projects/#{project}"
+          ProjectShowPage.new driver, base_url, project
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/projects.rb b/test/selenium/pages/projects.rb
new file mode 100644 (file)
index 0000000..202c9c4
--- /dev/null
@@ -0,0 +1,29 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class ProjectsPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-projects action-index']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/projects"
+          ProjectsPage.new driver, base_url, project
+        end
+
+        def open_new_page
+          ProjectNewPage.open @driver, @base_url, @project
+        end
+
+        def open_settings_page(project)
+          ProjectSettingsPage.open @driver, @base_url, project
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/start.rb b/test/selenium/pages/start.rb
new file mode 100644 (file)
index 0000000..d66923b
--- /dev/null
@@ -0,0 +1,25 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class StartPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          get "#{base_url}/login"
+          find_element :id, "username"
+        end
+
+        def login(login_id, password)
+          input_text :id, "username", login_id
+          input_text :id, "password", password
+          click :name, "login"
+
+          MyPage.new @driver, @base_url, @project
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/user_edit.rb b/test/selenium/pages/user_edit.rb
new file mode 100644 (file)
index 0000000..e010f70
--- /dev/null
@@ -0,0 +1,27 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class UserEditPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-users action-edit']"
+        end
+
+        def self.open(driver, base_url, project, user_id)
+          driver.get "#{base_url}/users/#{user_id}/edit"
+          UserEditPage.new driver, base_url, project
+        end
+
+        def id
+          url = @driver.getCurrentUrl()
+          /users\/(\d+)\/edit/ =~ url
+          Regexp.last_match(1)
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/user_new.rb b/test/selenium/pages/user_new.rb
new file mode 100644 (file)
index 0000000..4e21033
--- /dev/null
@@ -0,0 +1,32 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class UserNewPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-users action-new']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/users/new"
+          UserNewPage.new driver, base_url, project
+        end
+
+        def create(username, firstname, lastname, mail, password)
+          input_text :id, :user_login, username
+          input_text :id, :user_firstname, firstname
+          input_text :id, :user_lastname, lastname
+          input_text :id, :user_mail, mail
+          input_text :id, :user_password, password
+          input_text :id, :user_password_confirmation, password
+          click :name, :commit
+          UserEditPage.new @driver, @base_url, @project
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/users.rb b/test/selenium/pages/users.rb
new file mode 100644 (file)
index 0000000..34af225
--- /dev/null
@@ -0,0 +1,45 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class UsersPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-users action-index']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/users"
+          UsersPage.new driver, base_url, project
+        end
+
+        def open_new_page
+          UserNewPage.open @driver, @base_url, @project
+        end
+
+        def open_user_page(user_id)
+          UserShowPage.open @driver, @base_url, @project, user_id
+        end
+
+
+        def find_user(username)
+          elements = find_elements(:css, "tr.user>td>a")
+          users = elements.select do |u|
+            u.text == username.to_s
+          end
+
+          if users.empty?
+            return nil
+          else
+            url = users.first.attribute("href")
+            /users\/(\d+)\/edit/ =~ url
+            return Regexp.last_match(1)
+          end
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/welcome.rb b/test/selenium/pages/welcome.rb
new file mode 100644 (file)
index 0000000..acb1737
--- /dev/null
@@ -0,0 +1,16 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class WelcomePage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-welcome action-index']"
+        end
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/workflow_edit.rb b/test/selenium/pages/workflow_edit.rb
new file mode 100644 (file)
index 0000000..a0f10a9
--- /dev/null
@@ -0,0 +1,26 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class WorkflowEditPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-workflows action-edit']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/workflows/edit"
+          WorkflowEditPage.new driver, base_url, project
+        end
+
+        def open_field_permission_page
+          WorkflowPermissionsPage.open @driver, @base_url, @project
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/pages/workflow_permissions.rb b/test/selenium/pages/workflow_permissions.rb
new file mode 100644 (file)
index 0000000..6b539b3
--- /dev/null
@@ -0,0 +1,65 @@
+#coding: utf-8
+
+module QuickEdit
+  module Test
+    module Pages
+      class WorkflowPermissionsPage < Page
+        def initialize(driver, base_url, project)
+          super(driver, base_url, project)
+
+          find_element :css, "body[class='controller-workflows action-permissions']"
+        end
+
+        def self.open(driver, base_url, project)
+          driver.get "#{base_url}/workflows/permissions"
+          WorkflowPermissionsPage.new driver, base_url, project
+        end
+
+        def get_permissions(role_id, tracker, target_state, target_field_ids)
+          select :id, :role_id, role_id
+          click :css, "input[type='submit']"
+
+          permission_elements = find_elements(:css, 'select[name^=permissions]')
+
+          permissions = {}
+          permission_elements.each do |permission_element|
+            name = permission_element.attribute("name")
+            /permissions\[(.+?)\]\[(\d+)\]/ =~ name
+            id = Regexp.last_match(1)
+            state = Regexp.last_match(2)
+
+            if state == target_state && target_field_ids.include?(id)
+              permissions[id] = { state => selected(permission_element).first.attribute("value") }
+            end
+          end
+
+          target_field_ids.each do |id|
+            unless permissions.has_key? id
+              permissions[id] = {}
+            end
+          end
+
+          permissions
+        end
+
+        def update(role_id, tracker, permissions)
+          select :id, :role_id, role_id
+          click :css, "input[type='submit']"
+
+          find_elements :class, :fields_permissions
+
+          permissions.each do |k,v| 
+            v.each do |state, permission|
+              select :name, "permissions[#{k}][#{state}]", permission
+            end
+          end
+          click :name, :commit
+
+          WorkflowPermissionsPage.new @driver, @base_url, @project
+        end
+
+      end
+    end
+  end
+end
+
diff --git a/test/selenium/setup.rb b/test/selenium/setup.rb
new file mode 100644 (file)
index 0000000..984f0a5
--- /dev/null
@@ -0,0 +1,164 @@
+# coding: utf-8
+
+require "json"
+require "selenium-webdriver"
+$: << File.expand_path('../../', __FILE__)
+require 'spec_helper'
+Dir[File.dirname(__FILE__) + '/pages/page.rb'].each {|file| require file }
+Dir[File.dirname(__FILE__) + '/pages/*.rb'].each {|file| require file }
+require "uri"
+require "net/http"
+include RSpec::Expectations
+
+describe "Edit" do
+
+  before(:each) do
+    profile = Selenium::WebDriver::Firefox::Profile.new
+    @driver = Selenium::WebDriver.for :firefox, :profile => profile
+    @driver.manage.window.maximize
+    @base_url = "http://localhost:3000/"
+    @accept_next_alert = true
+    @driver.manage.timeouts.implicit_wait = 10
+    @verification_errors = []
+    @default_project = "test"
+    @default_user = "admin"
+    @default_password = "dummy"
+    start_page = QuickEdit::Test::Pages::StartPage.new(@driver, @base_url, @default_project)
+    @first_page = start_page.login @default_user, @default_password
+  end
+  
+  after(:each) do
+    @driver.quit
+    expect(@verification_errors).to match_array []
+  end
+
+  it "setup project" do
+    json = get_json("projects.json")
+    test_project = json["projects"].select do |project|
+       project["name"] == "test"
+    end
+    if test_project.empty?
+      projects_page = @first_page.open_projects
+      project_new_page = projects_page.open_new_page
+      project_settings_page = project_new_page.create @default_project, @default_project
+    end
+  end
+
+  it "setup issues" do
+    issues_page = @first_page.open_issues
+    issue_ids = issues_page.issue_ids_on_page
+    if issue_ids.empty?
+      issue_new_page = issues_page.open_new_page()
+      issue_show_page = issue_new_page.create(:bug, 'first subject')
+      @issue_id = issue_show_page.id
+    else
+      @issue_id = issue_ids.first
+    end
+  end
+
+  it "setup custom fields" do
+    custom_fields_page = @first_page.open_custom_fields
+    id = custom_fields_page.find_field(:custom_text)
+    if id.nil?
+      new_page = custom_fields_page.open_new_page
+      custom_fields_page = new_page.create :custom_text, :string
+    end
+
+    id = custom_fields_page.find_field(:custom_long)
+    if id.nil?
+      new_page = custom_fields_page.open_new_page
+      custom_fields_page = new_page.create :custom_long, :text
+    end
+
+    id = custom_fields_page.find_field(:custom_int)
+    if id.nil?
+      new_page = custom_fields_page.open_new_page
+      custom_fields_page = new_page.create :custom_int, :int
+    end
+
+    id = custom_fields_page.find_field(:custom_float)
+    if id.nil?
+      new_page = custom_fields_page.open_new_page
+      custom_fields_page = new_page.create :custom_float, :float
+    end
+
+    id = custom_fields_page.find_field(:custom_date)
+    if id.nil?
+      new_page = custom_fields_page.open_new_page
+      custom_fields_page = new_page.create :custom_date, :date
+    end
+
+    id = custom_fields_page.find_field(:readonly_in_progress)
+    if id.nil?
+      new_page = custom_fields_page.open_new_page
+      custom_fields_page = new_page.create :readonly_in_progress, :string
+    end
+  end
+
+  it "setup users" do
+    users_page = @first_page.open_users
+    rep_user_id = users_page.find_user("rep1")
+    if rep_user_id.nil?
+      user_new_page = users_page.open_new_page
+      user_edit_page = user_new_page.create("rep1", "1", "rep", "rep1@localhost.com", "dummy")
+    end
+  end
+
+  it "setup roles" do
+    users_page = @first_page.open_users
+    rep_user_id = users_page.find_user("rep1")
+
+    projects_page = users_page.open_projects
+    project_page = projects_page.open_settings_page(@default_project)
+    members_page = project_page.open_members
+    role_name = members_page.find_role(rep_user_id)
+    #p role_name
+    if role_name.nil?
+      reporter_role_id = 5 #reporter_role_id
+      members_page = members_page.add rep_user_id, reporter_role_id
+      members_page.find_role(rep_user_id)
+    end
+  end
+
+  it "setup permissions" do
+    role_reporter = "5" #reporter
+    tracker_bug = "1" #bug
+    state_new = "1" #new
+    custom_field_readonly = get_custom_field(1, "readonly_in_progress")["id"].to_s
+    #p "readonly in progress's id = #{custom_field_readonly}"
+
+    workflow_edit_page = @first_page.open_workflow_edit
+    permission_page = workflow_edit_page.open_field_permission_page
+    permissions = permission_page.get_permissions(role_reporter, tracker_bug, state_new, [custom_field_readonly])
+    #p permissions.inspect
+
+    permission = permissions[custom_field_readonly][state_new]
+    if permission.nil? || permission != "readonly"
+      permissions = { custom_field_readonly => {state_new => "readonly"} }
+      permission_page.update role_reporter, tracker_bug, permissions
+    end
+  end
+
+  def get_custom_field(issue_id, custom_field_name)
+    cf_hash_list = get_custom_fields(issue_id)
+
+    cf_hash = cf_hash_list.select do |cf_hash|
+      cf_hash["name"] == custom_field_name.to_s
+    end
+
+    cf_hash.first
+  end
+
+  def get_custom_fields(issue_id)
+    json = get_json("issues/#{issue_id}.json")
+
+    json["issue"]["custom_fields"]
+  end
+
+  def get_json(path)
+    uri = URI::parse "#{@base_url}#{path}"
+    res = Net::HTTP::get_response(uri)
+    JSON.parse(res.body)
+  end
+  
+end
diff --git a/test/spec_helper.rb b/test/spec_helper.rb
new file mode 100644 (file)
index 0000000..b598abe
--- /dev/null
@@ -0,0 +1,91 @@
+# This file was generated by the `rspec --init` command. Conventionally, all
+# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
+# The generated `.rspec` file contains `--require spec_helper` which will cause
+# this file to always be loaded, without a need to explicitly require it in any
+# files.
+#
+# Given that it is always loaded, you are encouraged to keep this file as
+# light-weight as possible. Requiring heavyweight dependencies from this file
+# will add to the boot time of your test suite on EVERY test run, even for an
+# individual file that may not need all of that loaded. Instead, consider making
+# a separate helper file that requires the additional dependencies and performs
+# the additional setup, and require it from the spec files that actually need
+# it.
+#
+# The `.rspec` file also contains a few flags that are not defaults but that
+# users commonly want.
+#
+# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
+RSpec.configure do |config|
+  # rspec-expectations config goes here. You can use an alternate
+  # assertion/expectation library such as wrong or the stdlib/minitest
+  # assertions if you prefer.
+  config.expect_with :rspec do |expectations|
+    # This option will default to `true` in RSpec 4. It makes the `description`
+    # and `failure_message` of custom matchers include text for helper methods
+    # defined using `chain`, e.g.:
+    #     be_bigger_than(2).and_smaller_than(4).description
+    #     # => "be bigger than 2 and smaller than 4"
+    # ...rather than:
+    #     # => "be bigger than 2"
+    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
+  end
+
+  # rspec-mocks config goes here. You can use an alternate test double
+  # library (such as bogus or mocha) by changing the `mock_with` option here.
+  config.mock_with :rspec do |mocks|
+    # Prevents you from mocking or stubbing a method that does not exist on
+    # a real object. This is generally recommended, and will default to
+    # `true` in RSpec 4.
+    mocks.verify_partial_doubles = true
+  end
+
+# The settings below are suggested to provide a good initial experience
+# with RSpec, but feel free to customize to your heart's content.
+=begin
+  # These two settings work together to allow you to limit a spec run
+  # to individual examples or groups you care about by tagging them with
+  # `:focus` metadata. When nothing is tagged with `:focus`, all examples
+  # get run.
+  config.filter_run :focus
+  config.run_all_when_everything_filtered = true
+
+  # Limits the available syntax to the non-monkey patched syntax that is
+  # recommended. For more details, see:
+  #   - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
+  #   - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
+  #   - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
+  config.disable_monkey_patching!
+
+  # This setting enables warnings. It's recommended, but in some cases may
+  # be too noisy due to issues in dependencies.
+  config.warnings = true
+
+  # Many RSpec users commonly either run the entire suite or an individual
+  # file, and it's useful to allow more verbose output when running an
+  # individual spec file.
+  if config.files_to_run.one?
+    # Use the documentation formatter for detailed output,
+    # unless a formatter has already been configured
+    # (e.g. via a command-line flag).
+    config.default_formatter = 'doc'
+  end
+
+  # Print the 10 slowest examples and example groups at the
+  # end of the spec run, to help surface which specs are running
+  # particularly slow.
+  config.profile_examples = 10
+
+  # Run specs in random order to surface order dependencies. If you find an
+  # order dependency and want to debug it, you can fix the order by providing
+  # the seed, which is printed after each run.
+  #     --seed 1234
+  config.order = :random
+
+  # Seed global randomization in this process using the `--seed` CLI option.
+  # Setting this allows you to use `--seed` to deterministically reproduce
+  # test failures related to randomization by passing the same `--seed` value
+  # as the one that triggered the failure.
+  Kernel.srand config.seed
+=end
+end