summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémy Coutable <remy@rymai.me>2018-09-27 18:43:44 +0200
committerRémy Coutable <remy@rymai.me>2018-10-02 18:36:16 +0200
commit98c7cbc8ce8402557d46799e7cabac59a2a5b238 (patch)
tree2630f01e941ca94f11178d30c3aa7462cf4d7605
parent39265b5ab46001a27e8ba009dac1da9126547859 (diff)
downloadgitlab-ce-qa-123.tar.gz
Simplify API fabrication internal methodsqa-123
Also, raise an error when a product attribute doesn't have a value. Signed-off-by: Rémy Coutable <remy@rymai.me>
-rw-r--r--qa/qa/factory/api_fabricator.rb32
-rw-r--r--qa/qa/factory/base.rb56
-rw-r--r--qa/qa/factory/product.rb37
-rw-r--r--qa/qa/factory/resource/group.rb10
-rw-r--r--qa/qa/factory/resource/project.rb14
-rw-r--r--qa/qa/factory/resource/sandbox.rb26
-rw-r--r--qa/qa/factory/resource/wiki.rb12
-rw-r--r--qa/qa/runtime/env.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb17
-rw-r--r--qa/spec/factory/api_fabricator_spec.rb61
-rw-r--r--qa/spec/factory/base_spec.rb205
-rw-r--r--qa/spec/factory/product_spec.rb60
-rw-r--r--qa/spec/runtime/env_spec.rb66
13 files changed, 250 insertions, 348 deletions
diff --git a/qa/qa/factory/api_fabricator.rb b/qa/qa/factory/api_fabricator.rb
index 85d6286207e..0c8f994c90f 100644
--- a/qa/qa/factory/api_fabricator.rb
+++ b/qa/qa/factory/api_fabricator.rb
@@ -2,11 +2,13 @@
require 'airborne'
require 'active_support/core_ext/object/deep_dup'
+require 'capybara/dsl'
module QA
module Factory
module ApiFabricator
include Airborne
+ include Capybara::DSL
ResourceNotFoundError = Class.new(RuntimeError)
ResourceFabricationFailedError = Class.new(RuntimeError)
@@ -21,15 +23,7 @@ module QA
alias_method :api_post_path, :api_get_path
alias_method :api_post_body, :api_get_path
- def api_support?
- api_get_path && api_post_path && api_post_body
- rescue NotImplementedError
- false
- end
-
def fabricate_via_api!
- resource_web_url(api_get)
- rescue ResourceNotFoundError
resource_web_url(api_post)
end
@@ -37,41 +31,43 @@ module QA
attr_writer :api_resource, :api_response
+ def api_support?
+ api_get_path && api_post_path && api_post_body
+ rescue NotImplementedError
+ false
+ end
+
def resource_web_url(resource)
- unless resource.key?(:web_url)
+ resource.fetch(:web_url) do
raise ResourceURLMissingError, "API resource for #{self.class.name} does not expose a `web_url` property: `#{resource}`."
end
-
- resource[:web_url]
end
def api_get
url = Runtime::API::Request.new(api_client, api_get_path).url
response = get(url)
- parsed_response = parse_body(response)
unless response.code == 200
- raise ResourceNotFoundError, "Resource at #{url} could not be found (#{response.code}): `#{parsed_response}`."
+ raise ResourceNotFoundError, "Resource at #{url} could not be found (#{response.code}): `#{response}`."
end
- process_api_response(parsed_response)
+ process_api_response(parse_body(response))
end
def api_post
response = post(
Runtime::API::Request.new(api_client, api_post_path).url,
api_post_body)
- parsed_response = parse_body(response)
unless response.code == 201
- raise ResourceFabricationFailedError, "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{parsed_response}`."
+ raise ResourceFabricationFailedError, "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`."
end
- process_api_response(parsed_response)
+ process_api_response(parse_body(response))
end
def api_client
- @api_client ||= Runtime::API::Client.new(:gitlab, is_new_session: false)
+ @api_client ||= Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'))
end
def parse_body(response)
diff --git a/qa/qa/factory/base.rb b/qa/qa/factory/base.rb
index c3f154d1203..a254a831b66 100644
--- a/qa/qa/factory/base.rb
+++ b/qa/qa/factory/base.rb
@@ -18,62 +18,52 @@ module QA
end
def self.fabricate!(*args, &prepare_block)
- do_fabricate!(prepare_block, *args) do |factory|
- if factory.api_support?
- log_fabrication(:do_fabricate_via_api, factory, *args)
- else
- log_fabrication(:do_fabricate_via_browser_ui, factory, *args)
- end
- end
+ fabricate_via_api!(*args, &prepare_block)
+ rescue NotImplementedError
+ fabricate_via_browser_ui!(*args, &prepare_block)
end
def self.fabricate_via_browser_ui!(*args, &prepare_block)
- do_fabricate!(prepare_block, *args) do |factory|
- log_fabrication(:do_fabricate_via_browser_ui, factory, *args)
+ do_fabricate!(prepare_block) do |factory|
+ log_fabrication(:browser_ui, factory) { factory.fabricate!(*args) }
+
+ current_url
end
end
def self.fabricate_via_api!(*args, &prepare_block)
- do_fabricate!(prepare_block, *args) do |factory|
- log_fabrication(:do_fabricate_via_api, factory, *args)
+ do_fabricate!(prepare_block) do |factory|
+ log_fabrication(:api, factory) { factory.fabricate_via_api! }
end
end
- def self.do_fabricate!(prepare_block, *args)
- new.tap do |factory|
- prepare_block.call(factory) if prepare_block
-
- dependencies.each do |signature|
- Factory::Dependency.new(factory, signature).build!
- end
+ def self.do_fabricate!(prepare_block)
+ factory = new
+ prepare_block.call(factory) if prepare_block
- resource_web_url = yield(factory)
-
- break Factory::Product.populate!(factory, resource_web_url)
+ dependencies.each do |signature|
+ Factory::Dependency.new(factory, signature).build!
end
- end
- def self.do_fabricate_via_browser_ui(factory, *args)
- factory.fabricate!(*args)
-
- current_url
- end
+ resource_web_url = yield(factory)
- def self.do_fabricate_via_api(factory, *_args)
- factory.fabricate_via_api!
+ Factory::Product.populate!(factory, resource_web_url)
end
+ private_class_method :do_fabricate!
- def self.log_fabrication(method, factory, *args)
+ def self.log_fabrication(method, factory)
start = Time.now
- public_send(method, factory, *args).tap do
+ yield.tap do
puts "Resource #{factory.class.name} built via #{method} in #{Time.now - start} seconds" if Runtime::Env.verbose?
end
end
+ private_class_method :log_fabrication
def self.evaluator
@evaluator ||= Factory::Base::DSL.new(self)
end
+ private_class_method :evaluator
class DSL
attr_reader :dependencies, :attributes
@@ -81,7 +71,7 @@ module QA
def initialize(base)
@base = base
@dependencies = []
- @attributes = {}
+ @attributes = []
end
def dependency(factory, as:, &block)
@@ -96,7 +86,7 @@ module QA
def product(attribute, &block)
Product::Attribute.new(attribute, block).tap do |signature|
- @attributes.store(attribute, signature)
+ @attributes << signature
end
end
end
diff --git a/qa/qa/factory/product.rb b/qa/qa/factory/product.rb
index dc30701a9d4..5ee2552eeb5 100644
--- a/qa/qa/factory/product.rb
+++ b/qa/qa/factory/product.rb
@@ -5,28 +5,47 @@ module QA
class Product
include Capybara::DSL
- attr_reader :web_url
+ NoValueError = Class.new(RuntimeError)
+
+ attr_reader :factory, :web_url
Attribute = Struct.new(:name, :block)
- def initialize(web_url)
+ def initialize(factory, web_url)
+ @factory = factory
@web_url = web_url
+
+ populate_attributes!
end
def visit!
- visit @web_url
+ visit(web_url)
end
def self.populate!(factory, web_url)
- new(web_url).tap do |product|
- factory.class.attributes.each_value do |attribute|
- product.instance_exec(factory, attribute.block) do |factory, block|
- value = factory.api_resource&.dig(attribute.name) || block.call(factory)
- product.define_singleton_method(attribute.name) { value }
- end
+ new(factory, web_url)
+ end
+
+ private
+
+ def populate_attributes!
+ factory.class.attributes.each do |attribute|
+ instance_exec(factory, attribute.block) do |factory, block|
+ value = attribute_value(attribute, block)
+
+ raise NoValueError, "No value was computed for product #{attribute.name} of factory #{factory.class.name}." unless value
+
+ define_singleton_method(attribute.name) { value }
end
end
end
+
+ def attribute_value(attribute, block)
+ value = factory.api_resource&.dig(attribute.name) || (factory.respond_to?(attribute.name) && factory.public_send(attribute.name))
+ value ||= block.call(factory) if block
+
+ value
+ end
end
end
end
diff --git a/qa/qa/factory/resource/group.rb b/qa/qa/factory/resource/group.rb
index b6703c202b5..2688328df92 100644
--- a/qa/qa/factory/resource/group.rb
+++ b/qa/qa/factory/resource/group.rb
@@ -6,7 +6,9 @@ module QA
dependency Factory::Resource::Sandbox, as: :sandbox
- product :id
+ product :id do
+ true # We don't retrieve the Group ID when using the Browser UI
+ end
def initialize
@path = Runtime::Namespace.name
@@ -38,6 +40,12 @@ module QA
end
end
+ def fabricate_via_api!
+ resource_web_url(api_get)
+ rescue ResourceNotFoundError
+ super
+ end
+
def api_get_path
"/groups/#{CGI.escape("#{sandbox.path}/#{path}")}"
end
diff --git a/qa/qa/factory/resource/project.rb b/qa/qa/factory/resource/project.rb
index 166ef00bf56..5b92afa9da2 100644
--- a/qa/qa/factory/resource/project.rb
+++ b/qa/qa/factory/resource/project.rb
@@ -11,9 +11,19 @@ module QA
product :name
- product :repository_ssh_location
+ product :repository_ssh_location do
+ Page::Project::Show.act do
+ choose_repository_clone_ssh
+ repository_location
+ end
+ end
- product :repository_http_location
+ product :repository_http_location do
+ Page::Project::Show.act do
+ choose_repository_clone_http
+ repository_location
+ end
+ end
def initialize
@description = 'My awesome project'
diff --git a/qa/qa/factory/resource/sandbox.rb b/qa/qa/factory/resource/sandbox.rb
index 6f2c3f22120..eaa83e1a0a3 100644
--- a/qa/qa/factory/resource/sandbox.rb
+++ b/qa/qa/factory/resource/sandbox.rb
@@ -6,27 +6,29 @@ module QA
# creating it if it doesn't yet exist.
#
class Sandbox < Factory::Base
- attr_reader :group_path
+ attr_reader :path
- product :id
+ product :id do
+ true # We don't retrieve the Group ID when using the Browser UI
+ end
product :path
def initialize
- @group_path = Runtime::Namespace.sandbox_name
+ @path = Runtime::Namespace.sandbox_name
end
def fabricate!
Page::Menu::Main.act { go_to_groups }
Page::Dashboard::Groups.perform do |page|
- if page.has_group?(group_path)
- page.go_to_group(group_path)
+ if page.has_group?(path)
+ page.go_to_group(path)
else
page.go_to_new_group
Page::Group::New.perform do |group|
- group.set_path(group_path)
+ group.set_path(path)
group.set_description('GitLab QA Sandbox Group')
group.set_visibility('Public')
group.create
@@ -35,8 +37,14 @@ module QA
end
end
+ def fabricate_via_api!
+ resource_web_url(api_get)
+ rescue ResourceNotFoundError
+ super
+ end
+
def api_get_path
- "/groups/#{group_path}"
+ "/groups/#{path}"
end
def api_post_path
@@ -45,8 +53,8 @@ module QA
def api_post_body
{
- path: group_path,
- name: group_path,
+ path: path,
+ name: path,
visibility: 'public'
}
end
diff --git a/qa/qa/factory/resource/wiki.rb b/qa/qa/factory/resource/wiki.rb
index acd3f0da171..4a733432311 100644
--- a/qa/qa/factory/resource/wiki.rb
+++ b/qa/qa/factory/resource/wiki.rb
@@ -14,12 +14,12 @@ module QA
Page::Menu::Side.perform { |menu_side| menu_side.click_wiki }
- Page::Project::Wiki::New.perform do |page|
- page.go_to_create_first_page
- page.set_title(@title)
- page.set_content(@content)
- page.set_message(@message)
- page.create_new_page
+ Page::Project::Wiki::New.perform do |wiki_new|
+ wiki_new.go_to_create_first_page
+ wiki_new.set_title(@title)
+ wiki_new.set_content(@content)
+ wiki_new.set_message(@message)
+ wiki_new.create_new_page
end
end
end
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 0c3ed2d77f5..457dc1fe43b 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -40,7 +40,7 @@ module QA
end
def forker?
- forker_username && forker_password
+ !!(forker_username && forker_password)
end
def forker_username
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
index f344edeec0c..c8ea558aed6 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
@@ -7,21 +7,12 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
- group = Factory::Resource::Group.fabricate!
- group.visit!
- Page::Group::Show.act { go_to_new_project }
-
- name = "awesome-project-#{SecureRandom.hex(8)}"
-
- Page::Project::New.perform do |page|
- page.choose_test_namespace
- page.choose_name(name)
- page.add_description('create awesome project test')
- page.set_visibility('Public')
- page.create_new_project
+ created_project = Factory::Resource::Project.fabricate_via_browser_ui! do |project|
+ project.name = 'awesome-project'
+ project.description = 'create awesome project test'
end
- expect(page).to have_content(name)
+ expect(page).to have_content(created_project.name)
expect(page).to have_content(
/Project \S?awesome-project\S+ was successfully created/
)
diff --git a/qa/spec/factory/api_fabricator_spec.rb b/qa/spec/factory/api_fabricator_spec.rb
index 3fda5407549..8f8c29dd92d 100644
--- a/qa/spec/factory/api_fabricator_spec.rb
+++ b/qa/spec/factory/api_fabricator_spec.rb
@@ -27,26 +27,12 @@ describe QA::Factory::ApiFabricator do
end
end
- subject { factory.tap { |f| f.include(described_class) }.new }
-
- describe '#api_support?' do
- context 'when factory does not respond to api_get_path, api_post_path, and api_post_body' do
- let(:factory) { factory_without_api_support }
-
- it 'returns false' do
- expect(subject).not_to be_api_support
- end
- end
-
- context 'when factory responds to api_get_path, api_post_path, and api_post_body' do
- let(:factory) { factory_with_api_support }
-
- it 'returns true' do
- expect(subject).to be_api_support
- end
- end
+ before do
+ allow(subject).to receive(:current_url).and_return('')
end
+ subject { factory.tap { |f| f.include(described_class) }.new }
+
describe '#fabricate_via_api!' do
context 'when factory does not support fabrication via the API' do
let(:factory) { factory_without_api_support }
@@ -63,7 +49,7 @@ describe QA::Factory::ApiFabricator do
let(:api_request) { spy('Runtime::API::Request') }
let(:resource_web_url) { 'http://example.org/api/v4/foo' }
let(:resource) { { id: 1, name: 'John Doe', web_url: resource_web_url } }
- let(:raw_get) { double('Raw GET response', code: 200, body: resource.to_json) }
+ let(:raw_post) { double('Raw POST response', code: 201, body: resource.to_json) }
before do
stub_const('QA::Runtime::API::Client', api_client)
@@ -71,44 +57,15 @@ describe QA::Factory::ApiFabricator do
allow(api_client).to receive(:new).and_return(api_client_instance)
allow(api_request).to receive(:new).and_return(double(url: resource_web_url))
- allow(subject).to receive(:get).with(resource_web_url).and_return(raw_get)
- end
-
- context 'when resource already exists' do
- it 'returns the resource URL' do
- expect(api_request).to receive(:new).with(api_client_instance, subject.api_get_path).and_return(double(url: resource_web_url))
- expect(subject).to receive(:get).with(resource_web_url).and_return(raw_get)
-
- expect(subject.fabricate_via_api!).to eq(resource_web_url)
- end
-
- it 'populates api_resource with the resource' do
- subject.fabricate_via_api!
-
- expect(subject.api_resource).to eq(resource)
- end
-
- context 'when the resource does not expose a `web_url` property' do
- let(:resource) { { id: 1, name: 'John Doe' } }
-
- it 'raises a ResourceFabricationFailedError exception' do
- expect { subject.fabricate_via_api! }.to raise_error(described_class::ResourceURLMissingError, "API resource for FooBarFactory does not expose a `web_url` property: `#{resource}`.")
- expect(subject.api_resource).to eq(resource)
- end
- end
end
context 'when the resource does not exist' do
- let(:raw_get) { double('Raw GET response', code: 404, body: { error: "404 not found." }.to_json) }
- let(:raw_post) { double('Raw POST response', code: 201, body: resource.to_json) }
-
before do
allow(subject).to receive(:post).with(resource_web_url, subject.api_post_body).and_return(raw_post)
end
it 'returns the resource URL' do
- expect(api_request).to receive(:new).with(api_client_instance, subject.api_get_path).and_return(double(url: resource_web_url))
- expect(subject).to receive(:get).with(resource_web_url).and_return(raw_get)
+ expect(api_request).to receive(:new).with(api_client_instance, subject.api_post_path).and_return(double(url: resource_web_url))
expect(subject).to receive(:post).with(resource_web_url, subject.api_post_body).and_return(raw_post)
expect(subject.fabricate_via_api!).to eq(resource_web_url)
@@ -125,11 +82,10 @@ describe QA::Factory::ApiFabricator do
let(:raw_post) { double('Raw POST response', code: 400, body: post_response.to_json) }
it 'raises a ResourceFabricationFailedError exception' do
- expect(api_request).to receive(:new).with(api_client_instance, subject.api_get_path).and_return(double(url: resource_web_url))
- expect(subject).to receive(:get).with(resource_web_url).and_return(raw_get)
+ expect(api_request).to receive(:new).with(api_client_instance, subject.api_post_path).and_return(double(url: resource_web_url))
expect(subject).to receive(:post).with(resource_web_url, subject.api_post_body).and_return(raw_post)
- expect { subject.fabricate_via_api! }.to raise_error(described_class::ResourceFabricationFailedError, "Fabrication of FooBarFactory using the API failed (400) with `#{post_response}`.")
+ expect { subject.fabricate_via_api! }.to raise_error(described_class::ResourceFabricationFailedError, "Fabrication of FooBarFactory using the API failed (400) with `#{raw_post}`.")
expect(subject.api_resource).to be_nil
end
end
@@ -165,6 +121,7 @@ describe QA::Factory::ApiFabricator do
let(:transformed_resource) { { existing: 'foo', new: 'foobar', web_url: resource_web_url } }
it 'transforms the resource' do
+ expect(subject).to receive(:post).with(resource_web_url, subject.api_post_body).and_return(raw_post)
expect(subject).to receive(:transform_api_resource).with(resource).and_return(transformed_resource)
subject.fabricate_via_api!
diff --git a/qa/spec/factory/base_spec.rb b/qa/spec/factory/base_spec.rb
index 0457d878270..b9cf60e4cc0 100644
--- a/qa/spec/factory/base_spec.rb
+++ b/qa/spec/factory/base_spec.rb
@@ -11,124 +11,107 @@ describe QA::Factory::Base do
subject { Class.new(described_class) }
before do
- allow(QA::Factory::Product).to receive(:new).with(product_location).and_return(product)
- allow(QA::Factory::Product).to receive(:populate!).and_return(product)
allow(subject).to receive(:current_url).and_return(product_location)
allow(subject).to receive(:new).and_return(factory)
+ allow(QA::Factory::Product).to receive(:populate!).with(factory, product_location).and_return(product)
end
end
- shared_examples 'API fabrication method' do |fabrication_method_called, actual_fabrication_method = nil|
+ shared_examples 'fabrication method' do |fabrication_method_called, actual_fabrication_method = nil|
let(:fabrication_method_used) { actual_fabrication_method || fabrication_method_called }
- include_context 'fabrication context'
+ it 'yields factory before calling factory method' do
+ allow(subject).to receive(:new).and_return(factory)
- it_behaves_like 'fabrication method', fabrication_method_called, actual_fabrication_method
+ expect(factory).to receive(:something!).ordered
+ expect(factory).to receive(fabrication_method_used).ordered.and_return(product_location)
- it 'instantiates the factory and calls factory method' do
- expect(subject).to receive(:new).and_return(factory)
+ subject.public_send(fabrication_method_called) do |factory|
+ factory.something!
+ end
+ end
- subject.public_send(fabrication_method_called)
+ it 'does not log the factory and build method when VERBOSE=false' do
+ stub_env('VERBOSE', 'false')
+ expect(factory).to receive(fabrication_method_used).and_return(product_location)
- expect(factory).to have_received(fabrication_method_used)
+ expect { subject.public_send(fabrication_method_called, 'something') }
+ .not_to output(/Resource #{factory.class.name} built via/)
+ .to_stdout
end
+ end
- it 'returns fabrication product' do
- result = subject.public_send(fabrication_method_called)
+ describe '.fabricate!' do
+ context 'when factory does not support fabrication via the API' do
+ before do
+ expect(described_class).to receive(:fabricate_via_api!).and_raise(NotImplementedError)
+ end
+
+ it 'calls .fabricate_via_browser_ui!' do
+ expect(described_class).to receive(:fabricate_via_browser_ui!)
- expect(result).to eq product
+ described_class.fabricate!
+ end
end
- it 'logs the factory and build method when VERBOSE=true' do
- stub_env('VERBOSE', 'true')
+ context 'when factory supports fabrication via the API' do
+ it 'calls .fabricate_via_browser_ui!' do
+ expect(described_class).to receive(:fabricate_via_api!)
- expect { subject.public_send(fabrication_method_called) }
- .to output(/Resource #{factory.class.name} built via do_fabricate_via_api/)
- .to_stdout
+ described_class.fabricate!
+ end
end
end
- shared_examples 'Browser UI fabrication method' do |fabrication_method_called, actual_fabrication_method = nil|
- let(:fabrication_method_used) { actual_fabrication_method || fabrication_method_called }
-
+ describe '.fabricate_via_api!' do
include_context 'fabrication context'
- it_behaves_like 'fabrication method', fabrication_method_called, actual_fabrication_method
-
- it 'instantiates the factory and calls factory method' do
- expect(subject).to receive(:new).and_return(factory)
-
- subject.public_send(fabrication_method_called, 'something')
+ it_behaves_like 'fabrication method', :fabricate_via_api!
- expect(factory).to have_received(fabrication_method_used).with('something')
- end
+ it 'instantiates the factory, calls factory method returns fabrication product' do
+ expect(factory).to receive(:fabricate_via_api!).and_return(product_location)
- it 'returns fabrication product' do
- result = subject.public_send(fabrication_method_called, 'something')
+ result = subject.fabricate_via_api!
- expect(result).to eq product
+ expect(result).to eq(product)
end
it 'logs the factory and build method when VERBOSE=true' do
stub_env('VERBOSE', 'true')
+ expect(factory).to receive(:fabricate_via_api!).and_return(product_location)
- expect { subject.public_send(fabrication_method_called, 'something') }
- .to output(/Resource #{factory.class.name} built via do_fabricate_via_browser_ui/)
+ expect { subject.fabricate_via_api! }
+ .to output(/Resource #{factory.class.name} built via api/)
.to_stdout
end
end
- shared_examples 'fabrication method' do |fabrication_method_called, actual_fabrication_method = nil|
- let(:fabrication_method_used) { actual_fabrication_method || fabrication_method_called }
-
+ describe '.fabricate_via_browser_ui!' do
include_context 'fabrication context'
- it 'yields factory before calling factory method' do
- allow(subject).to receive(:new).and_return(factory)
-
- subject.public_send(fabrication_method_called) do |factory|
- factory.something!
- end
+ it_behaves_like 'fabrication method', :fabricate_via_browser_ui!, :fabricate!
- expect(factory).to have_received(:something!).ordered
- expect(factory).to have_received(fabrication_method_used).ordered
- end
-
- it 'does not log the factory and build method when VERBOSE=false' do
- stub_env('VERBOSE', 'false')
+ it 'instantiates the factory and calls factory method' do
+ subject.fabricate_via_browser_ui!('something')
- expect { subject.public_send(fabrication_method_called, 'something') }
- .not_to output(/Resource #{factory.class.name} built via/)
- .to_stdout
+ expect(factory).to have_received(:fabricate!).with('something')
end
- end
- describe '.fabricate!' do
- context 'when factory does not support fabrication via the API' do
- before do
- allow(factory).to receive(:api_support?).and_return(false)
- end
+ it 'returns fabrication product' do
+ result = subject.fabricate_via_browser_ui!('something')
- it_behaves_like 'Browser UI fabrication method', :fabricate!
+ expect(result).to eq(product)
end
- context 'when factory supports fabrication via the API' do
- before do
- allow(factory).to receive(:api_support?).and_return(true)
- end
+ it 'logs the factory and build method when VERBOSE=true' do
+ stub_env('VERBOSE', 'true')
- it_behaves_like 'API fabrication method', :fabricate!, :fabricate_via_api!
+ expect { subject.fabricate_via_browser_ui!('something') }
+ .to output(/Resource #{factory.class.name} built via browser_ui/)
+ .to_stdout
end
end
- describe '.fabricate_via_api!' do
- it_behaves_like 'API fabrication method', :fabricate_via_api!
- end
-
- describe '.fabricate_via_browser_ui!' do
- it_behaves_like 'Browser UI fabrication method', :fabricate_via_browser_ui!, :fabricate!
- end
-
describe '.dependency' do
let(:dependency) { spy('dependency') }
@@ -168,8 +151,7 @@ describe QA::Factory::Base do
allow(subject).to receive(:new).and_return(instance)
allow(subject).to receive(:current_url).and_return(product_location)
allow(instance).to receive(:mydep).and_return(nil)
- allow(QA::Factory::Product).to receive(:new)
- allow(QA::Factory::Product).to receive(:populate!)
+ expect(QA::Factory::Product).to receive(:populate!)
end
it 'builds all dependencies first' do
@@ -181,79 +163,22 @@ describe QA::Factory::Base do
end
describe '.product' do
- context 'when the product is produced via the browser' do
- subject do
- Class.new(described_class) do
- def fabricate!
- "any"
- end
-
- # Defined only to be stubbed
- def self.find_page
- end
-
- product :token do
- find_page.do_something_on_page!
- 'resulting value'
- end
- end
- end
-
- it 'appends new product attribute' do
- expect(subject.attributes).to be_one
- expect(subject.attributes).to have_key(:token)
- end
-
- describe 'populating fabrication product with data' do
- let(:page) { spy('page') }
+ include_context 'fabrication context'
- before do
- allow(QA::Factory::Product).to receive(:new).and_return(product)
- allow(product).to receive(:page).and_return(page)
- allow(subject).to receive(:current_url).and_return(product_location)
- allow(subject).to receive(:find_page).and_return(page)
+ subject do
+ Class.new(described_class) do
+ def fabricate!
+ "any"
end
- it 'populates product after fabrication' do
- subject.fabricate!
-
- expect(product.token).to eq 'resulting value'
- expect(page).to have_received(:do_something_on_page!)
- end
+ product :token
end
end
- context 'when the product is producted via the API' do
- subject do
- Class.new(described_class) do
- def fabricate!
- "any"
- end
-
- product :token
- end
- end
-
- it 'appends new product attribute' do
- expect(subject.attributes).to be_one
- expect(subject.attributes).to have_key(:token)
- end
-
- describe 'populating fabrication product with data' do
- before do
- allow(subject).to receive(:new).and_return(factory)
- allow(factory).to receive(:class).and_return(subject)
- allow(factory).to receive(:api_support?).and_return(true)
- allow(factory).to receive(:api_resource).and_return({ token: 'resulting value' })
- allow(QA::Factory::Product).to receive(:new).and_return(product)
- end
-
- it 'populates product after fabrication' do
- subject.fabricate!
-
- expect(product.token).to eq 'resulting value'
- end
- end
+ it 'appends new product attribute' do
+ expect(subject.attributes).to be_one
+ expect(subject.attributes[0]).to be_a(QA::Factory::Product::Attribute)
+ expect(subject.attributes[0].name).to eq(:token)
end
end
end
diff --git a/qa/spec/factory/product_spec.rb b/qa/spec/factory/product_spec.rb
index 2f2d5568af7..43b1d93d769 100644
--- a/qa/spec/factory/product_spec.rb
+++ b/qa/spec/factory/product_spec.rb
@@ -1,51 +1,71 @@
describe QA::Factory::Product do
let(:factory) do
- QA::Factory::Base.new
+ Class.new(QA::Factory::Base) do
+ def foo
+ 'bar'
+ end
+ end.new
end
let(:product) { spy('product') }
let(:product_location) { 'http://product_location' }
- subject { described_class.new(product_location) }
+ subject { described_class.new(factory, product_location) }
describe '.populate!' do
before do
- allow(QA::Factory::Base).to receive(:attributes).and_return(attributes)
+ expect(factory.class).to receive(:attributes).and_return(attributes)
end
- context 'when the product is produced via the browser' do
+ context 'when the product attribute is populated via a block' do
let(:attributes) do
- { test: QA::Factory::Product::Attribute.new(:test, proc { 'returned' }) }
+ [QA::Factory::Product::Attribute.new(:test, proc { 'returned' })]
end
it 'returns a fabrication product and defines factory attributes as its methods' do
- expect(described_class).to receive(:new).with(product_location).and_return(product)
+ result = described_class.populate!(factory, product_location)
+
+ expect(result).to be_a(described_class)
+ expect(result.test).to eq('returned')
+ end
+ end
- result = described_class.populate!(factory, product_location) do |instance|
- instance.something = 'string'
- end
+ context 'when the product attribute is populated via the api' do
+ let(:attributes) do
+ [QA::Factory::Product::Attribute.new(:test)]
+ end
+
+ it 'returns a fabrication product and defines factory attributes as its methods' do
+ expect(factory).to receive(:api_resource).and_return({ test: 'returned' })
- expect(result).to be product
+ result = described_class.populate!(factory, product_location)
+
+ expect(result).to be_a(described_class)
expect(result.test).to eq('returned')
end
end
- context 'when the product is produced via the api' do
+ context 'when the product attribute is populated via a factory attribute' do
let(:attributes) do
- { test: QA::Factory::Product::Attribute.new(:test) }
+ [QA::Factory::Product::Attribute.new(:foo)]
end
it 'returns a fabrication product and defines factory attributes as its methods' do
- allow(factory).to receive(:api_resource).and_return({ test: 'returned' })
+ result = described_class.populate!(factory, product_location)
- expect(described_class).to receive(:new).with(product_location).and_return(product)
+ expect(result).to be_a(described_class)
+ expect(result.foo).to eq('bar')
+ end
+ end
- result = described_class.populate!(factory, product_location) do |instance|
- instance.something = 'string'
- end
+ context 'when the product attribute has no value' do
+ let(:attributes) do
+ [QA::Factory::Product::Attribute.new(:bar)]
+ end
- expect(result).to be product
- expect(result.test).to eq('returned')
+ it 'returns a fabrication product and defines factory attributes as its methods' do
+ expect { described_class.populate!(factory, product_location) }
+ .to raise_error(described_class::NoValueError, "No value was computed for product bar of factory #{factory.class.name}.")
end
end
end
@@ -53,8 +73,6 @@ describe QA::Factory::Product do
describe '.visit!' do
it 'makes it possible to visit fabrication product' do
allow_any_instance_of(described_class)
- .to receive(:current_url).and_return('some url')
- allow_any_instance_of(described_class)
.to receive(:visit).and_return('visited some url')
expect(subject.visit!).to eq 'visited some url'
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index c06e2dba8e7..e298795c6cf 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -1,28 +1,28 @@
describe QA::Runtime::Env do
include Support::StubENV
- describe '.verbose?' do
+ shared_examples 'boolean method' do |method, env_key|
context 'when there is an env variable set' do
it 'returns false when falsey values specified' do
- stub_env('VERBOSE', 'false')
- expect(described_class.verbose?).to be_falsey
+ stub_env(env_key, 'false')
+ expect(described_class.public_send(method)).to be_falsey
- stub_env('VERBOSE', 'no')
- expect(described_class.verbose?).to be_falsey
+ stub_env(env_key, 'no')
+ expect(described_class.public_send(method)).to be_falsey
- stub_env('VERBOSE', '0')
- expect(described_class.verbose?).to be_falsey
+ stub_env(env_key, '0')
+ expect(described_class.public_send(method)).to be_falsey
end
it 'returns true when anything else specified' do
- stub_env('VERBOSE', 'true')
- expect(described_class.verbose?).to be_truthy
+ stub_env(env_key, 'true')
+ expect(described_class.public_send(method)).to be_truthy
- stub_env('VERBOSE', '1')
- expect(described_class.verbose?).to be_truthy
+ stub_env(env_key, '1')
+ expect(described_class.public_send(method)).to be_truthy
- stub_env('VERBOSE', 'anything')
- expect(described_class.verbose?).to be_truthy
+ stub_env(env_key, 'anything')
+ expect(described_class.public_send(method)).to be_truthy
end
end
@@ -34,37 +34,12 @@ describe QA::Runtime::Env do
end
end
- describe '.chrome_headless?' do
- context 'when there is an env variable set' do
- it 'returns false when falsey values specified' do
- stub_env('CHROME_HEADLESS', 'false')
- expect(described_class.chrome_headless?).to be_falsey
-
- stub_env('CHROME_HEADLESS', 'no')
- expect(described_class.chrome_headless?).to be_falsey
-
- stub_env('CHROME_HEADLESS', '0')
- expect(described_class.chrome_headless?).to be_falsey
- end
-
- it 'returns true when anything else specified' do
- stub_env('CHROME_HEADLESS', 'true')
- expect(described_class.chrome_headless?).to be_truthy
-
- stub_env('CHROME_HEADLESS', '1')
- expect(described_class.chrome_headless?).to be_truthy
-
- stub_env('CHROME_HEADLESS', 'anything')
- expect(described_class.chrome_headless?).to be_truthy
- end
- end
+ describe '.verbose?' do
+ it_behaves_like 'boolean method', :verbose?, 'VERBOSE'
+ end
- context 'when there is no env variable set' do
- it 'returns the default, true' do
- stub_env('CHROME_HEADLESS', nil)
- expect(described_class.chrome_headless?).to be_truthy
- end
- end
+ describe '.chrome_headless?' do
+ it_behaves_like 'boolean method', :chrome_headless?, 'CHROME_HEADLESS'
end
describe '.running_in_ci?' do
@@ -132,6 +107,11 @@ describe QA::Runtime::Env do
end
describe '.forker?' do
+ before do
+ stub_env('GITLAB_FORKER_USERNAME', nil)
+ stub_env('GITLAB_FORKER_PASSWORD', nil)
+ end
+
it 'returns false if no forker credentials are defined' do
expect(described_class).not_to be_forker
end