summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLin Jen-Shin <godfat@godfat.org>2018-10-25 20:29:24 +0000
committerDouglas Barbosa Alexandre <dbalexandre@gmail.com>2018-10-25 20:29:24 +0000
commit51518019645ad514b98951df0bd30ecb898786aa (patch)
tree65fdeda5aa21db221ee296a87fa9ed7f4fc9f68c
parentbf96ec85c736747672fa550707829fef635ddd60 (diff)
downloadgitlab-ce-51518019645ad514b98951df0bd30ecb898786aa.tar.gz
Always use `attribute` to define the product
-rw-r--r--qa/qa.rb1
-rw-r--r--qa/qa/factory/README.md369
-rw-r--r--qa/qa/factory/base.rb79
-rw-r--r--qa/qa/factory/dependency.rb28
-rw-r--r--qa/qa/factory/product.rb33
-rw-r--r--qa/qa/factory/repository/project_push.rb11
-rw-r--r--qa/qa/factory/repository/wiki_push.rb10
-rw-r--r--qa/qa/factory/resource/branch.rb10
-rw-r--r--qa/qa/factory/resource/deploy_key.rb22
-rw-r--r--qa/qa/factory/resource/deploy_token.rb20
-rw-r--r--qa/qa/factory/resource/file.rb8
-rw-r--r--qa/qa/factory/resource/fork.rb25
-rw-r--r--qa/qa/factory/resource/group.rb8
-rw-r--r--qa/qa/factory/resource/issue.rb17
-rw-r--r--qa/qa/factory/resource/kubernetes_cluster.rb19
-rw-r--r--qa/qa/factory/resource/label.rb16
-rw-r--r--qa/qa/factory/resource/merge_request.rb42
-rw-r--r--qa/qa/factory/resource/merge_request_from_fork.rb21
-rw-r--r--qa/qa/factory/resource/personal_access_token.rb8
-rw-r--r--qa/qa/factory/resource/project.rb29
-rw-r--r--qa/qa/factory/resource/project_imported_from_github.rb8
-rw-r--r--qa/qa/factory/resource/project_milestone.rb15
-rw-r--r--qa/qa/factory/resource/runner.rb10
-rw-r--r--qa/qa/factory/resource/sandbox.rb8
-rw-r--r--qa/qa/factory/resource/secret_variable.rb10
-rw-r--r--qa/qa/factory/resource/ssh_key.rb12
-rw-r--r--qa/qa/factory/resource/user.rb11
-rw-r--r--qa/qa/factory/resource/wiki.rb8
-rw-r--r--qa/qa/factory/settings/hashed_storage.rb8
-rw-r--r--qa/qa/runtime/logger.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb4
-rw-r--r--qa/spec/factory/base_spec.rb143
-rw-r--r--qa/spec/factory/dependency_spec.rb79
-rw-r--r--qa/spec/factory/product_spec.rb66
34 files changed, 540 insertions, 620 deletions
diff --git a/qa/qa.rb b/qa/qa.rb
index 36a37dbb270..f760dd972a7 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -39,7 +39,6 @@ module QA
module Factory
autoload :ApiFabricator, 'qa/factory/api_fabricator'
autoload :Base, 'qa/factory/base'
- autoload :Dependency, 'qa/factory/dependency'
autoload :Product, 'qa/factory/product'
module Resource
diff --git a/qa/qa/factory/README.md b/qa/qa/factory/README.md
index 10140e39510..cfce096ab39 100644
--- a/qa/qa/factory/README.md
+++ b/qa/qa/factory/README.md
@@ -26,11 +26,7 @@ module QA
module Factory
module Resource
class Shirt < Factory::Base
- attr_accessor :name, :size
-
- def initialize(name)
- @name = name
- end
+ attr_accessor :name
def fabricate!
Page::Dashboard::Index.perform do |dashboard_index|
@@ -64,21 +60,10 @@ module QA
module Factory
module Resource
class Shirt < Factory::Base
- attr_accessor :name, :size
-
- def initialize(name)
- @name = name
- end
+ attr_accessor :name
def fabricate!
- Page::Dashboard::Index.perform do |dashboard_index|
- dashboard_index.go_to_new_shirt
- end
-
- Page::Shirt::New.perform do |shirt_new|
- shirt_new.set_name(name)
- shirt_new.create_shirt!
- end
+ # ... same as before
end
def api_get_path
@@ -103,33 +88,69 @@ end
The [`Project` factory](./resource/project.rb) is a good real example of Browser
UI and API implementations.
-### Define dependencies
+### Define attributes
+
+After the resource is fabricated, we would like to access the attributes on
+the resource. We define the attributes with `attribute` method. Suppose
+we want to access the name on the resource, we could change `attr_accessor`
+to `attribute`:
+
+```ruby
+module QA
+ module Factory
+ module Resource
+ class Shirt < Factory::Base
+ attribute :name
-A resource may need an other resource to exist first. For instance, a project
+ # ... same as before
+ end
+ end
+ end
+end
+```
+
+The difference between `attr_accessor` and `attribute` is that by using
+`attribute` it can also be accessed from the product:
+
+```ruby
+shirt =
+ QA::Factory::Resource::Shirt.fabricate! do |resource|
+ resource.name = "GitLab QA"
+ end
+
+shirt.name # => "GitLab QA"
+```
+
+In the above example, if we use `attr_accessor :name` then `shirt.name` won't
+be available. On the other hand, using `attribute :name` will allow you to use
+`shirt.name`, so most of the time you'll want to use `attribute` instead of
+`attr_accessor` unless we clearly don't need it for the product.
+
+#### Resource attributes
+
+A resource may need another resource to exist first. For instance, a project
needs a group to be created in.
-To define a dependency, you can use the `dependency` DSL method.
-The first argument is a factory class, then you should pass `as: <name>` to give
-a name to the dependency.
-That will allow access to the dependency from your resource object's methods.
-You would usually use it in `#fabricate!`, `#api_get_path`, `#api_post_path`,
-`#api_post_body`.
+To define a resource attribute, you can use the `attribute` method with a
+block using the other factory to fabricate the resource.
-Let's take the `Shirt` factory, and add a `project` dependency to it:
+That will allow access to the other resource from your resource object's
+methods. You would usually use it in `#fabricate!`, `#api_get_path`,
+`#api_post_path`, `#api_post_body`.
+
+Let's take the `Shirt` factory, and add a `project` attribute to it:
```ruby
module QA
module Factory
module Resource
class Shirt < Factory::Base
- attr_accessor :name, :size
+ attribute :name
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-to-create-a-shirt'
- end
-
- def initialize(name)
- @name = name
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-to-create-a-shirt'
+ end
end
def fabricate!
@@ -164,19 +185,19 @@ module QA
end
```
-**Note that dependencies are always built via the API fabrication method if
-supported by their factories.**
+**Note that all the attributes are lazily constructed. This means if you want
+a specific attribute to be fabricated first, you'll need to call the
+attribute method first even if you're not using it.**
-### Define attributes on the created resource
+#### Product data attributes
Once created, you may want to populate a resource with attributes that can be
found in the Web page, or in the API response.
For instance, once you create a project, you may want to store its repository
SSH URL as an attribute.
-To define an attribute, you can use the `product` DSL method.
-The first argument is the attribute name, then you should define a name for the
-dependency to be accessible from your resource object's methods.
+Again we could use the `attribute` method with a block, using a page object
+to retrieve the data on the page.
Let's take the `Shirt` factory, and define a `:brand` attribute:
@@ -185,22 +206,74 @@ module QA
module Factory
module Resource
class Shirt < Factory::Base
- attr_accessor :name, :size
+ attribute :name
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-to-create-a-shirt'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-to-create-a-shirt'
+ end
end
# Attribute populated from the Browser UI (using the block)
- product :brand do
+ attribute :brand do
Page::Shirt::Show.perform do |shirt_show|
shirt_show.fetch_brand_from_page
end
end
- def initialize(name)
- @name = name
- end
+ # ... same as before
+ end
+ end
+ end
+end
+```
+
+**Note again that all the attributes are lazily constructed. This means if
+you call `shirt.brand` after moving to the other page, it'll not properly
+retrieve the data because we're no longer on the expected page.**
+
+Consider this:
+
+```ruby
+shirt =
+ QA::Factory::Resource::Shirt.fabricate! do |resource|
+ resource.name = "GitLab QA"
+ end
+
+shirt.project.visit!
+
+shirt.brand # => FAIL!
+```
+
+The above example will fail because now we're on the project page, trying to
+construct the brand data from the shirt page, however we moved to the project
+page already. There are two ways to solve this, one is that we could try to
+retrieve the brand before visiting the project again:
+
+```ruby
+shirt =
+ QA::Factory::Resource::Shirt.fabricate! do |resource|
+ resource.name = "GitLab QA"
+ end
+
+shirt.brand # => OK!
+
+shirt.project.visit!
+
+shirt.brand # => OK!
+```
+
+The attribute will be stored in the instance therefore all the following calls
+will be fine, using the data previously constructed. If we think that this
+might be too brittle, we could eagerly construct the data right before
+ending fabrication:
+
+```ruby
+module QA
+ module Factory
+ module Resource
+ class Shirt < Factory::Base
+ # ... same as before
def fabricate!
project.visit!
@@ -213,20 +286,8 @@ module QA
shirt_new.set_name(name)
shirt_new.create_shirt!
end
- end
- def api_get_path
- "/project/#{project.path}/shirt/#{name}"
- end
-
- def api_post_path
- "/project/#{project.path}/shirts"
- end
-
- def api_post_body
- {
- name: name
- }
+ brand # Eagerly construct the data
end
end
end
@@ -234,74 +295,48 @@ module QA
end
```
-#### Inherit a factory's attribute
+This will make sure we construct the data right after we created the shirt.
+The drawback for this will become we're forced to construct the data even
+if we don't really need to use it.
-Sometimes, you want a resource to inherit its factory attributes. For instance,
-it could be useful to pass the `size` attribute from the `Shirt` factory to the
-created resource.
-You can do that by defining `product :attribute_name` without a block.
-
-Let's take the `Shirt` factory, and define a `:name` and a `:size` attributes:
+Alternatively, we could just make sure we're on the right page before
+constructing the brand data:
```ruby
module QA
module Factory
module Resource
class Shirt < Factory::Base
- attr_accessor :name, :size
-
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-to-create-a-shirt'
- end
+ attribute :name
- # Attribute from the Browser UI (using the block)
- product :brand do
- Page::Shirt::Show.perform do |shirt_show|
- shirt_show.fetch_brand_from_page
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-to-create-a-shirt'
end
end
- # Attribute inherited from the Shirt factory if present,
- # or a QA::Factory::Product::NoValueError is raised otherwise
- product :name
- product :size
-
- def initialize(name)
- @name = name
- end
-
- def fabricate!
- project.visit!
-
- Page::Project::Show.perform do |project_show|
- project_show.go_to_new_shirt
- end
+ # Attribute populated from the Browser UI (using the block)
+ attribute :brand do
+ back_url = current_url
+ visit!
- Page::Shirt::New.perform do |shirt_new|
- shirt_new.set_name(name)
- shirt_new.create_shirt!
+ Page::Shirt::Show.perform do |shirt_show|
+ shirt_show.fetch_brand_from_page
end
- end
- def api_get_path
- "/project/#{project.path}/shirt/#{name}"
+ visit(back_url)
end
- def api_post_path
- "/project/#{project.path}/shirts"
- end
-
- def api_post_body
- {
- name: name
- }
- end
+ # ... same as before
end
end
end
end
```
+This will make sure it's on the shirt page before constructing brand, and
+move back to the previous page to avoid breaking the state.
+
#### Define an attribute based on an API response
Sometimes, you want to define a resource attribute based on the API response
@@ -311,7 +346,6 @@ the API returns
```ruby
{
brand: 'a-brand-new-brand',
- size: 'extra-small',
style: 't-shirt',
materials: [[:cotton, 80], [:polyamide, 20]]
}
@@ -320,18 +354,6 @@ the API returns
you may want to store `style` as-is in the resource, and fetch the first value
of the first `materials` item in a `main_fabric` attribute.
-For both attributes, you will need to define an inherited attribute, as shown
-in "Inherit a factory's attribute" above, but in the case of `main_fabric`, you
-will need to implement the
-`#transform_api_resource` method to first populate the `:main_fabric` key in the
-API response so that it can be used later to automatically populate the
-attribute on your resource.
-
-If an attribute can only be retrieved from the API response, you should define
-a block to give it a default value, otherwise you could get a
-`QA::Factory::Product::NoValueError` when creating your resource via the
-Browser UI.
-
Let's take the `Shirt` factory, and define a `:style` and a `:main_fabric`
attributes:
@@ -340,69 +362,21 @@ module QA
module Factory
module Resource
class Shirt < Factory::Base
- attr_accessor :name, :size
+ # ... same as before
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-to-create-a-shirt'
- end
-
- # Attribute fetched from the API response if present,
- # or from the Browser UI otherwise (using the block)
- product :brand do
- Page::Shirt::Show.perform do |shirt_show|
- shirt_show.fetch_brand_from_page
- end
- end
-
- # Attribute fetched from the API response if present,
- # or from the Shirt factory if present,
- # or a QA::Factory::Product::NoValueError is raised otherwise
- product :name
- product :size
- product :style do
- 'unknown'
- end
- product :main_fabric do
- 'unknown'
- end
-
- def initialize(name)
- @name = name
- end
-
- def fabricate!
- project.visit!
-
- Page::Project::Show.perform do |project_show|
- project_show.go_to_new_shirt
- end
-
- Page::Shirt::New.perform do |shirt_new|
- shirt_new.set_name(name)
- shirt_new.create_shirt!
- end
- end
+ # Attribute from the Shirt factory if present,
+ # or fetched from the API response if present,
+ # or a QA::Factory::Base::NoValueError is raised otherwise
+ attribute :style
- def api_get_path
- "/project/#{project.path}/shirt/#{name}"
+ # If the attribute from the Shirt factory is not present,
+ # and if the API does not contain this field, this block will be
+ # used to construct the value based on the API response.
+ attribute :main_fabric do
+ api_response.&dig(:materials, 0, 0)
end
- def api_post_path
- "/project/#{project.path}/shirts"
- end
-
- def api_post_body
- {
- name: name
- }
- end
-
- private
-
- def transform_api_resource(api_response)
- api_response[:main_fabric] = api_response[:materials][0][0]
- api_response
- end
+ # ... same as before
end
end
end
@@ -411,11 +385,10 @@ end
**Notes on attributes precedence:**
+- attributes from the factory have the highest precedence
- attributes from the API response take precedence over attributes from the
- Browser UI
-- attributes from the Browser UI take precedence over attributes from the
- factory (i.e inherited)
-- attributes without a value will raise a `QA::Factory::Product::NoValueError` error
+ block (usually from Browser UI)
+- attributes without a value will raise a `QA::Factory::Base::NoValueError` error
## Creating resources in your tests
@@ -428,42 +401,40 @@ Here is an example that will use the API fabrication method under the hood since
it's supported by the `Shirt` factory:
```ruby
-my_shirt = Factory::Resource::Shirt.fabricate!('my-shirt') do |shirt|
- shirt.size = 'small'
+my_shirt = Factory::Resource::Shirt.fabricate! do |shirt|
+ shirt.name = 'my-shirt'
end
+expect(page).to have_text(my_shirt.name) # => "my-shirt" from the factory's attribute
expect(page).to have_text(my_shirt.brand) # => "a-brand-new-brand" from the API response
-expect(page).to have_text(my_shirt.name) # => "my-shirt" from the inherited factory's attribute
-expect(page).to have_text(my_shirt.size) # => "extra-small" from the API response
expect(page).to have_text(my_shirt.style) # => "t-shirt" from the API response
-expect(page).to have_text(my_shirt.main_fabric) # => "cotton" from the (transformed) API response
+expect(page).to have_text(my_shirt.main_fabric) # => "cotton" from the API response via the block
```
-If you explicitely want to use the Browser UI fabrication method, you can call
+If you explicitly want to use the Browser UI fabrication method, you can call
the `.fabricate_via_browser_ui!` method instead:
```ruby
-my_shirt = Factory::Resource::Shirt.fabricate_via_browser_ui!('my-shirt') do |shirt|
- shirt.size = 'small'
+my_shirt = Factory::Resource::Shirt.fabricate_via_browser_ui! do |shirt|
+ shirt.name = 'my-shirt'
end
-expect(page).to have_text(my_shirt.brand) # => the brand name fetched from the `Page::Shirt::Show` page
-expect(page).to have_text(my_shirt.name) # => "my-shirt" from the inherited factory's attribute
-expect(page).to have_text(my_shirt.size) # => "small" from the inherited factory's attribute
-expect(page).to have_text(my_shirt.style) # => "unknown" from the attribute block
-expect(page).to have_text(my_shirt.main_fabric) # => "unknown" from the attribute block
+expect(page).to have_text(my_shirt.name) # => "my-shirt" from the factory's attribute
+expect(page).to have_text(my_shirt.brand) # => the brand name fetched from the `Page::Shirt::Show` page via the block
+expect(page).to have_text(my_shirt.style) # => QA::Factory::Base::NoValueError will be raised because no API response nor a block is provided
+expect(page).to have_text(my_shirt.main_fabric) # => QA::Factory::Base::NoValueError will be raised because no API response and the block didn't provide a value (because it's also based on the API response)
```
-You can also explicitely use the API fabrication method, by calling the
+You can also explicitly use the API fabrication method, by calling the
`.fabricate_via_api!` method:
```ruby
-my_shirt = Factory::Resource::Shirt.fabricate_via_api!('my-shirt') do |shirt|
- shirt.size = 'small'
+my_shirt = Factory::Resource::Shirt.fabricate_via_api! do |shirt|
+ shirt.name = 'my-shirt'
end
```
-In this case, the result will be similar to calling `Factory::Resource::Shirt.fabricate!('my-shirt')`.
+In this case, the result will be similar to calling `Factory::Resource::Shirt.fabricate!`.
## Where to ask for help?
diff --git a/qa/qa/factory/base.rb b/qa/qa/factory/base.rb
index e1dc23d350d..e82e16f9415 100644
--- a/qa/qa/factory/base.rb
+++ b/qa/qa/factory/base.rb
@@ -10,13 +10,42 @@ module QA
include ApiFabricator
extend Capybara::DSL
- def_delegators :evaluator, :dependency, :dependencies
- def_delegators :evaluator, :product, :attributes
+ NoValueError = Class.new(RuntimeError)
+
+ def_delegators :evaluator, :attribute
def fabricate!(*_args)
raise NotImplementedError
end
+ def visit!
+ visit(web_url)
+ end
+
+ private
+
+ def populate_attribute(name, block)
+ value = attribute_value(name, block)
+
+ raise NoValueError, "No value was computed for product #{name} of factory #{self.class.name}." unless value
+
+ value
+ end
+
+ def attribute_value(name, block)
+ api_value = api_resource&.dig(name)
+
+ if api_value && block
+ log_having_both_api_result_and_block(name, api_value)
+ end
+
+ api_value || (block && instance_exec(&block))
+ end
+
+ def log_having_both_api_result_and_block(name, api_value)
+ QA::Runtime::Logger.info "<#{self.class}> Attribute #{name.inspect} has both API response `#{api_value}` and a block. API response will be picked. Block will be ignored."
+ end
+
def self.fabricate!(*args, &prepare_block)
fabricate_via_api!(*args, &prepare_block)
rescue NotImplementedError
@@ -52,13 +81,10 @@ module QA
def self.do_fabricate!(factory:, prepare_block:, parents: [])
prepare_block.call(factory) if prepare_block
- dependencies.each do |signature|
- Factory::Dependency.new(factory, signature).build!(parents: parents + [self])
- end
-
resource_web_url = yield
+ factory.web_url = resource_web_url
- Factory::Product.populate!(factory, resource_web_url)
+ Factory::Product.new(factory)
end
private_class_method :do_fabricate!
@@ -85,31 +111,40 @@ module QA
end
private_class_method :evaluator
- class DSL
- attr_reader :dependencies, :attributes
+ def self.dynamic_attributes
+ const_get(:DynamicAttributes)
+ rescue NameError
+ mod = const_set(:DynamicAttributes, Module.new)
+
+ include mod
+
+ mod
+ end
+ def self.attributes_names
+ dynamic_attributes.instance_methods(false).sort.grep_v(/=$/)
+ end
+
+ class DSL
def initialize(base)
@base = base
- @dependencies = []
- @attributes = []
end
- def dependency(factory, as:, &block)
- as.tap do |name|
- @base.class_eval { attr_accessor name }
+ def attribute(name, &block)
+ @base.dynamic_attributes.module_eval do
+ attr_writer(name)
- Dependency::Signature.new(name, factory, block).tap do |signature|
- @dependencies << signature
+ define_method(name) do
+ instance_variable_get("@#{name}") ||
+ instance_variable_set(
+ "@#{name}",
+ populate_attribute(name, block))
end
end
end
-
- def product(attribute, &block)
- Product::Attribute.new(attribute, block).tap do |signature|
- @attributes << signature
- end
- end
end
+
+ attribute :web_url
end
end
end
diff --git a/qa/qa/factory/dependency.rb b/qa/qa/factory/dependency.rb
deleted file mode 100644
index 655e2677db0..00000000000
--- a/qa/qa/factory/dependency.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-module QA
- module Factory
- class Dependency
- Signature = Struct.new(:name, :factory, :block)
-
- def initialize(caller_factory, dependency_signature)
- @caller_factory = caller_factory
- @dependency_signature = dependency_signature
- end
-
- def overridden?
- !!@caller_factory.public_send(@dependency_signature.name)
- end
-
- def build!(parents: [])
- return if overridden?
-
- dependency = @dependency_signature.factory.fabricate!(parents: parents) do |factory|
- @dependency_signature.block&.call(factory, @caller_factory)
- end
-
- dependency.tap do |dependency|
- @caller_factory.public_send("#{@dependency_signature.name}=", dependency)
- end
- end
- end
- end
-end
diff --git a/qa/qa/factory/product.rb b/qa/qa/factory/product.rb
index 17fe908eaa2..34df0bda8e5 100644
--- a/qa/qa/factory/product.rb
+++ b/qa/qa/factory/product.rb
@@ -5,46 +5,31 @@ module QA
class Product
include Capybara::DSL
- NoValueError = Class.new(RuntimeError)
+ attr_reader :factory
- attr_reader :factory, :web_url
-
- Attribute = Struct.new(:name, :block)
-
- def initialize(factory, web_url)
+ def initialize(factory)
@factory = factory
- @web_url = web_url
- populate_attributes!
+ define_attributes
end
def visit!
visit(web_url)
end
- def self.populate!(factory, web_url)
- new(factory, web_url)
+ def populate(*attributes)
+ attributes.each(&method(:public_send))
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 }
+ def define_attributes
+ factory.class.attributes_names.each do |name|
+ define_singleton_method(name) do
+ factory.public_send(name)
end
end
end
-
- def attribute_value(attribute, block)
- factory.api_resource&.dig(attribute.name) ||
- (block && block.call(factory)) ||
- (factory.respond_to?(attribute.name) && factory.public_send(attribute.name))
- end
end
end
end
diff --git a/qa/qa/factory/repository/project_push.rb b/qa/qa/factory/repository/project_push.rb
index 6f878396f0e..a9dfbc0a783 100644
--- a/qa/qa/factory/repository/project_push.rb
+++ b/qa/qa/factory/repository/project_push.rb
@@ -2,13 +2,14 @@ module QA
module Factory
module Repository
class ProjectPush < Factory::Repository::Push
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-with-code'
- project.description = 'Project with repository'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-with-code'
+ resource.description = 'Project with repository'
+ end
end
- product :output
- product :project
+ attribute :output
def initialize
@file_name = 'file.txt'
diff --git a/qa/qa/factory/repository/wiki_push.rb b/qa/qa/factory/repository/wiki_push.rb
index ecc6cc18c88..25b6ffe8323 100644
--- a/qa/qa/factory/repository/wiki_push.rb
+++ b/qa/qa/factory/repository/wiki_push.rb
@@ -2,10 +2,12 @@ module QA
module Factory
module Repository
class WikiPush < Factory::Repository::Push
- dependency Factory::Resource::Wiki, as: :wiki do |wiki|
- wiki.title = 'Home'
- wiki.content = '# My First Wiki Content'
- wiki.message = 'Update home'
+ attribute :wiki do
+ Factory::Resource::Wiki.fabricate! do |resource|
+ resource.title = 'Home'
+ resource.content = '# My First Wiki Content'
+ resource.message = 'Update home'
+ end
end
def initialize
diff --git a/qa/qa/factory/resource/branch.rb b/qa/qa/factory/resource/branch.rb
index f3b52565d17..b05d1e252ec 100644
--- a/qa/qa/factory/resource/branch.rb
+++ b/qa/qa/factory/resource/branch.rb
@@ -5,8 +5,10 @@ module QA
attr_accessor :project, :branch_name,
:allow_to_push, :allow_to_merge, :protected
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'protected-branch-project'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'protected-branch-project'
+ end
end
def initialize
@@ -43,9 +45,7 @@ module QA
# to `allow_to_push` variable.
return branch unless @protected
- Page::Project::Menu.act do
- click_repository_settings
- end
+ Page::Project::Menu.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_protected_branches do |page|
diff --git a/qa/qa/factory/resource/deploy_key.rb b/qa/qa/factory/resource/deploy_key.rb
index 4c53c500c27..aea99c9f80d 100644
--- a/qa/qa/factory/resource/deploy_key.rb
+++ b/qa/qa/factory/resource/deploy_key.rb
@@ -4,11 +4,11 @@ module QA
class DeployKey < Factory::Base
attr_accessor :title, :key
- product :fingerprint do |resource|
- Page::Project::Settings::Repository.act do
- expand_deploy_keys do |key|
- key_offset = key.key_titles.index do |title|
- title.text == resource.title
+ attribute :fingerprint do
+ Page::Project::Settings::Repository.perform do |setting|
+ setting.expand_deploy_keys do |key|
+ key_offset = key.key_titles.index do |key_title|
+ key_title.text == title
end
key.key_fingerprints[key_offset].text
@@ -16,17 +16,17 @@ module QA
end
end
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-to-deploy'
- project.description = 'project for adding deploy key test'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-to-deploy'
+ resource.description = 'project for adding deploy key test'
+ end
end
def fabricate!
project.visit!
- Page::Project::Menu.act do
- click_repository_settings
- end
+ Page::Project::Menu.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_deploy_keys do |page|
diff --git a/qa/qa/factory/resource/deploy_token.rb b/qa/qa/factory/resource/deploy_token.rb
index 159f79ac50b..68e98f0aa01 100644
--- a/qa/qa/factory/resource/deploy_token.rb
+++ b/qa/qa/factory/resource/deploy_token.rb
@@ -4,25 +4,27 @@ module QA
class DeployToken < Factory::Base
attr_accessor :name, :expires_at
- product :username do |resource|
- Page::Project::Settings::Repository.act do
- expand_deploy_tokens do |token|
+ attribute :username do
+ Page::Project::Settings::Repository.perform do |page|
+ page.expand_deploy_tokens do |token|
token.token_username
end
end
end
- product :password do |password|
- Page::Project::Settings::Repository.act do
- expand_deploy_tokens do |token|
+ attribute :password do
+ Page::Project::Settings::Repository.perform do |page|
+ page.expand_deploy_tokens do |token|
token.token_password
end
end
end
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-to-deploy'
- project.description = 'project for adding deploy token test'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-to-deploy'
+ resource.description = 'project for adding deploy token test'
+ end
end
def fabricate!
diff --git a/qa/qa/factory/resource/file.rb b/qa/qa/factory/resource/file.rb
index f8dea06d361..1148876c2d3 100644
--- a/qa/qa/factory/resource/file.rb
+++ b/qa/qa/factory/resource/file.rb
@@ -8,8 +8,10 @@ module QA
:content,
:commit_message
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-with-new-file'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-with-new-file'
+ end
end
def initialize
@@ -21,7 +23,7 @@ module QA
def fabricate!
project.visit!
- Page::Project::Show.act { create_new_file! }
+ Page::Project::Show.perform(&:create_new_file!)
Page::File::Form.perform do |page|
page.add_name(@name)
diff --git a/qa/qa/factory/resource/fork.rb b/qa/qa/factory/resource/fork.rb
index 6e2a668df64..0fac4377040 100644
--- a/qa/qa/factory/resource/fork.rb
+++ b/qa/qa/factory/resource/fork.rb
@@ -2,17 +2,19 @@ module QA
module Factory
module Resource
class Fork < Factory::Base
- dependency Factory::Repository::ProjectPush, as: :push
+ attribute :push do
+ Factory::Repository::ProjectPush.fabricate!
+ end
- dependency Factory::Resource::User, as: :user do |user|
- if Runtime::Env.forker?
- user.username = Runtime::Env.forker_username
- user.password = Runtime::Env.forker_password
+ attribute :user do
+ Factory::Resource::User.fabricate! do |resource|
+ if Runtime::Env.forker?
+ resource.username = Runtime::Env.forker_username
+ resource.password = Runtime::Env.forker_password
+ end
end
end
- product :user
-
def visit_project_with_retry
# The user intermittently fails to stay signed in after visiting the
# project page. The new user is registered and then signs in and a
@@ -48,15 +50,20 @@ module QA
end
def fabricate!
+ push
+ user
+
visit_project_with_retry
- Page::Project::Show.act { fork_project }
+ Page::Project::Show.perform(&:fork_project)
Page::Project::Fork::New.perform do |fork_new|
fork_new.choose_namespace(user.name)
end
- Page::Layout::Banner.act { has_notice?('The project was successfully forked.') }
+ Page::Layout::Banner.perform do |page|
+ page.has_notice?('The project was successfully forked.')
+ end
end
end
end
diff --git a/qa/qa/factory/resource/group.rb b/qa/qa/factory/resource/group.rb
index 2688328df92..45e49da86f9 100644
--- a/qa/qa/factory/resource/group.rb
+++ b/qa/qa/factory/resource/group.rb
@@ -4,12 +4,12 @@ module QA
class Group < Factory::Base
attr_accessor :path, :description
- dependency Factory::Resource::Sandbox, as: :sandbox
-
- product :id do
- true # We don't retrieve the Group ID when using the Browser UI
+ attribute :sandbox do
+ Factory::Resource::Sandbox.fabricate!
end
+ attribute :id
+
def initialize
@path = Runtime::Namespace.name
@description = "QA test run at #{Runtime::Namespace.time}"
diff --git a/qa/qa/factory/resource/issue.rb b/qa/qa/factory/resource/issue.rb
index 9b444cb0bf1..3a28e0d5aa6 100644
--- a/qa/qa/factory/resource/issue.rb
+++ b/qa/qa/factory/resource/issue.rb
@@ -2,22 +2,21 @@ module QA
module Factory
module Resource
class Issue < Factory::Base
- attr_accessor :title, :description, :project
+ attr_writer :description
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-for-issues'
- project.description = 'project for adding issues'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-for-issues'
+ resource.description = 'project for adding issues'
+ end
end
- product :project
- product :title
+ attribute :title
def fabricate!
project.visit!
- Page::Project::Show.act do
- go_to_new_issue
- end
+ Page::Project::Show.perform(&:go_to_new_issue)
Page::Project::Issue::New.perform do |page|
page.add_title(@title)
diff --git a/qa/qa/factory/resource/kubernetes_cluster.rb b/qa/qa/factory/resource/kubernetes_cluster.rb
index cdee35c54e3..aac6864f42f 100644
--- a/qa/qa/factory/resource/kubernetes_cluster.rb
+++ b/qa/qa/factory/resource/kubernetes_cluster.rb
@@ -7,24 +7,21 @@ module QA
attr_writer :project, :cluster,
:install_helm_tiller, :install_ingress, :install_prometheus, :install_runner
- product :ingress_ip do
- Page::Project::Operations::Kubernetes::Show.perform do |page|
- page.ingress_ip
- end
+ attribute :ingress_ip do
+ Page::Project::Operations::Kubernetes::Show.perform(&:ingress_ip)
end
def fabricate!
@project.visit!
- Page::Project::Menu.act { click_operations_kubernetes }
+ Page::Project::Menu.perform(
+ &:click_operations_kubernetes)
- Page::Project::Operations::Kubernetes::Index.perform do |page|
- page.add_kubernetes_cluster
- end
+ Page::Project::Operations::Kubernetes::Index.perform(
+ &:add_kubernetes_cluster)
- Page::Project::Operations::Kubernetes::Add.perform do |page|
- page.add_existing_cluster
- end
+ Page::Project::Operations::Kubernetes::Add.perform(
+ &:add_existing_cluster)
Page::Project::Operations::Kubernetes::AddExisting.perform do |page|
page.set_cluster_name(@cluster.cluster_name)
diff --git a/qa/qa/factory/resource/label.rb b/qa/qa/factory/resource/label.rb
index 4080f15bf66..32bc519b48c 100644
--- a/qa/qa/factory/resource/label.rb
+++ b/qa/qa/factory/resource/label.rb
@@ -4,14 +4,14 @@ module QA
module Factory
module Resource
class Label < Factory::Base
- attr_accessor :title,
- :description,
- :color
+ attr_accessor :description, :color
- product(:title) { |factory| factory.title }
+ attribute :title
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-with-label'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-with-label'
+ end
end
def initialize
@@ -23,8 +23,8 @@ module QA
def fabricate!
project.visit!
- Page::Project::Menu.act { go_to_labels }
- Page::Label::Index.act { go_to_new_label }
+ Page::Project::Menu.perform(&:go_to_labels)
+ Page::Label::Index.perform(&:go_to_new_label)
Page::Label::New.perform do |page|
page.fill_title(@title)
diff --git a/qa/qa/factory/resource/merge_request.rb b/qa/qa/factory/resource/merge_request.rb
index d30da8a3db0..92b8bdf4a21 100644
--- a/qa/qa/factory/resource/merge_request.rb
+++ b/qa/qa/factory/resource/merge_request.rb
@@ -12,27 +12,33 @@ module QA
:milestone,
:labels
- product :project
- product :source_branch
+ attribute :source_branch
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-with-merge-request'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-with-merge-request'
+ end
end
- dependency Factory::Repository::ProjectPush, as: :target do |push, factory|
- factory.project.visit!
- push.project = factory.project
- push.branch_name = 'master'
- push.remote_branch = factory.target_branch
+ attribute :target do
+ project.visit!
+
+ Factory::Repository::ProjectPush.fabricate! do |resource|
+ resource.project = project
+ resource.branch_name = 'master'
+ resource.remote_branch = target_branch
+ end
end
- dependency Factory::Repository::ProjectPush, as: :source do |push, factory|
- push.project = factory.project
- push.branch_name = factory.target_branch
- push.remote_branch = factory.source_branch
- push.new_branch = false
- push.file_name = "added_file.txt"
- push.file_content = "File Added"
+ attribute :source do
+ Factory::Repository::ProjectPush.fabricate! do |resource|
+ resource.project = project
+ resource.branch_name = target_branch
+ resource.remote_branch = source_branch
+ resource.new_branch = false
+ resource.file_name = "added_file.txt"
+ resource.file_content = "File Added"
+ end
end
def initialize
@@ -46,8 +52,10 @@ module QA
end
def fabricate!
+ target
+ source
project.visit!
- Page::Project::Show.act { new_merge_request }
+ Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform do |page|
page.fill_title(@title)
page.fill_description(@description)
diff --git a/qa/qa/factory/resource/merge_request_from_fork.rb b/qa/qa/factory/resource/merge_request_from_fork.rb
index 6caaf65f673..fbe062539b9 100644
--- a/qa/qa/factory/resource/merge_request_from_fork.rb
+++ b/qa/qa/factory/resource/merge_request_from_fork.rb
@@ -4,19 +4,24 @@ module QA
class MergeRequestFromFork < MergeRequest
attr_accessor :fork_branch
- dependency Factory::Resource::Fork, as: :fork
+ attribute :fork do
+ Factory::Resource::Fork.fabricate!
+ end
- dependency Factory::Repository::ProjectPush, as: :push do |push, factory|
- push.project = factory.fork
- push.branch_name = factory.fork_branch
- push.file_name = 'file2.txt'
- push.user = factory.fork.user
+ attribute :push do
+ Factory::Repository::ProjectPush.fabricate! do |resource|
+ resource.project = fork
+ resource.branch_name = fork_branch
+ resource.file_name = 'file2.txt'
+ resource.user = fork.user
+ end
end
def fabricate!
+ push
fork.visit!
- Page::Project::Show.act { new_merge_request }
- Page::MergeRequest::New.act { create_merge_request }
+ Page::Project::Show.perform(&:new_merge_request)
+ Page::MergeRequest::New.perform(&:create_merge_request)
end
end
end
diff --git a/qa/qa/factory/resource/personal_access_token.rb b/qa/qa/factory/resource/personal_access_token.rb
index 166054cfcdc..ceb0f1c3d75 100644
--- a/qa/qa/factory/resource/personal_access_token.rb
+++ b/qa/qa/factory/resource/personal_access_token.rb
@@ -7,13 +7,13 @@ module QA
class PersonalAccessToken < Factory::Base
attr_accessor :name
- product :access_token do
- Page::Profile::PersonalAccessTokens.act { created_access_token }
+ attribute :access_token do
+ Page::Profile::PersonalAccessTokens.perform(&:created_access_token)
end
def fabricate!
- Page::Main::Menu.act { go_to_profile_settings }
- Page::Profile::Menu.act { click_access_tokens }
+ Page::Main::Menu.perform(&:go_to_profile_settings)
+ Page::Profile::Menu.perform(&:click_access_tokens)
Page::Profile::PersonalAccessTokens.perform do |page|
page.fill_token_name(name || 'api-test-token')
diff --git a/qa/qa/factory/resource/project.rb b/qa/qa/factory/resource/project.rb
index 105e42b23ec..f691ae5a342 100644
--- a/qa/qa/factory/resource/project.rb
+++ b/qa/qa/factory/resource/project.rb
@@ -4,25 +4,24 @@ module QA
module Factory
module Resource
class Project < Factory::Base
- attr_accessor :description
- attr_reader :name
+ attribute :name
+ attribute :description
- dependency Factory::Resource::Group, as: :group
-
- product :group
- product :name
+ attribute :group do
+ Factory::Resource::Group.fabricate!
+ end
- product :repository_ssh_location do
- Page::Project::Show.act do
- choose_repository_clone_ssh
- repository_location
+ attribute :repository_ssh_location do
+ Page::Project::Show.perform do |page|
+ page.choose_repository_clone_ssh
+ page.repository_location
end
end
- product :repository_http_location do
- Page::Project::Show.act do
- choose_repository_clone_http
- repository_location
+ attribute :repository_http_location do
+ Page::Project::Show.perform do |page|
+ page.choose_repository_clone_http
+ page.repository_location
end
end
@@ -37,7 +36,7 @@ module QA
def fabricate!
group.visit!
- Page::Group::Show.act { go_to_new_project }
+ Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |page|
page.choose_test_namespace
diff --git a/qa/qa/factory/resource/project_imported_from_github.rb b/qa/qa/factory/resource/project_imported_from_github.rb
index a45e7fee03b..f62092ae122 100644
--- a/qa/qa/factory/resource/project_imported_from_github.rb
+++ b/qa/qa/factory/resource/project_imported_from_github.rb
@@ -6,14 +6,16 @@ module QA
class ProjectImportedFromGithub < Resource::Project
attr_writer :personal_access_token, :github_repository_path
- dependency Factory::Resource::Group, as: :group
+ attribute :group do
+ Factory::Resource::Group.fabricate!
+ end
- product :name
+ attribute :name
def fabricate!
group.visit!
- Page::Group::Show.act { go_to_new_project }
+ Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |page|
page.go_to_import_project
diff --git a/qa/qa/factory/resource/project_milestone.rb b/qa/qa/factory/resource/project_milestone.rb
index 35383842142..cfda58dc103 100644
--- a/qa/qa/factory/resource/project_milestone.rb
+++ b/qa/qa/factory/resource/project_milestone.rb
@@ -3,11 +3,12 @@ module QA
module Resource
class ProjectMilestone < Factory::Base
attr_accessor :description
- attr_reader :title
- dependency Factory::Resource::Project, as: :project
+ attribute :project do
+ Factory::Resource::Project.fabricate!
+ end
- product :title
+ attribute :title
def title=(title)
@title = "#{title}-#{SecureRandom.hex(4)}"
@@ -17,12 +18,12 @@ module QA
def fabricate!
project.visit!
- Page::Project::Menu.act do
- click_issues
- click_milestones
+ Page::Project::Menu.perform do |page|
+ page.click_issues
+ page.click_milestones
end
- Page::Project::Milestone::Index.act { click_new_milestone }
+ Page::Project::Milestone::Index.perform(&:click_new_milestone)
Page::Project::Milestone::New.perform do |milestone_new|
milestone_new.set_title(@title)
diff --git a/qa/qa/factory/resource/runner.rb b/qa/qa/factory/resource/runner.rb
index 7ac65fe6913..7108db1e55a 100644
--- a/qa/qa/factory/resource/runner.rb
+++ b/qa/qa/factory/resource/runner.rb
@@ -6,9 +6,11 @@ module QA
class Runner < Factory::Base
attr_writer :name, :tags, :image
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-with-ci-cd'
- project.description = 'Project with CI/CD Pipelines'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-with-ci-cd'
+ resource.description = 'Project with CI/CD Pipelines'
+ end
end
def name
@@ -26,7 +28,7 @@ module QA
def fabricate!
project.visit!
- Page::Project::Menu.act { click_ci_cd_settings }
+ Page::Project::Menu.perform(&:click_ci_cd_settings)
Service::Runner.new(name).tap do |runner|
Page::Project::Settings::CICD.perform do |settings|
diff --git a/qa/qa/factory/resource/sandbox.rb b/qa/qa/factory/resource/sandbox.rb
index e592f4e0dd2..56bcda9e2f3 100644
--- a/qa/qa/factory/resource/sandbox.rb
+++ b/qa/qa/factory/resource/sandbox.rb
@@ -8,17 +8,15 @@ module QA
class Sandbox < Factory::Base
attr_reader :path
- product :id do
- true # We don't retrieve the Group ID when using the Browser UI
- end
- product :path
+ attribute :id
+ attribute :path
def initialize
@path = Runtime::Namespace.sandbox_name
end
def fabricate!
- Page::Main::Menu.act { go_to_groups }
+ Page::Main::Menu.perform(&:go_to_groups)
Page::Dashboard::Groups.perform do |page|
if page.has_group?(path)
diff --git a/qa/qa/factory/resource/secret_variable.rb b/qa/qa/factory/resource/secret_variable.rb
index 4084a7fc2cd..24ba3408810 100644
--- a/qa/qa/factory/resource/secret_variable.rb
+++ b/qa/qa/factory/resource/secret_variable.rb
@@ -4,15 +4,17 @@ module QA
class SecretVariable < Factory::Base
attr_accessor :key, :value
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-with-secret-variables'
- project.description = 'project for adding secret variable test'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-with-secret-variables'
+ resource.description = 'project for adding secret variable test'
+ end
end
def fabricate!
project.visit!
- Page::Project::Menu.act { click_ci_cd_settings }
+ Page::Project::Menu.perform(&:click_ci_cd_settings)
Page::Project::Settings::CICD.perform do |setting|
setting.expand_secret_variables do |page|
diff --git a/qa/qa/factory/resource/ssh_key.rb b/qa/qa/factory/resource/ssh_key.rb
index a512d071dd4..a48a93fbe65 100644
--- a/qa/qa/factory/resource/ssh_key.rb
+++ b/qa/qa/factory/resource/ssh_key.rb
@@ -6,21 +6,19 @@ module QA
class SSHKey < Factory::Base
extend Forwardable
- attr_accessor :title
- attr_reader :private_key, :public_key, :fingerprint
def_delegators :key, :private_key, :public_key, :fingerprint
- product :private_key
- product :title
- product :fingerprint
+ attribute :private_key
+ attribute :title
+ attribute :fingerprint
def key
@key ||= Runtime::Key::RSA.new
end
def fabricate!
- Page::Main::Menu.act { go_to_profile_settings }
- Page::Profile::Menu.act { click_ssh_keys }
+ Page::Main::Menu.perform(&:go_to_profile_settings)
+ Page::Profile::Menu.perform(&:click_ssh_keys)
Page::Profile::SSHKeys.perform do |page|
page.add_key(public_key, title)
diff --git a/qa/qa/factory/resource/user.rb b/qa/qa/factory/resource/user.rb
index 36edf787b64..6e6f46f7a95 100644
--- a/qa/qa/factory/resource/user.rb
+++ b/qa/qa/factory/resource/user.rb
@@ -5,7 +5,6 @@ module QA
module Resource
class User < Factory::Base
attr_reader :unique_id
- attr_writer :username, :password, :name, :email
def initialize
@unique_id = SecureRandom.hex(8)
@@ -31,14 +30,14 @@ module QA
defined?(@username) && defined?(@password)
end
- product :name
- product :username
- product :email
- product :password
+ attribute :name
+ attribute :username
+ attribute :email
+ attribute :password
def fabricate!
# Don't try to log-out if we're not logged-in
- if Page::Main::Menu.act { has_personal_area?(wait: 0) }
+ if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
Page::Main::Menu.perform { |main| main.sign_out }
end
diff --git a/qa/qa/factory/resource/wiki.rb b/qa/qa/factory/resource/wiki.rb
index d697433736e..769f394e85c 100644
--- a/qa/qa/factory/resource/wiki.rb
+++ b/qa/qa/factory/resource/wiki.rb
@@ -4,9 +4,11 @@ module QA
class Wiki < Factory::Base
attr_accessor :title, :content, :message
- dependency Factory::Resource::Project, as: :project do |project|
- project.name = 'project-for-wikis'
- project.description = 'project for adding wikis'
+ attribute :project do
+ Factory::Resource::Project.fabricate! do |resource|
+ resource.name = 'project-for-wikis'
+ resource.description = 'project for adding wikis'
+ end
end
def fabricate!
diff --git a/qa/qa/factory/settings/hashed_storage.rb b/qa/qa/factory/settings/hashed_storage.rb
index 5e8f883e25f..4e32382f910 100644
--- a/qa/qa/factory/settings/hashed_storage.rb
+++ b/qa/qa/factory/settings/hashed_storage.rb
@@ -5,9 +5,9 @@ module QA
def fabricate!(*traits)
raise ArgumentError unless traits.include?(:enabled)
- Page::Main::Login.act { sign_in_using_credentials }
- Page::Main::Menu.act { go_to_admin_area }
- Page::Admin::Menu.act { go_to_repository_settings }
+ Page::Main::Login.perform(&:sign_in_using_credentials)
+ Page::Main::Menu.perform(&:go_to_admin_area)
+ Page::Admin::Menu.perform(&:go_to_repository_settings)
Page::Admin::Settings::Repository.perform do |setting|
setting.expand_repository_storage do |page|
@@ -16,7 +16,7 @@ module QA
end
end
- QA::Page::Main::Menu.act { sign_out }
+ QA::Page::Main::Menu.perform(&:sign_out)
end
end
end
diff --git a/qa/qa/runtime/logger.rb b/qa/qa/runtime/logger.rb
index 3baa24de0ec..83b10e73ad9 100644
--- a/qa/qa/runtime/logger.rb
+++ b/qa/qa/runtime/logger.rb
@@ -7,7 +7,7 @@ module QA
module Logger
extend SingleForwardable
- def_delegators :logger, :debug, :info, :error, :warn, :fatal, :unknown
+ def_delegators :logger, :debug, :info, :warn, :error, :fatal, :unknown
singleton_class.module_eval do
def logger
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index c98ede25b68..40cae0793dd 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -49,11 +49,13 @@ module QA
cluster.install_prometheus = true
cluster.install_runner = true
end
+ kubernetes_cluster.populate(:ingress_ip)
project.visit!
Page::Project::Menu.act { click_ci_cd_settings }
Page::Project::Settings::CICD.perform do |p|
- p.enable_auto_devops_with_domain("#{kubernetes_cluster.ingress_ip}.nip.io")
+ p.enable_auto_devops_with_domain(
+ "#{kubernetes_cluster.ingress_ip}.nip.io")
end
project.visit!
diff --git a/qa/spec/factory/base_spec.rb b/qa/spec/factory/base_spec.rb
index 229f93a1041..d7b92052894 100644
--- a/qa/spec/factory/base_spec.rb
+++ b/qa/spec/factory/base_spec.rb
@@ -19,7 +19,7 @@ describe QA::Factory::Base do
before do
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)
+ allow(QA::Factory::Product).to receive(:new).with(factory).and_return(product)
end
end
@@ -115,73 +115,134 @@ describe QA::Factory::Base do
end
end
- describe '.dependency' do
- let(:dependency) { spy('dependency') }
+ shared_context 'simple factory' do
+ subject do
+ Class.new(QA::Factory::Base) do
+ attribute :test do
+ 'block'
+ end
- before do
- stub_const('Some::MyDependency', dependency)
- end
+ attribute :no_block
- subject do
- Class.new(described_class) do
- dependency Some::MyDependency, as: :mydep do |factory|
- factory.something!
+ def fabricate!
+ 'any'
+ end
+
+ def self.current_url
+ 'http://stub'
end
end
end
- it 'appends a new dependency and accessors' do
- expect(subject.dependencies).to be_one
+ let(:factory) { subject.new }
+ end
+
+ describe '.attribute' do
+ include_context 'simple factory'
+
+ it 'appends new product attribute' do
+ expect(subject.attributes_names).to eq([:no_block, :test, :web_url])
end
- it 'defines dependency accessors' do
- expect(subject.new).to respond_to :mydep, :mydep=
+ context 'when the product attribute is populated via a block' do
+ it 'returns a fabrication product and defines factory attributes as its methods' do
+ result = subject.fabricate!(factory: factory)
+
+ expect(result).to be_a(QA::Factory::Product)
+ expect(result.test).to eq('block')
+ end
end
- describe 'dependencies fabrication' do
- let(:dependency) { double('dependency') }
- let(:instance) { spy('instance') }
+ context 'when the product attribute is populated via the api' do
+ let(:api_resource) { { no_block: 'api' } }
+
+ before do
+ expect(factory).to receive(:api_resource).and_return(api_resource)
+ end
+
+ it 'returns a fabrication product and defines factory attributes as its methods' do
+ result = subject.fabricate!(factory: factory)
+
+ expect(result).to be_a(QA::Factory::Product)
+ expect(result.no_block).to eq('api')
+ end
+
+ context 'when the attribute also has a block in the factory' do
+ let(:api_resource) { { test: 'api_with_block' } }
+
+ before do
+ allow(QA::Runtime::Logger).to receive(:info)
+ end
+
+ it 'returns the api value and emits an INFO log entry' do
+ result = subject.fabricate!(factory: factory)
- subject do
- Class.new(described_class) do
- dependency Some::MyDependency, as: :mydep
+ expect(result).to be_a(QA::Factory::Product)
+ expect(result.test).to eq('api_with_block')
+ expect(QA::Runtime::Logger)
+ .to have_received(:info).with(/api_with_block/)
end
end
+ end
+ context 'when the product attribute is populated via a factory attribute' do
before do
- stub_const('Some::MyDependency', dependency)
+ factory.test = 'value'
+ end
+
+ it 'returns a fabrication product and defines factory attributes as its methods' do
+ result = subject.fabricate!(factory: factory)
+
+ expect(result).to be_a(QA::Factory::Product)
+ expect(result.test).to eq('value')
+ end
- 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)
- expect(QA::Factory::Product).to receive(:populate!)
+ context 'when the api also has such response' do
+ before do
+ allow(factory).to receive(:api_resource).and_return({ test: 'api' })
+ end
+
+ it 'returns the factory attribute for the product' do
+ result = subject.fabricate!(factory: factory)
+
+ expect(result).to be_a(QA::Factory::Product)
+ expect(result.test).to eq('value')
+ end
end
+ end
- it 'builds all dependencies first' do
- expect(dependency).to receive(:fabricate!).once
+ context 'when the product attribute has no value' do
+ it 'raises an error because no values could be found' do
+ result = subject.fabricate!(factory: factory)
- subject.fabricate!
+ expect { result.no_block }
+ .to raise_error(described_class::NoValueError, "No value was computed for product no_block of factory #{factory.class.name}.")
end
end
end
- describe '.product' do
- include_context 'fabrication context'
+ describe '#web_url' do
+ include_context 'simple factory'
- subject do
- Class.new(described_class) do
- def fabricate!
- "any"
- end
+ it 'sets #web_url to #current_url after fabrication' do
+ subject.fabricate!(factory: factory)
- product :token
- end
+ expect(factory.web_url).to eq(subject.current_url)
+ end
+ end
+
+ describe '#visit!' do
+ include_context 'simple factory'
+
+ before do
+ allow(factory).to receive(:visit)
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)
+ it 'calls #visit with the underlying #web_url' do
+ factory.web_url = subject.current_url
+ factory.visit!
+
+ expect(factory).to have_received(:visit).with(subject.current_url)
end
end
end
diff --git a/qa/spec/factory/dependency_spec.rb b/qa/spec/factory/dependency_spec.rb
deleted file mode 100644
index 657beddffb1..00000000000
--- a/qa/spec/factory/dependency_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-describe QA::Factory::Dependency do
- let(:dependency) { spy('dependency' ) }
- let(:factory) { spy('factory') }
- let(:block) { spy('block') }
-
- let(:signature) do
- double('signature', name: :mydep, factory: dependency, block: block)
- end
-
- subject do
- described_class.new(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
-
- it 'calls given block with dependency factory and caller factory' do
- expect(dependency).to receive(:fabricate!).and_yield(dependency)
-
- subject.build!
-
- expect(block).to have_received(:call).with(dependency, factory)
- end
-
- context 'with no block given' do
- let(:signature) do
- double('signature', name: :mydep, factory: dependency, block: nil)
- end
-
- it 'does not error' do
- subject.build!
-
- expect(dependency).to have_received(:fabricate!)
- end
- end
- end
- end
-end
diff --git a/qa/spec/factory/product_spec.rb b/qa/spec/factory/product_spec.rb
index 43b1d93d769..5b6eaa13e9c 100644
--- a/qa/spec/factory/product_spec.rb
+++ b/qa/spec/factory/product_spec.rb
@@ -1,73 +1,21 @@
describe QA::Factory::Product do
let(:factory) do
Class.new(QA::Factory::Base) do
- def foo
- 'bar'
+ attribute :test do
+ 'block'
end
+
+ attribute :no_block
end.new
end
let(:product) { spy('product') }
let(:product_location) { 'http://product_location' }
- subject { described_class.new(factory, product_location) }
-
- describe '.populate!' do
- before do
- expect(factory.class).to receive(:attributes).and_return(attributes)
- end
-
- context 'when the product attribute is populated via a block' do
- let(:attributes) do
- [QA::Factory::Product::Attribute.new(:test, proc { 'returned' })]
- end
-
- it 'returns a fabrication product and defines factory attributes as its methods' do
- 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 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' })
-
- result = described_class.populate!(factory, product_location)
+ subject { described_class.new(factory) }
- expect(result).to be_a(described_class)
- expect(result.test).to eq('returned')
- end
- end
-
- context 'when the product attribute is populated via a factory attribute' do
- let(:attributes) do
- [QA::Factory::Product::Attribute.new(:foo)]
- end
-
- it 'returns a fabrication product and defines factory attributes as its methods' do
- result = described_class.populate!(factory, product_location)
-
- expect(result).to be_a(described_class)
- expect(result.foo).to eq('bar')
- end
- end
-
- context 'when the product attribute has no value' do
- let(:attributes) do
- [QA::Factory::Product::Attribute.new(:bar)]
- end
-
- 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
+ before do
+ factory.web_url = product_location
end
describe '.visit!' do