diff options
Diffstat (limited to 'spec/features')
31 files changed, 653 insertions, 98 deletions
diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb index 435de3861cf..d820a59aa16 100644 --- a/spec/features/boards/keyboard_shortcut_spec.rb +++ b/spec/features/boards/keyboard_shortcut_spec.rb @@ -1,20 +1,38 @@ require 'rails_helper' describe 'Issue Boards shortcut', :js do - let(:project) { create(:project) } + context 'issues are enabled' do + let(:project) { create(:project) } - before do - create(:board, project: project) + before do + create(:board, project: project) - sign_in(create(:admin)) + sign_in(create(:admin)) - visit project_path(project) + visit project_path(project) + end + + it 'takes user to issue board index' do + find('body').native.send_keys('gb') + expect(page).to have_selector('.boards-list') + + wait_for_requests + end end - it 'takes user to issue board index' do - find('body').native.send_keys('gb') - expect(page).to have_selector('.boards-list') + context 'issues are not enabled' do + let(:project) { create(:project, :issues_disabled) } + + before do + sign_in(create(:admin)) + + visit project_path(project) + end + + it 'does not take user to the issue board index' do + find('body').native.send_keys('gb') - wait_for_requests + expect(page).to have_selector("body[data-page='projects:show']") + end end end diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb index 1fcb8d5bc67..f82ed6300cc 100644 --- a/spec/features/copy_as_gfm_spec.rb +++ b/spec/features/copy_as_gfm_spec.rb @@ -285,6 +285,102 @@ describe 'Copy as GFM', :js do end verify( + 'MermaidFilter: mermaid as converted from GFM to HTML', + + <<-GFM.strip_heredoc + ```mermaid + graph TD; + A-->B; + ``` + GFM + ) + + aggregate_failures('MermaidFilter: mermaid as transformed from HTML to SVG') do + gfm = <<-GFM.strip_heredoc + ```mermaid + graph TD; + A-->B; + ``` + GFM + + html = <<-HTML.strip_heredoc + <svg id="mermaidChart1" xmlns="http://www.w3.org/2000/svg" height="100%" viewBox="0 0 87.234375 174" style="max-width:87.234375px;" class="mermaid"> + <style> + .mermaid { + /* Flowchart variables */ + /* Sequence Diagram variables */ + /* Gantt chart variables */ + /** Section styling */ + /* Grid and axis */ + /* Today line */ + /* Task styling */ + /* Default task */ + /* Specific task settings for the sections*/ + /* Active task */ + /* Completed task */ + /* Tasks on the critical line */ + } + </style> + <g> + <g class="output"> + <g class="clusters"></g> + <g class="edgePaths"> + <g class="edgePath" style="opacity: 1;"> + <path class="path" d="M33.6171875,52L33.6171875,77L33.6171875,102" marker-end="url(#arrowhead65)" style="fill:none"></path> + <defs> + <marker id="arrowhead65" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto"> + <path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"></path> + </marker> + </defs> + </g> + </g> + <g class="edgeLabels"> + <g class="edgeLabel" style="opacity: 1;" transform=""> + <g transform="translate(0,0)" class="label"> + <foreignObject width="0" height="0"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;"> + <span class="edgeLabel"></span> + </div> + </foreignObject> + </g> + </g> + </g> + <g class="nodes"> + <g class="node" id="A" transform="translate(33.6171875,36)" style="opacity: 1;"> + <rect rx="0" ry="0" x="-13.6171875" y="-16" width="27.234375" height="32"></rect> + <g class="label" transform="translate(0,0)"> + <g transform="translate(-3.6171875,-6)"> + <foreignObject width="7.234375" height="12"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">A</div> + </foreignObject> + </g> + </g> + </g> + <g class="node" id="B" transform="translate(33.6171875,118)" style="opacity: 1;"> + <rect rx="0" ry="0" x="-13.6171875" y="-16" width="27.234375" height="32"> + </rect> + <g class="label" transform="translate(0,0)"> + <g transform="translate(-3.6171875,-6)"> + <foreignObject width="7.234375" height="12"> + <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">B</div> + </foreignObject> + </g> + </g> + </g> + </g> + </g> + </g> + <text class="source" display="none">graph TD; + A-->B; + </text> + </svg> + HTML + + output_gfm = html_to_gfm(html) + expect(output_gfm.strip).to eq(gfm.strip) + end + + verify( 'SanitizationFilter', <<-GFM.strip_heredoc @@ -654,7 +750,7 @@ describe 'Copy as GFM', :js do js = <<-JS.strip_heredoc (function(selector) { var els = document.querySelectorAll(selector); - var htmls = _.map(els, function(el) { return el.outerHTML; }); + var htmls = [].slice.call(els).map(function(el) { return el.outerHTML; }); return htmls.join("\\n"); })("#{escape_javascript(selector)}") JS diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb index bd115785646..a74a8aac2b2 100644 --- a/spec/features/dashboard/activity_spec.rb +++ b/spec/features/dashboard/activity_spec.rb @@ -24,6 +24,7 @@ feature 'Dashboard > Activity' do end let(:note) { create(:note, project: project, noteable: merge_request) } + let(:milestone) { create(:milestone, :active, project: project, title: '1.0') } let!(:push_event) do event = create(:push_event, project: project, author: user) @@ -54,6 +55,10 @@ feature 'Dashboard > Activity' do create(:event, :commented, project: project, target: note, author: user) end + let!(:milestone_event) do + create(:event, :closed, project: project, target: milestone, author: user) + end + before do project.add_master(user) @@ -68,6 +73,7 @@ feature 'Dashboard > Activity' do expect(page).to have_content('accepted') expect(page).to have_content('closed') expect(page).to have_content('commented on') + expect(page).to have_content('closed milestone') end end @@ -107,6 +113,7 @@ feature 'Dashboard > Activity' do expect(page).not_to have_content('accepted') expect(page).to have_content('closed') expect(page).not_to have_content('commented on') + expect(page).to have_content('closed milestone') end end diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb index d92c002b4e7..a71020002dc 100644 --- a/spec/features/dashboard/groups_list_spec.rb +++ b/spec/features/dashboard/groups_list_spec.rb @@ -94,22 +94,14 @@ feature 'Dashboard Groups page', :js do end it 'can toggle parent group' do - # Collapsed by default - expect(page).not_to have_selector("#group-#{group.id} .fa-caret-down", count: 1) - expect(page).to have_selector("#group-#{group.id} .fa-caret-right") - # expand click_group_caret(group) - expect(page).to have_selector("#group-#{group.id} .fa-caret-down") - expect(page).not_to have_selector("#group-#{group.id} .fa-caret-right", count: 1) expect(page).to have_selector("#group-#{group.id} #group-#{subgroup.id}") # collapse click_group_caret(group) - expect(page).not_to have_selector("#group-#{group.id} .fa-caret-down", count: 1) - expect(page).to have_selector("#group-#{group.id} .fa-caret-right") expect(page).not_to have_selector("#group-#{group.id} #group-#{subgroup.id}") end end diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb new file mode 100644 index 00000000000..e4ef47d88dd --- /dev/null +++ b/spec/features/explore/groups_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe 'Explore Groups', :js do + let(:user) { create :user } + let(:group) { create :group } + let!(:private_project) do + create :project, :private, namespace: group do |project| + create(:issue, project: internal_project) + create(:merge_request, source_project: project, target_project: project) + end + end + + let!(:internal_project) do + create :project, :internal, namespace: group do |project| + create(:issue, project: project) + create(:merge_request, source_project: project, target_project: project) + end + end + + let!(:public_project) do + create(:project, :public, namespace: group) do |project| + create(:issue, project: project) + create(:merge_request, source_project: project, target_project: project) + end + end + + shared_examples 'renders public and internal projects' do + it do + visit_page + expect(page).to have_content(public_project.name) + expect(page).to have_content(internal_project.name) + expect(page).not_to have_content(private_project.name) + end + end + + shared_examples 'renders only public project' do + it do + visit_page + expect(page).to have_content(public_project.name) + expect(page).not_to have_content(internal_project.name) + expect(page).not_to have_content(private_project.name) + end + end + + shared_examples 'renders group in public groups area' do + it do + visit explore_groups_path + expect(page).to have_content(group.name) + end + end + + context 'when signed in' do + before do + sign_in(user) + end + + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit group_path(group) } + end + + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit issues_group_path(group) } + end + + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end + + it_behaves_like 'renders group in public groups area' + end + + context 'when signed out' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit group_path(group) } + end + + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit issues_group_path(group) } + end + + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end + + it_behaves_like 'renders group in public groups area' + end +end diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index 7fc2b383749..ceccc471405 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -55,4 +55,20 @@ feature 'Group show page' do end end end + + context 'group has a project with emoji in description', :js do + let(:user) { create(:user) } + let!(:project) { create(:project, description: ':smile:', namespace: group) } + + before do + group.add_owner(user) + sign_in(user) + visit path + end + + it 'shows the project info' do + expect(page).to have_content(project.title) + expect(page).to have_selector('gl-emoji[data-name="smile"]') + end + end end diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb new file mode 100644 index 00000000000..e4be6193b8b --- /dev/null +++ b/spec/features/invites_spec.rb @@ -0,0 +1,97 @@ +require 'spec_helper' + +describe 'Invites' do + let(:user) { create(:user) } + let(:owner) { create(:user, name: 'John Doe') } + let(:group) { create(:group, name: 'Owned') } + let(:project) { create(:project, :repository, namespace: group) } + let(:invite) { group.group_members.invite.last } + + before do + project.add_master(owner) + group.add_user(owner, Gitlab::Access::OWNER) + group.add_developer('user@example.com', owner) + invite.generate_invite_token! + end + + context 'when signed out' do + before do + visit invite_path(invite.raw_invite_token) + end + + it 'renders sign in page with sign in notice' do + expect(current_path).to eq(new_user_session_path) + expect(page).to have_content('To accept this invitation, sign in') + end + + it 'sign in and redirects to invitation page' do + fill_in 'user_login', with: user.email + fill_in 'user_password', with: user.password + check 'user_remember_me' + click_button 'Sign in' + + expect(current_path).to eq(invite_path(invite.raw_invite_token)) + expect(page).to have_content( + 'You have been invited by John Doe to join group Owned as Developer.' + ) + expect(page).to have_link('Accept invitation') + expect(page).to have_link('Decline') + end + end + + context 'when signed in as an exists member' do + before do + sign_in(owner) + end + + it 'shows message user already a member' do + visit invite_path(invite.raw_invite_token) + expect(page).to have_content('However, you are already a member of this group.') + end + end + + describe 'accepting the invitation' do + before do + sign_in(user) + visit invite_path(invite.raw_invite_token) + end + + it 'grants access and redirects to group page' do + page.click_link 'Accept invitation' + expect(current_path).to eq(group_path(group)) + expect(page).to have_content( + 'You have been granted Developer access to group Owned.' + ) + end + end + + describe 'declining the application' do + context 'when signed in' do + before do + sign_in(user) + visit invite_path(invite.raw_invite_token) + end + + it 'declines application and redirects to dashboard' do + page.click_link 'Decline' + expect(current_path).to eq(dashboard_projects_path) + expect(page).to have_content( + 'You have declined the invitation to join group Owned.' + ) + end + end + + context 'when signed out' do + before do + visit decline_invite_path(invite.raw_invite_token) + end + + it 'declines application and redirects to sign in page' do + expect(current_path).to eq(new_user_session_path) + expect(page).to have_content( + 'You have declined the invitation to join group Owned.' + ) + end + end + end +end diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 587ece22ec7..cf283119f36 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -377,6 +377,7 @@ feature 'Issues > Labels bulk assignment' do items.map do |item| click_link item end + if unmark items.map do |item| # Make sure we are unmarking the item no matter the state it has currently diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index 18ae45aa340..ef40dddfd3a 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -176,6 +176,7 @@ describe 'Dropdown hint', :js do it 'reuses existing author text' do filtered_search.send_keys('author:') filtered_search.send_keys(:backspace) + filtered_search.send_keys(:backspace) click_hint('author') expect_tokens([{ name: 'author' }]) @@ -185,6 +186,7 @@ describe 'Dropdown hint', :js do it 'reuses existing assignee text' do filtered_search.send_keys('assignee:') filtered_search.send_keys(:backspace) + filtered_search.send_keys(:backspace) click_hint('assignee') expect_tokens([{ name: 'assignee' }]) @@ -194,6 +196,7 @@ describe 'Dropdown hint', :js do it 'reuses existing milestone text' do filtered_search.send_keys('milestone:') filtered_search.send_keys(:backspace) + filtered_search.send_keys(:backspace) click_hint('milestone') expect_tokens([{ name: 'milestone' }]) @@ -203,6 +206,7 @@ describe 'Dropdown hint', :js do it 'reuses existing label text' do filtered_search.send_keys('label:') filtered_search.send_keys(:backspace) + filtered_search.send_keys(:backspace) click_hint('label') expect_tokens([{ name: 'label' }]) @@ -212,6 +216,7 @@ describe 'Dropdown hint', :js do it 'reuses existing emoji text' do filtered_search.send_keys('my-reaction:') filtered_search.send_keys(:backspace) + filtered_search.send_keys(:backspace) click_hint('my-reaction') expect_tokens([{ name: 'my-reaction' }]) diff --git a/spec/features/issues/keyboard_shortcut_spec.rb b/spec/features/issues/keyboard_shortcut_spec.rb new file mode 100644 index 00000000000..961de9d3d25 --- /dev/null +++ b/spec/features/issues/keyboard_shortcut_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' + +describe 'Issues shortcut', :js do + context 'New Issue shortcut' do + context 'issues are enabled' do + let(:project) { create(:project) } + + before do + sign_in(create(:admin)) + + visit project_path(project) + end + + it 'takes user to the new issue page' do + find('body').native.send_keys('i') + expect(page).to have_selector('#new_issue') + end + end + + context 'issues are not enabled' do + let(:project) { create(:project, :issues_disabled) } + + before do + sign_in(create(:admin)) + + visit project_path(project) + end + + it 'does not take user to the new issue page' do + find('body').native.send_keys('i') + + expect(page).to have_selector("body[data-page='projects:show']") + end + end + end +end diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb index e285befc66f..a2b78a5e021 100644 --- a/spec/features/markdown_spec.rb +++ b/spec/features/markdown_spec.rb @@ -71,7 +71,7 @@ describe 'GitLab Markdown' do it 'parses mermaid code block' do aggregate_failures do - expect(doc).to have_selector('pre.code.js-render-mermaid') + expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid') end end diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb index b45972b7f6b..73a526c3d8a 100644 --- a/spec/features/password_reset_spec.rb +++ b/spec/features/password_reset_spec.rb @@ -33,6 +33,25 @@ feature 'Password reset' do end end + describe 'Changing password while logged in' do + it 'updates the password' do + user = create(:user) + token = user.send_reset_password_instructions + + sign_in(user) + + visit(edit_user_password_path(reset_password_token: token)) + + fill_in 'New password', with: 'hello1234' + fill_in 'Confirm new password', with: 'hello1234' + + click_button 'Change your password' + + expect(page).to have_content(I18n.t('devise.passwords.updated_not_active')) + expect(current_path).to eq new_user_session_path + end + end + def forgot_password(user) visit root_path click_on 'Forgot your password?' diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb index 7d5ba3a7328..b04a5422fed 100644 --- a/spec/features/profiles/keys_spec.rb +++ b/spec/features/profiles/keys_spec.rb @@ -27,6 +27,7 @@ feature 'Profile > SSH Keys' do expect(page).to have_content("Title: #{attrs[:title]}") expect(page).to have_content(attrs[:key]) + expect(find('.breadcrumbs-sub-title')).to have_link(attrs[:title]) end context 'when only DSA and ECDSA keys are allowed' do diff --git a/spec/features/profiles/oauth_applications_spec.rb b/spec/features/profiles/oauth_applications_spec.rb index d1edeef8da4..7d204f89fba 100644 --- a/spec/features/profiles/oauth_applications_spec.rb +++ b/spec/features/profiles/oauth_applications_spec.rb @@ -2,12 +2,20 @@ require 'spec_helper' describe 'Profile > Applications' do let(:user) { create(:user) } + let(:application) { create(:oauth_application, owner: user) } before do sign_in(user) end describe 'User manages applications', :js do + it 'views an application' do + visit oauth_application_path(application) + + expect(page).to have_content("Application: #{application.name}") + expect(find('.breadcrumbs-sub-title')).to have_link(application.name) + end + it 'deletes an application' do create(:oauth_application, owner: user) visit oauth_applications_path diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb index 90d6841af0e..266af8f4e3d 100644 --- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb +++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb @@ -32,6 +32,18 @@ describe 'User visits the profile preferences page' do end end + describe 'User changes their multi file editor preferences', :js do + it 'set the new_repo cookie when the option is ON' do + choose 'user_multi_file_on' + expect(get_cookie('new_repo')).not_to be_nil + end + + it 'deletes the new_repo cookie when the option is OFF' do + choose 'user_multi_file_off' + expect(get_cookie('new_repo')).to be_nil + end + end + describe 'User changes their default dashboard', :js do it 'creates a flash message' do select 'Starred Projects', from: 'user_dashboard' diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 67b8901f8fb..8953b30bebf 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -13,6 +13,8 @@ feature 'Gcp Cluster', :js do end context 'when user has signed with Google' do + let(:project_id) { 'test-project-1234' } + before do allow_any_instance_of(Projects::Clusters::GcpController) .to receive(:token_in_session).and_return('token') @@ -20,105 +22,152 @@ feature 'Gcp Cluster', :js do .to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s) end - context 'when user does not have a cluster and visits cluster index page' do + context 'when user has a GCP project with billing enabled' do before do - visit project_clusters_path(project) - - click_link 'Add cluster' - click_link 'Create on GKE' + allow_any_instance_of(Projects::Clusters::GcpController).to receive(:authorize_google_project_billing) + allow_any_instance_of(Projects::Clusters::GcpController).to receive(:google_project_billing_status).and_return('true') end - context 'when user filled form with valid parameters' do + context 'when user does not have a cluster and visits cluster index page' do before do - allow_any_instance_of(GoogleApi::CloudPlatform::Client) - .to receive(:projects_zones_clusters_create) do - OpenStruct.new( - self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', - status: 'RUNNING' - ) + visit project_clusters_path(project) + + click_link 'Add cluster' + click_link 'Create on GKE' + end + + context 'when user filled form with valid parameters' do + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_clusters_create) do + OpenStruct.new( + self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', + status: 'RUNNING' + ) + end + + allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil) + + fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123' + fill_in 'cluster_name', with: 'dev-cluster' + click_button 'Create cluster' end - allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil) + it 'user sees a cluster details page and creation status' do + expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') - fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123' - fill_in 'cluster_name', with: 'dev-cluster' - click_button 'Create cluster' - end + Clusters::Cluster.last.provider.make_created! - it 'user sees a cluster details page and creation status' do - expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') + expect(page).to have_content('Cluster was successfully created on Google Kubernetes Engine') + end - Clusters::Cluster.last.provider.make_created! + it 'user sees a error if something worng during creation' do + expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') - expect(page).to have_content('Cluster was successfully created on Google Kubernetes Engine') - end + Clusters::Cluster.last.provider.make_errored!('Something wrong!') - it 'user sees a error if something worng during creation' do - expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') + expect(page).to have_content('Something wrong!') + end + end - Clusters::Cluster.last.provider.make_errored!('Something wrong!') + context 'when user filled form with invalid parameters' do + before do + click_button 'Create cluster' + end - expect(page).to have_content('Something wrong!') + it 'user sees a validation error' do + expect(page).to have_css('#error_explanation') + end end end - context 'when user filled form with invalid parameters' do + context 'when user does have a cluster and visits cluster page' do + let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } + before do - click_button 'Create cluster' + visit project_cluster_path(project, cluster) end - it 'user sees a validation error' do - expect(page).to have_css('#error_explanation') + it 'user sees a cluster details page' do + expect(page).to have_button('Save changes') + expect(page.find(:css, '.cluster-name').value).to eq(cluster.name) end - end - end - context 'when user does have a cluster and visits cluster page' do - let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } + context 'when user disables the cluster' do + before do + page.find(:css, '.js-toggle-cluster').click + page.within('#cluster-integration') { click_button 'Save changes' } + end - before do - visit project_cluster_path(project, cluster) - end + it 'user sees the successful message' do + expect(page).to have_content('Cluster was successfully updated.') + end + end - it 'user sees a cluster details page' do - expect(page).to have_button('Save') - expect(page.find(:css, '.cluster-name').value).to eq(cluster.name) - end + context 'when user changes cluster parameters' do + before do + fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' + page.within('#js-cluster-details') { click_button 'Save changes' } + end - context 'when user disables the cluster' do - before do - page.find(:css, '.js-toggle-cluster').click - click_button 'Save' + it 'user sees the successful message' do + expect(page).to have_content('Cluster was successfully updated.') + expect(cluster.reload.platform_kubernetes.namespace).to eq('my-namespace') + end end - it 'user sees the successful message' do - expect(page).to have_content('Cluster was successfully updated.') + context 'when user destroy the cluster' do + before do + page.accept_confirm do + click_link 'Remove integration' + end + end + + it 'user sees creation form with the successful message' do + expect(page).to have_content('Cluster integration was successfully removed.') + expect(page).to have_link('Add cluster') + end end end + end - context 'when user changes cluster parameters' do - before do - fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' - click_button 'Save changes' - end + context 'when user does not have a GCP project with billing enabled' do + before do + allow_any_instance_of(Projects::Clusters::GcpController).to receive(:authorize_google_project_billing) + allow_any_instance_of(Projects::Clusters::GcpController).to receive(:google_project_billing_status).and_return('false') - it 'user sees the successful message' do - expect(page).to have_content('Cluster was successfully updated.') - expect(cluster.reload.platform_kubernetes.namespace).to eq('my-namespace') - end + visit project_clusters_path(project) + + click_link 'Add cluster' + click_link 'Create on GKE' + + fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123' + fill_in 'cluster_name', with: 'dev-cluster' + click_button 'Create cluster' end - context 'when user destroy the cluster' do - before do - page.accept_confirm do - click_link 'Remove integration' - end - end + it 'user sees form with error' do + expect(page).to have_content('Please enable billing for one of your projects to be able to create a cluster, then try again.') + end + end - it 'user sees creation form with the successful message' do - expect(page).to have_content('Cluster integration was successfully removed.') - expect(page).to have_link('Add cluster') - end + context 'when gcp billing status is not in redis' do + before do + allow_any_instance_of(Projects::Clusters::GcpController).to receive(:authorize_google_project_billing) + allow_any_instance_of(Projects::Clusters::GcpController).to receive(:google_project_billing_status).and_return(nil) + + visit project_clusters_path(project) + + click_link 'Add cluster' + click_link 'Create on GKE' + + fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123' + fill_in 'cluster_name', with: 'dev-cluster' + click_button 'Create cluster' + end + + it 'user sees form with error' do + expect(page).to have_content('We could not verify that one of your projects on GCP has billing enabled. Please try again.') end end end diff --git a/spec/features/projects/clusters/interchangeability_spec.rb b/spec/features/projects/clusters/interchangeability_spec.rb index 01f9526608f..3ddb35c755c 100644 --- a/spec/features/projects/clusters/interchangeability_spec.rb +++ b/spec/features/projects/clusters/interchangeability_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Interchangeability between KubernetesService and Platform::Kubernetes' do - EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url=].freeze + EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url= deprecated? deprecation_message].freeze EXCEPT_METHODS_GREP_V = %w[_touched? _changed? _was].freeze it 'Clusters::Platform::Kubernetes covers core interfaces in KubernetesService' do diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb index 414f4acba86..a519b9f9c7e 100644 --- a/spec/features/projects/clusters/user_spec.rb +++ b/spec/features/projects/clusters/user_spec.rb @@ -29,7 +29,7 @@ feature 'User Cluster', :js do end it 'user sees a cluster details page' do - expect(page).to have_content('Enable cluster integration') + expect(page).to have_content('Cluster integration') expect(page.find_field('cluster[name]').value).to eq('dev-cluster') expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value) .to have_content('http://example.com') @@ -57,14 +57,14 @@ feature 'User Cluster', :js do end it 'user sees a cluster details page' do - expect(page).to have_button('Save') + expect(page).to have_button('Save changes') end context 'when user disables the cluster' do before do page.find(:css, '.js-toggle-cluster').click fill_in 'cluster_name', with: 'dev-cluster' - click_button 'Save' + page.within('#cluster-integration') { click_button 'Save changes' } end it 'user sees the successful message' do @@ -76,7 +76,7 @@ feature 'User Cluster', :js do before do fill_in 'cluster_name', with: 'my-dev-cluster' fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' - click_button 'Save changes' + page.within('#js-cluster-details') { click_button 'Save changes' } end it 'user sees the successful message' do diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index 93929bf6814..eae2910a8f6 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -77,4 +77,18 @@ feature 'Clusters', :js do end end end + + context 'when user has not signed in Google' do + before do + visit project_clusters_path(project) + + click_link 'Add cluster' + click_link 'Create on GKE' + end + + it 'user sees a login page' do + expect(page).to have_css('.signin-with-google') + expect(page).to have_link('Google account') + end + end end diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index 41f3c15a94c..b650c1f4197 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'User broweses commits' do +describe 'User browses commits' do let(:user) { create(:user) } let(:project) { create(:project, :repository, namespace: user.namespace) } @@ -31,6 +31,19 @@ describe 'User broweses commits' do check_author_link(RepoHelpers.sample_commit.author_email, user) end end + + context 'when the blob does not exist' do + let(:commit) { create(:commit, project: project) } + + it 'shows a blank label' do + allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil) + allow_any_instance_of(Gitlab::Diff::File).to receive(:raw_binary?).and_return(true) + + visit(project_commit_path(project, commit)) + + expect(find('.diff-file-changes', visible: false)).to have_content('No file name available') + end + end end private diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index 461aa39d0ad..6732cf61767 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' # Integration test that exports a file using the Import/Export feature # It looks up for any sensitive word inside the JSON, so if a sensitive word is found -# we''l have to either include it adding the model that includes it to the +safe_list+ +# we'll have to either include it adding the model that includes it to the +safe_list+ # or make sure the attribute is blacklisted in the +import_export.yml+ configuration feature 'Import/Export - project export integration test', :js do include Select2Helper diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz Binary files differindex 0c354298433..0cc68aff494 100644 --- a/spec/features/projects/import_export/test_project_export.tar.gz +++ b/spec/features/projects/import_export/test_project_export.tar.gz diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index 5d9208ebadd..4c49cff30d4 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'User browses a job', :js do - let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) } + let!(:build) { create(:ci_build, :running, :coverage, pipeline: pipeline) } let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } let(:project) { create(:project, :repository, namespace: user.namespace) } let(:user) { create(:user) } diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index f8ea1a52656..9a6b27c00f8 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -369,6 +369,34 @@ feature 'Jobs' do end end end + + context 'Playable manual action' do + let(:job) { create(:ci_build, :playable, pipeline: pipeline) } + + before do + project.add_developer(user) + visit project_job_path(project, job) + end + + it 'shows manual action empty state' do + expect(page).to have_content('This job requires a manual action') + expect(page).to have_content('This job depends on a user to trigger its process. Often they are used to deploy code to production environments.') + expect(page).to have_link('Trigger this manual action') + end + end + + context 'Non triggered job' do + let(:job) { create(:ci_build, :created, pipeline: pipeline) } + + before do + visit project_job_path(project, job) + end + + it 'shows manual action empty state' do + expect(page).to have_content('This job has not been triggered yet') + expect(page).to have_content('This job depends on upstream jobs that need to succeed in order for this job to be triggered.') + end + end end describe "POST /:project/jobs/:id/cancel", :js do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index df261c246f7..592c99fc64a 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -545,6 +545,40 @@ describe 'Pipelines', :js do end end end + + describe 'Reset runner caches' do + let(:project) { create(:project, :repository) } + + before do + create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master') + project.add_master(user) + visit project_pipelines_path(project) + end + + it 'has a clear caches button' do + expect(page).to have_link 'Clear runner caches' + end + + describe 'user clicks the button' do + context 'when project already has jobs_cache_index' do + before do + project.update_attributes(jobs_cache_index: 1) + end + + it 'increments jobs_cache_index' do + click_link 'Clear runner caches' + expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' + end + end + + context 'when project does not have jobs_cache_index' do + it 'sets jobs_cache_index to 1' do + click_link 'Clear runner caches' + expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' + end + end + end + end end context 'when user is not logged in' do diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb index 3f6d16c8acf..0c67196f53e 100644 --- a/spec/features/projects/tree/create_directory_spec.rb +++ b/spec/features/projects/tree/create_directory_spec.rb @@ -14,7 +14,7 @@ feature 'Multi-file editor new directory', :js do wait_for_requests - click_link('Multi Edit') + click_link('Web IDE') wait_for_requests end diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb index ba71eef07f4..85f7318c05d 100644 --- a/spec/features/projects/tree/create_file_spec.rb +++ b/spec/features/projects/tree/create_file_spec.rb @@ -14,7 +14,7 @@ feature 'Multi-file editor new file', :js do wait_for_requests - click_link('Multi Edit') + click_link('Web IDE') wait_for_requests end diff --git a/spec/features/projects/tree/upload_file_spec.rb b/spec/features/projects/tree/upload_file_spec.rb index 9fbb1dbd0e8..f81e8677e92 100644 --- a/spec/features/projects/tree/upload_file_spec.rb +++ b/spec/features/projects/tree/upload_file_spec.rb @@ -16,7 +16,7 @@ feature 'Multi-file editor upload file', :js do wait_for_requests - click_link('Multi Edit') + click_link('Web IDE') wait_for_requests end diff --git a/spec/features/projects/user_edits_files_spec.rb b/spec/features/projects/user_edits_files_spec.rb index 5c5c6a398f6..05c2be473da 100644 --- a/spec/features/projects/user_edits_files_spec.rb +++ b/spec/features/projects/user_edits_files_spec.rb @@ -33,7 +33,9 @@ describe 'User edits files' do binary_file = File.join(project.repository.root_ref, 'files/images/logo-black.png') visit(project_blob_path(project, binary_file)) - expect(page).not_to have_link('edit') + page.within '.content' do + expect(page).not_to have_link('edit') + end end it 'commits an edited file', :js do diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index c7f0e342809..aec9de6c7ca 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -33,6 +33,26 @@ feature 'Runners' do expect(page).to have_content(specific_runner.platform) end + scenario 'user can pause and resume the specific runner' do + visit runners_path(project) + + within '.activated-specific-runners' do + expect(page).to have_content('Pause') + end + + click_on 'Pause' + + within '.activated-specific-runners' do + expect(page).to have_content('Resume') + end + + click_on 'Resume' + + within '.activated-specific-runners' do + expect(page).to have_content('Pause') + end + end + scenario 'user removes an activated specific runner if this is last project for that runners' do visit runners_path(project) diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index c9afef2a8de..50ee1656e10 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -264,7 +264,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do end it "deletes u2f registrations" do - visit profile_account_path + visit profile_two_factor_auth_path expect do accept_confirm { click_on "Disable" } end.to change { U2fRegistration.count }.by(-1) |