Commit 57bc28e7 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch '53224-rename-to-resource-base-qa' into 'master'

CE: Rename QA::Factory to QA::Resource

See merge request gitlab-org/gitlab-ce!22772
parents ec37e707 4d0fd75c
...@@ -36,42 +36,40 @@ module QA ...@@ -36,42 +36,40 @@ module QA
## ##
# GitLab QA fabrication mechanisms # GitLab QA fabrication mechanisms
# #
module Factory module Resource
autoload :ApiFabricator, 'qa/factory/api_fabricator' autoload :ApiFabricator, 'qa/resource/api_fabricator'
autoload :Base, 'qa/factory/base' autoload :Base, 'qa/resource/base'
module Resource autoload :Sandbox, 'qa/resource/sandbox'
autoload :Sandbox, 'qa/factory/resource/sandbox' autoload :Group, 'qa/resource/group'
autoload :Group, 'qa/factory/resource/group' autoload :Issue, 'qa/resource/issue'
autoload :Issue, 'qa/factory/resource/issue' autoload :Project, 'qa/resource/project'
autoload :Project, 'qa/factory/resource/project' autoload :Label, 'qa/resource/label'
autoload :Label, 'qa/factory/resource/label' autoload :MergeRequest, 'qa/resource/merge_request'
autoload :MergeRequest, 'qa/factory/resource/merge_request' autoload :ProjectImportedFromGithub, 'qa/resource/project_imported_from_github'
autoload :ProjectImportedFromGithub, 'qa/factory/resource/project_imported_from_github' autoload :MergeRequestFromFork, 'qa/resource/merge_request_from_fork'
autoload :MergeRequestFromFork, 'qa/factory/resource/merge_request_from_fork' autoload :DeployKey, 'qa/resource/deploy_key'
autoload :DeployKey, 'qa/factory/resource/deploy_key' autoload :DeployToken, 'qa/resource/deploy_token'
autoload :DeployToken, 'qa/factory/resource/deploy_token' autoload :Branch, 'qa/resource/branch'
autoload :Branch, 'qa/factory/resource/branch' autoload :CiVariable, 'qa/resource/ci_variable'
autoload :CiVariable, 'qa/factory/resource/ci_variable' autoload :Runner, 'qa/resource/runner'
autoload :Runner, 'qa/factory/resource/runner' autoload :PersonalAccessToken, 'qa/resource/personal_access_token'
autoload :PersonalAccessToken, 'qa/factory/resource/personal_access_token' autoload :KubernetesCluster, 'qa/resource/kubernetes_cluster'
autoload :KubernetesCluster, 'qa/factory/resource/kubernetes_cluster' autoload :User, 'qa/resource/user'
autoload :User, 'qa/factory/resource/user' autoload :ProjectMilestone, 'qa/resource/project_milestone'
autoload :ProjectMilestone, 'qa/factory/resource/project_milestone' autoload :Wiki, 'qa/resource/wiki'
autoload :Wiki, 'qa/factory/resource/wiki' autoload :File, 'qa/resource/file'
autoload :File, 'qa/factory/resource/file' autoload :Fork, 'qa/resource/fork'
autoload :Fork, 'qa/factory/resource/fork' autoload :SSHKey, 'qa/resource/ssh_key'
autoload :SSHKey, 'qa/factory/resource/ssh_key'
end
module Repository module Repository
autoload :Push, 'qa/factory/repository/push' autoload :Push, 'qa/resource/repository/push'
autoload :ProjectPush, 'qa/factory/repository/project_push' autoload :ProjectPush, 'qa/resource/repository/project_push'
autoload :WikiPush, 'qa/factory/repository/wiki_push' autoload :WikiPush, 'qa/resource/repository/wiki_push'
end end
module Settings module Settings
autoload :HashedStorage, 'qa/factory/settings/hashed_storage' autoload :HashedStorage, 'qa/resource/settings/hashed_storage'
end end
end end
......
module QA
module Factory
module Resource
class Branch < Factory::Base
attr_accessor :project, :branch_name,
:allow_to_push, :allow_to_merge, :protected
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'protected-branch-project'
end
end
def initialize
@branch_name = 'test/branch'
@allow_to_push = true
@allow_to_merge = true
@protected = false
end
def fabricate!
project.visit!
Factory::Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.file_name = 'kick-off.txt'
resource.commit_message = 'First commit'
end
branch = Factory::Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.file_name = 'README.md'
resource.commit_message = 'Add readme'
resource.branch_name = 'master'
resource.new_branch = false
resource.remote_branch = @branch_name
end
Page::Project::Show.perform do |page|
page.wait { page.has_content?(branch_name) }
end
# The upcoming process will make it access the Protected Branches page,
# select the already created branch and protect it according
# to `allow_to_push` variable.
return branch unless @protected
Page::Project::Menu.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_protected_branches do |page|
page.select_branch(branch_name)
if allow_to_push
page.allow_devs_and_maintainers_to_push
else
page.allow_no_one_to_push
end
if allow_to_merge
page.allow_devs_and_maintainers_to_merge
else
page.allow_no_one_to_merge
end
page.wait(reload: false) do
!page.first('.btn-success').disabled?
end
page.protect_branch
end
end
end
end
end
end
end
module QA
module Factory
module Resource
class CiVariable < Factory::Base
attr_accessor :key, :value
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-ci-variables'
resource.description = 'project for adding CI variable test'
end
end
def fabricate!
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_settings)
Page::Project::Settings::CICD.perform do |setting|
setting.expand_ci_variables do |page|
page.fill_variable(key, value)
page.save_variables
end
end
end
end
end
end
end
module QA
module Factory
module Resource
class DeployKey < Factory::Base
attr_accessor :title, :key
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
end
end
end
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.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_deploy_keys do |page|
page.fill_key_title(title)
page.fill_key_value(key)
page.add_key
end
end
end
end
end
end
end
module QA
module Factory
module Resource
class DeployToken < Factory::Base
attr_accessor :name, :expires_at
attribute :username do
Page::Project::Settings::Repository.perform do |page|
page.expand_deploy_tokens do |token|
token.token_username
end
end
end
attribute :password do
Page::Project::Settings::Repository.perform do |page|
page.expand_deploy_tokens do |token|
token.token_password
end
end
end
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!
project.visit!
Page::Project::Menu.act do
click_repository_settings
end
Page::Project::Settings::Repository.perform do |setting|
setting.expand_deploy_tokens do |page|
page.fill_token_name(name)
page.fill_token_expires_at(expires_at)
page.fill_scopes(read_repository: true, read_registry: false)
page.add_token
end
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Factory
module Resource
class File < Factory::Base
attr_accessor :name,
:content,
:commit_message
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-new-file'
end
end
def initialize
@name = 'QA Test - File name'
@content = 'QA Test - File content'
@commit_message = 'QA Test - Commit message'
end
def fabricate!
project.visit!
Page::Project::Show.perform(&:create_new_file!)
Page::File::Form.perform do |page|
page.add_name(@name)
page.add_content(@content)
page.add_commit_message(@commit_message)
page.commit_changes
end
end
end
end
end
end
module QA
module Factory
module Resource
class Fork < Factory::Base
attribute :push do
Factory::Repository::ProjectPush.fabricate!
end
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
def fabricate!
populate(:push, :user)
# Sign out as admin and sign is as the fork user
Page::Main::Menu.perform(&:sign_out)
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(user)
end
push.project.visit!
Page::Project::Show.perform(&:fork_project)
Page::Project::Fork::New.perform do |fork_new|
fork_new.choose_namespace(user.name)
end
Page::Layout::Banner.perform do |page|
page.has_notice?('The project was successfully forked.')
end
end
end
end
end
end
module QA
module Factory
module Resource
class Group < Factory::Base
attr_accessor :path, :description
attribute :sandbox do
Factory::Resource::Sandbox.fabricate!
end
attribute :id
def initialize
@path = Runtime::Namespace.name
@description = "QA test run at #{Runtime::Namespace.time}"
end
def fabricate!
sandbox.visit!
Page::Group::Show.perform do |group_show|
if group_show.has_subgroup?(path)
group_show.go_to_subgroup(path)
else
group_show.go_to_new_subgroup
Page::Group::New.perform do |group_new|
group_new.set_path(path)
group_new.set_description(description)
group_new.set_visibility('Public')
group_new.create
end
# Ensure that the group was actually created
group_show.wait(time: 1) do
group_show.has_text?(path) &&
group_show.has_new_project_or_subgroup_dropdown?
end
end
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
def api_post_path
'/groups'
end
def api_post_body
{
parent_id: sandbox.id,
path: path,
name: path,
visibility: 'public'
}
end
end
end
end
end
module QA
module Factory
module Resource
class Issue < Factory::Base
attr_writer :description
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-for-issues'
resource.description = 'project for adding issues'
end
end
attribute :title
def fabricate!
project.visit!
Page::Project::Show.perform(&:go_to_new_issue)
Page::Project::Issue::New.perform do |page|
page.add_title(@title)
page.add_description(@description)
page.create_new_issue
end
end
end
end
end
end
require 'securerandom'
module QA
module Factory
module Resource
class KubernetesCluster < Factory::Base
attr_writer :project, :cluster,
:install_helm_tiller, :install_ingress, :install_prometheus, :install_runner
attribute :ingress_ip do
Page::Project::Operations::Kubernetes::Show.perform(&:ingress_ip)
end
def fabricate!
@project.visit!
Page::Project::Menu.perform(
&:click_operations_kubernetes)
Page::Project::Operations::Kubernetes::Index.perform(
&:add_kubernetes_cluster)
Page::Project::Operations::Kubernetes::Add.perform(
&:add_existing_cluster)
Page::Project::Operations::Kubernetes::AddExisting.perform do |page|
page.set_cluster_name(@cluster.cluster_name)
page.set_api_url(@cluster.api_url)
page.set_ca_certificate(@cluster.ca_certificate)
page.set_token(@cluster.token)
page.check_rbac! if @cluster.rbac
page.add_cluster!
end
if @install_helm_tiller
Page::Project::Operations::Kubernetes::Show.perform do |page|
# We must wait a few seconds for permissions to be set up correctly for new cluster
sleep 10
# Helm must be installed before everything else
page.install!(:helm)
page.await_installed(:helm)
page.install!(:ingress) if @install_ingress
page.install!(:prometheus) if @install_prometheus
page.install!(:runner) if @install_runner
page.await_installed(:ingress) if @install_ingress
page.await_installed(:prometheus) if @install_prometheus
page.await_installed(:runner) if @install_runner
end
end
end
end
end
end
end
require 'securerandom'
module QA
module Factory
module Resource
class Label < Factory::Base
attr_accessor :description, :color
attribute :title
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-label'
end
end
def initialize
@title = "qa-test-#{SecureRandom.hex(8)}"
@description = 'This is a test label'
@color = '#0033CC'
end
def fabricate!
project.visit!
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)
page.fill_description(@description)
page.fill_color(@color)
page.create_label
end
end
end
end
end
end
require 'securerandom'
module QA
module Factory
module Resource
class MergeRequest < Factory::Base
attr_accessor :title,
:description,
:source_branch,
:target_branch,
:assignee,
:milestone,
:labels
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-with-merge-request'
end
end
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
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
@title = 'QA test - merge request'
@description = 'This is a test merge request'
@source_branch = "qa-test-feature-#{SecureRandom.hex(8)}"
@target_branch = "master"
@assignee = nil
@milestone = nil
@labels = []
end
def fabricate!
populate(:target, :source)
project.visit!
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform do |page|
page.fill_title(@title)
page.fill_description(@description)
page.choose_milestone(@milestone) if @milestone
labels.each do |label|
page.select_label(label)
end
page.create_merge_request
end
end
end
end
end
end
module QA
module Factory
module Resource
class MergeRequestFromFork < MergeRequest
attr_accessor :fork_branch
attribute :fork do
Factory::Resource::Fork.fabricate!
end
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!
populate(:push)
fork.visit!
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform(&:create_merge_request)
end
end
end
end
end
module QA
module Factory
module Resource
##
# Create a personal access token that can be used by the api
#
class PersonalAccessToken < Factory::Base
attr_accessor :name
attribute :access_token do
Page::Profile::PersonalAccessTokens.perform(&:created_access_token)
end
def fabricate!
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')
page.check_api
page.create_token
end
end
end
end
end
end
require 'securerandom'
module QA
module Factory
module Resource
class Project < Factory::Base
attribute :name
attribute :description
attribute :group do
Factory::Resource::Group.fabricate!
end
attribute :repository_ssh_location do
Page::Project::Show.perform do |page|
page.choose_repository_clone_ssh
page.repository_location
end
end
attribute :repository_http_location do
Page::Project::Show.perform do |page|
page.choose_repository_clone_http
page.repository_location
end
end
def initialize
@description = 'My awesome project'
end
def name=(raw_name)
@name = "#{raw_name}-#{SecureRandom.hex(8)}"
end
def fabricate!
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |page|
page.choose_test_namespace
page.choose_name(@name)
page.add_description(@description)
page.set_visibility('Public')
page.create_new_project
end
end
def api_get_path
"/projects/#{name}"
end
def api_post_path
'/projects'
end
def api_post_body
{
namespace_id: group.id,
path: name,
name: name,
description: description,
visibility: 'public'
}
end
private
def transform_api_resource(resource)
resource[:repository_ssh_location] = Git::Location.new(resource[:ssh_url_to_repo])
resource[:repository_http_location] = Git::Location.new(resource[:http_url_to_repo])
resource
end
end
end
end
end
require 'securerandom'
module QA
module Factory
module Resource
class ProjectImportedFromGithub < Resource::Project
attr_accessor :name
attr_writer :personal_access_token, :github_repository_path
attribute :group do
Factory::Resource::Group.fabricate!
end
def fabricate!
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |page|
page.go_to_import_project
end
Page::Project::New.perform do |page|
page.go_to_github_import
end
Page::Project::Import::Github.perform do |page|
page.add_personal_access_token(@personal_access_token)
page.list_repos
page.import!(@github_repository_path, @name)
end
end
end
end
end
end
module QA
module Factory
module Resource
class ProjectMilestone < Factory::Base
attr_reader :title
attr_accessor :description
attribute :project do
Factory::Resource::Project.fabricate!
end
def title=(title)
@title = "#{title}-#{SecureRandom.hex(4)}"
@description = 'A milestone'
end
def fabricate!
project.visit!
Page::Project::Menu.perform do |page|
page.click_issues
page.click_milestones
end
Page::Project::Milestone::Index.perform(&:click_new_milestone)
Page::Project::Milestone::New.perform do |milestone_new|
milestone_new.set_title(@title)
milestone_new.set_description(@description)
milestone_new.create_new_milestone
end
end
end
end
end
end
require 'securerandom'
module QA
module Factory
module Resource
class Runner < Factory::Base
attr_writer :name, :tags, :image
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
@name || "qa-runner-#{SecureRandom.hex(4)}"
end
def tags
@tags || %w[qa e2e]
end
def image
@image || 'gitlab/gitlab-runner:alpine'
end
def fabricate!
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_settings)
Service::Runner.new(name).tap do |runner|
Page::Project::Settings::CICD.perform do |settings|
settings.expand_runners_settings do |runners|
runner.pull
runner.token = runners.registration_token
runner.address = runners.coordinator_address
runner.tags = tags
runner.image = image
runner.register!
end
end
end
end
end
end
end
end
module QA
module Factory
module Resource
##
# Ensure we're in our sandbox namespace, either by navigating to it or by
# creating it if it doesn't yet exist.
#
class Sandbox < Factory::Base
attr_reader :path
attribute :id
def initialize
@path = Runtime::Namespace.sandbox_name
end
def fabricate!
Page::Main::Menu.perform(&:go_to_groups)
Page::Dashboard::Groups.perform do |page|
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(path)
group.set_description('GitLab QA Sandbox Group')
group.set_visibility('Public')
group.create
end
end
end
end
def fabricate_via_api!
resource_web_url(api_get)
rescue ResourceNotFoundError
super
end
def api_get_path
"/groups/#{path}"
end
def api_post_path
'/groups'
end
def api_post_body
{
path: path,
name: path,
visibility: 'public'
}
end
end
end
end
end
# frozen_string_literal: true
module QA
module Factory
module Resource
class SSHKey < Factory::Base
extend Forwardable
attr_accessor :title
def_delegators :key, :private_key, :public_key, :fingerprint
def key
@key ||= Runtime::Key::RSA.new
end
def fabricate!
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)
end
end
end
end
end
end
require 'securerandom'
module QA
module Factory
module Resource
class User < Factory::Base
attr_reader :unique_id
attr_writer :username, :password
def initialize
@unique_id = SecureRandom.hex(8)
end
def username
@username ||= "qa-user-#{unique_id}"
end
def password
@password ||= 'password'
end
def name
@name ||= username
end
def email
@email ||= "#{username}@example.com"
end
def credentials_given?
defined?(@username) && defined?(@password)
end
def fabricate!
# Don't try to log-out if we're not logged-in
if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
Page::Main::Menu.perform { |main| main.sign_out }
end
if credentials_given?
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(self)
end
else
Page::Main::Login.perform do |login|
login.switch_to_register_tab
end
Page::Main::SignUp.perform do |signup|
signup.sign_up!(self)
end
end
end
def fabricate_via_api!
resource_web_url(api_get)
rescue ResourceNotFoundError
super
end
def api_get_path
"/users/#{fetch_id(username)}"
end
def api_post_path
'/users'
end
def api_post_body
{
email: email,
password: password,
username: username,
name: name,
skip_confirmation: true
}
end
private
def fetch_id(username)
users = parse_body(api_get_from("/users?username=#{username}"))
unless users.size == 1 && users.first[:username] == username
raise ResourceNotFoundError, "Expected one user with username #{username} but found: `#{users}`."
end
users.first[:id]
end
end
end
end
end
module QA
module Factory
module Resource
class Wiki < Factory::Base
attr_accessor :title, :content, :message
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-for-wikis'
resource.description = 'project for adding wikis'
end
end
def fabricate!
project.visit!
Page::Project::Menu.perform { |menu_side| menu_side.click_wiki }
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
end
end
end
...@@ -65,7 +65,7 @@ module QA ...@@ -65,7 +65,7 @@ module QA
end end
def sign_in_using_admin_credentials def sign_in_using_admin_credentials
admin = QA::Factory::Resource::User.new.tap do |user| admin = QA::Resource::User.new.tap do |user|
user.username = QA::Runtime::User.admin_username user.username = QA::Runtime::User.admin_username
user.password = QA::Runtime::User.admin_password user.password = QA::Runtime::User.admin_password
end end
......
# Factory objects in GitLab QA # Resource class in GitLab QA
In GitLab QA we are using factories to create resources. Resources are primarily created using Browser UI steps, but can also
be created via the API.
Factories implementation are primarily done using Browser UI steps, but can also ## How to properly implement a resource class?
be done via the API.
## Why do we need that? All resource classes should inherit from [`Resource::Base`](./base.rb).
We need factory objects because we need to reduce duplication when creating There is only one mandatory method to implement to define a resource class.
resources for our QA tests. This is the `#fabricate!` method, which is used to build the resource via the
browser UI. Note that you should only use [Page objects](../page/README.md) to
## How to properly implement a factory object? interact with a Web page in this method.
All factories should inherit from [`Factory::Base`](./base.rb).
There is only one mandatory method to implement to define a factory. This is the
`#fabricate!` method, which is used to build a resource via the browser UI.
Note that you should only use [Page objects](../page/README.md) to interact with
a Web page in this method.
Here is an imaginary example: Here is an imaginary example:
```ruby ```ruby
module QA module QA
module Factory module Resource
module Resource class Shirt < Base
class Shirt < Factory::Base attr_accessor :name
attr_accessor :name
def fabricate!
def fabricate! Page::Dashboard::Index.perform do |dashboard_index|
Page::Dashboard::Index.perform do |dashboard_index| dashboard_index.go_to_new_shirt
dashboard_index.go_to_new_shirt end
end
Page::Shirt::New.perform do |shirt_new|
Page::Shirt::New.perform do |shirt_new| shirt_new.set_name(name)
shirt_new.set_name(name) shirt_new.create_shirt!
shirt_new.create_shirt!
end
end end
end end
end end
...@@ -46,46 +37,44 @@ end ...@@ -46,46 +37,44 @@ end
### Define API implementation ### Define API implementation
A factory may also implement the three following methods to be able to create a A resource class may also implement the three following methods to be able to
resource via the public GitLab API: create the resource via the public GitLab API:
- `#api_get_path`: The `GET` path to fetch an existing resource. - `#api_get_path`: The `GET` path to fetch an existing resource.
- `#api_post_path`: The `POST` path to create a new resource. - `#api_post_path`: The `POST` path to create a new resource.
- `#api_post_body`: The `POST` body (as a Ruby hash) to create a new resource. - `#api_post_body`: The `POST` body (as a Ruby hash) to create a new resource.
Let's take the `Shirt` factory example, and add these three API methods: Let's take the `Shirt` resource class, and add these three API methods:
```ruby ```ruby
module QA module QA
module Factory module Resource
module Resource class Shirt < Base
class Shirt < Factory::Base attr_accessor :name
attr_accessor :name
def fabricate! def fabricate!
# ... same as before # ... same as before
end end
def api_get_path def api_get_path
"/shirt/#{name}" "/shirt/#{name}"
end end
def api_post_path def api_post_path
"/shirts" "/shirts"
end end
def api_post_body def api_post_body
{ {
name: name name: name
} }
end
end end
end end
end end
end end
``` ```
The [`Project` factory](./resource/project.rb) is a good real example of Browser The [`Project` resource](./project.rb) is a good real example of Browser
UI and API implementations. UI and API implementations.
#### Resource attributes #### Resource attributes
...@@ -94,53 +83,51 @@ A resource may need another resource to exist first. For instance, a project ...@@ -94,53 +83,51 @@ A resource may need another resource to exist first. For instance, a project
needs a group to be created in. needs a group to be created in.
To define a resource attribute, you can use the `attribute` method with a To define a resource attribute, you can use the `attribute` method with a
block using the other factory to fabricate the resource. block using the other resource class to fabricate the resource.
That will allow access to the other resource from your resource object's That will allow access to the other resource from your resource object's
methods. You would usually use it in `#fabricate!`, `#api_get_path`, methods. You would usually use it in `#fabricate!`, `#api_get_path`,
`#api_post_path`, `#api_post_body`. `#api_post_path`, `#api_post_body`.
Let's take the `Shirt` factory, and add a `project` attribute to it: Let's take the `Shirt` resource class, and add a `project` attribute to it:
```ruby ```ruby
module QA module QA
module Factory module Resource
module Resource class Shirt < Base
class Shirt < Factory::Base attr_accessor :name
attr_accessor :name
attribute :project do
Factory::Resource::Project.fabricate! do |resource|
resource.name = 'project-to-create-a-shirt'
end
end
def fabricate! attribute :project do
project.visit! Project.fabricate! do |resource|
resource.name = 'project-to-create-a-shirt'
end
end
Page::Project::Show.perform do |project_show| def fabricate!
project_show.go_to_new_shirt project.visit!
end
Page::Shirt::New.perform do |shirt_new| Page::Project::Show.perform do |project_show|
shirt_new.set_name(name) project_show.go_to_new_shirt
shirt_new.create_shirt!
end
end end
def api_get_path Page::Shirt::New.perform do |shirt_new|
"/project/#{project.path}/shirt/#{name}" shirt_new.set_name(name)
shirt_new.create_shirt!
end end
end
def api_post_path def api_get_path
"/project/#{project.path}/shirts" "/project/#{project.path}/shirt/#{name}"
end end
def api_post_body def api_post_path
{ "/project/#{project.path}/shirts"
name: name end
}
end def api_post_body
{
name: name
}
end end
end end
end end
...@@ -161,30 +148,28 @@ SSH URL as an attribute. ...@@ -161,30 +148,28 @@ SSH URL as an attribute.
Again we could use the `attribute` method with a block, using a page object Again we could use the `attribute` method with a block, using a page object
to retrieve the data on the page. to retrieve the data on the page.
Let's take the `Shirt` factory, and define a `:brand` attribute: Let's take the `Shirt` resource class, and define a `:brand` attribute:
```ruby ```ruby
module QA module QA
module Factory module Resource
module Resource class Shirt < Base
class Shirt < Factory::Base attr_accessor :name
attr_accessor :name
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) attribute :project do
attribute :brand do Project.fabricate! do |resource|
Page::Shirt::Show.perform do |shirt_show| resource.name = 'project-to-create-a-shirt'
shirt_show.fetch_brand_from_page
end
end end
end
# ... same as before # Attribute populated from the Browser UI (using the block)
attribute :brand do
Page::Shirt::Show.perform do |shirt_show|
shirt_show.fetch_brand_from_page
end
end end
# ... same as before
end end
end end
end end
...@@ -198,7 +183,7 @@ Consider this: ...@@ -198,7 +183,7 @@ Consider this:
```ruby ```ruby
shirt = shirt =
QA::Factory::Resource::Shirt.fabricate! do |resource| QA::Resource::Shirt.fabricate! do |resource|
resource.name = "GitLab QA" resource.name = "GitLab QA"
end end
...@@ -214,7 +199,7 @@ retrieve the brand before visiting the project again: ...@@ -214,7 +199,7 @@ retrieve the brand before visiting the project again:
```ruby ```ruby
shirt = shirt =
QA::Factory::Resource::Shirt.fabricate! do |resource| QA::Resource::Shirt.fabricate! do |resource|
resource.name = "GitLab QA" resource.name = "GitLab QA"
end end
...@@ -232,25 +217,23 @@ ending fabrication: ...@@ -232,25 +217,23 @@ ending fabrication:
```ruby ```ruby
module QA module QA
module Factory module Resource
module Resource class Shirt < Base
class Shirt < Factory::Base # ... same as before
# ... same as before
def fabricate!
project.visit!
Page::Project::Show.perform do |project_show| def fabricate!
project_show.go_to_new_shirt project.visit!
end
Page::Shirt::New.perform do |shirt_new| Page::Project::Show.perform do |project_show|
shirt_new.set_name(name) project_show.go_to_new_shirt
shirt_new.create_shirt! end
end
populate(:brand) # Eagerly construct the data Page::Shirt::New.perform do |shirt_new|
shirt_new.set_name(name)
shirt_new.create_shirt!
end end
populate(:brand) # Eagerly construct the data
end end
end end
end end
...@@ -262,38 +245,37 @@ attribute respectively. Here `populate(:brand)` has the same effect as ...@@ -262,38 +245,37 @@ attribute respectively. Here `populate(:brand)` has the same effect as
just `brand`. Using the populate method makes the intention clearer. just `brand`. Using the populate method makes the intention clearer.
With this, it will make sure we construct the data right after we create the With this, it will make sure we construct the data right after we create the
shirt. The drawback is that this will always construct the data when the resource is fabricated even if we don't need to use the data. shirt. The drawback is that this will always construct the data when the
resource is fabricated even if we don't need to use the data.
Alternatively, we could just make sure we're on the right page before Alternatively, we could just make sure we're on the right page before
constructing the brand data: constructing the brand data:
```ruby ```ruby
module QA module QA
module Factory module Resource
module Resource class Shirt < Base
class Shirt < Factory::Base attr_accessor :name
attr_accessor :name
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) attribute :project do
attribute :brand do Project.fabricate! do |resource|
back_url = current_url resource.name = 'project-to-create-a-shirt'
visit! end
end
Page::Shirt::Show.perform do |shirt_show| # Attribute populated from the Browser UI (using the block)
shirt_show.fetch_brand_from_page attribute :brand do
end back_url = current_url
visit!
visit(back_url) Page::Shirt::Show.perform do |shirt_show|
shirt_show.fetch_brand_from_page
end end
# ... same as before visit(back_url)
end end
# ... same as before
end end
end end
end end
...@@ -319,30 +301,29 @@ the API returns ...@@ -319,30 +301,29 @@ the API returns
you may want to store `style` as-is in the resource, and fetch the first value 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. of the first `materials` item in a `main_fabric` attribute.
Let's take the `Shirt` factory, and define a `:style` and a `:main_fabric` Let's take the `Shirt` resource class, and define a `:style` and a
attributes: `:main_fabric` attributes:
```ruby ```ruby
module QA module QA
module Factory module Resource
module Resource class Shirt < Base
class Shirt < Factory::Base # ... same as before
# ... same as before
# @style from the instance if present,
# Attribute from the Shirt factory if present, # or fetched from the API response if present,
# or fetched from the API response if present, # or a QA::Resource::Base::NoValueError is raised otherwise
# or a QA::Factory::Base::NoValueError is raised otherwise attribute :style
attribute :style
# If @main_fabric is not present,
# If the attribute from the Shirt factory is not present, # and if the API does not contain this field, this block will be
# and if the API does not contain this field, this block will be # used to construct the value based on the API response, and
# used to construct the value based on the API response. # store the result in @main_fabric
attribute :main_fabric do attribute :main_fabric do
api_response.&dig(:materials, 0, 0) api_response.&dig(:materials, 0, 0)
end
# ... same as before
end end
# ... same as before
end end
end end
end end
...@@ -350,27 +331,27 @@ end ...@@ -350,27 +331,27 @@ end
**Notes on attributes precedence:** **Notes on attributes precedence:**
- factory instance variables have the highest precedence - resource instance variables have the highest precedence
- attributes from the API response take precedence over attributes from the - attributes from the API response take precedence over attributes from the
block (usually from Browser UI) block (usually from Browser UI)
- attributes without a value will raise a `QA::Factory::Base::NoValueError` error - attributes without a value will raise a `QA::Resource::Base::NoValueError` error
## Creating resources in your tests ## Creating resources in your tests
To create a resource in your tests, you can call the `.fabricate!` method on the To create a resource in your tests, you can call the `.fabricate!` method on
factory class. the resource class.
Note that if the factory supports API fabrication, this will use this Note that if the resource class supports API fabrication, this will use this
fabrication by default. fabrication by default.
Here is an example that will use the API fabrication method under the hood since Here is an example that will use the API fabrication method under the hood
it's supported by the `Shirt` factory: since it's supported by the `Shirt` resource class:
```ruby ```ruby
my_shirt = Factory::Resource::Shirt.fabricate! do |shirt| my_shirt = Resource::Shirt.fabricate! do |shirt|
shirt.name = 'my-shirt' shirt.name = 'my-shirt'
end end
expect(page).to have_text(my_shirt.name) # => "my-shirt" from the factory's attribute expect(page).to have_text(my_shirt.name) # => "my-shirt" from the resource's instance variable
expect(page).to have_text(my_shirt.brand) # => "a-brand-new-brand" from the API response expect(page).to have_text(my_shirt.brand) # => "a-brand-new-brand" 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.style) # => "t-shirt" from the API response
expect(page).to have_text(my_shirt.main_fabric) # => "cotton" from the API response via the block expect(page).to have_text(my_shirt.main_fabric) # => "cotton" from the API response via the block
...@@ -380,26 +361,27 @@ If you explicitly want to use the Browser UI fabrication method, you can call ...@@ -380,26 +361,27 @@ If you explicitly want to use the Browser UI fabrication method, you can call
the `.fabricate_via_browser_ui!` method instead: the `.fabricate_via_browser_ui!` method instead:
```ruby ```ruby
my_shirt = Factory::Resource::Shirt.fabricate_via_browser_ui! do |shirt| my_shirt = Resource::Shirt.fabricate_via_browser_ui! do |shirt|
shirt.name = 'my-shirt' shirt.name = 'my-shirt'
end end
expect(page).to have_text(my_shirt.name) # => "my-shirt" from the factory's attribute expect(page).to have_text(my_shirt.name) # => "my-shirt" from the resource's instance variable
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.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.style) # => QA::Resource::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) expect(page).to have_text(my_shirt.main_fabric) # => QA::Resource::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 explicitly use the API fabrication method, by calling the You can also explicitly use the API fabrication method, by calling the
`.fabricate_via_api!` method: `.fabricate_via_api!` method:
```ruby ```ruby
my_shirt = Factory::Resource::Shirt.fabricate_via_api! do |shirt| my_shirt = Resource::Shirt.fabricate_via_api! do |shirt|
shirt.name = 'my-shirt' shirt.name = 'my-shirt'
end end
``` ```
In this case, the result will be similar to calling `Factory::Resource::Shirt.fabricate!`. In this case, the result will be similar to calling
`Resource::Shirt.fabricate!`.
## Where to ask for help? ## Where to ask for help?
......
...@@ -5,7 +5,7 @@ require 'active_support/core_ext/object/deep_dup' ...@@ -5,7 +5,7 @@ require 'active_support/core_ext/object/deep_dup'
require 'capybara/dsl' require 'capybara/dsl'
module QA module QA
module Factory module Resource
module ApiFabricator module ApiFabricator
include Airborne include Airborne
include Capybara::DSL include Capybara::DSL
...@@ -27,7 +27,7 @@ module QA ...@@ -27,7 +27,7 @@ module QA
def fabricate_via_api! def fabricate_via_api!
unless api_support? unless api_support?
raise NotImplementedError, "Factory #{self.class.name} does not support fabrication via the API!" raise NotImplementedError, "Resource #{self.class.name} does not support fabrication via the API!"
end end
resource_web_url(api_post) resource_web_url(api_post)
...@@ -93,8 +93,8 @@ module QA ...@@ -93,8 +93,8 @@ module QA
self.api_resource = transform_api_resource(parsed_response.deep_dup) self.api_resource = transform_api_resource(parsed_response.deep_dup)
end end
def transform_api_resource(resource) def transform_api_resource(api_resource)
resource api_resource
end end
end end
end end
......
...@@ -4,7 +4,7 @@ require 'forwardable' ...@@ -4,7 +4,7 @@ require 'forwardable'
require 'capybara/dsl' require 'capybara/dsl'
module QA module QA
module Factory module Resource
class Base class Base
extend SingleForwardable extend SingleForwardable
include ApiFabricator include ApiFabricator
...@@ -58,11 +58,11 @@ module QA ...@@ -58,11 +58,11 @@ module QA
def self.fabricate_via_browser_ui!(*args, &prepare_block) def self.fabricate_via_browser_ui!(*args, &prepare_block)
options = args.extract_options! options = args.extract_options!
factory = options.fetch(:factory) { new } resource = options.fetch(:resource) { new }
parents = options.fetch(:parents) { [] } parents = options.fetch(:parents) { [] }
do_fabricate!(factory: factory, prepare_block: prepare_block, parents: parents) do do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
log_fabrication(:browser_ui, factory, parents, args) { factory.fabricate!(*args) } log_fabrication(:browser_ui, resource, parents, args) { resource.fabricate!(*args) }
current_url current_url
end end
...@@ -70,29 +70,29 @@ module QA ...@@ -70,29 +70,29 @@ module QA
def self.fabricate_via_api!(*args, &prepare_block) def self.fabricate_via_api!(*args, &prepare_block)
options = args.extract_options! options = args.extract_options!
factory = options.fetch(:factory) { new } resource = options.fetch(:resource) { new }
parents = options.fetch(:parents) { [] } parents = options.fetch(:parents) { [] }
raise NotImplementedError unless factory.api_support? raise NotImplementedError unless resource.api_support?
factory.eager_load_api_client! resource.eager_load_api_client!
do_fabricate!(factory: factory, prepare_block: prepare_block, parents: parents) do do_fabricate!(resource: resource, prepare_block: prepare_block, parents: parents) do
log_fabrication(:api, factory, parents, args) { factory.fabricate_via_api! } log_fabrication(:api, resource, parents, args) { resource.fabricate_via_api! }
end end
end end
def self.do_fabricate!(factory:, prepare_block:, parents: []) def self.do_fabricate!(resource:, prepare_block:, parents: [])
prepare_block.call(factory) if prepare_block prepare_block.call(resource) if prepare_block
resource_web_url = yield resource_web_url = yield
factory.web_url = resource_web_url resource.web_url = resource_web_url
factory resource
end end
private_class_method :do_fabricate! private_class_method :do_fabricate!
def self.log_fabrication(method, factory, parents, args) def self.log_fabrication(method, resource, parents, args)
return yield unless Runtime::Env.debug? return yield unless Runtime::Env.debug?
start = Time.now start = Time.now
...@@ -111,7 +111,7 @@ module QA ...@@ -111,7 +111,7 @@ module QA
private_class_method :log_fabrication private_class_method :log_fabrication
def self.evaluator def self.evaluator
@evaluator ||= Factory::Base::DSL.new(self) @evaluator ||= Base::DSL.new(self)
end end
private_class_method :evaluator private_class_method :evaluator
......
# frozen_string_literal: true
module QA
module Resource
class Branch < Base
attr_accessor :project, :branch_name,
:allow_to_push, :allow_to_merge, :protected
attribute :project do
Project.fabricate! do |resource|
resource.name = 'protected-branch-project'
end
end
def initialize
@branch_name = 'test/branch'
@allow_to_push = true
@allow_to_merge = true
@protected = false
end
def fabricate!
project.visit!
Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.file_name = 'kick-off.txt'
resource.commit_message = 'First commit'
end
branch = Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.file_name = 'README.md'
resource.commit_message = 'Add readme'
resource.branch_name = 'master'
resource.new_branch = false
resource.remote_branch = @branch_name
end
Page::Project::Show.perform do |page|
page.wait { page.has_content?(branch_name) }
end
# The upcoming process will make it access the Protected Branches page,
# select the already created branch and protect it according
# to `allow_to_push` variable.
return branch unless @protected
Page::Project::Menu.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_protected_branches do |page|
page.select_branch(branch_name)
if allow_to_push
page.allow_devs_and_maintainers_to_push
else
page.allow_no_one_to_push
end
if allow_to_merge
page.allow_devs_and_maintainers_to_merge
else
page.allow_no_one_to_merge
end
page.wait(reload: false) do
!page.first('.btn-success').disabled?
end
page.protect_branch
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class CiVariable < Base
attr_accessor :key, :value
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-with-ci-variables'
resource.description = 'project for adding CI variable test'
end
end
def fabricate!
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_settings)
Page::Project::Settings::CICD.perform do |setting|
setting.expand_ci_variables do |page|
page.fill_variable(key, value)
page.save_variables
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class DeployKey < Base
attr_accessor :title, :key
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
end
end
end
attribute :project do
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.perform(&:click_repository_settings)
Page::Project::Settings::Repository.perform do |setting|
setting.expand_deploy_keys do |page|
page.fill_key_title(title)
page.fill_key_value(key)
page.add_key
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class DeployToken < Base
attr_accessor :name, :expires_at
attribute :username do
Page::Project::Settings::Repository.perform do |page|
page.expand_deploy_tokens do |token|
token.token_username
end
end
end
attribute :password do
Page::Project::Settings::Repository.perform do |page|
page.expand_deploy_tokens do |token|
token.token_password
end
end
end
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-to-deploy'
resource.description = 'project for adding deploy token test'
end
end
def fabricate!
project.visit!
Page::Project::Menu.act do
click_repository_settings
end
Page::Project::Settings::Repository.perform do |setting|
setting.expand_deploy_tokens do |page|
page.fill_token_name(name)
page.fill_token_expires_at(expires_at)
page.fill_scopes(read_repository: true, read_registry: false)
page.add_token
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class File < Base
attr_accessor :name,
:content,
:commit_message
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-with-new-file'
end
end
def initialize
@name = 'QA Test - File name'
@content = 'QA Test - File content'
@commit_message = 'QA Test - Commit message'
end
def fabricate!
project.visit!
Page::Project::Show.perform(&:create_new_file!)
Page::File::Form.perform do |page|
page.add_name(@name)
page.add_content(@content)
page.add_commit_message(@commit_message)
page.commit_changes
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class Fork < Base
attribute :push do
Repository::ProjectPush.fabricate!
end
attribute :user do
User.fabricate! do |resource|
if Runtime::Env.forker?
resource.username = Runtime::Env.forker_username
resource.password = Runtime::Env.forker_password
end
end
end
def fabricate!
populate(:push, :user)
# Sign out as admin and sign is as the fork user
Page::Main::Menu.perform(&:sign_out)
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(user)
end
push.project.visit!
Page::Project::Show.perform(&:fork_project)
Page::Project::Fork::New.perform do |fork_new|
fork_new.choose_namespace(user.name)
end
Page::Layout::Banner.perform do |page|
page.has_notice?('The project was successfully forked.')
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class Group < Base
attr_accessor :path, :description
attribute :sandbox do
Sandbox.fabricate!
end
attribute :id
def initialize
@path = Runtime::Namespace.name
@description = "QA test run at #{Runtime::Namespace.time}"
end
def fabricate!
sandbox.visit!
Page::Group::Show.perform do |group_show|
if group_show.has_subgroup?(path)
group_show.go_to_subgroup(path)
else
group_show.go_to_new_subgroup
Page::Group::New.perform do |group_new|
group_new.set_path(path)
group_new.set_description(description)
group_new.set_visibility('Public')
group_new.create
end
# Ensure that the group was actually created
group_show.wait(time: 1) do
group_show.has_text?(path) &&
group_show.has_new_project_or_subgroup_dropdown?
end
end
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
def api_post_path
'/groups'
end
def api_post_body
{
parent_id: sandbox.id,
path: path,
name: path,
visibility: 'public'
}
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class Issue < Base
attr_writer :description
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-for-issues'
resource.description = 'project for adding issues'
end
end
attribute :title
def fabricate!
project.visit!
Page::Project::Show.perform(&:go_to_new_issue)
Page::Project::Issue::New.perform do |page|
page.add_title(@title)
page.add_description(@description)
page.create_new_issue
end
end
end
end
end
# frozen_string_literal: true
require 'securerandom'
module QA
module Resource
class KubernetesCluster < Base
attr_writer :project, :cluster,
:install_helm_tiller, :install_ingress, :install_prometheus, :install_runner
attribute :ingress_ip do
Page::Project::Operations::Kubernetes::Show.perform(&:ingress_ip)
end
def fabricate!
@project.visit!
Page::Project::Menu.perform(
&:click_operations_kubernetes)
Page::Project::Operations::Kubernetes::Index.perform(
&:add_kubernetes_cluster)
Page::Project::Operations::Kubernetes::Add.perform(
&:add_existing_cluster)
Page::Project::Operations::Kubernetes::AddExisting.perform do |page|
page.set_cluster_name(@cluster.cluster_name)
page.set_api_url(@cluster.api_url)
page.set_ca_certificate(@cluster.ca_certificate)
page.set_token(@cluster.token)
page.check_rbac! if @cluster.rbac
page.add_cluster!
end
if @install_helm_tiller
Page::Project::Operations::Kubernetes::Show.perform do |page|
# We must wait a few seconds for permissions to be set up correctly for new cluster
sleep 10
# Helm must be installed before everything else
page.install!(:helm)
page.await_installed(:helm)
page.install!(:ingress) if @install_ingress
page.install!(:prometheus) if @install_prometheus
page.install!(:runner) if @install_runner
page.await_installed(:ingress) if @install_ingress
page.await_installed(:prometheus) if @install_prometheus
page.await_installed(:runner) if @install_runner
end
end
end
end
end
end
# frozen_string_literal: true
require 'securerandom'
module QA
module Resource
class Label < Base
attr_accessor :description, :color
attribute :title
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-with-label'
end
end
def initialize
@title = "qa-test-#{SecureRandom.hex(8)}"
@description = 'This is a test label'
@color = '#0033CC'
end
def fabricate!
project.visit!
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)
page.fill_description(@description)
page.fill_color(@color)
page.create_label
end
end
end
end
end
# frozen_string_literal: true
require 'securerandom'
module QA
module Resource
class MergeRequest < Base
attr_accessor :title,
:description,
:source_branch,
:target_branch,
:assignee,
:milestone,
:labels
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-with-merge-request'
end
end
attribute :target do
project.visit!
Repository::ProjectPush.fabricate! do |resource|
resource.project = project
resource.branch_name = 'master'
resource.remote_branch = target_branch
end
end
attribute :source do
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
@title = 'QA test - merge request'
@description = 'This is a test merge request'
@source_branch = "qa-test-feature-#{SecureRandom.hex(8)}"
@target_branch = "master"
@assignee = nil
@milestone = nil
@labels = []
end
def fabricate!
populate(:target, :source)
project.visit!
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform do |page|
page.fill_title(@title)
page.fill_description(@description)
page.choose_milestone(@milestone) if @milestone
labels.each do |label|
page.select_label(label)
end
page.create_merge_request
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class MergeRequestFromFork < MergeRequest
attr_accessor :fork_branch
attribute :fork do
Fork.fabricate!
end
attribute :push do
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!
populate(:push)
fork.visit!
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform(&:create_merge_request)
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
##
# Create a personal access token that can be used by the api
#
class PersonalAccessToken < Base
attr_accessor :name
attribute :access_token do
Page::Profile::PersonalAccessTokens.perform(&:created_access_token)
end
def fabricate!
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')
page.check_api
page.create_token
end
end
end
end
end
# frozen_string_literal: true
require 'securerandom'
module QA
module Resource
class Project < Base
attribute :name
attribute :description
attribute :group do
Group.fabricate!
end
attribute :repository_ssh_location do
Page::Project::Show.perform do |page|
page.choose_repository_clone_ssh
page.repository_location
end
end
attribute :repository_http_location do
Page::Project::Show.perform do |page|
page.choose_repository_clone_http
page.repository_location
end
end
def initialize
@description = 'My awesome project'
end
def name=(raw_name)
@name = "#{raw_name}-#{SecureRandom.hex(8)}"
end
def fabricate!
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |page|
page.choose_test_namespace
page.choose_name(@name)
page.add_description(@description)
page.set_visibility('Public')
page.create_new_project
end
end
def api_get_path
"/projects/#{name}"
end
def api_post_path
'/projects'
end
def api_post_body
{
namespace_id: group.id,
path: name,
name: name,
description: description,
visibility: 'public'
}
end
private
def transform_api_resource(api_resource)
api_resource[:repository_ssh_location] =
Git::Location.new(api_resource[:ssh_url_to_repo])
api_resource[:repository_http_location] =
Git::Location.new(api_resource[:http_url_to_repo])
api_resource
end
end
end
end
# frozen_string_literal: true
require 'securerandom'
module QA
module Resource
class ProjectImportedFromGithub < Project
attr_accessor :name
attr_writer :personal_access_token, :github_repository_path
attribute :group do
Group.fabricate!
end
def fabricate!
group.visit!
Page::Group::Show.perform(&:go_to_new_project)
Page::Project::New.perform do |page|
page.go_to_import_project
end
Page::Project::New.perform do |page|
page.go_to_github_import
end
Page::Project::Import::Github.perform do |page|
page.add_personal_access_token(@personal_access_token)
page.list_repos
page.import!(@github_repository_path, @name)
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class ProjectMilestone < Base
attr_reader :title
attr_accessor :description
attribute :project do
Project.fabricate!
end
def title=(title)
@title = "#{title}-#{SecureRandom.hex(4)}"
@description = 'A milestone'
end
def fabricate!
project.visit!
Page::Project::Menu.perform do |page|
page.click_issues
page.click_milestones
end
Page::Project::Milestone::Index.perform(&:click_new_milestone)
Page::Project::Milestone::New.perform do |milestone_new|
milestone_new.set_title(@title)
milestone_new.set_description(@description)
milestone_new.create_new_milestone
end
end
end
end
end
# frozen_string_literal: true
module QA module QA
module Factory module Resource
module Repository module Repository
class ProjectPush < Factory::Repository::Push class ProjectPush < Repository::Push
attribute :project do attribute :project do
Factory::Resource::Project.fabricate! do |resource| Project.fabricate! do |resource|
resource.name = 'project-with-code' resource.name = 'project-with-code'
resource.description = 'Project with repository' resource.description = 'Project with repository'
end end
......
# frozen_string_literal: true
require 'pathname' require 'pathname'
module QA module QA
module Factory module Resource
module Repository module Repository
class Push < Factory::Base class Push < Base
attr_accessor :file_name, :file_content, :commit_message, attr_accessor :file_name, :file_content, :commit_message,
:branch_name, :new_branch, :output, :repository_http_uri, :branch_name, :new_branch, :output, :repository_http_uri,
:repository_ssh_uri, :ssh_key, :user :repository_ssh_uri, :ssh_key, :user
......
# frozen_string_literal: true
module QA module QA
module Factory module Resource
module Repository module Repository
class WikiPush < Factory::Repository::Push class WikiPush < Repository::Push
attribute :wiki do attribute :wiki do
Factory::Resource::Wiki.fabricate! do |resource| Wiki.fabricate! do |resource|
resource.title = 'Home' resource.title = 'Home'
resource.content = '# My First Wiki Content' resource.content = '# My First Wiki Content'
resource.message = 'Update home' resource.message = 'Update home'
......
# frozen_string_literal: true
require 'securerandom'
module QA
module Resource
class Runner < Base
attr_writer :name, :tags, :image
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-with-ci-cd'
resource.description = 'Project with CI/CD Pipelines'
end
end
def name
@name || "qa-runner-#{SecureRandom.hex(4)}"
end
def tags
@tags || %w[qa e2e]
end
def image
@image || 'gitlab/gitlab-runner:alpine'
end
def fabricate!
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_settings)
Service::Runner.new(name).tap do |runner|
Page::Project::Settings::CICD.perform do |settings|
settings.expand_runners_settings do |runners|
runner.pull
runner.token = runners.registration_token
runner.address = runners.coordinator_address
runner.tags = tags
runner.image = image
runner.register!
end
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
##
# Ensure we're in our sandbox namespace, either by navigating to it or by
# creating it if it doesn't yet exist.
#
class Sandbox < Base
attr_reader :path
attribute :id
def initialize
@path = Runtime::Namespace.sandbox_name
end
def fabricate!
Page::Main::Menu.perform(&:go_to_groups)
Page::Dashboard::Groups.perform do |page|
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(path)
group.set_description('GitLab QA Sandbox Group')
group.set_visibility('Public')
group.create
end
end
end
end
def fabricate_via_api!
resource_web_url(api_get)
rescue ResourceNotFoundError
super
end
def api_get_path
"/groups/#{path}"
end
def api_post_path
'/groups'
end
def api_post_body
{
path: path,
name: path,
visibility: 'public'
}
end
end
end
end
# frozen_string_literal: true
module QA module QA
module Factory module Resource
module Settings module Settings
class HashedStorage < Factory::Base class HashedStorage < Base
def fabricate!(*traits) def fabricate!(*traits)
raise ArgumentError unless traits.include?(:enabled) raise ArgumentError unless traits.include?(:enabled)
......
# frozen_string_literal: true
module QA
module Resource
class SSHKey < Base
extend Forwardable
attr_accessor :title
def_delegators :key, :private_key, :public_key, :fingerprint
def key
@key ||= Runtime::Key::RSA.new
end
def fabricate!
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)
end
end
end
end
end
# frozen_string_literal: true
require 'securerandom'
module QA
module Resource
class User < Base
attr_reader :unique_id
attr_writer :username, :password
def initialize
@unique_id = SecureRandom.hex(8)
end
def username
@username ||= "qa-user-#{unique_id}"
end
def password
@password ||= 'password'
end
def name
@name ||= username
end
def email
@email ||= "#{username}@example.com"
end
def credentials_given?
defined?(@username) && defined?(@password)
end
def fabricate!
# Don't try to log-out if we're not logged-in
if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
Page::Main::Menu.perform { |main| main.sign_out }
end
if credentials_given?
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(self)
end
else
Page::Main::Login.perform do |login|
login.switch_to_register_tab
end
Page::Main::SignUp.perform do |signup|
signup.sign_up!(self)
end
end
end
def fabricate_via_api!
resource_web_url(api_get)
rescue ResourceNotFoundError
super
end
def api_get_path
"/users/#{fetch_id(username)}"
end
def api_post_path
'/users'
end
def api_post_body
{
email: email,
password: password,
username: username,
name: name,
skip_confirmation: true
}
end
private
def fetch_id(username)
users = parse_body(api_get_from("/users?username=#{username}"))
unless users.size == 1 && users.first[:username] == username
raise ResourceNotFoundError, "Expected one user with username #{username} but found: `#{users}`."
end
users.first[:id]
end
end
end
end
# frozen_string_literal: true
module QA
module Resource
class Wiki < Base
attr_accessor :title, :content, :message
attribute :project do
Project.fabricate! do |resource|
resource.name = 'project-for-wikis'
resource.description = 'project for adding wikis'
end
end
def fabricate!
project.visit!
Page::Project::Menu.perform { |menu_side| menu_side.click_wiki }
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
end
end
...@@ -32,7 +32,7 @@ module QA ...@@ -32,7 +32,7 @@ module QA
def do_create_personal_access_token def do_create_personal_access_token
Page::Main::Login.act { sign_in_using_credentials } Page::Main::Login.act { sign_in_using_credentials }
Factory::Resource::PersonalAccessToken.fabricate!.access_token Resource::PersonalAccessToken.fabricate!.access_token
end end
end end
end end
......
...@@ -5,7 +5,7 @@ module QA ...@@ -5,7 +5,7 @@ module QA
it 'user registers and logs in' do it 'user registers and logs in' do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Factory::Resource::User.fabricate_via_browser_ui! Resource::User.fabricate!
# TODO, since `Signed in successfully` message was removed # TODO, since `Signed in successfully` message was removed
# this is the only way to tell if user is signed in correctly. # this is the only way to tell if user is signed in correctly.
......
...@@ -7,9 +7,9 @@ module QA ...@@ -7,9 +7,9 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials) Page::Main::Login.perform(&:sign_in_using_credentials)
user = Factory::Resource::User.fabricate! user = Resource::User.fabricate!
project = Factory::Resource::Project.fabricate! do |resource| project = Resource::Project.fabricate! do |resource|
resource.name = 'add-member-project' resource.name = 'add-member-project'
end end
project.visit! project.visit!
......
...@@ -7,7 +7,7 @@ module QA ...@@ -7,7 +7,7 @@ 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 }
created_project = Factory::Resource::Project.fabricate_via_browser_ui! do |project| created_project = Resource::Project.fabricate_via_browser_ui! do |project|
project.name = 'awesome-project' project.name = 'awesome-project'
project.description = 'create awesome project test' project.description = 'create awesome project test'
end end
......
...@@ -4,7 +4,7 @@ module QA ...@@ -4,7 +4,7 @@ module QA
context 'Manage', :orchestrated, :github do context 'Manage', :orchestrated, :github do
describe 'Project import from GitHub' do describe 'Project import from GitHub' do
let(:imported_project) do let(:imported_project) do
Factory::Resource::ProjectImportedFromGithub.fabricate! do |project| Resource::ProjectImportedFromGithub.fabricate! do |project|
project.name = 'imported-project' project.name = 'imported-project'
project.personal_access_token = Runtime::Env.github_access_token project.personal_access_token = Runtime::Env.github_access_token
project.github_repository_path = 'gitlab-qa/test-project' project.github_repository_path = 'gitlab-qa/test-project'
......
...@@ -7,7 +7,7 @@ module QA ...@@ -7,7 +7,7 @@ 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::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.file_name = 'README.md' push.file_name = 'README.md'
push.file_content = '# This is a test project' push.file_content = '# This is a test project'
push.commit_message = 'Add README.md' push.commit_message = 'Add README.md'
......
...@@ -9,7 +9,7 @@ module QA ...@@ -9,7 +9,7 @@ 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::Issue.fabricate! do |issue| Resource::Issue.fabricate! do |issue|
issue.title = issue_title issue.title = issue_title
end end
end end
......
...@@ -9,7 +9,7 @@ module QA ...@@ -9,7 +9,7 @@ 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::Issue.fabricate! do |issue| Resource::Issue.fabricate! do |issue|
issue.title = issue_title issue.title = issue_title
end end
......
...@@ -7,22 +7,22 @@ module QA ...@@ -7,22 +7,22 @@ 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 }
current_project = Factory::Resource::Project.fabricate! do |project| current_project = Resource::Project.fabricate! do |project|
project.name = 'project-with-merge-request-and-milestone' project.name = 'project-with-merge-request-and-milestone'
end end
current_milestone = Factory::Resource::ProjectMilestone.fabricate! do |milestone| current_milestone = Resource::ProjectMilestone.fabricate! do |milestone|
milestone.title = 'unique-milestone' milestone.title = 'unique-milestone'
milestone.project = current_project milestone.project = current_project
end end
new_label = Factory::Resource::Label.fabricate! do |label| new_label = Resource::Label.fabricate! do |label|
label.project = current_project label.project = current_project
label.title = 'qa-mr-test-label' label.title = 'qa-mr-test-label'
label.description = 'Merge Request label' label.description = 'Merge Request label'
end end
Factory::Resource::MergeRequest.fabricate! do |merge_request| Resource::MergeRequest.fabricate! do |merge_request|
merge_request.title = 'This is a merge request with a milestone' merge_request.title = 'This is a merge request with a milestone'
merge_request.description = 'Great feature with milestone' merge_request.description = 'Great feature with milestone'
merge_request.project = current_project merge_request.project = current_project
...@@ -49,11 +49,11 @@ module QA ...@@ -49,11 +49,11 @@ 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 }
current_project = Factory::Resource::Project.fabricate! do |project| current_project = Resource::Project.fabricate! do |project|
project.name = 'project-with-merge-request' project.name = 'project-with-merge-request'
end end
Factory::Resource::MergeRequest.fabricate! do |merge_request| Resource::MergeRequest.fabricate! do |merge_request|
merge_request.title = 'This is a merge request' merge_request.title = 'This is a merge request'
merge_request.description = 'Great feature' merge_request.description = 'Great feature'
merge_request.project = current_project merge_request.project = current_project
......
...@@ -7,7 +7,7 @@ module QA ...@@ -7,7 +7,7 @@ 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 }
merge_request = Factory::Resource::MergeRequestFromFork.fabricate! do |merge_request| merge_request = Resource::MergeRequestFromFork.fabricate! do |merge_request|
merge_request.fork_branch = 'feature-branch' merge_request.fork_branch = 'feature-branch'
end end
......
...@@ -7,7 +7,7 @@ module QA ...@@ -7,7 +7,7 @@ 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 }
project = Factory::Resource::Project.fabricate! do |project| project = Resource::Project.fabricate! do |project|
project.name = "only-fast-forward" project.name = "only-fast-forward"
end end
project.visit! project.visit!
...@@ -15,12 +15,12 @@ module QA ...@@ -15,12 +15,12 @@ module QA
Page::Project::Menu.act { go_to_settings } Page::Project::Menu.act { go_to_settings }
Page::Project::Settings::MergeRequest.act { enable_ff_only } Page::Project::Settings::MergeRequest.act { enable_ff_only }
merge_request = Factory::Resource::MergeRequest.fabricate! do |merge_request| merge_request = Resource::MergeRequest.fabricate! do |merge_request|
merge_request.project = project merge_request.project = project
merge_request.title = 'Needs rebasing' merge_request.title = 'Needs rebasing'
end end
Factory::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project push.project = project
push.file_name = "other.txt" push.file_name = "other.txt"
push.file_content = "New file added!" push.file_content = "New file added!"
......
...@@ -7,16 +7,16 @@ module QA ...@@ -7,16 +7,16 @@ 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 }
project = Factory::Resource::Project.fabricate! do |project| project = Resource::Project.fabricate! do |project|
project.name = "squash-before-merge" project.name = "squash-before-merge"
end end
merge_request = Factory::Resource::MergeRequest.fabricate! do |merge_request| merge_request = Resource::MergeRequest.fabricate! do |merge_request|
merge_request.project = project merge_request.project = project
merge_request.title = 'Squashing commits' merge_request.title = 'Squashing commits'
end end
Factory::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project push.project = project
push.commit_message = 'to be squashed' push.commit_message = 'to be squashed'
push.branch_name = merge_request.source_branch push.branch_name = merge_request.source_branch
......
...@@ -13,7 +13,7 @@ module QA ...@@ -13,7 +13,7 @@ module QA
before(:all) do before(:all) do
login login
@project = Factory::Resource::Project.fabricate! do |project| @project = Resource::Project.fabricate! do |project|
project.name = 'file-template-project' project.name = 'file-template-project'
project.description = 'Add file templates via the Files view' project.description = 'Add file templates via the Files view'
end end
......
...@@ -9,7 +9,7 @@ module QA ...@@ -9,7 +9,7 @@ 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 }
key = Factory::Resource::SSHKey.fabricate! do |resource| key = Resource::SSHKey.fabricate! do |resource|
resource.title = key_title resource.title = key_title
end end
......
...@@ -14,7 +14,7 @@ module QA ...@@ -14,7 +14,7 @@ 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 }
project = Factory::Resource::Project.fabricate! do |scenario| project = Resource::Project.fabricate! do |scenario|
scenario.name = 'project-with-code' scenario.name = 'project-with-code'
scenario.description = 'project for git clone tests' scenario.description = 'project for git clone tests'
end end
......
...@@ -12,7 +12,7 @@ module QA ...@@ -12,7 +12,7 @@ module QA
file_content = 'QA Test - File content' file_content = 'QA Test - File content'
commit_message_for_create = 'QA Test - Create new file' commit_message_for_create = 'QA Test - Create new file'
Factory::Resource::File.fabricate! do |file| Resource::File.fabricate! do |file|
file.name = file_name file.name = file_name
file.content = file_content file.content = file_content
file.commit_message = commit_message_for_create file.commit_message = commit_message_for_create
......
...@@ -7,14 +7,14 @@ module QA ...@@ -7,14 +7,14 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials) Page::Main::Login.perform(&:sign_in_using_credentials)
access_token = Factory::Resource::PersonalAccessToken.fabricate!.access_token access_token = Resource::PersonalAccessToken.fabricate!.access_token
user = Factory::Resource::User.new.tap do |user| user = Resource::User.new.tap do |user|
user.username = Runtime::User.username user.username = Runtime::User.username
user.password = access_token user.password = access_token
end end
push = Factory::Repository::ProjectPush.fabricate! do |push| push = Resource::Repository::ProjectPush.fabricate! do |push|
push.user = user push.user = user
push.file_name = 'README.md' push.file_name = 'README.md'
push.file_content = '# This is a test project' push.file_content = '# This is a test project'
......
...@@ -7,7 +7,7 @@ module QA ...@@ -7,7 +7,7 @@ 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::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.file_name = 'README.md' push.file_name = 'README.md'
push.file_content = '# This is a test project' push.file_content = '# This is a test project'
push.commit_message = 'Add README.md' push.commit_message = 'Add README.md'
......
...@@ -6,7 +6,7 @@ module QA ...@@ -6,7 +6,7 @@ module QA
let(:branch_name) { 'protected-branch' } let(:branch_name) { 'protected-branch' }
let(:commit_message) { 'Protected push commit message' } let(:commit_message) { 'Protected push commit message' }
let(:project) do let(:project) do
Factory::Resource::Project.fabricate! do |resource| Resource::Project.fabricate! do |resource|
resource.name = 'protected-branch-project' resource.name = 'protected-branch-project'
end end
end end
...@@ -47,7 +47,7 @@ module QA ...@@ -47,7 +47,7 @@ module QA
end end
def create_protected_branch(allow_to_push:) def create_protected_branch(allow_to_push:)
Factory::Resource::Branch.fabricate! do |resource| Resource::Branch.fabricate! do |resource|
resource.branch_name = branch_name resource.branch_name = branch_name
resource.project = project resource.project = project
resource.allow_to_push = allow_to_push resource.allow_to_push = allow_to_push
...@@ -56,7 +56,7 @@ module QA ...@@ -56,7 +56,7 @@ module QA
end end
def push_new_file(branch) def push_new_file(branch)
Factory::Repository::ProjectPush.fabricate! do |resource| Resource::Repository::ProjectPush.fabricate! do |resource|
resource.project = project resource.project = project
resource.file_name = 'new_file.md' resource.file_name = 'new_file.md'
resource.file_content = '# This is a new file' resource.file_content = '# This is a new file'
......
...@@ -12,11 +12,11 @@ module QA ...@@ -12,11 +12,11 @@ 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 }
key = Factory::Resource::SSHKey.fabricate! do |resource| key = Resource::SSHKey.fabricate! do |resource|
resource.title = key_title resource.title = key_title
end end
Factory::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.ssh_key = key push.ssh_key = key
push.file_name = 'README.md' push.file_name = 'README.md'
push.file_content = '# Test Use SSH Key' push.file_content = '# Test Use SSH Key'
......
...@@ -13,7 +13,7 @@ module QA ...@@ -13,7 +13,7 @@ module QA
before(:all) do before(:all) do
login login
@project = Factory::Resource::Project.fabricate! do |project| @project = Resource::Project.fabricate! do |project|
project.name = 'file-template-project' project.name = 'file-template-project'
project.description = 'Add file templates via the Web IDE' project.description = 'Add file templates via the Web IDE'
end end
......
...@@ -18,7 +18,7 @@ module QA ...@@ -18,7 +18,7 @@ module QA
end end
it 'user creates, edits, clones, and pushes to the wiki' do it 'user creates, edits, clones, and pushes to the wiki' do
wiki = Factory::Resource::Wiki.fabricate! do |resource| wiki = Resource::Wiki.fabricate! do |resource|
resource.title = 'Home' resource.title = 'Home'
resource.content = '# My First Wiki Content' resource.content = '# My First Wiki Content'
resource.message = 'Update home' resource.message = 'Update home'
...@@ -34,7 +34,7 @@ module QA ...@@ -34,7 +34,7 @@ module QA
validate_content('My Second Wiki Content') validate_content('My Second Wiki Content')
Factory::Repository::WikiPush.fabricate! do |push| Resource::Repository::WikiPush.fabricate! do |push|
push.wiki = wiki push.wiki = wiki
push.file_name = 'Home.md' push.file_name = 'Home.md'
push.file_content = '# My Third Wiki Content' push.file_content = '# My Third Wiki Content'
......
...@@ -7,7 +7,7 @@ module QA ...@@ -7,7 +7,7 @@ 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::CiVariable.fabricate! do |resource| Resource::CiVariable.fabricate! do |resource|
resource.key = 'VARIABLE_KEY' resource.key = 'VARIABLE_KEY'
resource.value = 'some CI variable' resource.value = 'some CI variable'
end end
......
...@@ -13,18 +13,18 @@ module QA ...@@ -13,18 +13,18 @@ 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 }
project = Factory::Resource::Project.fabricate! do |project| project = Resource::Project.fabricate! do |project|
project.name = 'project-with-pipelines' project.name = 'project-with-pipelines'
project.description = 'Project with CI/CD Pipelines.' project.description = 'Project with CI/CD Pipelines.'
end end
Factory::Resource::Runner.fabricate! do |runner| Resource::Runner.fabricate! do |runner|
runner.project = project runner.project = project
runner.name = executor runner.name = executor
runner.tags = %w[qa test] runner.tags = %w[qa test]
end end
Factory::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project push.project = project
push.file_name = '.gitlab-ci.yml' push.file_name = '.gitlab-ci.yml'
push.commit_message = 'Add .gitlab-ci.yml' push.commit_message = 'Add .gitlab-ci.yml'
......
...@@ -13,7 +13,7 @@ module QA ...@@ -13,7 +13,7 @@ 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::Runner.fabricate! do |runner| Resource::Runner.fabricate! do |runner|
runner.name = executor runner.name = executor
end end
......
...@@ -11,7 +11,7 @@ module QA ...@@ -11,7 +11,7 @@ module QA
deploy_key_title = 'deploy key title' deploy_key_title = 'deploy key title'
deploy_key_value = key.public_key deploy_key_value = key.public_key
deploy_key = Factory::Resource::DeployKey.fabricate! do |resource| deploy_key = Resource::DeployKey.fabricate! do |resource|
resource.title = deploy_key_title resource.title = deploy_key_title
resource.key = deploy_key_value resource.key = deploy_key_value
end end
......
...@@ -15,13 +15,13 @@ module QA ...@@ -15,13 +15,13 @@ module QA
@runner_name = "qa-runner-#{Time.now.to_i}" @runner_name = "qa-runner-#{Time.now.to_i}"
@project = Factory::Resource::Project.fabricate! do |resource| @project = Resource::Project.fabricate! do |resource|
resource.name = 'deploy-key-clone-project' resource.name = 'deploy-key-clone-project'
end end
@repository_location = @project.repository_ssh_location @repository_location = @project.repository_ssh_location
Factory::Resource::Runner.fabricate! do |resource| Resource::Runner.fabricate! do |resource|
resource.project = @project resource.project = @project
resource.name = @runner_name resource.name = @runner_name
resource.tags = %w[qa docker] resource.tags = %w[qa docker]
...@@ -47,7 +47,7 @@ module QA ...@@ -47,7 +47,7 @@ module QA
login login
Factory::Resource::DeployKey.fabricate! do |resource| Resource::DeployKey.fabricate! do |resource|
resource.project = @project resource.project = @project
resource.title = "deploy key #{key.name}(#{key.bits})" resource.title = "deploy key #{key.name}(#{key.bits})"
resource.key = key.public_key resource.key = key.public_key
...@@ -55,7 +55,7 @@ module QA ...@@ -55,7 +55,7 @@ module QA
deploy_key_name = "DEPLOY_KEY_#{key.name}_#{key.bits}" deploy_key_name = "DEPLOY_KEY_#{key.name}_#{key.bits}"
Factory::Resource::CiVariable.fabricate! do |resource| Resource::CiVariable.fabricate! do |resource|
resource.project = @project resource.project = @project
resource.key = deploy_key_name resource.key = deploy_key_name
resource.value = key.private_key resource.value = key.private_key
...@@ -78,7 +78,7 @@ module QA ...@@ -78,7 +78,7 @@ module QA
- docker - docker
YAML YAML
Factory::Repository::ProjectPush.fabricate! do |resource| Resource::Repository::ProjectPush.fabricate! do |resource|
resource.project = @project resource.project = @project
resource.file_name = '.gitlab-ci.yml' resource.file_name = '.gitlab-ci.yml'
resource.commit_message = 'Add .gitlab-ci.yml' resource.commit_message = 'Add .gitlab-ci.yml'
......
...@@ -10,7 +10,7 @@ module QA ...@@ -10,7 +10,7 @@ module QA
deploy_token_name = 'deploy token name' deploy_token_name = 'deploy token name'
deploy_token_expires_at = Date.today + 7 # 1 Week from now deploy_token_expires_at = Date.today + 7 # 1 Week from now
deploy_token = Factory::Resource::DeployToken.fabricate! do |resource| deploy_token = Resource::DeployToken.fabricate! do |resource|
resource.name = deploy_token_name resource.name = deploy_token_name
resource.expires_at = deploy_token_expires_at resource.expires_at = deploy_token_expires_at
end end
......
...@@ -15,21 +15,21 @@ module QA ...@@ -15,21 +15,21 @@ 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 }
project = Factory::Resource::Project.fabricate! do |p| project = Resource::Project.fabricate! do |p|
p.name = 'project-with-autodevops' p.name = 'project-with-autodevops'
p.description = 'Project with Auto Devops' p.description = 'Project with Auto Devops'
end end
# Disable code_quality check in Auto DevOps pipeline as it takes # Disable code_quality check in Auto DevOps pipeline as it takes
# too long and times out the test # too long and times out the test
Factory::Resource::CiVariable.fabricate! do |resource| Resource::CiVariable.fabricate! do |resource|
resource.project = project resource.project = project
resource.key = 'CODE_QUALITY_DISABLED' resource.key = 'CODE_QUALITY_DISABLED'
resource.value = '1' resource.value = '1'
end end
# Create Auto Devops compatible repo # Create Auto Devops compatible repo
Factory::Repository::ProjectPush.fabricate! do |push| Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project push.project = project
push.directory = Pathname push.directory = Pathname
.new(__dir__) .new(__dir__)
...@@ -41,7 +41,7 @@ module QA ...@@ -41,7 +41,7 @@ module QA
# Create and connect K8s cluster # Create and connect K8s cluster
@cluster = Service::KubernetesCluster.new(rbac: rbac).create! @cluster = Service::KubernetesCluster.new(rbac: rbac).create!
kubernetes_cluster = Factory::Resource::KubernetesCluster.fabricate! do |cluster| kubernetes_cluster = Resource::KubernetesCluster.fabricate! do |cluster|
cluster.project = project cluster.project = project
cluster.cluster = @cluster cluster.cluster = @cluster
cluster.install_helm_tiller = true cluster.install_helm_tiller = true
......
# frozen_string_literal: true # frozen_string_literal: true
describe QA::Factory::Resource::User do describe QA::Resource::User do
describe "#fabricate_via_api!" do describe "#fabricate_via_api!" do
Response = Struct.new(:code, :body) Response = Struct.new(:code, :body)
......
# frozen_string_literal: true # frozen_string_literal: true
describe QA::Factory::ApiFabricator do describe QA::Resource::ApiFabricator do
let(:factory_without_api_support) do let(:resource_without_api_support) do
Class.new do Class.new do
def self.name def self.name
'FooBarFactory' 'FooBarResource'
end end
end end
end end
let(:factory_with_api_support) do let(:resource_with_api_support) do
Class.new do Class.new do
def self.name def self.name
'FooBarFactory' 'FooBarResource'
end end
def api_get_path def api_get_path
...@@ -33,22 +33,22 @@ describe QA::Factory::ApiFabricator do ...@@ -33,22 +33,22 @@ describe QA::Factory::ApiFabricator do
allow(subject).to receive(:current_url).and_return('') allow(subject).to receive(:current_url).and_return('')
end end
subject { factory.tap { |f| f.include(described_class) }.new } subject { resource.tap { |f| f.include(described_class) }.new }
describe '#api_support?' do describe '#api_support?' do
let(:api_client) { spy('Runtime::API::Client') } let(:api_client) { spy('Runtime::API::Client') }
let(:api_client_instance) { double('API Client') } let(:api_client_instance) { double('API Client') }
context 'when factory does not support fabrication via the API' do context 'when resource does not support fabrication via the API' do
let(:factory) { factory_without_api_support } let(:resource) { resource_without_api_support }
it 'returns false' do it 'returns false' do
expect(subject).not_to be_api_support expect(subject).not_to be_api_support
end end
end end
context 'when factory supports fabrication via the API' do context 'when resource supports fabrication via the API' do
let(:factory) { factory_with_api_support } let(:resource) { resource_with_api_support }
it 'returns false' do it 'returns false' do
expect(subject).to be_api_support expect(subject).to be_api_support
...@@ -67,20 +67,20 @@ describe QA::Factory::ApiFabricator do ...@@ -67,20 +67,20 @@ describe QA::Factory::ApiFabricator do
allow(api_client_instance).to receive(:personal_access_token).and_return('foo') allow(api_client_instance).to receive(:personal_access_token).and_return('foo')
end end
context 'when factory does not support fabrication via the API' do context 'when resource does not support fabrication via the API' do
let(:factory) { factory_without_api_support } let(:resource) { resource_without_api_support }
it 'raises a NotImplementedError exception' do it 'raises a NotImplementedError exception' do
expect { subject.fabricate_via_api! }.to raise_error(NotImplementedError, "Factory FooBarFactory does not support fabrication via the API!") expect { subject.fabricate_via_api! }.to raise_error(NotImplementedError, "Resource FooBarResource does not support fabrication via the API!")
end end
end end
context 'when factory supports fabrication via the API' do context 'when resource supports fabrication via the API' do
let(:factory) { factory_with_api_support } let(:resource) { resource_with_api_support }
let(:api_request) { spy('Runtime::API::Request') } let(:api_request) { spy('Runtime::API::Request') }
let(:resource_web_url) { 'http://example.org/api/v4/foo' } let(:resource_web_url) { 'http://example.org/api/v4/foo' }
let(:resource) { { id: 1, name: 'John Doe', web_url: resource_web_url } } let(:response) { { id: 1, name: 'John Doe', web_url: resource_web_url } }
let(:raw_post) { double('Raw POST response', code: 201, body: resource.to_json) } let(:raw_post) { double('Raw POST response', code: 201, body: response.to_json) }
before do before do
stub_const('QA::Runtime::API::Request', api_request) stub_const('QA::Runtime::API::Request', api_request)
...@@ -103,7 +103,7 @@ describe QA::Factory::ApiFabricator do ...@@ -103,7 +103,7 @@ describe QA::Factory::ApiFabricator do
it 'populates api_resource with the resource' do it 'populates api_resource with the resource' do
subject.fabricate_via_api! subject.fabricate_via_api!
expect(subject.api_resource).to eq(resource) expect(subject.api_resource).to eq(response)
end end
context 'when the POST fails' do context 'when the POST fails' do
...@@ -114,17 +114,17 @@ describe QA::Factory::ApiFabricator do ...@@ -114,17 +114,17 @@ describe QA::Factory::ApiFabricator do
expect(api_request).to receive(:new).with(api_client_instance, subject.api_post_path).and_return(double(url: resource_web_url)) 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).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 `#{raw_post}`.") expect { subject.fabricate_via_api! }.to raise_error(described_class::ResourceFabricationFailedError, "Fabrication of FooBarResource using the API failed (400) with `#{raw_post}`.")
expect(subject.api_resource).to be_nil expect(subject.api_resource).to be_nil
end end
end end
end end
context '#transform_api_resource' do context '#transform_api_resource' do
let(:factory) do let(:resource) do
Class.new do Class.new do
def self.name def self.name
'FooBarFactory' 'FooBarResource'
end end
def api_get_path def api_get_path
...@@ -146,12 +146,12 @@ describe QA::Factory::ApiFabricator do ...@@ -146,12 +146,12 @@ describe QA::Factory::ApiFabricator do
end end
end end
let(:resource) { { existing: 'foo', web_url: resource_web_url } } let(:response) { { existing: 'foo', web_url: resource_web_url } }
let(:transformed_resource) { { existing: 'foo', new: 'foobar', web_url: resource_web_url } } let(:transformed_resource) { { existing: 'foo', new: 'foobar', web_url: resource_web_url } }
it 'transforms the resource' do 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(: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) expect(subject).to receive(:transform_api_resource).with(response).and_return(transformed_resource)
subject.fabricate_via_api! subject.fabricate_via_api!
end end
......
# frozen_string_literal: true # frozen_string_literal: true
describe QA::Factory::Base do describe QA::Resource::Base do
include Support::StubENV include Support::StubENV
let(:factory) { spy('factory') } let(:resource) { spy('resource') }
let(:location) { 'http://location' } let(:location) { 'http://location' }
shared_context 'fabrication context' do shared_context 'fabrication context' do
subject do subject do
Class.new(described_class) do Class.new(described_class) do
def self.name def self.name
'MyFactory' 'MyResource'
end end
end end
end end
before do before do
allow(subject).to receive(:current_url).and_return(location) allow(subject).to receive(:current_url).and_return(location)
allow(subject).to receive(:new).and_return(factory) allow(subject).to receive(:new).and_return(resource)
end end
end end
shared_examples '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 } let(:fabrication_method_used) { actual_fabrication_method || fabrication_method_called }
it 'yields factory before calling factory method' do it 'yields resource before calling resource method' do
expect(factory).to receive(:something!).ordered expect(resource).to receive(:something!).ordered
expect(factory).to receive(fabrication_method_used).ordered.and_return(location) expect(resource).to receive(fabrication_method_used).ordered.and_return(location)
subject.public_send(fabrication_method_called, factory: factory) do |factory| subject.public_send(fabrication_method_called, resource: resource) do |resource|
factory.something! resource.something!
end end
end end
it 'does not log the factory and build method when QA_DEBUG=false' do it 'does not log the resource and build method when QA_DEBUG=false' do
stub_env('QA_DEBUG', 'false') stub_env('QA_DEBUG', 'false')
expect(factory).to receive(fabrication_method_used).and_return(location) expect(resource).to receive(fabrication_method_used).and_return(location)
expect { subject.public_send(fabrication_method_called, 'something', factory: factory) } expect { subject.public_send(fabrication_method_called, 'something', resource: resource) }
.not_to output.to_stdout .not_to output.to_stdout
end end
end end
describe '.fabricate!' do describe '.fabricate!' do
context 'when factory does not support fabrication via the API' do context 'when resource does not support fabrication via the API' do
before do before do
expect(described_class).to receive(:fabricate_via_api!).and_raise(NotImplementedError) expect(described_class).to receive(:fabricate_via_api!).and_raise(NotImplementedError)
end end
...@@ -55,7 +55,7 @@ describe QA::Factory::Base do ...@@ -55,7 +55,7 @@ describe QA::Factory::Base do
end end
end end
context 'when factory supports fabrication via the API' do context 'when resource supports fabrication via the API' do
it 'calls .fabricate_via_browser_ui!' do it 'calls .fabricate_via_browser_ui!' do
expect(described_class).to receive(:fabricate_via_api!) expect(described_class).to receive(:fabricate_via_api!)
...@@ -69,20 +69,20 @@ describe QA::Factory::Base do ...@@ -69,20 +69,20 @@ describe QA::Factory::Base do
it_behaves_like 'fabrication method', :fabricate_via_api! it_behaves_like 'fabrication method', :fabricate_via_api!
it 'instantiates the factory, calls factory method returns the resource' do it 'instantiates the resource, calls resource method returns the resource' do
expect(factory).to receive(:fabricate_via_api!).and_return(location) expect(resource).to receive(:fabricate_via_api!).and_return(location)
result = subject.fabricate_via_api!(factory: factory, parents: []) result = subject.fabricate_via_api!(resource: resource, parents: [])
expect(result).to eq(factory) expect(result).to eq(resource)
end end
it 'logs the factory and build method when QA_DEBUG=true' do it 'logs the resource and build method when QA_DEBUG=true' do
stub_env('QA_DEBUG', 'true') stub_env('QA_DEBUG', 'true')
expect(factory).to receive(:fabricate_via_api!).and_return(location) expect(resource).to receive(:fabricate_via_api!).and_return(location)
expect { subject.fabricate_via_api!('something', factory: factory, parents: []) } expect { subject.fabricate_via_api!('something', resource: resource, parents: []) }
.to output(/==> Built a MyFactory via api in [\d\.\-e]+ seconds+/) .to output(/==> Built a MyResource via api in [\d\.\-e]+ seconds+/)
.to_stdout .to_stdout
end end
end end
...@@ -92,30 +92,30 @@ describe QA::Factory::Base do ...@@ -92,30 +92,30 @@ describe QA::Factory::Base do
it_behaves_like 'fabrication method', :fabricate_via_browser_ui!, :fabricate! it_behaves_like 'fabrication method', :fabricate_via_browser_ui!, :fabricate!
it 'instantiates the factory and calls factory method' do it 'instantiates the resource and calls resource method' do
subject.fabricate_via_browser_ui!('something', factory: factory, parents: []) subject.fabricate_via_browser_ui!('something', resource: resource, parents: [])
expect(factory).to have_received(:fabricate!).with('something') expect(resource).to have_received(:fabricate!).with('something')
end end
it 'returns fabrication resource' do it 'returns fabrication resource' do
result = subject.fabricate_via_browser_ui!('something', factory: factory, parents: []) result = subject.fabricate_via_browser_ui!('something', resource: resource, parents: [])
expect(result).to eq(factory) expect(result).to eq(resource)
end end
it 'logs the factory and build method when QA_DEBUG=true' do it 'logs the resource and build method when QA_DEBUG=true' do
stub_env('QA_DEBUG', 'true') stub_env('QA_DEBUG', 'true')
expect { subject.fabricate_via_browser_ui!('something', factory: factory, parents: []) } expect { subject.fabricate_via_browser_ui!('something', resource: resource, parents: []) }
.to output(/==> Built a MyFactory via browser_ui in [\d\.\-e]+ seconds+/) .to output(/==> Built a MyResource via browser_ui in [\d\.\-e]+ seconds+/)
.to_stdout .to_stdout
end end
end end
shared_context 'simple factory' do shared_context 'simple resource' do
subject do subject do
Class.new(QA::Factory::Base) do Class.new(QA::Resource::Base) do
attribute :test do attribute :test do
'block' 'block'
end end
...@@ -132,11 +132,11 @@ describe QA::Factory::Base do ...@@ -132,11 +132,11 @@ describe QA::Factory::Base do
end end
end end
let(:factory) { subject.new } let(:resource) { subject.new }
end end
describe '.attribute' do describe '.attribute' do
include_context 'simple factory' include_context 'simple resource'
it 'appends new attribute' do it 'appends new attribute' do
expect(subject.attributes_names).to eq([:no_block, :test, :web_url]) expect(subject.attributes_names).to eq([:no_block, :test, :web_url])
...@@ -144,7 +144,7 @@ describe QA::Factory::Base do ...@@ -144,7 +144,7 @@ describe QA::Factory::Base do
context 'when the attribute is populated via a block' do context 'when the attribute is populated via a block' do
it 'returns value from the block' do it 'returns value from the block' do
result = subject.fabricate!(factory: factory) result = subject.fabricate!(resource: resource)
expect(result).to be_a(described_class) expect(result).to be_a(described_class)
expect(result.test).to eq('block') expect(result.test).to eq('block')
...@@ -155,11 +155,11 @@ describe QA::Factory::Base do ...@@ -155,11 +155,11 @@ describe QA::Factory::Base do
let(:api_resource) { { no_block: 'api' } } let(:api_resource) { { no_block: 'api' } }
before do before do
expect(factory).to receive(:api_resource).and_return(api_resource) expect(resource).to receive(:api_resource).and_return(api_resource)
end end
it 'returns value from api' do it 'returns value from api' do
result = subject.fabricate!(factory: factory) result = subject.fabricate!(resource: resource)
expect(result).to be_a(described_class) expect(result).to be_a(described_class)
expect(result.no_block).to eq('api') expect(result.no_block).to eq('api')
...@@ -173,7 +173,7 @@ describe QA::Factory::Base do ...@@ -173,7 +173,7 @@ describe QA::Factory::Base do
end end
it 'returns value from api and emits an INFO log entry' do it 'returns value from api and emits an INFO log entry' do
result = subject.fabricate!(factory: factory) result = subject.fabricate!(resource: resource)
expect(result).to be_a(described_class) expect(result).to be_a(described_class)
expect(result.test).to eq('api_with_block') expect(result.test).to eq('api_with_block')
...@@ -185,11 +185,11 @@ describe QA::Factory::Base do ...@@ -185,11 +185,11 @@ describe QA::Factory::Base do
context 'when the attribute is populated via direct assignment' do context 'when the attribute is populated via direct assignment' do
before do before do
factory.test = 'value' resource.test = 'value'
end end
it 'returns value from the assignment' do it 'returns value from the assignment' do
result = subject.fabricate!(factory: factory) result = subject.fabricate!(resource: resource)
expect(result).to be_a(described_class) expect(result).to be_a(described_class)
expect(result.test).to eq('value') expect(result.test).to eq('value')
...@@ -197,11 +197,11 @@ describe QA::Factory::Base do ...@@ -197,11 +197,11 @@ describe QA::Factory::Base do
context 'when the api also has such response' do context 'when the api also has such response' do
before do before do
allow(factory).to receive(:api_resource).and_return({ test: 'api' }) allow(resource).to receive(:api_resource).and_return({ test: 'api' })
end end
it 'returns value from the assignment' do it 'returns value from the assignment' do
result = subject.fabricate!(factory: factory) result = subject.fabricate!(resource: resource)
expect(result).to be_a(described_class) expect(result).to be_a(described_class)
expect(result.test).to eq('value') expect(result.test).to eq('value')
...@@ -211,36 +211,36 @@ describe QA::Factory::Base do ...@@ -211,36 +211,36 @@ describe QA::Factory::Base do
context 'when the attribute has no value' do context 'when the attribute has no value' do
it 'raises an error because no values could be found' do it 'raises an error because no values could be found' do
result = subject.fabricate!(factory: factory) result = subject.fabricate!(resource: resource)
expect { result.no_block } expect { result.no_block }
.to raise_error(described_class::NoValueError, "No value was computed for no_block of #{factory.class.name}.") .to raise_error(described_class::NoValueError, "No value was computed for no_block of #{resource.class.name}.")
end end
end end
end end
describe '#web_url' do describe '#web_url' do
include_context 'simple factory' include_context 'simple resource'
it 'sets #web_url to #current_url after fabrication' do it 'sets #web_url to #current_url after fabrication' do
subject.fabricate!(factory: factory) subject.fabricate!(resource: resource)
expect(factory.web_url).to eq(subject.current_url) expect(resource.web_url).to eq(subject.current_url)
end end
end end
describe '#visit!' do describe '#visit!' do
include_context 'simple factory' include_context 'simple resource'
before do before do
allow(factory).to receive(:visit) allow(resource).to receive(:visit)
end end
it 'calls #visit with the underlying #web_url' do it 'calls #visit with the underlying #web_url' do
factory.web_url = subject.current_url resource.web_url = subject.current_url
factory.visit! resource.visit!
expect(factory).to have_received(:visit).with(subject.current_url) expect(resource).to have_received(:visit).with(subject.current_url)
end end
end end
end end
# frozen_string_literal: true # frozen_string_literal: true
describe QA::Factory::Repository::Push do describe QA::Resource::Repository::Push do
describe '.files=' do describe '.files=' do
let(:files) do let(:files) do
[ [
......
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