Commit a78b1b27 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'blackst0ne-remove-spinach' into 'master'

Remove Spinach

Closes #23036

See merge request gitlab-org/gitlab-ce!18869
parents eb55592a ee70fd55
This diff is collapsed.
...@@ -325,8 +325,6 @@ group :development, :test do ...@@ -325,8 +325,6 @@ group :development, :test do
gem 'factory_bot_rails', '~> 4.8.2' gem 'factory_bot_rails', '~> 4.8.2'
gem 'rspec-rails', '~> 3.6.0' gem 'rspec-rails', '~> 3.6.0'
gem 'rspec-retry', '~> 0.4.5' gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2'
gem 'rspec_profiling', '~> 0.0.5' gem 'rspec_profiling', '~> 0.0.5'
gem 'rspec-set', '~> 0.1.3' gem 'rspec-set', '~> 0.1.3'
gem 'rspec-parameterized', require: false gem 'rspec-parameterized', require: false
...@@ -343,7 +341,6 @@ group :development, :test do ...@@ -343,7 +341,6 @@ group :development, :test do
gem 'spring', '~> 2.0.0' gem 'spring', '~> 2.0.0'
gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'gitlab-styles', '~> 2.3', require: false gem 'gitlab-styles', '~> 2.3', require: false
# Pin these dependencies, otherwise a new rule could break the CI pipelines # Pin these dependencies, otherwise a new rule could break the CI pipelines
......
...@@ -131,7 +131,6 @@ GEM ...@@ -131,7 +131,6 @@ GEM
coderay (1.1.1) coderay (1.1.1)
coercible (1.0.0) coercible (1.0.0)
descendants_tracker (~> 0.0.1) descendants_tracker (~> 0.0.1)
colorize (0.7.7)
commonmarker (0.17.8) commonmarker (0.17.8)
ruby-enum (~> 0.5) ruby-enum (~> 0.5)
concord (0.1.5) concord (0.1.5)
...@@ -288,7 +287,6 @@ GEM ...@@ -288,7 +287,6 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.99.0) gitaly-proto (0.99.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.10) grpc (~> 1.10)
...@@ -869,22 +867,10 @@ GEM ...@@ -869,22 +867,10 @@ GEM
simplecov-html (0.10.0) simplecov-html (0.10.0)
slack-notifier (1.5.1) slack-notifier (1.5.1)
slop (3.6.0) slop (3.6.0)
spinach (0.8.10)
colorize
gherkin-ruby (>= 0.3.2)
json
spinach-rails (0.2.1)
capybara (>= 2.0.0)
railties (>= 3)
spinach (>= 0.4)
spinach-rerun-reporter (0.0.2)
spinach (~> 0.8)
spring (2.0.1) spring (2.0.1)
activesupport (>= 4.2) activesupport (>= 4.2)
spring-commands-rspec (1.0.4) spring-commands-rspec (1.0.4)
spring (>= 0.9.1) spring (>= 0.9.1)
spring-commands-spinach (1.1.0)
spring (>= 0.9.1)
sprockets (3.7.1) sprockets (3.7.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
...@@ -1183,11 +1169,8 @@ DEPENDENCIES ...@@ -1183,11 +1169,8 @@ DEPENDENCIES
simple_po_parser (~> 1.1.2) simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0) simplecov (~> 0.14.0)
slack-notifier (~> 1.5.1) slack-notifier (~> 1.5.1)
spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2)
spring (~> 2.0.0) spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4) spring-commands-rspec (~> 1.0.4)
spring-commands-spinach (~> 1.1.0)
sprockets (~> 3.7.0) sprockets (~> 3.7.0)
sshkey (~> 1.9.0) sshkey (~> 1.9.0)
stackprof (~> 0.2.10) stackprof (~> 0.2.10)
......
...@@ -132,7 +132,6 @@ GEM ...@@ -132,7 +132,6 @@ GEM
coderay (1.1.2) coderay (1.1.2)
coercible (1.0.0) coercible (1.0.0)
descendants_tracker (~> 0.0.1) descendants_tracker (~> 0.0.1)
colorize (0.8.1)
commonmarker (0.17.9) commonmarker (0.17.9)
ruby-enum (~> 0.5) ruby-enum (~> 0.5)
concord (0.1.5) concord (0.1.5)
...@@ -289,7 +288,6 @@ GEM ...@@ -289,7 +288,6 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.99.0) gitaly-proto (0.99.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.10) grpc (~> 1.10)
...@@ -871,22 +869,10 @@ GEM ...@@ -871,22 +869,10 @@ GEM
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.2) simplecov-html (0.10.2)
slack-notifier (1.5.1) slack-notifier (1.5.1)
spinach (0.8.10)
colorize
gherkin-ruby (>= 0.3.2)
json
spinach-rails (0.2.1)
capybara (>= 2.0.0)
railties (>= 3)
spinach (>= 0.4)
spinach-rerun-reporter (0.0.2)
spinach (~> 0.8)
spring (2.0.2) spring (2.0.2)
activesupport (>= 4.2) activesupport (>= 4.2)
spring-commands-rspec (1.0.4) spring-commands-rspec (1.0.4)
spring (>= 0.9.1) spring (>= 0.9.1)
spring-commands-spinach (1.1.0)
spring (>= 0.9.1)
sprockets (3.7.1) sprockets (3.7.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
...@@ -1187,11 +1173,8 @@ DEPENDENCIES ...@@ -1187,11 +1173,8 @@ DEPENDENCIES
simple_po_parser (~> 1.1.2) simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0) simplecov (~> 0.14.0)
slack-notifier (~> 1.5.1) slack-notifier (~> 1.5.1)
spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2)
spring (~> 2.0.0) spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4) spring-commands-rspec (~> 1.0.4)
spring-commands-spinach (~> 1.1.0)
sprockets (~> 3.7.0) sprockets (~> 3.7.0)
sshkey (~> 1.9.0) sshkey (~> 1.9.0)
stackprof (~> 0.2.10) stackprof (~> 0.2.10)
......
...@@ -8,19 +8,6 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -8,19 +8,6 @@ class Projects::NotesController < Projects::ApplicationController
before_action :authorize_create_note!, only: [:create] before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve] before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
#
# This is a fix to make spinach feature tests passing:
# Controller actions are returned from AbstractController::Base and methods of parent classes are
# excluded in order to return only specific controller related methods.
# That is ok for the app (no :create method in ancestors)
# but fails for tests because there is a :create method on FactoryBot (one of the ancestors)
#
# see https://github.com/rails/rails/blob/v4.2.7/actionpack/lib/abstract_controller/base.rb#L78
#
def create
super
end
def delete_attachment def delete_attachment
note.remove_attachment! note.remove_attachment!
note.update_attribute(:attachment, nil) note.update_attribute(:attachment, nil)
......
#!/usr/bin/env ruby
# Remove this block when removing rails5? code.
gemfile = %w[1 true].include?(ENV["RAILS5"]) ? "Gemfile.rails5" : "Gemfile"
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../#{gemfile}", __dir__)
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
require 'bundler/setup'
load Gem.bin_path('spinach', 'spinach')
---
title: Remove Spinach
merge_request: 18869
author: '@blackst0ne'
type: other
...@@ -82,7 +82,7 @@ Example of response ...@@ -82,7 +82,7 @@ Example of response
"artifacts_file": null, "artifacts_file": null,
"finished_at": "2015-12-24T17:54:24.921Z", "finished_at": "2015-12-24T17:54:24.921Z",
"id": 6, "id": 6,
"name": "spinach:other", "name": "rspec:other",
"pipeline": { "pipeline": {
"id": 6, "id": 6,
"ref": "master", "ref": "master",
...@@ -196,7 +196,7 @@ Example of response ...@@ -196,7 +196,7 @@ Example of response
"artifacts_file": null, "artifacts_file": null,
"finished_at": "2015-12-24T17:54:24.921Z", "finished_at": "2015-12-24T17:54:24.921Z",
"id": 6, "id": 6,
"name": "spinach:other", "name": "rspec:other",
"pipeline": { "pipeline": {
"id": 6, "id": 6,
"ref": "master", "ref": "master",
......
...@@ -11,7 +11,7 @@ Available `RAILS_ENV` ...@@ -11,7 +11,7 @@ Available `RAILS_ENV`
- `production` (generally not for your main GDK db, but you may need this for e.g. omnibus) - `production` (generally not for your main GDK db, but you may need this for e.g. omnibus)
- `development` (this is your main GDK db) - `development` (this is your main GDK db)
- `test` (used for tests like rspec and spinach) - `test` (used for tests like rspec)
## Nuke everything and start over ## Nuke everything and start over
......
...@@ -65,12 +65,11 @@ To make sure that indices still fit. You could find great details in: ...@@ -65,12 +65,11 @@ To make sure that indices still fit. You could find great details in:
## Run tests ## Run tests
In order to run the test you can use the following commands: In order to run the test you can use the following commands:
- `rake spinach` to run the spinach suite
- `rake spec` to run the rspec suite - `rake spec` to run the rspec suite
- `rake karma` to run the karma test suite - `rake karma` to run the karma test suite
- `rake gitlab:test` to run all the tests - `rake gitlab:test` to run all the tests
Note: Both `rake spinach` and `rake spec` takes significant time to pass. Note: `rake spec` takes significant time to pass.
Instead of running full test suite locally you can save a lot of time by running Instead of running full test suite locally you can save a lot of time by running
a single test or directory related to your changes. After you submit merge request a single test or directory related to your changes. After you submit merge request
CI will run full test suite for you. Green CI status in the merge request means CI will run full test suite for you. Green CI status in the merge request means
...@@ -82,12 +81,10 @@ files it can find, also the ones in `/tmp` ...@@ -82,12 +81,10 @@ files it can find, also the ones in `/tmp`
To run a single test file you can use: To run a single test file you can use:
- `bin/rspec spec/controllers/commit_controller_spec.rb` for a rspec test - `bin/rspec spec/controllers/commit_controller_spec.rb` for a rspec test
- `bin/spinach features/project/issues/milestones.feature` for a spinach test
To run several tests inside one directory: To run several tests inside one directory:
- `bin/rspec spec/requests/api/` for the rspec tests if you want to test API only - `bin/rspec spec/requests/api/` for the rspec tests if you want to test API only
- `bin/spinach features/profile/` for the spinach tests if you want to test only profile pages
### Speed-up tests, rake tasks, and migrations ### Speed-up tests, rake tasks, and migrations
......
...@@ -12,8 +12,7 @@ Here are some things to keep in mind regarding test performance: ...@@ -12,8 +12,7 @@ Here are some things to keep in mind regarding test performance:
- `FactoryBot.build(...)` and `.build_stubbed` are faster than `.create`. - `FactoryBot.build(...)` and `.build_stubbed` are faster than `.create`.
- Don't `create` an object when `build`, `build_stubbed`, `attributes_for`, - Don't `create` an object when `build`, `build_stubbed`, `attributes_for`,
`spy`, or `double` will do. Database persistence is slow! `spy`, or `double` will do. Database persistence is slow!
- Don't mark a feature as requiring JavaScript (through `@javascript` in - Don't mark a feature as requiring JavaScript (through `:js` in RSpec) unless it's _actually_ required for the test
Spinach or `:js` in RSpec) unless it's _actually_ required for the test
to be valid. Headless browser testing is slow! to be valid. Headless browser testing is slow!
[parallelization]: ci.md#test-suite-parallelization-on-the-ci [parallelization]: ci.md#test-suite-parallelization-on-the-ci
......
...@@ -24,8 +24,7 @@ Our current CI parallelization setup is as follows: ...@@ -24,8 +24,7 @@ Our current CI parallelization setup is as follows:
uploaded to S3. uploaded to S3.
After that, the next pipeline will use the up-to-date After that, the next pipeline will use the up-to-date
`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file. The same strategy `knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file.
is used for Spinach tests as well.
### Monitoring ### Monitoring
......
...@@ -280,26 +280,6 @@ describe "Admin::AbuseReports", :js do ...@@ -280,26 +280,6 @@ describe "Admin::AbuseReports", :js do
end end
``` ```
### Spinach errors due to missing JavaScript
NOTE: **Note:** Since we are discouraging the use of Spinach when writing new
feature tests, you shouldn't ever need to use this. This information is kept
available for legacy purposes only.
In Spinach, the JavaScript driver is enabled differently. In the `*.feature`
file for the failing spec, add the `@javascript` flag above the Scenario:
```
@javascript
Scenario: Developer can approve merge request
Given I am a "Shop" developer
And I visit project "Shop" merge requests page
And merge request 'Bug NS-04' must be approved
And I click link "Bug NS-04"
When I click link "Approve"
Then I should see approved merge request "Bug NS-04"
```
[jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html [jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html
[jasmine-jquery]: https://github.com/velesin/jasmine-jquery [jasmine-jquery]: https://github.com/velesin/jasmine-jquery
[karma]: http://karma-runner.github.io/ [karma]: http://karma-runner.github.io/
......
...@@ -72,21 +72,6 @@ Everything you should know about how to run end-to-end tests using ...@@ -72,21 +72,6 @@ Everything you should know about how to run end-to-end tests using
--- ---
## Spinach (feature) tests
GitLab [moved from Cucumber to Spinach](https://github.com/gitlabhq/gitlabhq/pull/1426)
for its feature/integration tests in September 2012.
As of March 2016, we are [trying to avoid adding new Spinach
tests](https://gitlab.com/gitlab-org/gitlab-ce/issues/14121) going forward,
opting for [RSpec feature](#features-integration) specs.
Adding new Spinach scenarios is acceptable _only if_ the new scenario requires
no more than one new `step` definition. If more than that is required, the
test should be re-implemented using RSpec instead.
---
[Return to Development documentation](../README.md) [Return to Development documentation](../README.md)
[^1]: /ci/yaml/README.html#dependencies [^1]: /ci/yaml/README.html#dependencies
......
...@@ -81,7 +81,6 @@ possible). ...@@ -81,7 +81,6 @@ possible).
| Tests path | Testing engine | Notes | | Tests path | Testing engine | Notes |
| ---------- | -------------- | ----- | | ---------- | -------------- | ----- |
| `spec/features/` | [Capybara] + [RSpec] | If your spec has the `:js` metadata, the browser driver will be [Poltergeist], otherwise it's using [RackTest]. | | `spec/features/` | [Capybara] + [RSpec] | If your spec has the `:js` metadata, the browser driver will be [Poltergeist], otherwise it's using [RackTest]. |
| `features/` | Spinach | Spinach tests are deprecated, [you shouldn't add new Spinach tests](#spinach-feature-tests). |
### Consider **not** writing a system test! ### Consider **not** writing a system test!
......
class Spinach::Features::GroupMembers < Spinach::FeatureSteps
include WaitForRequests
include SharedAuthentication
include SharedPaths
include SharedGroup
include SharedUser
step 'I should see user "John Doe" in team list' do
expect(group_members_list).to have_content("John Doe")
end
step 'I should not see user "Mary Jane" in team list' do
expect(group_members_list).not_to have_content("Mary Jane")
end
step 'I click on the "Remove User From Group" button for "John Doe"' do
find(:css, '.project-members-page li', text: "John Doe").find(:css, 'a.btn-remove').click
# poltergeist always confirms popups.
end
step 'I click on the "Remove User From Group" button for "Mary Jane"' do
find(:css, 'li', text: "Mary Jane").find(:css, 'a.btn-remove').click
# poltergeist always confirms popups.
end
step 'I should not see the "Remove User From Group" button for "John Doe"' do
expect(find(:css, '.project-members-page li', text: "John Doe")).not_to have_selector(:css, 'a.btn-remove')
# poltergeist always confirms popups.
end
step 'I should not see the "Remove User From Group" button for "Mary Jane"' do
expect(find(:css, 'li', text: "Mary Jane")).not_to have_selector(:css, 'a.btn-remove')
# poltergeist always confirms popups.
end
step 'I change the "Mary Jane" role to "Developer"' do
member = mary_jane_member
page.within "#group_member_#{member.id}" do
click_button member.human_access
page.within '.dropdown-menu' do
click_link 'Developer'
end
wait_for_requests
end
end
step 'I should see "Mary Jane" as "Developer"' do
member = mary_jane_member
page.within "#group_member_#{member.id}" do
expect(page).to have_content "Developer"
end
end
private
def mary_jane_member
user = User.find_by(name: "Mary Jane")
owned_group.members.find_by(user_id: user.id)
end
def group_members_list
find(".panel .content-list")
end
end
class Spinach::Features::ProfileNotifications < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
step 'I visit profile notifications page' do
visit profile_notifications_path
end
step 'I should see global notifications settings' do
expect(page).to have_content "Notifications"
end
step 'I select Mention setting from dropdown' do
first(:link, "On mention").click
end
step 'I should see Notification saved message' do
expect(page).to have_content 'On mention'
end
end
class Spinach::Features::ProjectCommitsBranches < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
step 'I click link "All"' do
click_link "All"
end
step 'I click link "Protected"' do
click_link "Protected"
end
step 'I click new branch link' do
click_link "New branch"
end
step 'I submit new branch form with invalid name' do
fill_in 'branch_name', with: '1.0 stable'
page.find("body").click # defocus the branch_name input
select_branch('master')
click_button 'Create branch'
end
def select_branch(branch_name)
find('.git-revision-dropdown-toggle').click
page.within '#new-branch-form .dropdown-menu' do
click_link branch_name
end
end
end
class Spinach::Features::ProjectCommitsComments < Spinach::FeatureSteps
include SharedAuthentication
include SharedNote
include SharedPaths
include SharedProject
end
class Spinach::Features::ProjectCommitsDiffComments < Spinach::FeatureSteps
include SharedAuthentication
include SharedDiffNote
include SharedPaths
include SharedProject
end
class Spinach::Features::ProjectCreate < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedUser
step 'fill project form with valid data' do
fill_in 'project_path', with: 'Empty'
page.within '#content-body' do
click_button "Create project"
end
end
step 'I should see project page' do
expect(page).to have_content "Empty"
expect(current_path).to eq project_path(Project.last)
end
step 'I should see empty project instructions' do
expect(page).to have_content "git init"
expect(page).to have_content "git remote"
expect(page).to have_content Project.last.url_to_repo
end
end
class Spinach::Features::ProjectIssuesFilterLabels < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
include Select2Helper
step 'I should see "Bugfix1" in issues list' do
page.within ".issues-list" do
expect(page).to have_content "Bugfix1"
end
end
step 'I should see "Bugfix2" in issues list' do
page.within ".issues-list" do
expect(page).to have_content "Bugfix2"
end
end
step 'I should not see "Bugfix2" in issues list' do
page.within ".issues-list" do
expect(page).not_to have_content "Bugfix2"
end
end
step 'I should not see "Feature1" in issues list' do
page.within ".issues-list" do
expect(page).not_to have_content "Feature1"
end
end
step 'I click "dropdown close button"' do
page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
sleep 2
end
step 'I click link "feature"' do
page.within ".labels-filter" do
click_link "feature"
end
end
step 'project "Shop" has issue "Bugfix1" with labels: "bug", "feature"' do
project = Project.find_by(name: "Shop")
issue = create(:issue, title: "Bugfix1", project: project)
issue.labels << project.labels.find_by(title: 'bug')
issue.labels << project.labels.find_by(title: 'feature')
end
step 'project "Shop" has issue "Bugfix2" with labels: "bug", "enhancement"' do
project = Project.find_by(name: "Shop")
issue = create(:issue, title: "Bugfix2", project: project)
issue.labels << project.labels.find_by(title: 'bug')
issue.labels << project.labels.find_by(title: 'enhancement')
end
step 'project "Shop" has issue "Feature1" with labels: "feature"' do
project = Project.find_by(name: "Shop")
issue = create(:issue, title: "Feature1", project: project)
issue.labels << project.labels.find_by(title: 'feature')
end
end
class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
include SharedAuthentication
include SharedIssuable
include SharedProject
include SharedNote
include SharedPaths
include SharedMarkdown
include SharedUser
step 'I should not see "Release 0.3" in issues' do
expect(page).not_to have_content "Release 0.3"
end
step 'I click link "Closed"' do
find('.issues-state-filters [data-state="closed"] span', text: 'Closed').click
end
step 'I should see "Release 0.3" in issues' do
expect(page).to have_content "Release 0.3"
end
step 'I should not see "Release 0.4" in issues' do
expect(page).not_to have_content "Release 0.4"
end
step 'I click link "All"' do
find('.issues-state-filters [data-state="all"] span', text: 'All').click
# Waits for load
expect(find('.issues-state-filters > .active')).to have_content 'All'
end
step 'I should see issue "Tweet control"' do
expect(page).to have_content "Tweet control"
end
step 'I click "author" dropdown' do
page.find('.js-author-search').click
sleep 1
end
step 'I see current user as the first user' do
expect(page).to have_selector('.dropdown-content', visible: true)
users = page.all('.dropdown-menu-author .dropdown-content li a')
expect(users[0].text).to eq 'Any Author'
expect(users[1].text).to eq "#{current_user.name} #{current_user.to_reference}"
end
step 'I click link "500 error on profile"' do
click_link "500 error on profile"
end
step 'I should see label \'bug\' with issue' do
page.within '.issuable-show-labels' do
expect(page).to have_content 'bug'
end
end
step 'I fill in issue search with "Re"' do
filter_issue "Re"
end
step 'I fill in issue search with "Bu"' do
filter_issue "Bu"
end
step 'I fill in issue search with ".3"' do
filter_issue ".3"
end
step 'I fill in issue search with "Something"' do
filter_issue "Something"
end
step 'I fill in issue search with ""' do
filter_issue ""
end
step 'project "Shop" has milestone "v2.2"' do
milestone = create(:milestone, title: "v2.2", project: project)
3.times { create(:issue, project: project, milestone: milestone) }
end
step 'project "Shop" has milestone "v3.0"' do
milestone = create(:milestone, title: "v3.0", project: project)
3.times { create(:issue, project: project, milestone: milestone) }
end
When 'I select milestone "v3.0"' do
select "v3.0", from: "milestone_id"
end
step 'I should see selected milestone with title "v3.0"' do
issues_milestone_selector = "#issue_milestone_id_chzn > a"
expect(find(issues_milestone_selector)).to have_content("v3.0")
end
When 'I select first assignee from "Shop" project' do
first_assignee = project.users.first
select first_assignee.name, from: "assignee_id"
end
step 'I should see first assignee from "Shop" as selected assignee' do
issues_assignee_selector = "#issue_assignee_id_chzn > a"
assignee_name = project.users.first.name
expect(find(issues_assignee_selector)).to have_content(assignee_name)
end
step 'The list should be sorted by "Least popular"' do
page.within '.issues-list' do
page.within 'li.issue:nth-child(1)' do
expect(page).to have_content 'Tweet control'
expect(page).to have_content '1 2'
end
page.within 'li.issue:nth-child(2)' do
expect(page).to have_content 'Release 0.4'
expect(page).to have_content '2 1'
end
page.within 'li.issue:nth-child(3)' do
expect(page).to have_content 'Bugfix'
expect(page).not_to have_content '0 0'
end
end
end
When 'I visit empty project page' do
project = Project.find_by(name: 'Empty Project')
visit project_path(project)
end
When "I visit project \"Community\" issues page" do
project = Project.find_by(name: 'Community')
visit project_issues_path(project)
end
step 'project \'Shop\' has issue \'Bugfix1\' with description: \'Description for issue1\'' do
create(:issue, title: 'Bugfix1', description: 'Description for issue1', project: project)
end
step 'project \'Shop\' has issue \'Feature1\' with description: \'Feature submitted for issue1\'' do
create(:issue, title: 'Feature1', description: 'Feature submitted for issue1', project: project)
end
step 'I fill in issue search with \'Description for issue1\'' do
filter_issue 'Description for issue'
end
step 'I fill in issue search with \'issue1\'' do
filter_issue 'issue1'
end
step 'I fill in issue search with \'Rock and roll\'' do
filter_issue 'Rock and roll'
end
step 'I should see \'Bugfix1\' in issues' do
expect(page).to have_content 'Bugfix1'
end
step 'I should see \'Feature1\' in issues' do
expect(page).to have_content 'Feature1'
end
step 'I should not see \'Bugfix1\' in issues' do
expect(page).not_to have_content 'Bugfix1'
end
def filter_issue(text)
fill_in 'issuable_search', with: text
end
end
class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
include SharedMarkdown
step 'project "Shop" has milestone "v2.2"' do
project = Project.find_by(name: "Shop")
milestone = create(:milestone,
title: "v2.2",
project: project,
description: "# Description header"
)
3.times { create(:issue, project: project, milestone: milestone) }
end
When 'I click link "All Issues"' do
click_link 'All Issues'
end
end
class Spinach::Features::ProjectIssuesReferences < Spinach::FeatureSteps
include SharedAuthentication
include SharedIssuable
include SharedNote
include SharedProject
include SharedUser
end
class Spinach::Features::ProjectMergeRequestsReferences < Spinach::FeatureSteps
include SharedAuthentication
include SharedIssuable
include SharedNote
include SharedProject
include SharedUser
end
This diff is collapsed.
module SharedActiveTab
include Spinach::DSL
include WaitForRequests
after do
wait_for_requests if javascript_test?
end
def ensure_active_main_tab(content)
expect(find('.sidebar-top-level-items > li.active')).to have_content(content)
end
def ensure_active_sub_tab(content)
expect(find('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)')).to have_content(content)
end
def ensure_active_sub_nav(content)
expect(find('.layout-nav .controls li.active')).to have_content(content)
end
step 'no other main tabs should be active' do
expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1)
end
step 'no other sub tabs should be active' do
expect(page).to have_selector('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)', count: 1)
end
step 'no other sub navs should be active' do
expect(page).to have_selector('.layout-nav .controls li.active', count: 1)
end
end
module SharedAdmin
include Spinach::DSL
step 'there are projects in system' do
2.times { create(:project, :repository) }
end
step 'system has users' do
2.times { create(:user) }
end
end
require Rails.root.join('features', 'support', 'login_helpers')
module SharedAuthentication
include Spinach::DSL
include LoginHelpers
step 'I sign in as a user' do
sign_out(@user) if @user
@user = create(:user)
sign_in(@user)
end
step 'I sign in via the UI' do
gitlab_sign_in(create(:user))
end
step 'I should be redirected to sign in page' do
expect(current_path).to eq new_user_session_path
end
step "I logout directly" do
gitlab_sign_out
end
def current_user
@user || User.reorder(nil).first
end
private
def gitlab_sign_in(user)
visit new_user_session_path
fill_in "user_login", with: user.email
fill_in "user_password", with: "12345678"
check 'user_remember_me'
click_button "Sign in"
@user = user
end
def gitlab_sign_out
return unless @user
if Capybara.current_driver == Capybara.javascript_driver
find('.header-user-dropdown-toggle').click
click_link 'Sign out'
expect(page).to have_button('Sign in')
else
sign_out(@user)
end
@user = nil
end
end
module SharedDiffNote
include Spinach::DSL
include RepoHelpers
include WaitForRequests
after do
wait_for_requests if javascript_test?
end
step 'I delete a diff comment' do
find('.note').hover
find(".js-note-delete").click
end
step 'I haven\'t written any diff comment text' do
page.within(diff_file_selector) do
fill_in "note[note]", with: ""
end
end
step 'The diff comment preview tab should say there is nothing to do' do
page.within(diff_file_selector) do
find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_content('Nothing to preview.')
end
end
step 'I see side-by-side diff button' do
expect(page).to have_content "Side-by-side"
end
def diff_file_selector
'.diff-file:nth-of-type(1)'
end
def click_diff_line(code)
find(".line_holder[id='#{code}'] button").click
end
def click_parallel_diff_line(code, line_type)
find(".line_holder.parallel td[id='#{code}']").find(:xpath, 'preceding-sibling::*[1][self::td]').hover
find(".line_holder.parallel button[data-line-code='#{code}']").click
end
end
module SharedGroup
include Spinach::DSL
step 'current user is developer of group "Owned"' do
is_member_of(current_user.name, "Owned", Gitlab::Access::DEVELOPER)
end
step '"John Doe" is guest of group "Guest"' do
is_member_of("John Doe", "Guest", Gitlab::Access::GUEST)
end
step '"Mary Jane" is owner of group "Owned"' do
is_member_of("Mary Jane", "Owned", Gitlab::Access::OWNER)
end
step '"Mary Jane" is guest of group "Owned"' do
is_member_of("Mary Jane", "Owned", Gitlab::Access::GUEST)
end
step '"Mary Jane" is guest of group "Guest"' do
is_member_of("Mary Jane", "Guest", Gitlab::Access::GUEST)
end
step 'I should see group "TestGroup"' do
expect(page).to have_content "TestGroup"
end
step 'I should not see group "TestGroup"' do
expect(page).not_to have_content "TestGroup"
end
protected
def is_member_of(username, groupname, role)
user = User.find_by(name: username) || create(:user, name: username)
group = Group.find_by(name: groupname) || create(:group, name: groupname)
group.add_user(user, role)
project ||= create(:project, :repository, namespace: group)
create(:closed_issue_event, project: project)
project.add_master(user)
end
def owned_group
@owned_group ||= Group.find_by(name: "Owned")
end
end
module SharedIssuable
include Spinach::DSL
def edit_issuable
find('.js-issuable-edit', visible: true).click
end
step 'I leave a comment referencing issue "Community issue"' do
leave_reference_comment(
issuable: Issue.find_by(title: 'Community issue'),
from_project_name: 'Enterprise'
)
end
step 'I click link "Edit" for the merge request' do
edit_issuable
end
step 'I sort the list by "Least popular"' do
find('button.dropdown-toggle').click
page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
click_link 'Least popular'
end
end
step 'I click link "Next" in the sidebar' do
page.within '.issuable-sidebar' do
click_link 'Next'
end
end
def create_issuable_for_project(project_name:, title:, type: :issue)
project = Project.find_by(name: project_name)
attrs = {
title: title,
author: project.users.first,
description: '# Description header'
}
case type
when :issue
attrs[:project] = project
when :merge_request
attrs.merge!(
source_project: project,
target_project: project,
source_branch: 'fix',
target_branch: 'master'
)
end
create(type, attrs)
end
def leave_reference_comment(issuable:, from_project_name:)
project = Project.find_by(name: from_project_name)
page.within('.js-main-target-form') do
fill_in 'note[note]', with: "##{issuable.to_reference(project)}"
click_button 'Comment'
end
end
def visible_note(issuable:, from_project_name:, user_name:)
project = Project.find_by(name: from_project_name)
expect(page).to have_content(user_name)
expect(page).to have_content("mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}")
end
def expect_sidebar_content(content)
page.within '.issuable-sidebar' do
expect(page).to have_content content
end
end
end
module SharedMarkdown
include Spinach::DSL
step 'I should not see the Markdown preview' do
expect(find('.gfm-form .js-md-preview')).not_to be_visible
end
step 'I haven\'t written any description text' do
find('.gfm-form').fill_in 'Description', with: ''
end
end
module SharedNote
include Spinach::DSL
include WaitForRequests
after do
wait_for_requests if javascript_test?
end
step 'I haven\'t written any comment text' do
page.within(".js-main-target-form") do
fill_in "note[note]", with: ""
end
end
step 'The comment preview tab should say there is nothing to do' do
page.within(".js-main-target-form") do
find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_content('Nothing to preview.')
end
end
end
This diff is collapsed.
module SharedProject
include Spinach::DSL
# Create a project without caring about what it's called
step "I own a project" do
@project = create(:project, :repository, namespace: @user.namespace)
@project.add_master(@user)
end
step "I own a project in some group namespace" do
@group = create(:group, name: 'some group')
@project = create(:project, namespace: @group)
@project.add_master(@user)
end
def current_project
@project ||= Project.first
end
# ----------------------------------------
# Visibility of archived project
# ----------------------------------------
step 'I should not see project "Archive"' do
project = Project.find_by(name: "Archive")
expect(page).not_to have_content project.full_name
end
step 'I should see project "Archive"' do
project = Project.find_by(name: "Archive")
expect(page).to have_content project.full_name
end
# ----------------------------------------
# Visibility level
# ----------------------------------------
step 'I should see project "Enterprise"' do
expect(page).to have_content "Enterprise"
end
step 'I should not see project "Enterprise"' do
expect(page).not_to have_content "Enterprise"
end
step 'internal project "Internal"' do
create(:project, :internal, :repository, name: 'Internal')
end
step 'I should see project "Internal"' do
page.within '.js-projects-list-holder' do
expect(page).to have_content "Internal"
end
end
step 'I should not see project "Internal"' do
page.within '.js-projects-list-holder' do
expect(page).not_to have_content "Internal"
end
end
step 'I should see project "Community"' do
expect(page).to have_content "Community"
end
step 'I should not see project "Community"' do
expect(page).not_to have_content "Community"
end
step '"John Doe" owns private project "Enterprise"' do
user_owns_project(
user_name: 'John Doe',
project_name: 'Enterprise'
)
end
step '"John Doe" owns internal project "Internal"' do
user_owns_project(
user_name: 'John Doe',
project_name: 'Internal',
visibility: :internal
)
end
step 'public empty project "Empty Public Project"' do
create :project_empty_repo, :public, name: "Empty Public Project"
end
step 'project "Shop" has labels: "bug", "feature", "enhancement"' do
project = Project.find_by(name: "Shop")
create(:label, project: project, title: 'bug')
create(:label, project: project, title: 'feature')
create(:label, project: project, title: 'enhancement')
end
def user_owns_project(user_name:, project_name:, visibility: :private)
user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore)
project = Project.find_by(name: project_name)
project ||= create(:project, visibility, name: project_name, namespace: user.namespace)
project.add_master(user)
end
end
require_relative 'active_tab'
module SharedProjectTab
include Spinach::DSL
include SharedActiveTab
step 'the active main tab should be Project' do
ensure_active_main_tab('Overview')
end
step 'the active main tab should be Repository' do
ensure_active_main_tab('Repository')
end
step 'the active main tab should be Issues' do
ensure_active_main_tab('Issues')
end
step 'the active sub tab should be Members' do
ensure_active_sub_tab('Members')
end
step 'the active main tab should be Merge Requests' do
ensure_active_main_tab('Merge Requests')
end
step 'the active main tab should be Snippets' do
ensure_active_main_tab('Snippets')
end
step 'the active main tab should be Wiki' do
ensure_active_main_tab('Wiki')
end
step 'the active main tab should be Members' do
ensure_active_main_tab('Members')
end
step 'the active main tab should be Settings' do
ensure_active_main_tab('Settings')
end
step 'the active sub tab should be Graph' do
ensure_active_sub_tab('Graph')
end
step 'the active sub tab should be Files' do
ensure_active_sub_tab('Files')
end
step 'the active sub tab should be Commits' do
ensure_active_sub_tab('Commits')
end
step 'the active sub tab should be Home' do
ensure_active_sub_tab('Details')
end
step 'the active sub tab should be Activity' do
ensure_active_sub_tab('Activity')
end
step 'the active sub tab should be Charts' do
ensure_active_sub_tab('Charts')
end
end
module SharedShortcuts
include Spinach::DSL
step 'I press "g" and "p"' do
find('body').native.send_key('g')
find('body').native.send_key('p')
end
step 'I press "g" and "i"' do
find('body').native.send_key('g')
find('body').native.send_key('i')
end
step 'I press "g" and "m"' do
find('body').native.send_key('g')
find('body').native.send_key('m')
end
end
module SharedSidebarActiveTab
include Spinach::DSL
step 'no other main tabs should be active' do
expect(page).to have_selector('.nav-sidebar li.active', count: 1)
end
def ensure_active_main_tab(content)
expect(find('.nav-sidebar li.active')).to have_content(content)
end
step 'the active main tab should be Home' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Groups' do
ensure_active_main_tab('Groups')
end
step 'the active main tab should be Projects' do
ensure_active_main_tab('Projects')
end
step 'the active main tab should be Issues' do
ensure_active_main_tab('Issues')
end
step 'the active main tab should be Merge Requests' do
ensure_active_main_tab('Merge Requests')
end
end
module SharedUser
include Spinach::DSL
step 'User "John Doe" exists' do
user_exists("John Doe", { username: "john_doe" })
end
step 'User "Mary Jane" exists' do
user_exists("Mary Jane", { username: "mary_jane" })
end
step 'gitlab user "Mike"' do
create(:user, name: "Mike")
end
protected
def user_exists(name, options = {})
User.find_by(name: name) || create(:user, { name: name, admin: false }.merge(options))
end
step 'I have no ssh keys' do
@user.keys.delete_all
end
step 'I click on "Personal projects" tab' do
page.within '.nav-links' do
click_link 'Personal projects'
end
expect(page).to have_css('.tab-content #projects.active')
end
step 'I click on "Contributed projects" tab' do
page.within '.nav-links' do
click_link 'Contributed projects'
end
expect(page).to have_css('.tab-content #contributed.active')
end
end
require 'capybara-screenshot/spinach'
# Give CI some extra time
timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 60 : 30
Capybara.register_driver :chrome do |app|
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
# This enables access to logs with `page.driver.manage.get_log(:browser)`
loggingPrefs: {
browser: "ALL",
client: "ALL",
driver: "ALL",
server: "ALL"
}
)
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument("window-size=1240,1400")
# Chrome won't work properly in a Docker container in sandbox mode
options.add_argument("no-sandbox")
# Run headless by default unless CHROME_HEADLESS specified
options.add_argument("headless") unless ENV['CHROME_HEADLESS'] =~ /^(false|no|0)$/i
# Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab-ee/issues/4252
options.add_argument("disable-dev-shm-usage") if ENV['CI'] || ENV['CI_SERVER']
Capybara::Selenium::Driver.new(
app,
browser: :chrome,
desired_capabilities: capabilities,
options: options
)
end
Capybara.javascript_driver = :chrome
Capybara.default_max_wait_time = timeout
Capybara.ignore_hidden_elements = false
# Keep only the screenshots generated from the last failing test suite
Capybara::Screenshot.prune_strategy = :keep_last_run
# From https://github.com/mattheworiordan/capybara-screenshot/issues/84#issuecomment-41219326
Capybara::Screenshot.register_driver(:chrome) do |driver, path|
driver.browser.save_screenshot(path)
end
Spinach.hooks.before_run do
TestEnv.eager_load_driver_server
end
require 'database_cleaner'
DatabaseCleaner[:active_record].strategy = :deletion
Spinach.hooks.before_scenario do
DatabaseCleaner.start
end
Spinach.hooks.after_scenario do
DatabaseCleaner.clean
end
require './spec/simplecov_env'
SimpleCovEnv.start!
ENV['RAILS_ENV'] = 'test'
require './config/environment'
require 'rspec/expectations'
if ENV['CI']
require 'knapsack'
Knapsack::Adapters::SpinachAdapter.bind
end
WebMock.enable!
%w(select2_helper test_env repo_helpers wait_for_requests project_forks_helper).each do |f|
require Rails.root.join('spec', 'support', 'helpers', f)
end
%w(sidekiq webmock).each do |f|
require Rails.root.join('spec', 'support', f)
end
Dir["#{Rails.root}/features/steps/shared/*.rb"].each { |file| require file }
Spinach.hooks.before_run do
include RSpec::Mocks::ExampleMethods
include ActiveJob::TestHelper
include FactoryBot::Syntax::Methods
include GitlabRoutingHelper
RSpec::Mocks.setup
TestEnv.init(mailer: false)
# skip pre-receive hook check so we can use
# web editor and merge
TestEnv.disable_pre_receive
end
Spinach.hooks.after_scenario do |scenario_data, step_definitions|
if scenario_data.tags.include?('javascript')
include WaitForRequests
block_and_wait_for_requests_complete
end
end
module StdoutReporterWithScenarioLocation
# Override the standard reporter to show filename and line number next to each
# scenario for easy, focused re-runs
def before_scenario_run(scenario, step_definitions = nil)
@max_step_name_length = scenario.steps.map(&:name).map(&:length).max if scenario.steps.any? # rubocop:disable Gitlab/ModuleWithInstanceVariables
name = scenario.name
# This number has no significance, it's just to line things up
max_length = @max_step_name_length + 19 # rubocop:disable Gitlab/ModuleWithInstanceVariables
out.puts "\n #{'Scenario:'.green} #{name.light_green.ljust(max_length)}" \
" # #{scenario.feature.filename}:#{scenario.line}"
end
end
Spinach::Reporter::Stdout.prepend(StdoutReporterWithScenarioLocation)
Spinach.hooks.before_scenario do
allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true)
end
module LoginHelpers
# After inclusion, IntegrationHelpers calls these two methods that aren't
# supported by Spinach, so we perform the end results ourselves
class << self
def setup(*args)
Spinach.hooks.before_scenario do
Warden.test_mode!
end
end
def teardown(*args)
Spinach.hooks.after_scenario do
Warden.test_reset!
end
end
end
include Devise::Test::IntegrationHelpers
end
# The spinach-rerun-reporter doesn't define the on_undefined_step
# See it here: https://github.com/javierav/spinach-rerun-reporter/blob/master/lib/spinach/reporter/rerun.rb
require 'spinach-rerun-reporter'
module Spinach
class Reporter
class Rerun
def on_undefined_step(step_data, failure, step_definitions = nil)
super step_data, failure, step_definitions
# save feature file and scenario line
@rerun << "#{current_feature.filename}:#{current_scenario.line}"
end
end
end
end
...@@ -4,7 +4,6 @@ namespace :gitlab do ...@@ -4,7 +4,6 @@ namespace :gitlab do
cmds = [ cmds = [
%w(rake brakeman), %w(rake brakeman),
%w(rake rubocop), %w(rake rubocop),
%w(rake spinach),
%w(rake spec), %w(rake spec),
%w(rake karma) %w(rake karma)
] ]
......
Rake::Task["spinach"].clear if Rake::Task.task_defined?('spinach')
namespace :spinach do
namespace :project do
desc "GitLab | Spinach | Run project commits, issues and merge requests spinach features"
task :half do
run_spinach_tests('@project_commits,@project_issues,@project_merge_requests')
end
desc "GitLab | Spinach | Run remaining project spinach features"
task :rest do
run_spinach_tests('~@admin,~@dashboard,~@profile,~@public,~@snippets,~@project_commits,~@project_issues,~@project_merge_requests')
end
end
desc "GitLab | Spinach | Run project spinach features"
task :project do
run_spinach_tests('~@admin,~@dashboard,~@profile,~@public,~@snippets')
end
desc "GitLab | Spinach | Run other spinach features"
task :other do
run_spinach_tests('@admin,@dashboard,@profile,@public,@snippets')
end
desc "GitLab | Spinach | Run other spinach features"
task :builds do
run_spinach_tests('@builds')
end
end
desc "GitLab | Run spinach"
task :spinach do
run_spinach_tests(nil)
end
def run_system_command(cmd)
system({ 'RAILS_ENV' => 'test', 'force' => 'yes' }, *cmd)
end
def run_spinach_command(args)
run_system_command(%w(spinach -r rerun) + args)
end
def run_spinach_tests(tags)
success = run_spinach_command(%W(--tags #{tags}))
3.times do |_|
break if success
break unless File.exist?('tmp/spinach-rerun.txt')
tests = File.foreach('tmp/spinach-rerun.txt').map(&:chomp)
puts ''
puts "Spinach tests for #{tags}: Retrying tests... #{tests}".color(:red)
puts ''
sleep(3)
success = run_spinach_command(tests)
end
raise("spinach tests for #{tags} failed!") unless success
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment