Skip to content
Snippets Groups Projects
Commit 6df36c9d authored by Grzegorz Bizon's avatar Grzegorz Bizon Committed by Rémy Coutable
Browse files

Add support for defining explicit dependencies to QA factories

parent 88f41bf6
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -17,6 +17,8 @@ module QA
#
module Factory
autoload :Base, 'qa/factory/base'
autoload :Dependency, 'qa/factory/dependency'
autoload :Product, 'qa/factory/product'
 
module Resource
autoload :Sandbox, 'qa/factory/resource/sandbox'
Loading
Loading
module QA
module Factory
class Base
def fabricate!(*_args)
raise NotImplementedError
end
def self.fabricate!(*args)
new.tap do |factory|
Factory::Product.populate!(new) do |factory|
yield factory if block_given?
return factory.fabricate!(*args)
dependencies.each do |name, signature|
Factory::Dependency.new(name, factory, signature).build!
end
factory.fabricate!(*args)
end
end
 
def fabricate!(*_args)
raise NotImplementedError
def self.dependencies
@dependencies ||= {}
end
def self.dependency(factory, as:, &block)
as.tap do |name|
class_eval { attr_accessor name }
Dependency::Signature.new(factory, block).tap do |signature|
dependencies.store(name, signature)
end
end
end
end
end
Loading
Loading
module QA
module Factory
class Dependency
Signature = Struct.new(:factory, :block)
def initialize(name, factory, signature)
@name = name
@factory = factory
@signature = signature
end
def overridden?
!!@factory.public_send(@name)
end
def build!
return if overridden?
Builder.new(@signature).fabricate!.tap do |product|
@factory.public_send("#{@name}=", product)
end
end
class Builder
def initialize(signature)
@factory = signature.factory
@block = signature.block
end
def fabricate!
@factory.fabricate! do |factory|
@block&.call(factory)
end
end
end
end
end
end
require 'capybara/dsl'
module QA
module Factory
class Product
include Capybara::DSL
def initialize(factory)
@factory = factory
@location = current_url
end
def visit!
visit @location
end
def self.populate!(factory)
raise ArgumentError unless block_given?
yield factory
new(factory)
end
end
end
end
require "pry-byebug"
module QA
module Factory
module Repository
class Push < Factory::Base
PAGE_REGEX_CHECK =
%r{\/#{Runtime::Namespace.sandbox_name}\/qa-test[^\/]+\/{1}[^\/]+\z}.freeze
attr_writer :file_name, :file_content, :commit_message, :branch_name
 
attr_writer :file_name,
:file_content,
:commit_message,
:branch_name
dependency Factory::Resource::Project, as: :project do |project|
project.name = 'project-with-code'
project.description = 'Project with repository'
end
 
def initialize
@file_name = 'file.txt'
Loading
Loading
@@ -20,12 +17,10 @@ module QA
end
 
def fabricate!
project.visit!
Git::Repository.perform do |repository|
repository.location = Page::Project::Show.act do
unless PAGE_REGEX_CHECK.match(current_path)
raise "To perform this scenario the current page should be project show."
end
choose_repository_clone_http
repository_location
end
Loading
Loading
Loading
Loading
@@ -4,17 +4,29 @@ module QA
class Group < Factory::Base
attr_writer :path, :description
 
dependency Factory::Resource::Sandbox, as: :sandbox
def initialize
@path = Runtime::Namespace.name
@description = "QA test run at #{Runtime::Namespace.time}"
end
 
def fabricate!
Page::Group::New.perform do |group|
group.set_path(@path)
group.set_description(@description)
group.set_visibility('Private')
group.create
sandbox.visit!
Page::Group::Show.perform do |page|
if page.has_subgroup?(@path)
page.go_to_subgroup(@path)
else
page.go_to_new_subgroup
Page::Group::New.perform do |group|
group.set_path(@path)
group.set_description(@description)
group.set_visibility('Private')
group.create
end
end
end
end
end
Loading
Loading
Loading
Loading
@@ -6,26 +6,17 @@ module QA
class Project < Factory::Base
attr_writer :description
 
dependency Factory::Resource::Group, as: :group
def name=(name)
@name = "#{name}-#{SecureRandom.hex(8)}"
@description = 'My awesome project'
end
 
def fabricate!
Factory::Resource::Sandbox.fabricate!
Page::Group::Show.perform do |page|
if page.has_subgroup?(Runtime::Namespace.name)
page.go_to_subgroup(Runtime::Namespace.name)
else
page.go_to_new_subgroup
group.visit!
 
Factory::Resource::Group.fabricate! do |group|
group.path = Runtime::Namespace.name
end
end
page.go_to_new_project
end
Page::Group::Show.act { go_to_new_project }
 
Page::Project::New.perform do |page|
page.choose_test_namespace
Loading
Loading
Loading
Loading
@@ -6,18 +6,24 @@ module QA
# creating it if it doesn't yet exist.
#
class Sandbox < Factory::Base
def initialize
@name = Runtime::Namespace.sandbox_name
end
def fabricate!
Page::Main::Menu.act { go_to_groups }
 
Page::Dashboard::Groups.perform do |page|
if page.has_group?(Runtime::Namespace.sandbox_name)
page.go_to_group(Runtime::Namespace.sandbox_name)
if page.has_group?(@name)
page.go_to_group(@name)
else
page.go_to_new_group
 
Resource::Group.fabricate! do |group|
group.path = Runtime::Namespace.sandbox_name
group.description = 'GitLab QA Sandbox'
Page::Group::New.perform do |group|
group.set_path(@name)
group.set_description('GitLab QA Sandbox')
group.set_visibility('Private')
group.create
end
end
end
Loading
Loading
Loading
Loading
@@ -21,6 +21,7 @@ module QA
find('.dropdown-toggle').click
find("li[data-value='new-subgroup']").click
end
find("input[data-action='new-subgroup']").click
end
 
Loading
Loading
@@ -29,6 +30,7 @@ module QA
find('.dropdown-toggle').click
find("li[data-value='new-project']").click
end
find("input[data-action='new-project']").click
end
end
Loading
Loading
Loading
Loading
@@ -5,15 +5,10 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
 
Factory::Resource::Project.fabricate! do |scenario|
scenario.name = 'project_with_code'
scenario.description = 'project with repository'
end
Factory::Repository::Push.fabricate! do |scenario|
scenario.file_name = 'README.md'
scenario.file_content = '# This is test project'
scenario.commit_message = 'Add README.md'
Factory::Repository::Push.fabricate! do |push|
push.file_name = 'README.md'
push.file_content = '# This is a test project'
push.commit_message = 'Add README.md'
end
 
Page::Project::Show.act do
Loading
Loading
@@ -22,7 +17,7 @@ module QA
end
 
expect(page).to have_content('README.md')
expect(page).to have_content('This is test project')
expect(page).to have_content('This is a test project')
end
end
end
Loading
Loading
describe QA::Factory::Base do
describe '.fabricate!' do
subject { Class.new(described_class) }
let(:factory) { spy('factory') }
let(:product) { spy('product') }
before do
allow(QA::Factory::Product).to receive(:new).and_return(product)
end
it 'instantiates the factory and calls factory method' do
expect(subject).to receive(:new).and_return(factory)
subject.fabricate!('something')
expect(factory).to have_received(:fabricate!).with('something')
end
it 'returns fabrication product' do
allow(subject).to receive(:new).and_return(factory)
allow(factory).to receive(:fabricate!).and_return('something')
result = subject.fabricate!('something')
expect(result).to eq product
end
it 'yields factory before calling factory method' do
allow(subject).to receive(:new).and_return(factory)
subject.fabricate! do |factory|
factory.something!
end
expect(factory).to have_received(:something!).ordered
expect(factory).to have_received(:fabricate!).ordered
end
end
describe '.dependency' do
let(:dependency) { spy('dependency') }
before do
stub_const('Some::MyDependency', dependency)
end
subject do
Class.new(described_class) do
dependency Some::MyDependency, as: :mydep do |factory|
factory.something!
end
end
end
it 'appends a new dependency and accessors' do
expect(subject.dependencies).to be_one
end
it 'defines dependency accessors' do
expect(subject.new).to respond_to :mydep, :mydep=
end
end
describe 'building dependencies' do
let(:dependency) { double('dependency') }
let(:instance) { spy('instance') }
subject do
Class.new(described_class) do
dependency Some::MyDependency, as: :mydep
end
end
before do
stub_const('Some::MyDependency', dependency)
allow(subject).to receive(:new).and_return(instance)
allow(instance).to receive(:mydep).and_return(nil)
allow(QA::Factory::Product).to receive(:new)
end
it 'builds all dependencies first' do
expect(dependency).to receive(:fabricate!).once
subject.fabricate!
end
end
end
describe QA::Factory::Dependency do
let(:dependency) { spy('dependency' ) }
let(:factory) { spy('factory') }
let(:block) { spy('block') }
let(:signature) do
double('signature', factory: dependency, block: block)
end
subject do
described_class.new(:mydep, factory, signature)
end
describe '#overridden?' do
it 'returns true if factory has overridden dependency' do
allow(factory).to receive(:mydep).and_return('something')
expect(subject).to be_overridden
end
it 'returns false if dependency has not been overridden' do
allow(factory).to receive(:mydep).and_return(nil)
expect(subject).not_to be_overridden
end
end
describe '#build!' do
context 'when dependency has been overridden' do
before do
allow(subject).to receive(:overridden?).and_return(true)
end
it 'does not fabricate dependency' do
subject.build!
expect(dependency).not_to have_received(:fabricate!)
end
end
context 'when dependency has not been overridden' do
before do
allow(subject).to receive(:overridden?).and_return(false)
end
it 'fabricates dependency' do
subject.build!
expect(dependency).to have_received(:fabricate!)
end
it 'sets product in the factory' do
subject.build!
expect(factory).to have_received(:mydep=).with(dependency)
end
end
end
end
describe QA::Factory::Product do
let(:factory) { spy('factory') }
let(:product) { spy('product') }
describe '.populate!' do
it 'instantiates and yields factory' do
expect(described_class).to receive(:new).with(factory)
described_class.populate!(factory) do |instance|
instance.something = 'string'
end
expect(factory).to have_received(:something=).with('string')
end
it 'returns a fabrication product' do
expect(described_class).to receive(:new)
.with(factory).and_return(product)
result = described_class.populate!(factory) do |instance|
instance.something = 'string'
end
expect(result).to be product
end
it 'raises unless block given' do
expect { described_class.populate!(factory) }
.to raise_error ArgumentError
end
end
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(described_class.new(factory).visit!)
.to eq 'visited some url'
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment