summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
authorRegis <boudinot.regis@yahoo.com>2017-03-21 09:08:28 -0600
committerRegis <boudinot.regis@yahoo.com>2017-03-21 09:08:28 -0600
commit0b75b821c6cfd173291fcfd88c41da9922d082dd (patch)
tree41b578d299bd77423aa3591955a4cb5ca07ab025 /spec/features
parent6342da7bb6cbba1b1e026fc62a1da42b811b25f4 (diff)
parenta08c707c928092426e2334423e71c6b841309ddf (diff)
downloadgitlab-ce-issue-title-vue.tar.gz
update to current master and fix conflictsissue-title-vue
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/admin/admin_settings_spec.rb10
-rw-r--r--spec/features/atom/dashboard_issues_spec.rb15
-rw-r--r--spec/features/atom/issues_spec.rb11
-rw-r--r--spec/features/boards/add_issues_modal_spec.rb6
-rw-r--r--spec/features/boards/modal_filter_spec.rb183
-rw-r--r--spec/features/copy_as_gfm_spec.rb785
-rw-r--r--spec/features/dashboard/projects_spec.rb26
-rw-r--r--spec/features/groups/group_name_toggle_spec.rb44
-rw-r--r--spec/features/issues/award_emoji_spec.rb15
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb5
-rw-r--r--spec/features/issues/filtered_search/dropdown_milestone_spec.rb8
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb11
-rw-r--r--spec/features/issues_spec.rb20
-rw-r--r--spec/features/merge_requests/created_from_fork_spec.rb3
-rw-r--r--spec/features/merge_requests/reset_filters_spec.rb20
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb1
-rw-r--r--spec/features/profiles/user_changes_notified_of_own_activity_spec.rb32
-rw-r--r--spec/features/projects/blobs/user_create_spec.rb18
-rw-r--r--spec/features/projects/branches_spec.rb8
-rw-r--r--spec/features/projects/commit/mini_pipeline_graph_spec.rb55
-rw-r--r--spec/features/projects/compare_spec.rb8
-rw-r--r--spec/features/projects/group_links_spec.rb24
-rw-r--r--spec/features/projects/import_export/test_project_export.tar.gzbin681799 -> 679892 bytes
-rw-r--r--spec/features/projects/labels/issues_sorted_by_priority_spec.rb4
-rw-r--r--spec/features/projects/new_project_spec.rb9
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb32
-rw-r--r--spec/features/projects/services/slack_service_spec.rb4
-rw-r--r--spec/features/projects/settings/merge_requests_settings_spec.rb23
-rw-r--r--spec/features/projects/user_create_dir_spec.rb72
-rw-r--r--spec/features/projects/wiki/user_git_access_wiki_page_spec.rb26
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb33
-rw-r--r--spec/features/projects/wiki/user_views_project_wiki_page_spec.rb44
-rw-r--r--spec/features/projects_spec.rb4
-rw-r--r--spec/features/tags/master_views_tags_spec.rb10
-rw-r--r--spec/features/todos/todos_spec.rb56
35 files changed, 1102 insertions, 523 deletions
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index de42ab81fac..03daab12c8f 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -9,6 +9,13 @@ feature 'Admin updates settings', feature: true do
visit admin_application_settings_path
end
+ scenario 'Change visibility settings' do
+ choose "application_setting_default_project_visibility_20"
+ click_button 'Save'
+
+ expect(page).to have_content "Application settings saved successfully"
+ end
+
scenario 'Change application settings' do
uncheck 'Gravatar enabled'
fill_in 'Home page URL', with: 'https://about.gitlab.com/'
@@ -26,7 +33,7 @@ feature 'Admin updates settings', feature: true do
fill_in 'Webhook', with: 'http://localhost'
fill_in 'Username', with: 'test_user'
fill_in 'service_push_channel', with: '#test_channel'
- page.check('Notify only broken builds')
+ page.check('Notify only broken pipelines')
check_all_events
click_on 'Save'
@@ -50,7 +57,6 @@ feature 'Admin updates settings', feature: true do
page.check('Note')
page.check('Issue')
page.check('Merge request')
- page.check('Build')
page.check('Pipeline')
end
end
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb
index a7c22615b89..58b14e09740 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/features/atom/dashboard_issues_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
describe "Dashboard Issues Feed", feature: true do
describe "GET /issues" do
- let!(:user) { create(:user) }
+ let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
+ let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
let!(:project1) { create(:project) }
let!(:project2) { create(:project) }
@@ -31,7 +32,7 @@ describe "Dashboard Issues Feed", feature: true do
end
context "issue with basic fields" do
- let!(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'test desc') }
+ let!(:issue2) { create(:issue, author: user, assignee: assignee, project: project2, description: 'test desc') }
it "renders issue fields" do
visit issues_dashboard_path(:atom, private_token: user.private_token)
@@ -39,8 +40,8 @@ describe "Dashboard Issues Feed", feature: true do
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]")
expect(entry).to be_present
- expect(entry).to have_selector('author email', text: issue2.author_email)
- expect(entry).to have_selector('assignee email', text: issue2.author_email)
+ expect(entry).to have_selector('author email', text: issue2.author_public_email)
+ expect(entry).to have_selector('assignee email', text: issue2.assignee_public_email)
expect(entry).not_to have_selector('labels')
expect(entry).not_to have_selector('milestone')
expect(entry).to have_selector('description', text: issue2.description)
@@ -50,7 +51,7 @@ describe "Dashboard Issues Feed", feature: true do
context "issue with label and milestone" do
let!(:milestone1) { create(:milestone, project: project1, title: 'v1') }
let!(:label1) { create(:label, project: project1, title: 'label1') }
- let!(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone1) }
+ let!(:issue1) { create(:issue, author: user, assignee: assignee, project: project1, milestone: milestone1) }
before do
issue1.labels << label1
@@ -62,8 +63,8 @@ describe "Dashboard Issues Feed", feature: true do
entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]")
expect(entry).to be_present
- expect(entry).to have_selector('author email', text: issue1.author_email)
- expect(entry).to have_selector('assignee email', text: issue1.author_email)
+ expect(entry).to have_selector('author email', text: issue1.author_public_email)
+ expect(entry).to have_selector('assignee email', text: issue1.assignee_public_email)
expect(entry).to have_selector('labels label', text: label1.title)
expect(entry).to have_selector('milestone', text: milestone1.title)
expect(entry).not_to have_selector('description')
diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb
index a01a050a013..b3903ec2faf 100644
--- a/spec/features/atom/issues_spec.rb
+++ b/spec/features/atom/issues_spec.rb
@@ -2,10 +2,11 @@ require 'spec_helper'
describe 'Issues Feed', feature: true do
describe 'GET /issues' do
- let!(:user) { create(:user) }
+ let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') }
+ let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') }
let!(:group) { create(:group) }
let!(:project) { create(:project) }
- let!(:issue) { create(:issue, author: user, project: project) }
+ let!(:issue) { create(:issue, author: user, assignee: assignee, project: project) }
before do
project.team << [user, :developer]
@@ -20,7 +21,8 @@ describe 'Issues Feed', feature: true do
expect(response_headers['Content-Type']).
to have_content('application/atom+xml')
expect(body).to have_selector('title', text: "#{project.name} issues")
- expect(body).to have_selector('author email', text: issue.author_email)
+ expect(body).to have_selector('author email', text: issue.author_public_email)
+ expect(body).to have_selector('assignee email', text: issue.author_public_email)
expect(body).to have_selector('entry summary', text: issue.title)
end
end
@@ -33,7 +35,8 @@ describe 'Issues Feed', feature: true do
expect(response_headers['Content-Type']).
to have_content('application/atom+xml')
expect(body).to have_selector('title', text: "#{project.name} issues")
- expect(body).to have_selector('author email', text: issue.author_email)
+ expect(body).to have_selector('author email', text: issue.author_public_email)
+ expect(body).to have_selector('assignee email', text: issue.author_public_email)
expect(body).to have_selector('entry summary', text: issue.title)
end
end
diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb
index f7f2d883d2f..d17a418b8c3 100644
--- a/spec/features/boards/add_issues_modal_spec.rb
+++ b/spec/features/boards/add_issues_modal_spec.rb
@@ -107,6 +107,9 @@ describe 'Issue Boards add issue modal', :feature, :js do
it 'returns issues' do
page.within('.add-issues-modal') do
find('.form-control').native.send_keys(issue.title)
+ find('.form-control').native.send_keys(:enter)
+
+ wait_for_vue_resource
expect(page).to have_selector('.card', count: 1)
end
@@ -115,6 +118,9 @@ describe 'Issue Boards add issue modal', :feature, :js do
it 'returns no issues' do
page.within('.add-issues-modal') do
find('.form-control').native.send_keys('testing search')
+ find('.form-control').native.send_keys(:enter)
+
+ wait_for_vue_resource
expect(page).not_to have_selector('.card')
expect(page).not_to have_content("You haven't added any issues to your project yet")
diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb
index 1cf0d11d448..e2281a7da55 100644
--- a/spec/features/boards/modal_filter_spec.rb
+++ b/spec/features/boards/modal_filter_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
describe 'Issue Boards add issue modal filtering', :feature, :js do
- include WaitForAjax
include WaitForVueResource
let(:project) { create(:empty_project, :public) }
@@ -23,6 +22,7 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
page.within('.add-issues-modal') do
find('.form-control').native.send_keys('testing empty state')
+ find('.form-control').native.send_keys(:enter)
wait_for_vue_resource
@@ -33,13 +33,11 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
it 'restores filters when closing' do
visit_board
- page.within('.add-issues-modal') do
- click_button 'Milestone'
-
- wait_for_ajax
-
- click_link 'Upcoming'
+ set_filter('milestone')
+ click_filter_link('Upcoming')
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
expect(page).to have_selector('.card', count: 0)
@@ -56,39 +54,44 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
end
end
- context 'author' do
- let!(:issue) { create(:issue, project: project, author: user2) }
-
- before do
- project.team << [user2, :developer]
+ it 'resotres filters after clicking clear button' do
+ visit_board
- visit_board
- end
+ set_filter('milestone')
+ click_filter_link('Upcoming')
+ submit_filter
- it 'filters by any author' do
- page.within('.add-issues-modal') do
- click_button 'Author'
+ page.within('.add-issues-modal') do
+ wait_for_vue_resource
- wait_for_ajax
+ expect(page).to have_selector('.card', count: 0)
- click_link 'Any Author'
+ find('.clear-search').click
- wait_for_vue_resource
+ wait_for_vue_resource
- expect(page).to have_selector('.card', count: 2)
- end
+ expect(page).to have_selector('.card', count: 1)
end
+ end
- it 'filters by selected user' do
- page.within('.add-issues-modal') do
- click_button 'Author'
+ context 'author' do
+ let!(:issue) { create(:issue, project: project, author: user2) }
+
+ before do
+ project.team << [user2, :developer]
- wait_for_ajax
+ visit_board
+ end
- click_link user2.name
+ it 'filters by selected user' do
+ set_filter('author')
+ click_filter_link(user2.name)
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
+ expect(page).to have_selector('.js-visual-token', text: user2.username)
expect(page).to have_selector('.card', count: 1)
end
end
@@ -103,46 +106,28 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
visit_board
end
- it 'filters by any assignee' do
- page.within('.add-issues-modal') do
- click_button 'Assignee'
-
- wait_for_ajax
-
- click_link 'Any Assignee'
-
- wait_for_vue_resource
-
- expect(page).to have_selector('.card', count: 2)
- end
- end
-
it 'filters by unassigned' do
- page.within('.add-issues-modal') do
- click_button 'Assignee'
-
- wait_for_ajax
-
- click_link 'Unassigned'
+ set_filter('assignee')
+ click_filter_link('No Assignee')
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
+ expect(page).to have_selector('.js-visual-token', text: 'none')
expect(page).to have_selector('.card', count: 1)
end
end
it 'filters by selected user' do
- page.within('.add-issues-modal') do
- click_button 'Assignee'
-
- wait_for_ajax
-
- page.within '.dropdown-menu-user' do
- click_link user2.name
- end
+ set_filter('assignee')
+ click_filter_link(user2.name)
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
+ expect(page).to have_selector('.js-visual-token', text: user2.username)
expect(page).to have_selector('.card', count: 1)
end
end
@@ -156,44 +141,28 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
visit_board
end
- it 'filters by any milestone' do
- page.within('.add-issues-modal') do
- click_button 'Milestone'
-
- wait_for_ajax
-
- click_link 'Any Milestone'
-
- wait_for_vue_resource
-
- expect(page).to have_selector('.card', count: 2)
- end
- end
-
it 'filters by upcoming milestone' do
- page.within('.add-issues-modal') do
- click_button 'Milestone'
-
- wait_for_ajax
-
- click_link 'Upcoming'
+ set_filter('milestone')
+ click_filter_link('Upcoming')
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
+ expect(page).to have_selector('.js-visual-token', text: 'upcoming')
expect(page).to have_selector('.card', count: 0)
end
end
it 'filters by selected milestone' do
- page.within('.add-issues-modal') do
- click_button 'Milestone'
-
- wait_for_ajax
-
- click_link milestone.name
+ set_filter('milestone')
+ click_filter_link(milestone.name)
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
+ expect(page).to have_selector('.js-visual-token', text: milestone.name)
expect(page).to have_selector('.card', count: 1)
end
end
@@ -207,44 +176,28 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
visit_board
end
- it 'filters by any label' do
- page.within('.add-issues-modal') do
- click_button 'Label'
-
- wait_for_ajax
-
- click_link 'Any Label'
-
- wait_for_vue_resource
-
- expect(page).to have_selector('.card', count: 2)
- end
- end
-
it 'filters by no label' do
- page.within('.add-issues-modal') do
- click_button 'Label'
-
- wait_for_ajax
-
- click_link 'No Label'
+ set_filter('label')
+ click_filter_link('No Label')
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
+ expect(page).to have_selector('.js-visual-token', text: 'none')
expect(page).to have_selector('.card', count: 1)
end
end
it 'filters by label' do
- page.within('.add-issues-modal') do
- click_button 'Label'
-
- wait_for_ajax
-
- click_link label.title
+ set_filter('label')
+ click_filter_link(label.title)
+ submit_filter
+ page.within('.add-issues-modal') do
wait_for_vue_resource
+ expect(page).to have_selector('.js-visual-token', text: label.title)
expect(page).to have_selector('.card', count: 1)
end
end
@@ -256,4 +209,20 @@ describe 'Issue Boards add issue modal filtering', :feature, :js do
click_button('Add issues')
end
+
+ def set_filter(type, text = '')
+ find('.add-issues-modal .filtered-search').native.send_keys("#{type}:#{text}")
+ end
+
+ def submit_filter
+ find('.add-issues-modal .filtered-search').native.send_keys(:enter)
+ end
+
+ def click_filter_link(link_text)
+ page.within('.add-issues-modal .filtered-search-input-container') do
+ expect(page).to have_button(link_text)
+
+ click_button(link_text)
+ end
+ end
end
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb
index 4638812b2d9..55df7e45f79 100644
--- a/spec/features/copy_as_gfm_spec.rb
+++ b/spec/features/copy_as_gfm_spec.rb
@@ -2,437 +2,594 @@ require 'spec_helper'
describe 'Copy as GFM', feature: true, js: true do
include GitlabMarkdownHelper
+ include RepoHelpers
include ActionView::Helpers::JavaScriptHelper
before do
- @feat = MarkdownFeature.new
+ login_as :admin
+ end
- # `markdown` helper expects a `@project` variable
- @project = @feat.project
+ describe 'Copying rendered GFM' do
+ before do
+ @feat = MarkdownFeature.new
- visit namespace_project_issue_path(@project.namespace, @project, @feat.issue)
- end
+ # `markdown` helper expects a `@project` variable
+ @project = @feat.project
- # The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert GitLab Flavored Markdown (GFM) to HTML.
- # The handlers defined in app/assets/javascripts/copy_as_gfm.js.es6 consequently convert that same HTML to GFM.
- # To make sure these filters and handlers are properly aligned, this spec tests the GFM-to-HTML-to-GFM cycle
- # by verifying (`html_to_gfm(gfm_to_html(gfm)) == gfm`) for a number of examples of GFM for every filter, using the `verify` helper.
+ visit namespace_project_issue_path(@project.namespace, @project, @feat.issue)
+ end
- # These are all in a single `it` for performance reasons.
- it 'works', :aggregate_failures do
- verify(
- 'nesting',
+ # The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert GitLab Flavored Markdown (GFM) to HTML.
+ # The handlers defined in app/assets/javascripts/copy_as_gfm.js consequently convert that same HTML to GFM.
+ # To make sure these filters and handlers are properly aligned, this spec tests the GFM-to-HTML-to-GFM cycle
+ # by verifying (`html_to_gfm(gfm_to_html(gfm)) == gfm`) for a number of examples of GFM for every filter, using the `verify` helper.
- '> 1. [x] **[$`2 + 2`$ {-=-}{+=+} 2^2 ~~:thumbsup:~~](http://google.com)**'
- )
+ # These are all in a single `it` for performance reasons.
+ it 'works', :aggregate_failures do
+ verify(
+ 'nesting',
- verify(
- 'a real world example from the gitlab-ce README',
+ '> 1. [x] **[$`2 + 2`$ {-=-}{+=+} 2^2 ~~:thumbsup:~~](http://google.com)**'
+ )
- <<-GFM.strip_heredoc
- # GitLab
+ verify(
+ 'a real world example from the gitlab-ce README',
- [![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
- [![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby)
- [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
- [![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
+ <<-GFM.strip_heredoc
+ # GitLab
- ## Canonical source
+ [![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
+ [![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby)
+ [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
+ [![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
- The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/).
+ ## Canonical source
- ## Open source software to collaborate on code
+ The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/).
- To see how GitLab looks please see the [features page on our website](https://about.gitlab.com/features/).
+ ## Open source software to collaborate on code
+ To see how GitLab looks please see the [features page on our website](https://about.gitlab.com/features/).
- - Manage Git repositories with fine grained access controls that keep your code secure
- - Perform code reviews and enhance collaboration with merge requests
+ - Manage Git repositories with fine grained access controls that keep your code secure
- - Complete continuous integration (CI) and CD pipelines to builds, test, and deploy your applications
+ - Perform code reviews and enhance collaboration with merge requests
- - Each project can also have an issue tracker, issue board, and a wiki
+ - Complete continuous integration (CI) and CD pipelines to builds, test, and deploy your applications
- - Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises
+ - Each project can also have an issue tracker, issue board, and a wiki
- - Completely free and open source (MIT Expat license)
- GFM
- )
+ - Used by more than 100,000 organizations, GitLab is the most popular solution to manage Git repositories on-premises
- verify(
- 'InlineDiffFilter',
+ - Completely free and open source (MIT Expat license)
+ GFM
+ )
- '{-Deleted text-}',
- '{+Added text+}'
- )
+ verify(
+ 'InlineDiffFilter',
- verify(
- 'TaskListFilter',
+ '{-Deleted text-}',
+ '{+Added text+}'
+ )
- '- [ ] Unchecked task',
- '- [x] Checked task',
- '1. [ ] Unchecked numbered task',
- '1. [x] Checked numbered task'
- )
+ verify(
+ 'TaskListFilter',
- verify(
- 'ReferenceFilter',
+ '- [ ] Unchecked task',
+ '- [x] Checked task',
+ '1. [ ] Unchecked numbered task',
+ '1. [x] Checked numbered task'
+ )
- # issue reference
- @feat.issue.to_reference,
- # full issue reference
- @feat.issue.to_reference(full: true),
- # issue URL
- namespace_project_issue_url(@project.namespace, @project, @feat.issue),
- # issue URL with note anchor
- namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123'),
- # issue link
- "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue)})",
- # issue link with note anchor
- "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123')})",
- )
+ verify(
+ 'ReferenceFilter',
- verify(
- 'AutolinkFilter',
+ # issue reference
+ @feat.issue.to_reference,
+ # full issue reference
+ @feat.issue.to_reference(full: true),
+ # issue URL
+ namespace_project_issue_url(@project.namespace, @project, @feat.issue),
+ # issue URL with note anchor
+ namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123'),
+ # issue link
+ "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue)})",
+ # issue link with note anchor
+ "[Issue](#{namespace_project_issue_url(@project.namespace, @project, @feat.issue, anchor: 'note_123')})",
+ )
- 'https://example.com'
- )
+ verify(
+ 'AutolinkFilter',
- verify(
- 'TableOfContentsFilter',
+ 'https://example.com'
+ )
- '[[_TOC_]]'
- )
+ verify(
+ 'TableOfContentsFilter',
- verify(
- 'EmojiFilter',
+ '[[_TOC_]]'
+ )
- ':thumbsup:'
- )
+ verify(
+ 'EmojiFilter',
- verify(
- 'ImageLinkFilter',
-
- '![Image](https://example.com/image.png)'
- )
+ ':thumbsup:'
+ )
- verify(
- 'VideoLinkFilter',
+ verify(
+ 'ImageLinkFilter',
+
+ '![Image](https://example.com/image.png)'
+ )
- '![Video](https://example.com/video.mp4)'
- )
+ verify(
+ 'VideoLinkFilter',
- verify(
- 'MathFilter: math as converted from GFM to HTML',
+ '![Video](https://example.com/video.mp4)'
+ )
- '$`c = \pm\sqrt{a^2 + b^2}`$',
+ verify(
+ 'MathFilter: math as converted from GFM to HTML',
- # math block
- <<-GFM.strip_heredoc
- ```math
- c = \pm\sqrt{a^2 + b^2}
- ```
- GFM
- )
+ '$`c = \pm\sqrt{a^2 + b^2}`$',
- aggregate_failures('MathFilter: math as transformed from HTML to KaTeX') do
- gfm = '$`c = \pm\sqrt{a^2 + b^2}`$'
+ # math block
+ <<-GFM.strip_heredoc
+ ```math
+ c = \pm\sqrt{a^2 + b^2}
+ ```
+ GFM
+ )
- html = <<-HTML.strip_heredoc
- <span class="katex">
- <span class="katex-mathml">
- <math>
- <semantics>
- <mrow>
- <mi>c</mi>
- <mo>=</mo>
- <mo>±</mo>
- <msqrt>
- <mrow>
- <msup>
- <mi>a</mi>
- <mn>2</mn>
- </msup>
- <mo>+</mo>
- <msup>
- <mi>b</mi>
- <mn>2</mn>
- </msup>
- </mrow>
- </msqrt>
- </mrow>
- <annotation encoding="application/x-tex">c = \\pm\\sqrt{a^2 + b^2}</annotation>
- </semantics>
- </math>
- </span>
- <span class="katex-html" aria-hidden="true">
- <span class="strut" style="height: 0.913389em;"></span>
- <span class="strut bottom" style="height: 1.04em; vertical-align: -0.126611em;"></span>
- <span class="base textstyle uncramped">
- <span class="mord mathit">c</span>
- <span class="mrel">=</span>
- <span class="mord">±</span>
- <span class="sqrt mord"><span class="sqrt-sign" style="top: -0.073389em;">
- <span class="style-wrap reset-textstyle textstyle uncramped">√</span>
- </span>
- <span class="vlist">
- <span class="" style="top: 0em;">
- <span class="fontsize-ensurer reset-size5 size5">
- <span class="" style="font-size: 1em;">​</span>
- </span>
- <span class="mord textstyle cramped">
- <span class="mord">
- <span class="mord mathit">a</span>
- <span class="msupsub">
- <span class="vlist">
- <span class="" style="top: -0.289em; margin-right: 0.05em;">
- <span class="fontsize-ensurer reset-size5 size5">
- <span class="" style="font-size: 0em;">​</span>
- </span>
- <span class="reset-textstyle scriptstyle cramped">
- <span class="mord mathrm">2</span>
+ aggregate_failures('MathFilter: math as transformed from HTML to KaTeX') do
+ gfm = '$`c = \pm\sqrt{a^2 + b^2}`$'
+
+ html = <<-HTML.strip_heredoc
+ <span class="katex">
+ <span class="katex-mathml">
+ <math>
+ <semantics>
+ <mrow>
+ <mi>c</mi>
+ <mo>=</mo>
+ <mo>±</mo>
+ <msqrt>
+ <mrow>
+ <msup>
+ <mi>a</mi>
+ <mn>2</mn>
+ </msup>
+ <mo>+</mo>
+ <msup>
+ <mi>b</mi>
+ <mn>2</mn>
+ </msup>
+ </mrow>
+ </msqrt>
+ </mrow>
+ <annotation encoding="application/x-tex">c = \\pm\\sqrt{a^2 + b^2}</annotation>
+ </semantics>
+ </math>
+ </span>
+ <span class="katex-html" aria-hidden="true">
+ <span class="strut" style="height: 0.913389em;"></span>
+ <span class="strut bottom" style="height: 1.04em; vertical-align: -0.126611em;"></span>
+ <span class="base textstyle uncramped">
+ <span class="mord mathit">c</span>
+ <span class="mrel">=</span>
+ <span class="mord">±</span>
+ <span class="sqrt mord"><span class="sqrt-sign" style="top: -0.073389em;">
+ <span class="style-wrap reset-textstyle textstyle uncramped">√</span>
+ </span>
+ <span class="vlist">
+ <span class="" style="top: 0em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 1em;">​</span>
+ </span>
+ <span class="mord textstyle cramped">
+ <span class="mord">
+ <span class="mord mathit">a</span>
+ <span class="msupsub">
+ <span class="vlist">
+ <span class="" style="top: -0.289em; margin-right: 0.05em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ <span class="reset-textstyle scriptstyle cramped">
+ <span class="mord mathrm">2</span>
+ </span>
</span>
+ <span class="baseline-fix">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ ​</span>
</span>
- <span class="baseline-fix">
- <span class="fontsize-ensurer reset-size5 size5">
- <span class="" style="font-size: 0em;">​</span>
- </span>
- ​</span>
</span>
</span>
- </span>
- <span class="mbin">+</span>
- <span class="mord">
- <span class="mord mathit">b</span>
- <span class="msupsub">
- <span class="vlist">
- <span class="" style="top: -0.289em; margin-right: 0.05em;">
- <span class="fontsize-ensurer reset-size5 size5">
- <span class="" style="font-size: 0em;">​</span>
- </span>
- <span class="reset-textstyle scriptstyle cramped">
- <span class="mord mathrm">2</span>
+ <span class="mbin">+</span>
+ <span class="mord">
+ <span class="mord mathit">b</span>
+ <span class="msupsub">
+ <span class="vlist">
+ <span class="" style="top: -0.289em; margin-right: 0.05em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ <span class="reset-textstyle scriptstyle cramped">
+ <span class="mord mathrm">2</span>
+ </span>
</span>
+ <span class="baseline-fix">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 0em;">​</span>
+ </span>
+ ​</span>
</span>
- <span class="baseline-fix">
- <span class="fontsize-ensurer reset-size5 size5">
- <span class="" style="font-size: 0em;">​</span>
- </span>
- ​</span>
</span>
</span>
</span>
</span>
- </span>
- <span class="" style="top: -0.833389em;">
- <span class="fontsize-ensurer reset-size5 size5">
- <span class="" style="font-size: 1em;">​</span>
+ <span class="" style="top: -0.833389em;">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 1em;">​</span>
+ </span>
+ <span class="reset-textstyle textstyle uncramped sqrt-line"></span>
</span>
- <span class="reset-textstyle textstyle uncramped sqrt-line"></span>
+ <span class="baseline-fix">
+ <span class="fontsize-ensurer reset-size5 size5">
+ <span class="" style="font-size: 1em;">​</span>
+ </span>
+ ​</span>
</span>
- <span class="baseline-fix">
- <span class="fontsize-ensurer reset-size5 size5">
- <span class="" style="font-size: 1em;">​</span>
- </span>
- ​</span>
</span>
</span>
</span>
</span>
- </span>
- HTML
+ HTML
- output_gfm = html_to_gfm(html)
- expect(output_gfm.strip).to eq(gfm.strip)
- end
+ output_gfm = html_to_gfm(html)
+ expect(output_gfm.strip).to eq(gfm.strip)
+ end
- verify(
- 'SanitizationFilter',
+ verify(
+ 'SanitizationFilter',
- <<-GFM.strip_heredoc
- <a name="named-anchor"></a>
+ <<-GFM.strip_heredoc
+ <a name="named-anchor"></a>
- <sub>sub</sub>
+ <sub>sub</sub>
- <dl>
- <dt>dt</dt>
- <dd>dd</dd>
- </dl>
+ <dl>
+ <dt>dt</dt>
+ <dd>dd</dd>
+ </dl>
- <kbd>kbd</kbd>
+ <kbd>kbd</kbd>
- <q>q</q>
+ <q>q</q>
- <samp>samp</samp>
+ <samp>samp</samp>
- <var>var</var>
+ <var>var</var>
- <ruby>ruby</ruby>
+ <ruby>ruby</ruby>
- <rt>rt</rt>
+ <rt>rt</rt>
- <rp>rp</rp>
+ <rp>rp</rp>
- <abbr>abbr</abbr>
+ <abbr>abbr</abbr>
- <summary>summary</summary>
+ <summary>summary</summary>
- <details>details</details>
- GFM
- )
+ <details>details</details>
+ GFM
+ )
- verify(
- 'SanitizationFilter',
+ verify(
+ 'SanitizationFilter',
- <<-GFM.strip_heredoc,
- ```
- Plain text
- ```
- GFM
+ <<-GFM.strip_heredoc,
+ ```
+ Plain text
+ ```
+ GFM
- <<-GFM.strip_heredoc,
- ```ruby
- def foo
- bar
- end
- ```
- GFM
+ <<-GFM.strip_heredoc,
+ ```ruby
+ def foo
+ bar
+ end
+ ```
+ GFM
+
+ <<-GFM.strip_heredoc
+ Foo
+
+ This is an example of GFM
- <<-GFM.strip_heredoc
- Foo
+ ```js
+ Code goes here
+ ```
+ GFM
+ )
- This is an example of GFM
+ verify(
+ 'MarkdownFilter',
- ```js
- Code goes here
- ```
- GFM
- )
+ "Line with two spaces at the end \nto insert a linebreak",
- verify(
- 'MarkdownFilter',
+ '`code`',
+ '`` code with ` ticks ``',
- "Line with two spaces at the end \nto insert a linebreak",
+ '> Quote',
- '`code`',
- '`` code with ` ticks ``',
+ # multiline quote
+ <<-GFM.strip_heredoc,
+ > Multiline
+ > Quote
+ >
+ > With multiple paragraphs
+ GFM
- '> Quote',
+ '![Image](https://example.com/image.png)',
- # multiline quote
- <<-GFM.strip_heredoc,
- > Multiline
- > Quote
- >
- > With multiple paragraphs
- GFM
+ '# Heading with no anchor link',
- '![Image](https://example.com/image.png)',
+ '[Link](https://example.com)',
- '# Heading with no anchor link',
+ '- List item',
- '[Link](https://example.com)',
+ # multiline list item
+ <<-GFM.strip_heredoc,
+ - Multiline
+ List item
+ GFM
- '- List item',
+ # nested lists
+ <<-GFM.strip_heredoc,
+ - Nested
- # multiline list item
- <<-GFM.strip_heredoc,
- - Multiline
- List item
- GFM
- # nested lists
- <<-GFM.strip_heredoc,
- - Nested
+ - Lists
+ GFM
+ # list with blockquote
+ <<-GFM.strip_heredoc,
+ - List
- - Lists
- GFM
+ > Blockquote
+ GFM
- # list with blockquote
- <<-GFM.strip_heredoc,
- - List
+ '1. Numbered list item',
- > Blockquote
- GFM
+ # multiline numbered list item
+ <<-GFM.strip_heredoc,
+ 1. Multiline
+ Numbered list item
+ GFM
- '1. Numbered list item',
+ # nested numbered list
+ <<-GFM.strip_heredoc,
+ 1. Nested
- # multiline numbered list item
- <<-GFM.strip_heredoc,
- 1. Multiline
- Numbered list item
- GFM
- # nested numbered list
- <<-GFM.strip_heredoc,
- 1. Nested
+ 1. Numbered lists
+ GFM
+ '# Heading',
+ '## Heading',
+ '### Heading',
+ '#### Heading',
+ '##### Heading',
+ '###### Heading',
- 1. Numbered lists
- GFM
+ '**Bold**',
- '# Heading',
- '## Heading',
- '### Heading',
- '#### Heading',
- '##### Heading',
- '###### Heading',
+ '_Italics_',
- '**Bold**',
+ '~~Strikethrough~~',
- '_Italics_',
+ '2^2',
- '~~Strikethrough~~',
+ '-----',
- '2^2',
+ # table
+ <<-GFM.strip_heredoc,
+ | Centered | Right | Left |
+ |:--------:|------:|------|
+ | Foo | Bar | **Baz** |
+ | Foo | Bar | **Baz** |
+ GFM
- '-----',
+ # table with empty heading
+ <<-GFM.strip_heredoc,
+ | | x | y |
+ |---|---|---|
+ | a | 1 | 0 |
+ | b | 0 | 1 |
+ GFM
+ )
+ end
+
+ alias_method :gfm_to_html, :markdown
- # table
- <<-GFM.strip_heredoc,
- | Centered | Right | Left |
- |:--------:|------:|------|
- | Foo | Bar | **Baz** |
- | Foo | Bar | **Baz** |
- GFM
+ def verify(label, *gfms)
+ aggregate_failures(label) do
+ gfms.each do |gfm|
+ html = gfm_to_html(gfm)
+ output_gfm = html_to_gfm(html)
+ expect(output_gfm.strip).to eq(gfm.strip)
+ end
+ end
+ end
- # table with empty heading
- <<-GFM.strip_heredoc,
- | | x | y |
- |---|---|---|
- | a | 1 | 0 |
- | b | 0 | 1 |
- GFM
- )
+ # Fake a `current_user` helper
+ def current_user
+ @feat.user
+ end
end
- alias_method :gfm_to_html, :markdown
+ describe 'Copying code' do
+ let(:project) { create(:project) }
+
+ context 'from a diff' do
+ before do
+ visit namespace_project_commit_path(project.namespace, project, sample_commit.id)
+ end
+
+ context 'selecting one word of text' do
+ it 'copies as inline code' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"] .line .no',
- def html_to_gfm(html)
+ '`RuntimeError`'
+ )
+ end
+ end
+
+ context 'selecting one line of text' do
+ it 'copies as inline code' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"] .line',
+
+ '`raise RuntimeError, "System commands must be given as an array of strings"`'
+ )
+ end
+ end
+
+ context 'selecting multiple lines of text' do
+ it 'copies as a code block' do
+ verify(
+ '[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], [id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"]',
+
+ <<-GFM.strip_heredoc,
+ ```ruby
+ raise RuntimeError, "System commands must be given as an array of strings"
+ end
+ ```
+ GFM
+ )
+ end
+ end
+ end
+
+ context 'from a blob' do
+ before do
+ visit namespace_project_blob_path(project.namespace, project, File.join('master', 'files/ruby/popen.rb'))
+ end
+
+ context 'selecting one word of text' do
+ it 'copies as inline code' do
+ verify(
+ '.line[id="LC9"] .no',
+
+ '`RuntimeError`'
+ )
+ end
+ end
+
+ context 'selecting one line of text' do
+ it 'copies as inline code' do
+ verify(
+ '.line[id="LC9"]',
+
+ '`raise RuntimeError, "System commands must be given as an array of strings"`'
+ )
+ end
+ end
+
+ context 'selecting multiple lines of text' do
+ it 'copies as a code block' do
+ verify(
+ '.line[id="LC9"], .line[id="LC10"]',
+
+ <<-GFM.strip_heredoc,
+ ```ruby
+ raise RuntimeError, "System commands must be given as an array of strings"
+ end
+ ```
+ GFM
+ )
+ end
+ end
+ end
+
+ context 'from a GFM code block' do
+ before do
+ visit namespace_project_blob_path(project.namespace, project, File.join('markdown', 'doc/api/users.md'))
+ end
+
+ context 'selecting one word of text' do
+ it 'copies as inline code' do
+ verify(
+ '.line[id="LC27"] .s2',
+
+ '`"bio"`'
+ )
+ end
+ end
+
+ context 'selecting one line of text' do
+ it 'copies as inline code' do
+ verify(
+ '.line[id="LC27"]',
+
+ '`"bio": null,`'
+ )
+ end
+ end
+
+ context 'selecting multiple lines of text' do
+ it 'copies as a code block with the correct language' do
+ verify(
+ '.line[id="LC27"], .line[id="LC28"]',
+
+ <<-GFM.strip_heredoc,
+ ```json
+ "bio": null,
+ "skype": "",
+ ```
+ GFM
+ )
+ end
+ end
+ end
+
+ def verify(selector, gfm)
+ html = html_for_selector(selector)
+ output_gfm = html_to_gfm(html, 'transformCodeSelection')
+ expect(output_gfm.strip).to eq(gfm.strip)
+ end
+ end
+
+ def html_for_selector(selector)
+ js = <<-JS.strip_heredoc
+ (function(selector) {
+ var els = document.querySelectorAll(selector);
+ var htmls = _.map(els, function(el) { return el.outerHTML; });
+ return htmls.join("\\n");
+ })("#{escape_javascript(selector)}")
+ JS
+ page.evaluate_script(js)
+ end
+
+ def html_to_gfm(html, transformer = 'transformGFMSelection')
js = <<-JS.strip_heredoc
(function(html) {
+ var transformer = window.gl.CopyAsGFM[#{transformer.inspect}];
+
var node = document.createElement('div');
node.innerHTML = html;
+
+ node = transformer(node);
+ if (!node) return null;
+
return window.gl.CopyAsGFM.nodeToGFM(node);
})("#{escape_javascript(html)}")
JS
page.evaluate_script(js)
end
-
- def verify(label, *gfms)
- aggregate_failures(label) do
- gfms.each do |gfm|
- html = gfm_to_html(gfm)
- output_gfm = html_to_gfm(html)
- expect(output_gfm.strip).to eq(gfm.strip)
- end
- end
- end
-
- # Fake a `current_user` helper
- def current_user
- @feat.user
- end
end
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 63eb5c697c2..c4e58d14f75 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -1,10 +1,32 @@
require 'spec_helper'
RSpec.describe 'Dashboard Projects', feature: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, name: "awesome stuff") }
+
before do
- login_as(create :user)
+ project.team << [user, :developer]
+ login_as user
visit dashboard_projects_path
end
-
+
+ it 'shows the project the user in a member of in the list' do
+ visit dashboard_projects_path
+ expect(page).to have_content('awesome stuff')
+ end
+
+ describe "with a pipeline" do
+ let(:pipeline) { create(:ci_pipeline, :success, project: project, sha: project.commit.sha) }
+
+ before do
+ pipeline
+ end
+
+ it 'shows that the last pipeline passed' do
+ visit dashboard_projects_path
+ expect(page).to have_xpath("//a[@href='#{pipelines_namespace_project_commit_path(project.namespace, project, project.commit)}']")
+ end
+ end
+
it_behaves_like "an autodiscoverable RSS feed with current_user's private token"
end
diff --git a/spec/features/groups/group_name_toggle_spec.rb b/spec/features/groups/group_name_toggle_spec.rb
new file mode 100644
index 00000000000..8528718a2f7
--- /dev/null
+++ b/spec/features/groups/group_name_toggle_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+feature 'Group name toggle', feature: true, js: true do
+ let(:group) { create(:group) }
+ let(:nested_group_1) { create(:group, parent: group) }
+ let(:nested_group_2) { create(:group, parent: nested_group_1) }
+ let(:nested_group_3) { create(:group, parent: nested_group_2) }
+
+ before do
+ login_as :user
+ end
+
+ it 'is not present for less than 3 groups' do
+ visit group_path(group)
+ expect(page).not_to have_css('.group-name-toggle')
+
+ visit group_path(nested_group_1)
+ expect(page).not_to have_css('.group-name-toggle')
+ end
+
+ it 'is present for nested group of 3 or more in the namespace' do
+ visit group_path(nested_group_2)
+ expect(page).to have_css('.group-name-toggle')
+
+ visit group_path(nested_group_3)
+ expect(page).to have_css('.group-name-toggle')
+ end
+
+ context 'for group with at least 3 groups' do
+ before do
+ visit group_path(nested_group_2)
+ end
+
+ it 'should show the full group namespace when toggled' do
+ expect(page).not_to have_content(group.name)
+ expect(page).to have_css('.group-path.hidable', visible: false)
+
+ click_button '...'
+
+ expect(page).to have_content(group.name)
+ expect(page).to have_css('.group-path.hidable', visible: true)
+ end
+ end
+end
diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb
index f424186cf30..16e453bc328 100644
--- a/spec/features/issues/award_emoji_spec.rb
+++ b/spec/features/issues/award_emoji_spec.rb
@@ -17,8 +17,21 @@ describe 'Awards Emoji', feature: true do
login_as(user)
end
+ describe 'visiting an issue with a legacy award emoji that is not valid anymore' do
+ before do
+ # The `heart_tip` emoji is not valid anymore so we need to skip validation
+ issue.award_emoji.build(user: user, name: 'heart_tip').save!(validate: false)
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ # Regression test: https://gitlab.com/gitlab-org/gitlab-ce/issues/29529
+ it 'does not shows a 500 page' do
+ expect(page).to have_text(issue.title)
+ end
+ end
+
describe 'Click award emoji from issue#show' do
- let!(:note) { create(:note_on_issue, noteable: issue, project: issue.project, note: "Hello world") }
+ let!(:note) { create(:note_on_issue, noteable: issue, project: issue.project, note: "Hello world") }
before do
visit namespace_project_issue_path(project.namespace, project, issue)
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index 19a00618b12..1772a120045 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -14,9 +14,10 @@ describe 'Dropdown author', js: true, feature: true do
def send_keys_to_filtered_search(input)
input.split("").each do |i|
filtered_search.send_keys(i)
- sleep 5
- wait_for_ajax
end
+
+ sleep 0.5
+ wait_for_ajax
end
def dropdown_author_size
diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
index 85ffffe4b6d..ce96a420699 100644
--- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
@@ -202,6 +202,14 @@ describe 'Dropdown milestone', :feature, :js do
expect_tokens([{ name: 'milestone', value: 'upcoming' }])
expect_filtered_search_input_empty
end
+
+ it 'selects `started milestones`' do
+ click_static_milestone('Started')
+
+ expect(page).to have_css(js_dropdown_milestone, visible: false)
+ expect_tokens([{ name: 'milestone', value: 'started' }])
+ expect_filtered_search_input_empty
+ end
end
describe 'input has existing content' do
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index f079a9627e4..f463312bf57 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -8,13 +8,12 @@ describe 'Filter issues', js: true, feature: true do
let!(:project) { create(:project, group: group) }
let!(:user) { create(:user) }
let!(:user2) { create(:user) }
- let!(:milestone) { create(:milestone, project: project) }
let!(:label) { create(:label, project: project) }
let!(:wontfix) { create(:label, project: project, title: "Won't fix") }
let!(:bug_label) { create(:label, project: project, title: 'bug') }
let!(:caps_sensitive_label) { create(:label, project: project, title: 'CAPS_sensitive') }
- let!(:milestone) { create(:milestone, title: "8", project: project) }
+ let!(:milestone) { create(:milestone, title: "8", project: project, start_date: 2.days.ago) }
let!(:multiple_words_label) { create(:label, project: project, title: "Two words") }
let!(:closed_issue) { create(:issue, title: 'bug that is closed', project: project, state: :closed) }
@@ -505,6 +504,14 @@ describe 'Filter issues', js: true, feature: true do
expect_filtered_search_input_empty
end
+ it 'filters issues by started milestones' do
+ input_filtered_search("milestone:started")
+
+ expect_tokens([{ name: 'milestone', value: 'started' }])
+ expect_issues_list_count(5)
+ expect_filtered_search_input_empty
+ end
+
it 'filters issues by invalid milestones' do
skip('to be tested, issue #26546')
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 8c54259f475..6f831ea4b67 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -6,7 +6,7 @@ describe 'Issues', feature: true do
include SortingHelper
include WaitForAjax
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
before do
login_as :user
@@ -565,6 +565,24 @@ describe 'Issues', feature: true do
end
describe 'new issue' do
+ context 'by unauthenticated user' do
+ before do
+ logout
+ end
+
+ it 'redirects to signin then back to new issue after signin' do
+ visit namespace_project_issues_path(project.namespace, project)
+
+ click_link 'New issue'
+
+ expect(current_path).to eq new_user_session_path
+
+ login_as :user
+
+ expect(current_path).to eq new_namespace_project_issue_path(project.namespace, project)
+ end
+ end
+
context 'dropzone upload file', js: true do
before do
visit new_namespace_project_issue_path(project.namespace, project)
diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb
index 73c5ef31edc..18833ba7266 100644
--- a/spec/features/merge_requests/created_from_fork_spec.rb
+++ b/spec/features/merge_requests/created_from_fork_spec.rb
@@ -60,9 +60,6 @@ feature 'Merge request created from fork' do
expect(page).to have_content pipeline.status
expect(page).to have_content pipeline.id
end
-
- expect(page.find('a.btn-remove')[:href])
- .to include fork_project.path_with_namespace
end
end
diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb
index 6fed1568fcf..14511707af4 100644
--- a/spec/features/merge_requests/reset_filters_spec.rb
+++ b/spec/features/merge_requests/reset_filters_spec.rb
@@ -49,6 +49,26 @@ feature 'Merge requests filter clear button', feature: true, js: true do
end
end
+ context 'when multiple label filters have been applied' do
+ let!(:label) { create(:label, project: project, name: 'Frontend') }
+ let(:filter_dropdown) { find("#js-dropdown-label .filter-dropdown") }
+
+ before do
+ visit_merge_requests(project)
+ init_label_search
+ end
+
+ it 'filters bug label' do
+ filtered_search.set('~bug')
+
+ filter_dropdown.find('.filter-dropdown-item', text: bug.title).click
+ init_label_search
+
+ expect(filter_dropdown.find('.filter-dropdown-item', text: bug.title)).to be_visible
+ expect(filter_dropdown.find('.filter-dropdown-item', text: label.title)).to be_visible
+ end
+ end
+
context 'when a text search has been conducted' do
it 'resets the text search filter' do
visit_merge_requests(project, search: 'Bug')
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index 2f3c3e45ae6..a1f4eb2688b 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -133,7 +133,6 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do
it 'changes target_branch in new merge_request' do
visit new_namespace_project_merge_request_path(another_project.namespace, another_project, new_url_opts)
- click_button "Compare branches and continue"
fill_in "merge_request_title", with: 'My brand new feature'
fill_in "merge_request_description", with: "le feature \n/target_branch fix\nFeature description:"
diff --git a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb
deleted file mode 100644
index e05fbb3715c..00000000000
--- a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require 'spec_helper'
-
-feature 'Profile > Notifications > User changes notified_of_own_activity setting', feature: true, js: true do
- let(:user) { create(:user) }
-
- before do
- login_as(user)
- end
-
- scenario 'User opts into receiving notifications about their own activity' do
- visit profile_notifications_path
-
- expect(page).not_to have_checked_field('user[notified_of_own_activity]')
-
- check 'user[notified_of_own_activity]'
-
- expect(page).to have_content('Notification settings saved')
- expect(page).to have_checked_field('user[notified_of_own_activity]')
- end
-
- scenario 'User opts out of receiving notifications about their own activity' do
- user.update!(notified_of_own_activity: true)
- visit profile_notifications_path
-
- expect(page).to have_checked_field('user[notified_of_own_activity]')
-
- uncheck 'user[notified_of_own_activity]'
-
- expect(page).to have_content('Notification settings saved')
- expect(page).not_to have_checked_field('user[notified_of_own_activity]')
- end
-end
diff --git a/spec/features/projects/blobs/user_create_spec.rb b/spec/features/projects/blobs/user_create_spec.rb
index 03d08c12612..5686868a0c4 100644
--- a/spec/features/projects/blobs/user_create_spec.rb
+++ b/spec/features/projects/blobs/user_create_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
feature 'New blob creation', feature: true, js: true do
include WaitForAjax
+ include TargetBranchHelpers
given(:user) { create(:user) }
given(:role) { :developer }
@@ -20,19 +21,6 @@ feature 'New blob creation', feature: true, js: true do
execute_script("ace.edit('editor').setValue('#{content}')")
end
- def select_branch_index(index)
- first('button.js-target-branch').click
- wait_for_ajax
- all('a[data-group="Branches"]')[index].click
- end
-
- def create_new_branch(name)
- first('button.js-target-branch').click
- click_link 'Create new branch'
- fill_in 'new_branch_name', with: name
- click_button 'Create'
- end
-
def commit_file
click_button 'Commit Changes'
end
@@ -53,12 +41,12 @@ feature 'New blob creation', feature: true, js: true do
context 'with different target branch' do
background do
edit_file
- select_branch_index(0)
+ select_branch('feature')
commit_file
end
scenario 'creates the blob in the different branch' do
- expect(page).to have_content 'test'
+ expect(page).to have_content 'feature'
expect(page).to have_content 'successfully created'
end
end
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index d26a0caf036..8e0306ce83b 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -17,6 +17,14 @@ describe 'Branches', feature: true do
repository.branches { |branch| expect(page).to have_content("#{branch.name}") }
expect(page).to have_content("Protected branches can be managed in project settings")
end
+
+ it 'avoids a N+1 query in branches index' do
+ control_count = ActiveRecord::QueryRecorder.new { visit namespace_project_branches_path(project.namespace, project) }.count
+
+ %w(one two three four five).each { |ref| repository.add_branch(@user, ref, 'master') }
+
+ expect { visit namespace_project_branches_path(project.namespace, project) }.not_to exceed_query_limit(control_count)
+ end
end
describe 'Find branches' do
diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
new file mode 100644
index 00000000000..30a2b2bcf8c
--- /dev/null
+++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
@@ -0,0 +1,55 @@
+require 'rails_helper'
+
+feature 'Mini Pipeline Graph in Commit View', :js, :feature do
+ include WaitForAjax
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+
+ before do
+ login_as(user)
+ end
+
+ context 'when commit has pipelines' do
+ let(:pipeline) do
+ create(:ci_empty_pipeline,
+ project: project,
+ ref: project.default_branch,
+ sha: project.commit.sha)
+ end
+
+ let(:build) do
+ create(:ci_build, pipeline: pipeline)
+ end
+
+ before do
+ build.run
+ visit namespace_project_commit_path(project.namespace, project, project.commit.id)
+ end
+
+ it 'should display a mini pipeline graph' do
+ expect(page).to have_selector('.mr-widget-pipeline-graph')
+ end
+
+ it 'should show the builds list when stage is clicked' do
+ first('.mini-pipeline-graph-dropdown-toggle').click
+
+ wait_for_ajax
+
+ page.within '.js-builds-dropdown-list' do
+ expect(page).to have_selector('.ci-status-icon-running')
+ expect(page).to have_content(build.stage)
+ end
+ end
+ end
+
+ context 'when commit does not have pipelines' do
+ before do
+ visit namespace_project_commit_path(project.namespace, project, project.commit.id)
+ end
+
+ it 'should not display a mini pipeline graph' do
+ expect(page).not_to have_selector('.mr-widget-pipeline-graph')
+ end
+ end
+end
diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb
index 43eb4000e58..030043d14aa 100644
--- a/spec/features/projects/compare_spec.rb
+++ b/spec/features/projects/compare_spec.rb
@@ -26,6 +26,14 @@ describe "Compare", js: true do
click_button "Compare"
expect(page).to have_content "Commits"
end
+
+ it "filters branches" do
+ select_using_dropdown("from", "wip")
+
+ find(".js-compare-from-dropdown .compare-dropdown-toggle").click
+
+ expect(find(".js-compare-from-dropdown .dropdown-content")).to have_selector("li", count: 3)
+ end
end
describe "tags" do
diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb
index 8b302a6aa23..4c28205da9b 100644
--- a/spec/features/projects/group_links_spec.rb
+++ b/spec/features/projects/group_links_spec.rb
@@ -8,7 +8,7 @@ feature 'Project group links', feature: true, js: true do
let!(:group) { create(:group) }
background do
- project.team << [master, :master]
+ project.add_master(master)
login_as(master)
end
@@ -29,4 +29,26 @@ feature 'Project group links', feature: true, js: true do
end
end
end
+
+ context 'nested group project' do
+ let!(:nested_group) { create(:group, parent: group) }
+ let!(:another_group) { create(:group) }
+ let!(:project) { create(:project, namespace: nested_group) }
+
+ background do
+ group.add_master(master)
+ another_group.add_master(master)
+ end
+
+ it 'does not show ancestors' do
+ visit namespace_project_settings_members_path(project.namespace, project)
+
+ click_link 'Search for a group'
+
+ page.within '.select2-drop' do
+ expect(page).to have_content(another_group.name)
+ expect(page).not_to have_content(group.name)
+ end
+ end
+ end
end
diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz
index 20cdfbae24f..399c1d478c5 100644
--- a/spec/features/projects/import_export/test_project_export.tar.gz
+++ b/spec/features/projects/import_export/test_project_export.tar.gz
Binary files differ
diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
index de3c6eceb82..e2911a37e40 100644
--- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
+++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
@@ -29,7 +29,7 @@ feature 'Issue prioritization', feature: true do
issue_1.labels << label_5
login_as user
- visit namespace_project_issues_path(project.namespace, project, sort: 'priority')
+ visit namespace_project_issues_path(project.namespace, project, sort: 'label_priority')
# Ensure we are indicating that issues are sorted by priority
expect(page).to have_selector('.dropdown-toggle', text: 'Label priority')
@@ -68,7 +68,7 @@ feature 'Issue prioritization', feature: true do
issue_6.labels << label_5 # 8 - No priority
login_as user
- visit namespace_project_issues_path(project.namespace, project, sort: 'priority')
+ visit namespace_project_issues_path(project.namespace, project, sort: 'label_priority')
expect(page).to have_selector('.dropdown-toggle', text: 'Label priority')
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index 45185f2dd1f..52196ce49bd 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -16,6 +16,15 @@ feature "New project", feature: true do
expect(find_field("project_visibility_level_#{level}")).to be_checked
end
+
+ it 'saves visibility level on validation error' do
+ visit new_project_path
+
+ choose(key)
+ click_button('Create project')
+
+ expect(find_field("project_visibility_level_#{level}")).to be_checked
+ end
end
end
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 22bf1bfbdf0..162056671e0 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -99,15 +99,18 @@ describe 'Pipelines', :feature, :js do
end
it 'indicates that pipeline can be canceled' do
- expect(page).to have_link('Cancel')
+ expect(page).to have_selector('.js-pipelines-cancel-button')
expect(page).to have_selector('.ci-running')
end
context 'when canceling' do
- before { click_link('Cancel') }
+ before do
+ find('.js-pipelines-cancel-button').click
+ wait_for_vue_resource
+ end
it 'indicated that pipelines was canceled' do
- expect(page).not_to have_link('Cancel')
+ expect(page).not_to have_selector('.js-pipelines-cancel-button')
expect(page).to have_selector('.ci-canceled')
end
end
@@ -126,15 +129,18 @@ describe 'Pipelines', :feature, :js do
end
it 'indicates that pipeline can be retried' do
- expect(page).to have_link('Retry')
+ expect(page).to have_selector('.js-pipelines-retry-button')
expect(page).to have_selector('.ci-failed')
end
context 'when retrying' do
- before { click_link('Retry') }
+ before do
+ find('.js-pipelines-retry-button').click
+ wait_for_vue_resource
+ end
it 'shows running pipeline that is not retryable' do
- expect(page).not_to have_link('Retry')
+ expect(page).not_to have_selector('.js-pipelines-retry-button')
expect(page).to have_selector('.ci-running')
end
end
@@ -176,17 +182,17 @@ describe 'Pipelines', :feature, :js do
it 'has link to the manual action' do
find('.js-pipeline-dropdown-manual-actions').click
- expect(page).to have_link('manual build')
+ expect(page).to have_button('manual build')
end
context 'when manual action was played' do
before do
find('.js-pipeline-dropdown-manual-actions').click
- click_link('manual build')
+ click_button('manual build')
end
it 'enqueues manual action job' do
- expect(manual.reload).to be_pending
+ expect(page).to have_selector('.js-pipeline-dropdown-manual-actions:disabled')
end
end
end
@@ -203,7 +209,7 @@ describe 'Pipelines', :feature, :js do
before { visit_project_pipelines }
it 'is cancelable' do
- expect(page).to have_link('Cancel')
+ expect(page).to have_selector('.js-pipelines-cancel-button')
end
it 'has pipeline running' do
@@ -211,10 +217,10 @@ describe 'Pipelines', :feature, :js do
end
context 'when canceling' do
- before { click_link('Cancel') }
+ before { find('.js-pipelines-cancel-button').trigger('click') }
it 'indicates that pipeline was canceled' do
- expect(page).not_to have_link('Cancel')
+ expect(page).not_to have_selector('.js-pipelines-cancel-button')
expect(page).to have_selector('.ci-canceled')
end
end
@@ -233,7 +239,7 @@ describe 'Pipelines', :feature, :js do
end
it 'is not retryable' do
- expect(page).not_to have_link('Retry')
+ expect(page).not_to have_selector('.js-pipelines-retry-button')
end
it 'has failed pipeline' do
diff --git a/spec/features/projects/services/slack_service_spec.rb b/spec/features/projects/services/slack_service_spec.rb
index 16541f51d98..c0a4a1e4bf5 100644
--- a/spec/features/projects/services/slack_service_spec.rb
+++ b/spec/features/projects/services/slack_service_spec.rb
@@ -7,7 +7,7 @@ feature 'Projects > Slack service > Setup events', feature: true do
background do
service.fields
- service.update_attributes(push_channel: 1, issue_channel: 2, merge_request_channel: 3, note_channel: 4, tag_push_channel: 5, build_channel: 6, wiki_page_channel: 7)
+ service.update_attributes(push_channel: 1, issue_channel: 2, merge_request_channel: 3, note_channel: 4, tag_push_channel: 5, pipeline_channel: 6, wiki_page_channel: 7)
project.team << [user, :master]
login_as(user)
end
@@ -20,7 +20,7 @@ feature 'Projects > Slack service > Setup events', feature: true do
expect(page.find_field("service_merge_request_channel").value).to have_content '3'
expect(page.find_field("service_note_channel").value).to have_content '4'
expect(page.find_field("service_tag_push_channel").value).to have_content '5'
- expect(page.find_field("service_build_channel").value).to have_content '6'
+ expect(page.find_field("service_pipeline_channel").value).to have_content '6'
expect(page.find_field("service_wiki_page_channel").value).to have_content '7'
end
end
diff --git a/spec/features/projects/settings/merge_requests_settings_spec.rb b/spec/features/projects/settings/merge_requests_settings_spec.rb
index 6815039d5ed..321af416c91 100644
--- a/spec/features/projects/settings/merge_requests_settings_spec.rb
+++ b/spec/features/projects/settings/merge_requests_settings_spec.rb
@@ -62,4 +62,27 @@ feature 'Project settings > Merge Requests', feature: true, js: true do
expect(page).to have_content('Only allow merge requests to be merged if all discussions are resolved')
end
end
+
+ describe 'Checkbox to enable merge request link' do
+ before do
+ visit edit_project_path(project)
+ end
+
+ scenario 'is initially checked' do
+ checkbox = find_field('project_printing_merge_request_link_enabled')
+ expect(checkbox).to be_checked
+ end
+
+ scenario 'when unchecked sets :printing_merge_request_link_enabled to false' do
+ uncheck('project_printing_merge_request_link_enabled')
+ click_on('Save')
+
+ # Wait for save to complete and page to reload
+ checkbox = find_field('project_printing_merge_request_link_enabled')
+ expect(checkbox).not_to be_checked
+
+ project.reload
+ expect(project.printing_merge_request_link_enabled).to be(false)
+ end
+ end
end
diff --git a/spec/features/projects/user_create_dir_spec.rb b/spec/features/projects/user_create_dir_spec.rb
new file mode 100644
index 00000000000..2065abfb248
--- /dev/null
+++ b/spec/features/projects/user_create_dir_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+feature 'New directory creation', feature: true, js: true do
+ include WaitForAjax
+ include TargetBranchHelpers
+
+ given(:user) { create(:user) }
+ given(:role) { :developer }
+ given(:project) { create(:project) }
+
+ background do
+ login_as(user)
+ project.team << [user, role]
+ visit namespace_project_tree_path(project.namespace, project, 'master')
+ open_new_directory_modal
+ fill_in 'dir_name', with: 'new_directory'
+ end
+
+ def open_new_directory_modal
+ first('.add-to-tree').click
+ click_link 'New directory'
+ end
+
+ def create_directory
+ click_button 'Create directory'
+ end
+
+ context 'with default target branch' do
+ background do
+ create_directory
+ end
+
+ scenario 'creates the directory in the default branch' do
+ expect(page).to have_content 'master'
+ expect(page).to have_content 'The directory has been successfully created'
+ expect(page).to have_content 'new_directory'
+ end
+ end
+
+ context 'with different target branch' do
+ background do
+ select_branch('feature')
+ create_directory
+ end
+
+ scenario 'creates the directory in the different branch' do
+ expect(page).to have_content 'feature'
+ expect(page).to have_content 'The directory has been successfully created'
+ end
+ end
+
+ context 'with a new target branch' do
+ given(:new_branch_name) { 'new-feature' }
+
+ background do
+ create_new_branch(new_branch_name)
+ create_directory
+ end
+
+ scenario 'creates the directory in the new branch' do
+ expect(page).to have_content new_branch_name
+ expect(page).to have_content 'The directory has been successfully created'
+ end
+
+ scenario 'redirects to the merge request' do
+ expect(page).to have_content 'New Merge Request'
+ expect(page).to have_content "From #{new_branch_name} into master"
+ expect(page).to have_content 'Add new directory'
+ expect(current_path).to eq(new_namespace_project_merge_request_path(project.namespace, project))
+ end
+ end
+end
diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
new file mode 100644
index 00000000000..6825b95c8aa
--- /dev/null
+++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb
@@ -0,0 +1,26 @@
+require 'spec_helper'
+
+describe 'Projects > Wiki > User views Git access wiki page', :feature do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:wiki_page) do
+ WikiPages::CreateService.new(
+ project,
+ user,
+ title: 'home',
+ content: '[some link](other-page)'
+ ).execute
+ end
+
+ before do
+ login_as(user)
+ end
+
+ scenario 'Visit Wiki Page Current Commit' do
+ visit namespace_project_wiki_path(project.namespace, project, wiki_page)
+
+ click_link 'Clone repository'
+ expect(page).to have_text("Clone repository #{project.wiki.path_with_namespace}")
+ expect(page).to have_text(project.wiki.http_url_to_repo(user))
+ end
+end
diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
index f842d14fa96..aedc0333cb9 100644
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
@@ -15,15 +15,30 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do
context 'in the user namespace' do
let(:project) { create(:project, namespace: user.namespace) }
- scenario 'the home page' do
- click_link 'Edit'
-
- fill_in :wiki_content, with: 'My awesome wiki!'
- click_button 'Save changes'
-
- expect(page).to have_content('Home')
- expect(page).to have_content("Last edited by #{user.name}")
- expect(page).to have_content('My awesome wiki!')
+ context 'the home page' do
+ scenario 'success when the wiki content is not empty' do
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: 'My awesome wiki!'
+ click_button 'Save changes'
+
+ expect(page).to have_content('Home')
+ expect(page).to have_content("Last edited by #{user.name}")
+ expect(page).to have_content('My awesome wiki!')
+ end
+
+ scenario 'failure when the wiki content is empty' do
+ click_link 'Edit'
+
+ fill_in :wiki_content, with: ''
+ click_button 'Save changes'
+
+ expect(page).to have_selector('.wiki-form')
+ expect(page).to have_content('Edit Page')
+ expect(page).to have_content('The form contains the following error:')
+ expect(page).to have_content('Content can\'t be blank')
+ expect(find('textarea#wiki_content').value).to eq ''
+ end
end
end
diff --git a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb
new file mode 100644
index 00000000000..c17e06612de
--- /dev/null
+++ b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+feature 'Projects > Wiki > User views the wiki page', feature: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:old_page_version_id) { wiki_page.versions.last.id }
+ let(:wiki_page) do
+ WikiPages::CreateService.new(
+ project,
+ user,
+ title: 'home',
+ content: '[some link](other-page)'
+ ).execute
+ end
+
+ background do
+ project.team << [user, :master]
+ login_as(user)
+ WikiPages::UpdateService.new(
+ project,
+ user,
+ message: 'updated home',
+ content: 'updated [some link](other-page)',
+ format: :markdown
+ ).execute(wiki_page)
+ end
+
+ scenario 'Visit Wiki Page Current Commit' do
+ visit namespace_project_wiki_path(project.namespace, project, wiki_page)
+
+ expect(page).to have_selector('a.btn', text: 'Edit')
+ end
+
+ scenario 'Visit Wiki Page Historical Commit' do
+ visit namespace_project_wiki_path(
+ project.namespace,
+ project,
+ wiki_page,
+ version_id: old_page_version_id
+ )
+
+ expect(page).not_to have_selector('a.btn', text: 'Edit')
+ end
+end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 3a1240f95b5..ba56030e28d 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -56,7 +56,7 @@ feature 'Project', feature: true do
end
describe 'removal', js: true do
- let(:user) { create(:user) }
+ let(:user) { create(:user, username: 'test', name: 'test') }
let(:project) { create(:project, namespace: user.namespace, name: 'project1') }
before do
@@ -67,7 +67,7 @@ feature 'Project', feature: true do
it 'removes a project' do
expect { remove_with_confirm('Remove project', project.path) }.to change {Project.count}.by(-1)
- expect(page).to have_content "Project 'project1' will be deleted."
+ expect(page).to have_content "Project 'test / project1' will be deleted."
expect(Project.all.count).to be_zero
expect(project.issues).to be_empty
expect(project.merge_requests).to be_empty
diff --git a/spec/features/tags/master_views_tags_spec.rb b/spec/features/tags/master_views_tags_spec.rb
index 29d2c244720..555f84c4772 100644
--- a/spec/features/tags/master_views_tags_spec.rb
+++ b/spec/features/tags/master_views_tags_spec.rb
@@ -27,10 +27,20 @@ feature 'Master views tags', feature: true do
context 'when project has tags' do
let(:project) { create(:project, namespace: user.namespace) }
+ let(:repository) { project.repository }
+
before do
visit namespace_project_tags_path(project.namespace, project)
end
+ scenario 'avoids a N+1 query in branches index' do
+ control_count = ActiveRecord::QueryRecorder.new { visit namespace_project_tags_path(project.namespace, project) }.count
+
+ %w(one two three four five).each { |tag| repository.add_tag(user, tag, 'master', 'foo') }
+
+ expect { visit namespace_project_tags_path(project.namespace, project) }.not_to exceed_query_limit(control_count)
+ end
+
scenario 'views the tags list page' do
expect(page).to have_content 'v1.0.0'
end
diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb
index 5c2df949ac5..850020109d4 100644
--- a/spec/features/todos/todos_spec.rb
+++ b/spec/features/todos/todos_spec.rb
@@ -31,7 +31,7 @@ describe 'Dashboard Todos', feature: true do
end
it 'shows due date as today' do
- page.within first('.todo') do
+ within first('.todo') do
expect(page).to have_content 'Due today'
end
end
@@ -184,6 +184,60 @@ describe 'Dashboard Todos', feature: true do
expect(page).to have_content "You're all done!"
expect(page).not_to have_selector('.gl-pagination')
end
+
+ it 'shows "Undo mark all as done" button' do
+ expect(page).to have_selector('.js-todos-mark-all', visible: false)
+ expect(page).to have_selector('.js-todos-undo-all', visible: true)
+ end
+ end
+
+ describe 'undo mark all as done', js: true do
+ before do
+ visit dashboard_todos_path
+ end
+
+ it 'shows the restored todo list' do
+ mark_all_and_undo
+
+ expect(page).to have_selector('.todos-list .todo', count: 1)
+ expect(page).to have_selector('.gl-pagination')
+ expect(page).not_to have_content "You're all done!"
+ end
+
+ it 'updates todo count' do
+ mark_all_and_undo
+
+ expect(page).to have_content 'To do 2'
+ expect(page).to have_content 'Done 0'
+ end
+
+ it 'shows "Mark all as done" button' do
+ mark_all_and_undo
+
+ expect(page).to have_selector('.js-todos-mark-all', visible: true)
+ expect(page).to have_selector('.js-todos-undo-all', visible: false)
+ end
+
+ context 'User has deleted a todo' do
+ before do
+ within first('.todo') do
+ click_link 'Done'
+ end
+ end
+
+ it 'shows the restored todo list with the deleted todo' do
+ mark_all_and_undo
+
+ expect(page).to have_selector('.todos-list .todo.todo-pending', count: 1)
+ end
+ end
+
+ def mark_all_and_undo
+ click_link 'Mark all as done'
+ wait_for_ajax
+ click_link 'Undo mark all as done'
+ wait_for_ajax
+ end
end
end