diff options
author | Grzegorz Bizon <grzegorz@gitlab.com> | 2017-03-13 15:01:15 +0000 |
---|---|---|
committer | Grzegorz Bizon <grzegorz@gitlab.com> | 2017-03-13 15:01:15 +0000 |
commit | 0240caa02a69e6e4e30b7fa473ba3e1baf76ef0c (patch) | |
tree | 8afae53851b53f5c762e038cb14e42e726d72c20 | |
parent | a9aff2f7989df871f836a9963cef9264523903af (diff) | |
parent | 0731365b9de9411a937bd786d6e3fd7e10099800 (diff) | |
download | gitlab-ce-0240caa02a69e6e4e30b7fa473ba3e1baf76ef0c.tar.gz |
Merge branch 'feature/gb/gitlab-qa-integration-tests' into 'master'
Add GitLab QA integrations tests to GitLab CE / EE
Closes gitlab-qa#30
See merge request !9370
33 files changed, 897 insertions, 0 deletions
diff --git a/qa/.rspec b/qa/.rspec new file mode 100644 index 00000000000..b83d9b7aa65 --- /dev/null +++ b/qa/.rspec @@ -0,0 +1,3 @@ +--color +--format documentation +--require spec_helper diff --git a/qa/Dockerfile b/qa/Dockerfile new file mode 100644 index 00000000000..2814a7bdef0 --- /dev/null +++ b/qa/Dockerfile @@ -0,0 +1,14 @@ +FROM ruby:2.3 +LABEL maintainer "Grzegorz Bizon <grzegorz@gitlab.com>" + +RUN sed -i "s/httpredir.debian.org/ftp.us.debian.org/" /etc/apt/sources.list && \ + apt-get update && apt-get install -y --force-yes \ + libqt5webkit5-dev qt5-qmake qt5-default build-essential xvfb git && \ + apt-get clean + +WORKDIR /home/qa + +COPY ./ ./ +RUN bundle install + +ENTRYPOINT ["bin/test"] diff --git a/qa/Gemfile b/qa/Gemfile new file mode 100644 index 00000000000..6bfe25ba437 --- /dev/null +++ b/qa/Gemfile @@ -0,0 +1,7 @@ +source 'https://rubygems.org' + +gem 'capybara', '~> 2.12.1' +gem 'capybara-screenshot', '~> 1.0.14' +gem 'capybara-webkit', '~> 1.12.0' +gem 'rake', '~> 12.0.0' +gem 'rspec', '~> 3.5' diff --git a/qa/README.md b/qa/README.md new file mode 100644 index 00000000000..b6b5a76f1d3 --- /dev/null +++ b/qa/README.md @@ -0,0 +1,18 @@ +## Integration tests for GitLab + +This directory contains integration tests for GitLab. + +It is part of [GitLab QA project](https://gitlab.com/gitlab-org/gitlab-qa). + +## What GitLab QA is? + +GitLab QA is an integration tests suite for GitLab. + +These are black-box and entirely click-driven integration tests you can run +against any existing instance. + +## How does it work? + +1. When we release a new version of GitLab, we build a Docker images for it. +1. Along with GitLab Docker Images we also build and publish GitLab QA images. +1. GitLab QA project uses these images to execute integration tests. diff --git a/qa/bin/qa b/qa/bin/qa new file mode 100755 index 00000000000..cecdeac14db --- /dev/null +++ b/qa/bin/qa @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +require_relative '../qa' + +QA::Scenario + .const_get(ARGV.shift) + .perform(*ARGV) diff --git a/qa/bin/test b/qa/bin/test new file mode 100755 index 00000000000..997392ad6e4 --- /dev/null +++ b/qa/bin/test @@ -0,0 +1,3 @@ +#!/bin/bash + +xvfb-run bundle exec bin/qa $@ diff --git a/qa/qa.rb b/qa/qa.rb new file mode 100644 index 00000000000..58cf615cc9f --- /dev/null +++ b/qa/qa.rb @@ -0,0 +1,81 @@ +$: << File.expand_path(File.dirname(__FILE__)) + +module QA + ## + # GitLab QA runtime classes, mostly singletons. + # + module Runtime + autoload :Release, 'qa/runtime/release' + autoload :User, 'qa/runtime/user' + autoload :Namespace, 'qa/runtime/namespace' + end + + ## + # GitLab QA Scenarios + # + module Scenario + ## + # Support files + # + autoload :Actable, 'qa/scenario/actable' + autoload :Template, 'qa/scenario/template' + + ## + # Test scenario entrypoints. + # + module Test + autoload :Instance, 'qa/scenario/test/instance' + end + + ## + # GitLab instance scenarios. + # + module Gitlab + module Project + autoload :Create, 'qa/scenario/gitlab/project/create' + end + end + end + + ## + # Classes describing structure of GitLab, pages, menus etc. + # + # Needed to execute click-driven-only black-box tests. + # + module Page + autoload :Base, 'qa/page/base' + + module Main + autoload :Entry, 'qa/page/main/entry' + autoload :Menu, 'qa/page/main/menu' + autoload :Groups, 'qa/page/main/groups' + autoload :Projects, 'qa/page/main/projects' + end + + module Project + autoload :New, 'qa/page/project/new' + autoload :Show, 'qa/page/project/show' + end + + module Admin + autoload :Menu, 'qa/page/admin/menu' + end + end + + ## + # Classes describing operations on Git repositories. + # + module Git + autoload :Repository, 'qa/git/repository' + end + + ## + # Classes that make it possible to execute features tests. + # + module Specs + autoload :Config, 'qa/specs/config' + autoload :Runner, 'qa/specs/runner' + end +end + +QA::Runtime::Release.extend_autoloads! diff --git a/qa/qa/ce/strategy.rb b/qa/qa/ce/strategy.rb new file mode 100644 index 00000000000..6d1601dfa48 --- /dev/null +++ b/qa/qa/ce/strategy.rb @@ -0,0 +1,15 @@ +module QA + module CE + module Strategy + extend self + + def extend_autoloads! + # noop + end + + def perform_before_hooks + # noop + end + end + end +end diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb new file mode 100644 index 00000000000..b9e199000d6 --- /dev/null +++ b/qa/qa/git/repository.rb @@ -0,0 +1,71 @@ +require 'uri' + +module QA + module Git + class Repository + include Scenario::Actable + + def self.perform(*args) + Dir.mktmpdir do |dir| + Dir.chdir(dir) { super } + end + end + + def location=(address) + @location = address + @uri = URI(address) + end + + def username=(name) + @username = name + @uri.user = name + end + + def password=(pass) + @password = pass + @uri.password = pass + end + + def use_default_credentials + self.username = Runtime::User.name + self.password = Runtime::User.password + end + + def clone(opts = '') + `git clone #{opts} #{@uri.to_s} ./` + end + + def shallow_clone + clone('--depth 1') + end + + def configure_identity(name, email) + `git config user.name #{name}` + `git config user.email #{email}` + end + + def commit_file(name, contents, message) + add_file(name, contents) + commit(message) + end + + def add_file(name, contents) + File.write(name, contents) + + `git add #{name}` + end + + def commit(message) + `git commit -m "#{message}"` + end + + def push_changes(branch = 'master') + `git push #{@uri.to_s} #{branch}` + end + + def commits + `git log --oneline`.split("\n") + end + end + end +end diff --git a/qa/qa/page/admin/menu.rb b/qa/qa/page/admin/menu.rb new file mode 100644 index 00000000000..b01a4e10f93 --- /dev/null +++ b/qa/qa/page/admin/menu.rb @@ -0,0 +1,19 @@ +module QA + module Page + module Admin + class Menu < Page::Base + def go_to_license + within_middle_menu { click_link 'License' } + end + + private + + def within_middle_menu + page.within('.nav-control') do + yield + end + end + end + end + end +end diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb new file mode 100644 index 00000000000..d55326c5262 --- /dev/null +++ b/qa/qa/page/base.rb @@ -0,0 +1,12 @@ +module QA + module Page + class Base + include Capybara::DSL + include Scenario::Actable + + def refresh + visit current_path + end + end + end +end diff --git a/qa/qa/page/main/entry.rb b/qa/qa/page/main/entry.rb new file mode 100644 index 00000000000..fe80deb6429 --- /dev/null +++ b/qa/qa/page/main/entry.rb @@ -0,0 +1,26 @@ +module QA + module Page + module Main + class Entry < Page::Base + def initialize + visit('/') + + # This resolves cold boot problems with login page + find('.application', wait: 120) + end + + def sign_in_using_credentials + if page.has_content?('Change your password') + fill_in :user_password, with: Runtime::User.password + fill_in :user_password_confirmation, with: Runtime::User.password + click_button 'Change your password' + end + + fill_in :user_login, with: Runtime::User.name + fill_in :user_password, with: Runtime::User.password + click_button 'Sign in' + end + end + end + end +end diff --git a/qa/qa/page/main/groups.rb b/qa/qa/page/main/groups.rb new file mode 100644 index 00000000000..84597719a84 --- /dev/null +++ b/qa/qa/page/main/groups.rb @@ -0,0 +1,20 @@ +module QA + module Page + module Main + class Groups < Page::Base + def prepare_test_namespace + return if page.has_content?(Runtime::Namespace.name) + + click_on 'New Group' + + fill_in 'group_path', with: Runtime::Namespace.name + fill_in 'group_description', + with: "QA test run at #{Runtime::Namespace.time}" + choose 'Private' + + click_button 'Create group' + end + end + end + end +end diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb new file mode 100644 index 00000000000..45db7a92fa4 --- /dev/null +++ b/qa/qa/page/main/menu.rb @@ -0,0 +1,46 @@ +module QA + module Page + module Main + class Menu < Page::Base + def go_to_groups + within_global_menu { click_link 'Groups' } + end + + def go_to_projects + within_global_menu { click_link 'Projects' } + end + + def go_to_admin_area + within_user_menu { click_link 'Admin Area' } + end + + def sign_out + within_user_menu do + find('.header-user-dropdown-toggle').click + click_link('Sign out') + end + end + + def has_personal_area? + page.has_selector?('.header-user-dropdown-toggle') + end + + private + + def within_global_menu + find('.global-dropdown-toggle').click + + page.within('.global-dropdown-menu') do + yield + end + end + + def within_user_menu + page.within('.navbar-nav') do + yield + end + end + end + end + end +end diff --git a/qa/qa/page/main/projects.rb b/qa/qa/page/main/projects.rb new file mode 100644 index 00000000000..28d3a424022 --- /dev/null +++ b/qa/qa/page/main/projects.rb @@ -0,0 +1,16 @@ +module QA + module Page + module Main + class Projects < Page::Base + def go_to_new_project + ## + # There are 'New Project' and 'New project' buttons on the projects + # page, so we can't use `click_on`. + # + button = find('a', text: /^new project$/i) + button.click + end + end + end + end +end diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb new file mode 100644 index 00000000000..b31bec27b59 --- /dev/null +++ b/qa/qa/page/project/new.rb @@ -0,0 +1,24 @@ +module QA + module Page + module Project + class New < Page::Base + def choose_test_namespace + find('#s2id_project_namespace_id').click + find('.select2-result-label', text: Runtime::Namespace.name).click + end + + def choose_name(name) + fill_in 'project_path', with: name + end + + def add_description(description) + fill_in 'project_description', with: description + end + + def create_new_project + click_on 'Create project' + end + end + end + end +end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb new file mode 100644 index 00000000000..56a270d8fcc --- /dev/null +++ b/qa/qa/page/project/show.rb @@ -0,0 +1,23 @@ +module QA + module Page + module Project + class Show < Page::Base + def choose_repository_clone_http + find('#clone-dropdown').click + + page.within('#clone-dropdown') do + find('span', text: 'HTTP').click + end + end + + def repository_location + find('#project_clone').value + end + + def wait_for_push + sleep 5 + end + end + end + end +end diff --git a/qa/qa/runtime/namespace.rb b/qa/qa/runtime/namespace.rb new file mode 100644 index 00000000000..e4910b63a14 --- /dev/null +++ b/qa/qa/runtime/namespace.rb @@ -0,0 +1,15 @@ +module QA + module Runtime + module Namespace + extend self + + def time + @time ||= Time.now + end + + def name + 'qa_test_' + time.strftime('%d_%m_%Y_%H-%M-%S') + end + end + end +end diff --git a/qa/qa/runtime/release.rb b/qa/qa/runtime/release.rb new file mode 100644 index 00000000000..4f83a773645 --- /dev/null +++ b/qa/qa/runtime/release.rb @@ -0,0 +1,28 @@ +module QA + module Runtime + ## + # Class that is responsible for plugging CE/EE extensions in, depending on + # existence of EE module. + # + # We need that to reduce the probability of conflicts when merging + # CE to EE. + # + class Release + def initialize + require "qa/#{version.downcase}/strategy" + end + + def version + @version ||= File.directory?("#{__dir__}/../ee") ? :EE : :CE + end + + def strategy + QA.const_get("QA::#{version}::Strategy") + end + + def self.method_missing(name, *args) + self.new.strategy.public_send(name, *args) + end + end + end +end diff --git a/qa/qa/runtime/user.rb b/qa/qa/runtime/user.rb new file mode 100644 index 00000000000..12ceda015f0 --- /dev/null +++ b/qa/qa/runtime/user.rb @@ -0,0 +1,15 @@ +module QA + module Runtime + module User + extend self + + def name + ENV['GITLAB_USERNAME'] || 'root' + end + + def password + ENV['GITLAB_PASSWORD'] || 'test1234' + end + end + end +end diff --git a/qa/qa/scenario/actable.rb b/qa/qa/scenario/actable.rb new file mode 100644 index 00000000000..6cdbd24780e --- /dev/null +++ b/qa/qa/scenario/actable.rb @@ -0,0 +1,23 @@ +module QA + module Scenario + module Actable + def act(*args, &block) + instance_exec(*args, &block) + end + + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def perform + yield new if block_given? + end + + def act(*args, &block) + new.act(*args, &block) + end + end + end + end +end diff --git a/qa/qa/scenario/gitlab/project/create.rb b/qa/qa/scenario/gitlab/project/create.rb new file mode 100644 index 00000000000..38522714e64 --- /dev/null +++ b/qa/qa/scenario/gitlab/project/create.rb @@ -0,0 +1,31 @@ +require 'securerandom' + +module QA + module Scenario + module Gitlab + module Project + class Create < Scenario::Template + attr_writer :description + + def name=(name) + @name = "#{name}-#{SecureRandom.hex(8)}" + end + + def perform + Page::Main::Menu.act { go_to_groups } + Page::Main::Groups.act { prepare_test_namespace } + Page::Main::Menu.act { go_to_projects } + Page::Main::Projects.act { go_to_new_project } + + Page::Project::New.perform do |page| + page.choose_test_namespace + page.choose_name(@name) + page.add_description(@description) + page.create_new_project + end + end + end + end + end + end +end diff --git a/qa/qa/scenario/template.rb b/qa/qa/scenario/template.rb new file mode 100644 index 00000000000..341998af160 --- /dev/null +++ b/qa/qa/scenario/template.rb @@ -0,0 +1,16 @@ +module QA + module Scenario + class Template + def self.perform(*args) + new.tap do |scenario| + yield scenario if block_given? + return scenario.perform(*args) + end + end + + def perform(*_args) + raise NotImplementedError + end + end + end +end diff --git a/qa/qa/scenario/test/instance.rb b/qa/qa/scenario/test/instance.rb new file mode 100644 index 00000000000..689292bc60b --- /dev/null +++ b/qa/qa/scenario/test/instance.rb @@ -0,0 +1,26 @@ +module QA + module Scenario + module Test + ## + # Run test suite against any GitLab instance, + # including staging and on-premises installation. + # + class Instance < Scenario::Template + def perform(address, *files) + Specs::Config.perform do |specs| + specs.address = address + end + + ## + # Perform before hooks, which are different for CE and EE + # + Runtime::Release.perform_before_hooks + + Specs::Runner.perform do |specs| + specs.rspec('--tty', files.any? ? files : 'qa/specs/features') + end + end + end + end + end +end diff --git a/qa/qa/specs/config.rb b/qa/qa/specs/config.rb new file mode 100644 index 00000000000..d72187fcd34 --- /dev/null +++ b/qa/qa/specs/config.rb @@ -0,0 +1,78 @@ +require 'rspec/core' +require 'capybara/rspec' +require 'capybara-webkit' +require 'capybara-screenshot/rspec' + +# rubocop:disable Metrics/MethodLength +# rubocop:disable Metrics/LineLength + +module QA + module Specs + class Config < Scenario::Template + attr_writer :address + + def initialize + @address = ENV['GITLAB_URL'] + end + + def perform + raise 'Please configure GitLab address!' unless @address + + configure_rspec! + configure_capybara! + configure_webkit! + end + + def configure_rspec! + RSpec.configure do |config| + 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`. + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + 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 + + # Run specs in random order to surface order dependencies. + config.order = :random + Kernel.srand config.seed + + config.before(:all) do + page.current_window.resize_to(1200, 1800) + end + + config.formatter = :documentation + config.color = true + end + end + + def configure_capybara! + Capybara.configure do |config| + config.app_host = @address + config.default_driver = :webkit + config.javascript_driver = :webkit + config.default_max_wait_time = 4 + + # https://github.com/mattheworiordan/capybara-screenshot/issues/164 + config.save_path = 'tmp' + end + end + + def configure_webkit! + Capybara::Webkit.configure do |config| + config.allow_url(@address) + config.block_unknown_urls + end + rescue RuntimeError # rubocop:disable Lint/HandleExceptions + # TODO, Webkit is already configured, this make this + # configuration step idempotent, should be improved. + end + end + end +end diff --git a/qa/qa/specs/features/login/standard_spec.rb b/qa/qa/specs/features/login/standard_spec.rb new file mode 100644 index 00000000000..8e1ae6efa47 --- /dev/null +++ b/qa/qa/specs/features/login/standard_spec.rb @@ -0,0 +1,14 @@ +module QA + feature 'standard root login' do + scenario 'user logs in using credentials' do + Page::Main::Entry.act { sign_in_using_credentials } + + # TODO, since `Signed in successfully` message was removed + # this is the only way to tell if user is signed in correctly. + # + Page::Main::Menu.perform do |menu| + expect(menu).to have_personal_area + end + end + end +end diff --git a/qa/qa/specs/features/project/create_spec.rb b/qa/qa/specs/features/project/create_spec.rb new file mode 100644 index 00000000000..610492b9717 --- /dev/null +++ b/qa/qa/specs/features/project/create_spec.rb @@ -0,0 +1,19 @@ +module QA + feature 'create a new project' do + scenario 'user creates a new project' do + Page::Main::Entry.act { sign_in_using_credentials } + + Scenario::Gitlab::Project::Create.perform do |project| + project.name = 'awesome-project' + project.description = 'create awesome project test' + end + + expect(page).to have_content( + /Project \S?awesome-project\S+ was successfully created/ + ) + + expect(page).to have_content('create awesome project test') + expect(page).to have_content('The repository for this project is empty') + end + end +end diff --git a/qa/qa/specs/features/repository/clone_spec.rb b/qa/qa/specs/features/repository/clone_spec.rb new file mode 100644 index 00000000000..521bd955857 --- /dev/null +++ b/qa/qa/specs/features/repository/clone_spec.rb @@ -0,0 +1,57 @@ +module QA + feature 'clone code from the repository' do + context 'with regular account over http' do + given(:location) do + Page::Project::Show.act do + choose_repository_clone_http + repository_location + end + end + + before do + Page::Main::Entry.act { sign_in_using_credentials } + + Scenario::Gitlab::Project::Create.perform do |scenario| + scenario.name = 'project-with-code' + scenario.description = 'project for git clone tests' + end + + Git::Repository.perform do |repository| + repository.location = location + repository.use_default_credentials + + repository.act do + clone + configure_identity('GitLab QA', 'root@gitlab.com') + commit_file('test.rb', 'class Test; end', 'Add Test class') + commit_file('README.md', '# Test', 'Add Readme') + push_changes + end + end + end + + scenario 'user performs a deep clone' do + Git::Repository.perform do |repository| + repository.location = location + repository.use_default_credentials + + repository.act { clone } + + expect(repository.commits.size).to eq 2 + end + end + + scenario 'user performs a shallow clone' do + Git::Repository.perform do |repository| + repository.location = location + repository.use_default_credentials + + repository.act { shallow_clone } + + expect(repository.commits.size).to eq 1 + expect(repository.commits.first).to include 'Add Readme' + end + end + end + end +end diff --git a/qa/qa/specs/features/repository/push_spec.rb b/qa/qa/specs/features/repository/push_spec.rb new file mode 100644 index 00000000000..5fe45d63d37 --- /dev/null +++ b/qa/qa/specs/features/repository/push_spec.rb @@ -0,0 +1,39 @@ +module QA + feature 'push code to repository' do + context 'with regular account over http' do + scenario 'user pushes code to the repository' do + Page::Main::Entry.act { sign_in_using_credentials } + + Scenario::Gitlab::Project::Create.perform do |scenario| + scenario.name = 'project_with_code' + scenario.description = 'project with repository' + end + + Git::Repository.perform do |repository| + repository.location = Page::Project::Show.act do + choose_repository_clone_http + repository_location + end + + repository.use_default_credentials + + repository.act do + clone + configure_identity('GitLab QA', 'root@gitlab.com') + add_file('README.md', '# This is test project') + commit('Add README.md') + push_changes + end + end + + Page::Project::Show.act do + wait_for_push + refresh + end + + expect(page).to have_content('README.md') + expect(page).to have_content('This is test project') + end + end + end +end diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb new file mode 100644 index 00000000000..83ae15d0995 --- /dev/null +++ b/qa/qa/specs/runner.rb @@ -0,0 +1,15 @@ +require 'rspec/core' + +module QA + module Specs + class Runner + include Scenario::Actable + + def rspec(*args) + RSpec::Core::Runner.run(args.flatten, $stderr, $stdout).tap do |status| + abort if status.nonzero? + end + end + end + end +end diff --git a/qa/spec/runtime/release_spec.rb b/qa/spec/runtime/release_spec.rb new file mode 100644 index 00000000000..e6b5a8dc315 --- /dev/null +++ b/qa/spec/runtime/release_spec.rb @@ -0,0 +1,50 @@ +describe QA::Runtime::Release do + context 'when release version has extension strategy' do + let(:strategy) { spy('strategy') } + + before do + stub_const('QA::CE::Strategy', strategy) + stub_const('QA::EE::Strategy', strategy) + end + + describe '#version' do + it 'return either CE or EE version' do + expect(subject.version).to eq(:CE).or eq(:EE) + end + end + + describe '#strategy' do + it 'return the strategy constant' do + expect(subject.strategy).to eq strategy + end + end + + describe 'delegated class methods' do + it 'delegates all calls to strategy class' do + described_class.some_method(1, 2) + + expect(strategy).to have_received(:some_method) + .with(1, 2) + end + end + end + + context 'when release version does not have extension strategy' do + before do + allow_any_instance_of(described_class) + .to receive(:version).and_return('something') + end + + describe '#strategy' do + it 'raises error' do + expect { subject.strategy }.to raise_error(LoadError) + end + end + + describe 'delegated class methods' do + it 'raises error' do + expect { described_class.some_method(2, 3) }.to raise_error(LoadError) + end + end + end +end diff --git a/qa/spec/scenario/actable_spec.rb b/qa/spec/scenario/actable_spec.rb new file mode 100644 index 00000000000..422763910e4 --- /dev/null +++ b/qa/spec/scenario/actable_spec.rb @@ -0,0 +1,47 @@ +describe QA::Scenario::Actable do + subject do + Class.new do + include QA::Scenario::Actable + + attr_accessor :something + + def do_something(arg = nil) + "some#{arg}" + end + end + end + + describe '.act' do + it 'provides means to run steps' do + result = subject.act { do_something } + + expect(result).to eq 'some' + end + + it 'supports passing variables' do + result = subject.act('thing') do |variable| + do_something(variable) + end + + expect(result).to eq 'something' + end + + it 'returns value from the last method' do + result = subject.act { 'test' } + + expect(result).to eq 'test' + end + end + + describe '.perform' do + it 'makes it possible to pass binding' do + variable = 'something' + + result = subject.perform do |object| + object.something = variable + end + + expect(result).to eq 'something' + end + end +end diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb new file mode 100644 index 00000000000..c07a3234673 --- /dev/null +++ b/qa/spec/spec_helper.rb @@ -0,0 +1,19 @@ +require_relative '../qa' + +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + + config.shared_context_metadata_behavior = :apply_to_host_groups + config.disable_monkey_patching! + config.expose_dsl_globally = true + config.warnings = true + config.profile_examples = 10 + config.order = :random + Kernel.srand config.seed +end |