summaryrefslogtreecommitdiff
path: root/qa/qa/runtime/browser.rb
blob: 4c64270ce92666290398c1ed15d28845814965f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
require 'rspec/core'
require 'capybara/rspec'
require 'capybara-screenshot/rspec'
require 'selenium-webdriver'

module QA
  module Runtime
    class Browser
      include QA::Scenario::Actable

      def initialize
        self.class.configure!
      end

      ##
      # Visit a page that belongs to a GitLab instance under given address.
      #
      # Example:
      #
      # visit(:gitlab, Page::Main::Login)
      # visit('http://gitlab.example/users/sign_in')
      #
      # In case of an address that is a symbol we will try to guess address
      # based on `Runtime::Scenario#something_address`.
      #
      def visit(address, page = nil, &block)
        Browser::Session.new(address, page).perform(&block)
      end

      def self.visit(address, page = nil, &block)
        new.visit(address, page, &block)
      end

      def self.configure!
        RSpec.configure do |config|
          config.define_derived_metadata(file_path: %r{/qa/specs/features/}) do |metadata|
            metadata[:type] = :feature
          end
        end

        return if Capybara.drivers.include?(:chrome)

        Capybara.register_driver :chrome do |app|
          capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
            # This enables access to logs with `page.driver.manage.get_log(:browser)`
            loggingPrefs: {
              browser: "ALL",
              client: "ALL",
              driver: "ALL",
              server: "ALL"
            }
          )

          options = Selenium::WebDriver::Chrome::Options.new
          options.add_argument("window-size=1240,1680")

          # Chrome won't work properly in a Docker container in sandbox mode
          options.add_argument("no-sandbox")

          # Run headless by default unless CHROME_HEADLESS is false
          if QA::Runtime::Env.chrome_headless?
            options.add_argument("headless")

            # Chrome documentation says this flag is needed for now
            # https://developers.google.com/web/updates/2017/04/headless-chrome#cli
            options.add_argument("disable-gpu")
          end

          # Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab-ee/issues/4252
          options.add_argument("disable-dev-shm-usage") if QA::Runtime::Env.running_in_ci?

          Capybara::Selenium::Driver.new(
            app,
            browser: :chrome,
            clear_local_storage: true,
            desired_capabilities: capabilities,
            options: options
          )
        end

        # Keep only the screenshots generated from the last failing test suite
        Capybara::Screenshot.prune_strategy = :keep_last_run

        # From https://github.com/mattheworiordan/capybara-screenshot/issues/84#issuecomment-41219326
        Capybara::Screenshot.register_driver(:chrome) do |driver, path|
          driver.browser.save_screenshot(path)
        end

        Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example|
          ::File.join(QA::Runtime::Namespace.name, example.file_path.sub('./qa/specs/features/', ''))
        end

        Capybara.configure do |config|
          config.default_driver = :chrome
          config.javascript_driver = :chrome
          config.default_max_wait_time = 10
          # https://github.com/mattheworiordan/capybara-screenshot/issues/164
          config.save_path = ::File.expand_path('../../tmp', __dir__)
        end
      end

      class Session
        include Capybara::DSL

        def initialize(instance, page = nil)
          @session_address = Runtime::Address.new(instance, page)
        end

        def url
          @session_address.address
        end

        def perform(&block)
          visit(url)

          yield.tap { clear! } if block_given?
        end

        ##
        # Selenium allows to reset session cookies for current domain only.
        #
        # See gitlab-org/gitlab-qa#102
        #
        def clear!
          visit(url)
          reset_session!
        end
      end
    end
  end
end