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
...@@ -31,7 +31,6 @@ variables: ...@@ -31,7 +31,6 @@ variables:
GIT_SUBMODULE_STRATEGY: "none" GIT_SUBMODULE_STRATEGY: "none"
GET_SOURCES_ATTEMPTS: "3" GET_SOURCES_ATTEMPTS: "3"
KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
KNAPSACK_SPINACH_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/spinach_report-master.json
FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json
before_script: before_script:
...@@ -179,46 +178,6 @@ stages: ...@@ -179,46 +178,6 @@ stages:
<<: *rspec-metadata-mysql <<: *rspec-metadata-mysql
<<: *rails5 <<: *rails5
.spinach-metadata: &spinach-metadata
<<: *dedicated-runner
<<: *except-docs-and-qa
<<: *pull-cache
<<: *rails5-variables
stage: test
script:
- JOB_NAME=( $CI_JOB_NAME )
- export CI_NODE_INDEX=${JOB_NAME[-2]}
- export CI_NODE_TOTAL=${JOB_NAME[-1]}
- export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true
- export CACHE_CLASSES=true
- cp ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- scripts/gitaly-test-spawn
- knapsack spinach "-r rerun" -b || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -b -r rerun $(cat tmp/spinach-rerun.txt)'
artifacts:
expire_in: 31d
when: always
paths:
- coverage/
- knapsack/
- tmp/capybara/
.spinach-metadata-pg: &spinach-metadata-pg
<<: *spinach-metadata
<<: *use-pg
.spinach-metadata-pg-rails5: &spinach-metadata-pg-rails5
<<: *spinach-metadata-pg
<<: *rails5
.spinach-metadata-mysql: &spinach-metadata-mysql
<<: *spinach-metadata
<<: *use-mysql
.spinach-metadata-mysql-rails5: &spinach-metadata-mysql-rails5
<<: *spinach-metadata-mysql
<<: *rails5
.only-canonical-masters: &only-canonical-masters .only-canonical-masters: &only-canonical-masters
only: only:
- master@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ce
...@@ -350,9 +309,7 @@ retrieve-tests-metadata: ...@@ -350,9 +309,7 @@ retrieve-tests-metadata:
script: script:
- mkdir -p knapsack/${CI_PROJECT_NAME}/ - mkdir -p knapsack/${CI_PROJECT_NAME}/
- wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH - wget -O $KNAPSACK_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || rm $KNAPSACK_RSPEC_SUITE_REPORT_PATH
- wget -O $KNAPSACK_SPINACH_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$KNAPSACK_SPINACH_SUITE_REPORT_PATH || rm $KNAPSACK_SPINACH_SUITE_REPORT_PATH
- '[[ -f $KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}' - '[[ -f $KNAPSACK_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_RSPEC_SUITE_REPORT_PATH}'
- '[[ -f $KNAPSACK_SPINACH_SUITE_REPORT_PATH ]] || echo "{}" > ${KNAPSACK_SPINACH_SUITE_REPORT_PATH}'
- mkdir -p rspec_flaky/ - mkdir -p rspec_flaky/
- wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH - wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH
- '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}' - '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}'
...@@ -370,10 +327,9 @@ update-tests-metadata: ...@@ -370,10 +327,9 @@ update-tests-metadata:
script: script:
- retry gem install fog-aws mime-types activesupport - retry gem install fog-aws mime-types activesupport
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json - scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
- scripts/merge-reports ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/spinach-pg_node_*.json
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json - scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH} - FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH $KNAPSACK_SPINACH_SUITE_REPORT_PATH' - '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH'
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH' - '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json - rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
- rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json - rm -f rspec_flaky/all_*.json rspec_flaky/new_*.json
...@@ -441,133 +397,129 @@ setup-test-env: ...@@ -441,133 +397,129 @@ setup-test-env:
- config/secrets.yml - config/secrets.yml
- vendor/gitaly-ruby - vendor/gitaly-ruby
rspec-pg 0 28: *rspec-metadata-pg rspec-pg 0 30: *rspec-metadata-pg
rspec-pg 1 28: *rspec-metadata-pg rspec-pg 1 30: *rspec-metadata-pg
rspec-pg 2 28: *rspec-metadata-pg rspec-pg 2 30: *rspec-metadata-pg
rspec-pg 3 28: *rspec-metadata-pg rspec-pg 3 30: *rspec-metadata-pg
rspec-pg 4 28: *rspec-metadata-pg rspec-pg 4 30: *rspec-metadata-pg
rspec-pg 5 28: *rspec-metadata-pg rspec-pg 5 30: *rspec-metadata-pg
rspec-pg 6 28: *rspec-metadata-pg rspec-pg 6 30: *rspec-metadata-pg
rspec-pg 7 28: *rspec-metadata-pg rspec-pg 7 30: *rspec-metadata-pg
rspec-pg 8 28: *rspec-metadata-pg rspec-pg 8 30: *rspec-metadata-pg
rspec-pg 9 28: *rspec-metadata-pg rspec-pg 9 30: *rspec-metadata-pg
rspec-pg 10 28: *rspec-metadata-pg rspec-pg 10 30: *rspec-metadata-pg
rspec-pg 11 28: *rspec-metadata-pg rspec-pg 11 30: *rspec-metadata-pg
rspec-pg 12 28: *rspec-metadata-pg rspec-pg 12 30: *rspec-metadata-pg
rspec-pg 13 28: *rspec-metadata-pg rspec-pg 13 30: *rspec-metadata-pg
rspec-pg 14 28: *rspec-metadata-pg rspec-pg 14 30: *rspec-metadata-pg
rspec-pg 15 28: *rspec-metadata-pg rspec-pg 15 30: *rspec-metadata-pg
rspec-pg 16 28: *rspec-metadata-pg rspec-pg 16 30: *rspec-metadata-pg
rspec-pg 17 28: *rspec-metadata-pg rspec-pg 17 30: *rspec-metadata-pg
rspec-pg 18 28: *rspec-metadata-pg rspec-pg 18 30: *rspec-metadata-pg
rspec-pg 19 28: *rspec-metadata-pg rspec-pg 19 30: *rspec-metadata-pg
rspec-pg 20 28: *rspec-metadata-pg rspec-pg 20 30: *rspec-metadata-pg
rspec-pg 21 28: *rspec-metadata-pg rspec-pg 21 30: *rspec-metadata-pg
rspec-pg 22 28: *rspec-metadata-pg rspec-pg 22 30: *rspec-metadata-pg
rspec-pg 23 28: *rspec-metadata-pg rspec-pg 23 30: *rspec-metadata-pg
rspec-pg 24 28: *rspec-metadata-pg rspec-pg 24 30: *rspec-metadata-pg
rspec-pg 25 28: *rspec-metadata-pg rspec-pg 25 30: *rspec-metadata-pg
rspec-pg 26 28: *rspec-metadata-pg rspec-pg 26 30: *rspec-metadata-pg
rspec-pg 27 28: *rspec-metadata-pg rspec-pg 27 30: *rspec-metadata-pg
rspec-pg 28 30: *rspec-metadata-pg
rspec-mysql 0 28: *rspec-metadata-mysql rspec-pg 29 30: *rspec-metadata-pg
rspec-mysql 1 28: *rspec-metadata-mysql
rspec-mysql 2 28: *rspec-metadata-mysql rspec-mysql 0 30: *rspec-metadata-mysql
rspec-mysql 3 28: *rspec-metadata-mysql rspec-mysql 1 30: *rspec-metadata-mysql
rspec-mysql 4 28: *rspec-metadata-mysql rspec-mysql 2 30: *rspec-metadata-mysql
rspec-mysql 5 28: *rspec-metadata-mysql rspec-mysql 3 30: *rspec-metadata-mysql
rspec-mysql 6 28: *rspec-metadata-mysql rspec-mysql 4 30: *rspec-metadata-mysql
rspec-mysql 7 28: *rspec-metadata-mysql rspec-mysql 5 30: *rspec-metadata-mysql
rspec-mysql 8 28: *rspec-metadata-mysql rspec-mysql 6 30: *rspec-metadata-mysql
rspec-mysql 9 28: *rspec-metadata-mysql rspec-mysql 7 30: *rspec-metadata-mysql
rspec-mysql 10 28: *rspec-metadata-mysql rspec-mysql 8 30: *rspec-metadata-mysql
rspec-mysql 11 28: *rspec-metadata-mysql rspec-mysql 9 30: *rspec-metadata-mysql
rspec-mysql 12 28: *rspec-metadata-mysql rspec-mysql 10 30: *rspec-metadata-mysql
rspec-mysql 13 28: *rspec-metadata-mysql rspec-mysql 11 30: *rspec-metadata-mysql
rspec-mysql 14 28: *rspec-metadata-mysql rspec-mysql 12 30: *rspec-metadata-mysql
rspec-mysql 15 28: *rspec-metadata-mysql rspec-mysql 13 30: *rspec-metadata-mysql
rspec-mysql 16 28: *rspec-metadata-mysql rspec-mysql 14 30: *rspec-metadata-mysql
rspec-mysql 17 28: *rspec-metadata-mysql rspec-mysql 15 30: *rspec-metadata-mysql
rspec-mysql 18 28: *rspec-metadata-mysql rspec-mysql 16 30: *rspec-metadata-mysql
rspec-mysql 19 28: *rspec-metadata-mysql rspec-mysql 17 30: *rspec-metadata-mysql
rspec-mysql 20 28: *rspec-metadata-mysql rspec-mysql 18 30: *rspec-metadata-mysql
rspec-mysql 21 28: *rspec-metadata-mysql rspec-mysql 19 30: *rspec-metadata-mysql
rspec-mysql 22 28: *rspec-metadata-mysql rspec-mysql 20 30: *rspec-metadata-mysql
rspec-mysql 23 28: *rspec-metadata-mysql rspec-mysql 21 30: *rspec-metadata-mysql
rspec-mysql 24 28: *rspec-metadata-mysql rspec-mysql 22 30: *rspec-metadata-mysql
rspec-mysql 25 28: *rspec-metadata-mysql rspec-mysql 23 30: *rspec-metadata-mysql
rspec-mysql 26 28: *rspec-metadata-mysql rspec-mysql 24 30: *rspec-metadata-mysql
rspec-mysql 27 28: *rspec-metadata-mysql rspec-mysql 25 30: *rspec-metadata-mysql
rspec-mysql 26 30: *rspec-metadata-mysql
spinach-pg 0 2: *spinach-metadata-pg rspec-mysql 27 30: *rspec-metadata-mysql
spinach-pg 1 2: *spinach-metadata-pg rspec-mysql 28 30: *rspec-metadata-mysql
rspec-mysql 29 30: *rspec-metadata-mysql
spinach-mysql 0 2: *spinach-metadata-mysql
spinach-mysql 1 2: *spinach-metadata-mysql rspec-pg-rails5 0 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 1 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 0 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 2 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 1 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 3 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 2 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 4 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 3 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 5 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 4 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 6 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 5 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 7 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 6 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 8 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 7 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 9 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 8 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 10 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 9 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 11 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 10 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 12 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 11 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 13 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 12 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 14 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 13 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 15 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 14 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 16 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 15 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 17 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 16 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 18 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 17 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 19 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 18 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 20 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 19 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 21 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 20 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 22 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 21 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 23 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 22 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 24 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 23 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 25 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 24 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 26 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 25 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 27 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 26 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 28 30: *rspec-metadata-pg-rails5
rspec-pg-rails5 27 28: *rspec-metadata-pg-rails5 rspec-pg-rails5 29 30: *rspec-metadata-pg-rails5
rspec-mysql-rails5 0 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 0 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 1 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 1 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 2 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 2 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 3 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 3 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 4 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 4 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 5 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 5 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 6 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 6 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 7 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 7 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 8 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 8 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 9 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 9 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 10 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 10 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 11 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 11 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 12 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 12 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 13 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 13 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 14 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 14 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 15 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 15 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 16 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 16 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 17 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 17 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 18 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 18 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 19 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 19 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 20 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 20 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 21 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 21 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 22 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 22 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 23 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 23 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 24 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 24 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 25 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 25 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 26 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 26 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 27 28: *rspec-metadata-mysql-rails5 rspec-mysql-rails5 27 30: *rspec-metadata-mysql-rails5
rspec-mysql-rails5 28 30: *rspec-metadata-mysql-rails5
spinach-pg-rails5 0 2: *spinach-metadata-pg-rails5 rspec-mysql-rails5 29 30: *rspec-metadata-mysql-rails5
spinach-pg-rails5 1 2: *spinach-metadata-pg-rails5
spinach-mysql-rails5 0 2: *spinach-metadata-mysql-rails5
spinach-mysql-rails5 1 2: *spinach-metadata-mysql-rails5
static-analysis: static-analysis:
<<: *dedicated-no-docs-no-db-pull-cache-job <<: *dedicated-no-docs-no-db-pull-cache-job
......
...@@ -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
# coding: utf-8
class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
include RepoHelpers
include WaitForRequests
step "I don't have write access" do
@project = create(:project, :repository, name: "Other Project", path: "other-project")
@project.add_reporter(@user)
visit project_tree_path(@project, root_ref)
end
step 'I should see files from repository' do
expect(page).to have_content "VERSION"
expect(page).to have_content ".gitignore"
expect(page).to have_content "LICENSE"
end
step 'I should see files from repository for "6d39438"' do
expect(current_path).to eq project_tree_path(@project, "6d39438")
expect(page).to have_content ".gitignore"
expect(page).to have_content "LICENSE"
end
step 'I see the ".gitignore"' do
expect(page).to have_content '.gitignore'
end
step 'I don\'t see the ".gitignore"' do
expect(page).not_to have_content '.gitignore'
end
step 'I click on ".gitignore" file in repo' do
click_link ".gitignore"
end
step 'I should see its content' do
wait_for_requests
expect(page).to have_content old_gitignore_content
end
step 'I should see its new content' do
wait_for_requests
expect(page).to have_content new_gitignore_content
end
step 'I click link "Raw"' do
click_link 'Open raw'
end
step 'I should see raw file content' do
expect(source).to eq '' # Body is filled in by gitlab-workhorse
end
step 'I click button "Edit"' do
find('.js-edit-blob').click
end
step 'I cannot see the edit button' do
expect(page).not_to have_link 'edit'
end
step 'I click button "Fork"' do
click_link 'Fork'
end
step 'I edit code' do
expect(page).to have_selector('.file-editor')
set_new_content
end
step 'I fill the new file name' do
fill_in :file_name, with: new_file_name
end
step 'I fill the new branch name' do
fill_in :branch_name, with: 'new_branch_name', visible: true
end
step 'I fill the new file name with a new directory' do
fill_in :file_name, with: new_file_name_with_directory
end
step 'I fill the commit message' do
fill_in :commit_message, with: 'New commit message', visible: true
end
step 'I click link "Diff"' do
click_link 'Preview changes'
end
step 'I click on "Commit changes"' do
click_button 'Commit changes'
end
step 'I click on "Changes" tab' do
click_link 'Changes'
end
step 'I click on "Create directory"' do
click_button 'Create directory'
end
step 'I click on "Delete"' do
click_on 'Delete'
end
step 'I click on "Delete file"' do
click_button 'Delete file'
end
step 'I click on "Replace"' do
click_on "Replace"
end
step 'I click on "Replace file"' do
click_button 'Replace file'
end
step 'I see diff' do
expect(page).to have_css '.line_holder.new'
end
step 'I click on "New file" link in repo' do
find('.add-to-tree').click
click_link 'New file'
expect(page).to have_selector('.file-editor')
end
step 'I click on "Upload file" link in repo' do
find('.add-to-tree').click
click_link 'Upload file'
end
step 'I click on "New directory" link in repo' do
find('.add-to-tree').click
click_link 'New directory'
end
step 'I fill the new directory name' do
fill_in :dir_name, with: new_dir_name
end
step 'I fill an existing directory name' do
fill_in :dir_name, with: 'files'
end
step 'I can see new file page' do
expect(page).to have_content "New File"
expect(page).to have_content "Commit message"
end
step 'I click on "Upload file"' do
click_button 'Upload file'
end
step 'I can see the new commit message' do
expect(page).to have_content "New commit message"
end
step 'I upload a new text file' do
drop_in_dropzone test_text_file
end
step 'I fill the upload file commit message' do
page.within('#modal-upload-blob') do
fill_in :commit_message, with: 'New commit message'
end
end
step 'I replace it with a text file' do
drop_in_dropzone test_text_file
end
step 'I fill the replace file commit message' do
page.within('#modal-upload-blob') do
fill_in :commit_message, with: 'Replacement file commit message'
end
end
step 'I can see the replacement commit message' do
expect(page).to have_content "Replacement file commit message"
end
step 'I can see the new text file' do
expect(page).to have_content "Lorem ipsum dolor sit amet"
expect(page).to have_content "Sed ut perspiciatis unde omnis"
end
step 'I click on files directory' do
click_link 'files'
end
step 'I click on History link' do
click_link 'History'
end
step 'I see Browse dir link' do
expect(page).to have_link 'Browse Directory'
expect(page).not_to have_link 'Browse Code'
end
step 'I click on readme file' do
page.within '.tree-table' do
click_link 'README.md'
end
end
step 'I see Browse file link' do
expect(page).to have_link 'Browse File'
expect(page).not_to have_link 'Browse Files'
end
step 'I see Browse code link' do
expect(page).to have_link 'Browse Files'
expect(page).not_to have_link 'Browse Directory'
end
step 'I click on Permalink' do
click_link 'Permalink'
end
step 'I am redirected to the files URL' do
expect(current_path).to eq project_tree_path(@project, 'master')
end
step 'I am redirected to the ".gitignore"' do
expect(current_path).to eq(project_blob_path(@project, 'master/.gitignore'))
end
step 'I am redirected to the permalink URL' do
expect(current_path).to(
eq(project_blob_path(@project,
@project.repository.commit.sha +
'/.gitignore'))
)
end
step 'I am redirected to the new file' do
expect(current_path).to eq(
project_blob_path(@project, 'master/' + new_file_name))
end
step 'I am redirected to the new file with directory' do
expect(current_path).to eq(
project_blob_path(@project, 'master/' + new_file_name_with_directory))
end
step 'I am redirected to the new merge request page' do
expect(current_path).to eq(project_new_merge_request_path(@project))
end
step "I am redirected to the fork's new merge request page" do
fork = @user.fork_of(@project)
expect(current_path).to eq(project_new_merge_request_path(fork))
end
step 'I am redirected to the root directory' do
expect(current_path).to eq(
project_tree_path(@project, 'master'))
end
step "I don't see the permalink link" do
expect(page).not_to have_link('permalink')
end
step 'I see "Unable to create directory"' do
expect(page).to have_content('A directory with this name already exists')
end
step 'I see "Path can contain only..."' do
expect(page).to have_content('Path can contain only')
end
step 'I see a commit error message' do
expect(page).to have_content('Your changes could not be committed')
end
step "I switch ref to 'test'" do
first('.js-project-refs-dropdown').click
page.within '.project-refs-form' do
click_link "'test'"
end
end
step "I switch ref to fix" do
first('.js-project-refs-dropdown').click
page.within '.project-refs-form' do
click_link 'fix'
end
end
step "I see the ref 'test' has been selected" do
expect(page).to have_selector '.dropdown-toggle-text', text: "'test'"
end
step "I visit the 'test' tree" do
visit project_tree_path(@project, "'test'")
end
step "I visit the fix tree" do
visit project_tree_path(@project, "fix/.testdir")
end
step 'I see the commit data' do
expect(page).to have_css('.tree-commit-link', visible: true)
expect(page).not_to have_content('Loading commit data...')
end
step 'I see the commit data for a directory with a leading dot' do
expect(page).to have_css('.tree-commit-link', visible: true)
expect(page).not_to have_content('Loading commit data...')
end
step 'I click on "files/lfs/lfs_object.iso" file in repo' do
allow_any_instance_of(Project).to receive(:lfs_enabled?).and_return(true)
visit project_tree_path(@project, "lfs")
click_link 'files'
click_link "lfs"
click_link "lfs_object.iso"
end
step 'I should see download link and object size' do
expect(page).to have_content 'Download (1.5 MB)'
end
step 'I should not see lfs pointer details' do
expect(page).not_to have_content 'version https://git-lfs.github.com/spec/v1'
expect(page).not_to have_content 'oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897'
expect(page).not_to have_content 'size 1575078'
end
step 'I should see buttons for allowed commands' do
page.within '.content' do
expect(page).to have_link 'Download'
expect(page).to have_content 'History'
expect(page).to have_content 'Permalink'
expect(page).not_to have_content 'Edit'
expect(page).not_to have_content 'Blame'
expect(page).to have_content 'Delete'
expect(page).to have_content 'Replace'
end
end
step 'I should see a Fork/Cancel combo' do
expect(page).to have_link 'Fork'
expect(page).to have_button 'Cancel'
end
step 'I should see a notice about a new fork having been created' do
expect(page).to have_content "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
end
# SVG files
step 'I upload a new SVG file' do
drop_in_dropzone test_svg_file
end
step 'I visit the SVG file' do
visit project_blob_path(@project, 'new_branch_name/logo_sample.svg')
end
step 'I can see the new rendered SVG image' do
expect(page).to have_css('.file-content img')
end
private
def set_new_content
find('#editor')
execute_script("ace.edit('editor').setValue('#{new_gitignore_content}')")
end
# Content of the gitignore file on the seed repository.
def old_gitignore_content
'*.rbc'
end
# Constant value that differs from the content
# of the gitignore of the seed repository.
def new_gitignore_content
old_gitignore_content + 'a'
end
# Constant value that is a valid filename and
# not a filename present at root of the seed repository.
def new_file_name
'not_a_file.md'
end
# Constant value that is a valid filename with directory and
# not a filename present at root of the seed repository.
def new_file_name_with_directory
'foo/bar/baz.txt'
end
# Constant value that is a valid directory and
# not a directory present at root of the seed repository.
def new_dir_name
'new_dir/subdir'
end
def drop_in_dropzone(file_path)
# Generate a fake input selector
page.execute_script <<-JS
var fakeFileInput = window.$('<input/>').attr(
{id: 'fakeFileInput', type: 'file'}
).appendTo('body');
JS
# Attach the file to the fake input selector with Capybara
attach_file("fakeFileInput", file_path)
# Add the file to a fileList array and trigger the fake drop event
page.execute_script <<-JS
var fileList = [$('#fakeFileInput')[0].files[0]];
var e = jQuery.Event('drop', { dataTransfer : { files : fileList } });
$('.dropzone')[0].dropzone.listeners[0].events.drop(e);
JS
end
def test_text_file
File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt')
end
def test_image_file
File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
end
def test_svg_file
File.join(Rails.root, 'spec', 'fixtures', 'logo_sample.svg')
end
end
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
module SharedPaths
include Spinach::DSL
include RepoHelpers
include DashboardHelper
include WaitForRequests
step 'I visit new project page' do
visit new_project_path
end
step 'I visit login page' do
visit new_user_session_path
end
# ----------------------------------------
# User
# ----------------------------------------
step 'I visit user "John Doe" page' do
visit user_path("john_doe")
end
# ----------------------------------------
# Group
# ----------------------------------------
step 'I visit group "Owned" page' do
visit group_path(Group.find_by(name: "Owned"))
end
step 'I visit group "Owned" activity page' do
visit activity_group_path(Group.find_by(name: "Owned"))
end
step 'I visit group "Owned" issues page' do
visit issues_group_path(Group.find_by(name: "Owned"))
end
step 'I visit group "Owned" merge requests page' do
visit merge_requests_group_path(Group.find_by(name: "Owned"))
end
step 'I visit group "Owned" milestones page' do
visit group_milestones_path(Group.find_by(name: "Owned"))
end
step 'I visit group "Owned" members page' do
visit group_group_members_path(Group.find_by(name: "Owned"))
end
step 'I visit group "Owned" projects page' do
visit projects_group_path(Group.find_by(name: "Owned"))
end
step 'I visit group "Guest" page' do
visit group_path(Group.find_by(name: "Guest"))
end
step 'I visit group "Guest" issues page' do
visit issues_group_path(Group.find_by(name: "Guest"))
end
step 'I visit group "Guest" merge requests page' do
visit merge_requests_group_path(Group.find_by(name: "Guest"))
end
step 'I visit group "Guest" members page' do
visit group_group_members_path(Group.find_by(name: "Guest"))
end
step 'I visit group "Guest" settings page' do
visit edit_group_path(Group.find_by(name: "Guest"))
end
# ----------------------------------------
# Dashboard
# ----------------------------------------
step 'I visit dashboard page' do
visit dashboard_projects_path
end
step 'I visit dashboard activity page' do
visit activity_dashboard_path
end
step 'I visit dashboard projects page' do
visit projects_dashboard_path
end
step 'I visit dashboard issues page' do
visit assigned_issues_dashboard_path
end
step 'I visit dashboard search page' do
visit search_path
end
step 'I visit dashboard help page' do
visit help_path
end
step 'I visit dashboard groups page' do
visit dashboard_groups_path
end
step 'I should be redirected to the dashboard groups page' do
expect(current_path).to eq dashboard_groups_path
end
step 'I visit dashboard starred projects page' do
visit starred_dashboard_projects_path
end
# ----------------------------------------
# Profile
# ----------------------------------------
step 'I visit profile page' do
visit profile_path
end
step 'I visit profile applications page' do
visit applications_profile_path
end
step 'I visit profile password page' do
visit edit_profile_password_path
end
step 'I visit profile account page' do
visit profile_account_path
end
step 'I visit profile SSH keys page' do
visit profile_keys_path
end
step 'I visit profile preferences page' do
visit profile_preferences_path
end
step 'I visit Authentication log page' do
visit audit_log_profile_path
end
# ----------------------------------------
# Admin
# ----------------------------------------
step 'I visit admin page' do
visit admin_root_path
end
step 'I visit abuse reports page' do
visit admin_abuse_reports_path
end
step 'I visit admin projects page' do
visit admin_projects_path
end
step 'I visit admin users page' do
visit admin_users_path
end
step 'I visit admin logs page' do
visit admin_logs_path
end
step 'I visit admin messages page' do
visit admin_broadcast_messages_path
end
step 'I visit admin hooks page' do
visit admin_hooks_path
end
step 'I visit admin Resque page' do
visit admin_background_jobs_path
end
step 'I visit admin teams page' do
visit admin_teams_path
end
step 'I visit spam logs page' do
visit admin_spam_logs_path
end
# ----------------------------------------
# Generic Project
# ----------------------------------------
step "I visit my project's settings page" do
visit edit_project_path(@project)
end
step 'I visit a binary file in the repo' do
visit project_blob_path(@project,
File.join(root_ref, 'files/images/logo-black.png'))
end
step "I visit my project's commits page" do
visit project_commits_path(@project, root_ref, { limit: 5 })
end
step "I visit my project's commits page for a specific path" do
visit project_commits_path(@project, root_ref + "/files/ruby/regex.rb", { limit: 5 })
end
step 'I visit my project\'s commits stats page' do
visit stats_project_repository_path(@project)
end
step "I visit my project's graph page" do
# Stub Graph max_size to speed up test (10 commits vs. 650)
Network::Graph.stub(max_count: 10)
visit project_network_path(@project, root_ref)
end
step "I visit my project's issues page" do
visit project_issues_path(@project)
end
step "I visit my project's merge requests page" do
visit project_merge_requests_path(@project)
end
step "I visit my project's members page" do
visit project_project_members_path(@project)
end
step "I visit my project's wiki page" do
visit project_wiki_path(@project, :home)
end
step 'I visit project hooks page' do
visit project_settings_integrations_path(@project)
end
step 'I visit project find file page' do
visit project_find_file_path(@project, root_ref)
end
# ----------------------------------------
# "Shop" Project
# ----------------------------------------
step 'I visit project "Shop" page' do
visit project_path(project)
end
step 'I visit edit project "Shop" page' do
visit edit_project_path(project)
end
step 'I visit compare refs page' do
visit project_compare_index_path(@project)
end
step 'I visit project commits page' do
visit project_commits_path(@project, root_ref, { limit: 5 })
end
step 'I visit project commits page for stable branch' do
visit project_commits_path(@project, 'stable', { limit: 5 })
end
step 'I visit blob file from repo' do
visit project_blob_path(@project, File.join(sample_commit.id, sample_blob.path))
end
step 'I visit ".gitignore" file in repo' do
visit project_blob_path(@project, File.join(root_ref, '.gitignore'))
end
step 'I am on the new file page' do
expect(current_path).to eq(project_create_blob_path(@project, root_ref))
end
step 'I am on the ".gitignore" edit file page' do
expect(current_path).to eq(
project_edit_blob_path(@project, File.join(root_ref, '.gitignore')))
end
step 'I visit project source page for "6d39438"' do
visit project_tree_path(@project, "6d39438")
end
step 'I visit project source page for' \
' "6d394385cf567f80a8fd85055db1ab4c5295806f"' do
visit project_tree_path(@project,
'6d394385cf567f80a8fd85055db1ab4c5295806f')
end
step 'I visit project tags page' do
visit project_tags_path(@project)
end
step 'I visit issue page "Release 0.4"' do
issue = Issue.find_by(title: "Release 0.4")
visit project_issue_path(issue.project, issue)
end
step 'I visit project "Forum" labels page' do
project = Project.find_by(name: 'Forum')
visit project_labels_path(project)
end
step 'I visit project "Shop" new label page' do
project = Project.find_by(name: 'Shop')
visit new_project_label_path(project)
end
step 'I visit project "Forum" new label page' do
project = Project.find_by(name: 'Forum')
visit new_project_label_path(project)
end
step 'I visit merge request page "Bug NS-04"' do
visit merge_request_path("Bug NS-04")
wait_for_requests
end
step 'I visit merge request page "Bug NS-07"' do
visit merge_request_path("Bug NS-07")
wait_for_requests
end
step 'I visit merge request page "Bug NS-08"' do
visit merge_request_path("Bug NS-08")
wait_for_requests
end
step 'I visit merge request page "Bug CO-01"' do
mr = MergeRequest.find_by(title: "Bug CO-01")
visit project_merge_request_path(mr.target_project, mr)
wait_for_requests
end
step 'I visit forked project "Shop" merge requests page' do
visit project_merge_requests_path(project)
end
step 'I visit project "Shop" team page' do
visit project_project_members_path(project)
end
step 'I visit project wiki page' do
visit project_wiki_path(@project, :home)
end
# ----------------------------------------
# Visibility Projects
# ----------------------------------------
step 'I visit project "Community" source page' do
project = Project.find_by(name: 'Community')
visit project_tree_path(project, root_ref)
end
step 'I visit project "Internal" page' do
project = Project.find_by(name: "Internal")
visit project_path(project)
end
step 'I visit project "Enterprise" page' do
project = Project.find_by(name: "Enterprise")
visit project_path(project)
end
# ----------------------------------------
# Empty Projects
# ----------------------------------------
step "I should not see command line instructions" do
expect(page).not_to have_css('.empty_wrapper')
end
# ----------------------------------------
# Public Projects
# ----------------------------------------
step 'I visit the public groups area' do
visit explore_groups_path
end
# ----------------------------------------
# Snippets
# ----------------------------------------
step 'I visit project "Shop" snippets page' do
visit project_snippets_path(project)
end
step 'I visit snippets page' do
visit explore_snippets_path
end
def root_ref
@project.repository.root_ref
end
def project
Project.find_by!(name: 'Shop')
end
def merge_request_path(title)
mr = MergeRequest.find_by(title: title)
project_merge_request_path(mr.target_project, mr)
end
end
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