Commit 4fbe2a00 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'feature/qa/gb/populate-qa-factories-with-data' into 'master'

Make it possible to populate QA factory product with a data from a browser

See merge request gitlab-org/gitlab-ce!16384
parents b5e314a7 af1680ab
require 'forwardable'
module QA module QA
module Factory module Factory
class Base class Base
extend SingleForwardable
def_delegators :evaluator, :dependency, :dependencies
def_delegators :evaluator, :product, :attributes
def fabricate!(*_args) def fabricate!(*_args)
raise NotImplementedError raise NotImplementedError
end end
def self.fabricate!(*args) def self.fabricate!(*args)
Factory::Product.populate!(new) do |factory| new.tap do |factory|
yield factory if block_given? yield factory if block_given?
dependencies.each do |name, signature| dependencies.each do |name, signature|
...@@ -14,19 +21,37 @@ module QA ...@@ -14,19 +21,37 @@ module QA
end end
factory.fabricate!(*args) factory.fabricate!(*args)
return Factory::Product.populate!(self)
end end
end end
def self.dependencies def self.evaluator
@dependencies ||= {} @evaluator ||= Factory::Base::DSL.new(self)
end end
def self.dependency(factory, as:, &block) class DSL
as.tap do |name| attr_reader :dependencies, :attributes
class_eval { attr_accessor name }
def initialize(base)
@base = base
@dependencies = {}
@attributes = {}
end
def dependency(factory, as:, &block)
as.tap do |name|
@base.class_eval { attr_accessor name }
Dependency::Signature.new(factory, block).tap do |signature|
@dependencies.store(name, signature)
end
end
end
Dependency::Signature.new(factory, block).tap do |signature| def product(attribute, &block)
dependencies.store(name, signature) Product::Attribute.new(attribute, block).tap do |signature|
@attributes.store(attribute, signature)
end end
end end
end end
......
...@@ -5,8 +5,9 @@ module QA ...@@ -5,8 +5,9 @@ module QA
class Product class Product
include Capybara::DSL include Capybara::DSL
def initialize(factory) Attribute = Struct.new(:name, :block)
@factory = factory
def initialize
@location = current_url @location = current_url
end end
...@@ -15,11 +16,13 @@ module QA ...@@ -15,11 +16,13 @@ module QA
end end
def self.populate!(factory) def self.populate!(factory)
raise ArgumentError unless block_given? new.tap do |product|
factory.attributes.each_value do |attribute|
yield factory product.instance_exec(&attribute.block).tap do |value|
product.define_singleton_method(attribute.name) { value }
new(factory) end
end
end
end end
end end
end end
......
...@@ -13,6 +13,10 @@ module QA ...@@ -13,6 +13,10 @@ module QA
@description = 'My awesome project' @description = 'My awesome project'
end end
product :name do
Page::Project::Show.act { project_name }
end
def fabricate! def fabricate!
group.visit! group.visit!
......
...@@ -4,11 +4,13 @@ module QA ...@@ -4,11 +4,13 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials } Page::Main::Login.act { sign_in_using_credentials }
Factory::Resource::Project.fabricate! do |project| created_project = Factory::Resource::Project.fabricate! do |project|
project.name = 'awesome-project' project.name = 'awesome-project'
project.description = 'create awesome project test' project.description = 'create awesome project test'
end end
expect(created_project.name).to match /^awesome-project-\h{16}$/
expect(page).to have_content( expect(page).to have_content(
/Project \S?awesome-project\S+ was successfully created/ /Project \S?awesome-project\S+ was successfully created/
) )
......
describe QA::Factory::Base do describe QA::Factory::Base do
let(:factory) { spy('factory') }
let(:product) { spy('product') }
describe '.fabricate!' do describe '.fabricate!' do
subject { Class.new(described_class) } subject { Class.new(described_class) }
let(:factory) { spy('factory') }
let(:product) { spy('product') }
before do before do
allow(QA::Factory::Product).to receive(:new).and_return(product) allow(QA::Factory::Product).to receive(:new).and_return(product)
...@@ -59,30 +60,63 @@ describe QA::Factory::Base do ...@@ -59,30 +60,63 @@ describe QA::Factory::Base do
it 'defines dependency accessors' do it 'defines dependency accessors' do
expect(subject.new).to respond_to :mydep, :mydep= expect(subject.new).to respond_to :mydep, :mydep=
end end
end
describe 'building dependencies' do describe 'dependencies fabrication' do
let(:dependency) { double('dependency') } let(:dependency) { double('dependency') }
let(:instance) { spy('instance') } 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 '.product' do
subject do subject do
Class.new(described_class) do Class.new(described_class) do
dependency Some::MyDependency, as: :mydep product :token do
page.do_something_on_page!
'resulting value'
end
end end
end end
before do it 'appends new product attribute' do
stub_const('Some::MyDependency', dependency) expect(subject.attributes).to be_one
expect(subject.attributes).to have_key(:token)
allow(subject).to receive(:new).and_return(instance)
allow(instance).to receive(:mydep).and_return(nil)
allow(QA::Factory::Product).to receive(:new)
end end
it 'builds all dependencies first' do describe 'populating fabrication product with data' do
expect(dependency).to receive(:fabricate!).once let(:page) { spy('page') }
before do
allow(subject).to receive(:new).and_return(factory)
allow(QA::Factory::Product).to receive(:new).and_return(product)
allow(product).to receive(:page).and_return(page)
end
subject.fabricate! it 'populates product after fabrication' do
subject.fabricate!
expect(page).to have_received(:do_something_on_page!)
expect(product.token).to eq 'resulting value'
end
end end
end end
end end
...@@ -3,19 +3,8 @@ describe QA::Factory::Product do ...@@ -3,19 +3,8 @@ describe QA::Factory::Product do
let(:product) { spy('product') } let(:product) { spy('product') }
describe '.populate!' do 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 it 'returns a fabrication product' do
expect(described_class).to receive(:new) expect(described_class).to receive(:new).and_return(product)
.with(factory).and_return(product)
result = described_class.populate!(factory) do |instance| result = described_class.populate!(factory) do |instance|
instance.something = 'string' instance.something = 'string'
...@@ -23,11 +12,6 @@ describe QA::Factory::Product do ...@@ -23,11 +12,6 @@ describe QA::Factory::Product do
expect(result).to be product expect(result).to be product
end end
it 'raises unless block given' do
expect { described_class.populate!(factory) }
.to raise_error ArgumentError
end
end end
describe '.visit!' do describe '.visit!' do
...@@ -37,8 +21,7 @@ describe QA::Factory::Product do ...@@ -37,8 +21,7 @@ describe QA::Factory::Product do
allow_any_instance_of(described_class) allow_any_instance_of(described_class)
.to receive(:visit).and_return('visited some url') .to receive(:visit).and_return('visited some url')
expect(described_class.new(factory).visit!) expect(subject.visit!).to eq 'visited some url'
.to eq 'visited some url'
end end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment