diff options
Diffstat (limited to 'spec')
16 files changed, 761 insertions, 453 deletions
diff --git a/spec/features/todos/target_state_spec.rb b/spec/features/dashboard/todos/target_state_spec.rb index 99b70b3d3a1..030a86d1c01 100644 --- a/spec/features/todos/target_state_spec.rb +++ b/spec/features/dashboard/todos/target_state_spec.rb @@ -1,12 +1,12 @@ require 'rails_helper' -feature 'Todo target states', feature: true do +feature 'Dashboard > Todo target states' do let(:user) { create(:user) } let(:author) { create(:user) } - let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + let(:project) { create(:project, :public) } before do - gitlab_sign_in user + sign_in(user) end scenario 'on a closed issue todo has closed label' do @@ -30,7 +30,7 @@ feature 'Todo target states', feature: true do end scenario 'on a merged merge request todo has merged label' do - mr_merged = create(:merge_request, :simple, author: user, state: 'merged') + mr_merged = create(:merge_request, :simple, :merged, author: user) create_todo mr_merged visit dashboard_todos_path @@ -40,7 +40,7 @@ feature 'Todo target states', feature: true do end scenario 'on a closed merge request todo has closed label' do - mr_closed = create(:merge_request, :simple, author: user, state: 'closed') + mr_closed = create(:merge_request, :simple, :closed, author: user) create_todo mr_closed visit dashboard_todos_path diff --git a/spec/features/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb index 032fb479076..0a363259fe7 100644 --- a/spec/features/todos/todos_filtering_spec.rb +++ b/spec/features/dashboard/todos/todos_filtering_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Dashboard > User filters todos', feature: true, js: true do +feature 'Dashboard > User filters todos', js: true do let(:user_1) { create(:user, username: 'user_1', name: 'user_1') } let(:user_2) { create(:user, username: 'user_2', name: 'user_2') } @@ -17,7 +17,7 @@ describe 'Dashboard > User filters todos', feature: true, js: true do project_1.team << [user_1, :developer] project_2.team << [user_1, :developer] - gitlab_sign_in(user_1) + sign_in(user_1) visit dashboard_todos_path end @@ -34,7 +34,7 @@ describe 'Dashboard > User filters todos', feature: true, js: true do expect(page).not_to have_content project_2.name_with_namespace end - context "Author filter" do + context 'Author filter' do it 'filters by author' do click_button 'Author' @@ -49,18 +49,18 @@ describe 'Dashboard > User filters todos', feature: true, js: true do expect(find('.todos-list')).not_to have_content 'issue' end - it "shows only authors of existing todos" do + it 'shows only authors of existing todos' do click_button 'Author' within '.dropdown-menu-author' do - # It should contain two users + "Any Author" + # It should contain two users + 'Any Author' expect(page).to have_selector('.dropdown-menu-user-link', count: 3) expect(page).to have_content(user_1.name) expect(page).to have_content(user_2.name) end end - it "shows only authors of existing done todos" do + it 'shows only authors of existing done todos' do user_3 = create :user user_4 = create :user create(:todo, user: user_1, author: user_3, project: project_1, target: issue, action: 1, state: :done) @@ -74,7 +74,7 @@ describe 'Dashboard > User filters todos', feature: true, js: true do click_button 'Author' within '.dropdown-menu-author' do - # It should contain two users + "Any Author" + # It should contain two users + 'Any Author' expect(page).to have_selector('.dropdown-menu-user-link', count: 3) expect(page).to have_content(user_3.name) expect(page).to have_content(user_4.name) diff --git a/spec/features/todos/todos_sorting_spec.rb b/spec/features/dashboard/todos/todos_sorting_spec.rb index 498bbac6d14..5858f4aa101 100644 --- a/spec/features/todos/todos_sorting_spec.rb +++ b/spec/features/dashboard/todos/todos_sorting_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Dashboard > User sorts todos", feature: true do +feature 'Dashboard > User sorts todos' do let(:user) { create(:user) } let(:project) { create(:empty_project) } @@ -18,7 +18,7 @@ describe "Dashboard > User sorts todos", feature: true do let(:issue_3) { create(:issue, title: 'issue_3', project: project) } let(:issue_4) { create(:issue, title: 'issue_4', project: project) } - let!(:merge_request_1) { create(:merge_request, source_project: project, title: "merge_request_1") } + let!(:merge_request_1) { create(:merge_request, source_project: project, title: 'merge_request_1') } before do create(:todo, user: user, project: project, target: issue_4, created_at: 5.hours.ago) @@ -32,41 +32,41 @@ describe "Dashboard > User sorts todos", feature: true do issue_2.labels << label_3 issue_1.labels << label_2 - gitlab_sign_in(user) + sign_in(user) visit dashboard_todos_path end - it "sorts with oldest created todos first" do - click_link "Last created" + it 'sorts with oldest created todos first' do + click_link 'Last created' results_list = page.find('.todos-list') - expect(results_list.all('p')[0]).to have_content("merge_request_1") - expect(results_list.all('p')[1]).to have_content("issue_1") - expect(results_list.all('p')[2]).to have_content("issue_3") - expect(results_list.all('p')[3]).to have_content("issue_2") - expect(results_list.all('p')[4]).to have_content("issue_4") + expect(results_list.all('p')[0]).to have_content('merge_request_1') + expect(results_list.all('p')[1]).to have_content('issue_1') + expect(results_list.all('p')[2]).to have_content('issue_3') + expect(results_list.all('p')[3]).to have_content('issue_2') + expect(results_list.all('p')[4]).to have_content('issue_4') end - it "sorts with newest created todos first" do - click_link "Oldest created" + it 'sorts with newest created todos first' do + click_link 'Oldest created' results_list = page.find('.todos-list') - expect(results_list.all('p')[0]).to have_content("issue_4") - expect(results_list.all('p')[1]).to have_content("issue_2") - expect(results_list.all('p')[2]).to have_content("issue_3") - expect(results_list.all('p')[3]).to have_content("issue_1") - expect(results_list.all('p')[4]).to have_content("merge_request_1") + expect(results_list.all('p')[0]).to have_content('issue_4') + expect(results_list.all('p')[1]).to have_content('issue_2') + expect(results_list.all('p')[2]).to have_content('issue_3') + expect(results_list.all('p')[3]).to have_content('issue_1') + expect(results_list.all('p')[4]).to have_content('merge_request_1') end - it "sorts by label priority" do - click_link "Label priority" + it 'sorts by label priority' do + click_link 'Label priority' results_list = page.find('.todos-list') - expect(results_list.all('p')[0]).to have_content("issue_3") - expect(results_list.all('p')[1]).to have_content("merge_request_1") - expect(results_list.all('p')[2]).to have_content("issue_1") - expect(results_list.all('p')[3]).to have_content("issue_2") - expect(results_list.all('p')[4]).to have_content("issue_4") + expect(results_list.all('p')[0]).to have_content('issue_3') + expect(results_list.all('p')[1]).to have_content('merge_request_1') + expect(results_list.all('p')[2]).to have_content('issue_1') + expect(results_list.all('p')[3]).to have_content('issue_2') + expect(results_list.all('p')[4]).to have_content('issue_4') end end @@ -88,12 +88,12 @@ describe "Dashboard > User sorts todos", feature: true do end it "doesn't mix issues and merge requests label priorities" do - click_link "Label priority" + click_link 'Label priority' results_list = page.find('.todos-list') - expect(results_list.all('p')[0]).to have_content("issue_1") - expect(results_list.all('p')[1]).to have_content("issue_2") - expect(results_list.all('p')[2]).to have_content("merge_request_1") + expect(results_list.all('p')[0]).to have_content('issue_1') + expect(results_list.all('p')[1]).to have_content('issue_2') + expect(results_list.all('p')[2]).to have_content('merge_request_1') end end end diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb new file mode 100644 index 00000000000..24da5db305f --- /dev/null +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -0,0 +1,355 @@ +require 'spec_helper' + +feature 'Dashboard Todos' do + let(:user) { create(:user) } + let(:author) { create(:user) } + let(:project) { create(:project, :public) } + let(:issue) { create(:issue, due_date: Date.today) } + + context 'User does not have todos' do + before do + sign_in(user) + visit dashboard_todos_path + end + + it 'shows "All done" message' do + expect(page).to have_content 'Todos let you see what you should do next.' + end + end + + context 'User has a todo', js: true do + before do + create(:todo, :mentioned, user: user, project: project, target: issue, author: author) + sign_in(user) + + visit dashboard_todos_path + end + + it 'has todo present' do + expect(page).to have_selector('.todos-list .todo', count: 1) + end + + it 'shows due date as today' do + within first('.todo') do + expect(page).to have_content 'Due today' + end + end + + shared_examples 'deleting the todo' do + before do + within first('.todo') do + click_link 'Done' + end + end + + it 'is marked as done-reversible in the list' do + expect(page).to have_selector('.todos-list .todo.todo-pending.done-reversible') + end + + it 'shows Undo button' do + expect(page).to have_selector('.js-undo-todo', visible: true) + expect(page).to have_selector('.js-done-todo', visible: false) + end + + it 'updates todo count' do + expect(page).to have_content 'To do 0' + expect(page).to have_content 'Done 1' + end + + it 'has not "All done" message' do + expect(page).not_to have_selector('.todos-all-done') + end + end + + shared_examples 'deleting and restoring the todo' do + before do + within first('.todo') do + click_link 'Done' + wait_for_requests + click_link 'Undo' + end + end + + it 'is marked back as pending in the list' do + expect(page).not_to have_selector('.todos-list .todo.todo-pending.done-reversible') + expect(page).to have_selector('.todos-list .todo.todo-pending') + end + + it 'shows Done button' do + expect(page).to have_selector('.js-undo-todo', visible: false) + expect(page).to have_selector('.js-done-todo', visible: true) + end + + it 'updates todo count' do + expect(page).to have_content 'To do 1' + expect(page).to have_content 'Done 0' + end + end + + it_behaves_like 'deleting the todo' + it_behaves_like 'deleting and restoring the todo' + + context 'todo is stale on the page' do + before do + todos = TodosFinder.new(user, state: :pending).execute + TodoService.new.mark_todos_as_done(todos, user) + end + + it_behaves_like 'deleting the todo' + it_behaves_like 'deleting and restoring the todo' + end + end + + context 'User created todos for themself' do + before do + sign_in(user) + end + + context 'issue assigned todo' do + before do + create(:todo, :assigned, user: user, project: project, target: issue, author: user) + visit dashboard_todos_path + end + + it 'shows issue assigned to yourself message' do + page.within('.js-todos-all') do + expect(page).to have_content("You assigned issue #{issue.to_reference(full: true)} to yourself") + end + end + end + + context 'marked todo' do + before do + create(:todo, :marked, user: user, project: project, target: issue, author: user) + visit dashboard_todos_path + end + + it 'shows you added a todo message' do + page.within('.js-todos-all') do + expect(page).to have_content("You added a todo for issue #{issue.to_reference(full: true)}") + expect(page).not_to have_content('to yourself') + end + end + end + + context 'mentioned todo' do + before do + create(:todo, :mentioned, user: user, project: project, target: issue, author: user) + visit dashboard_todos_path + end + + it 'shows you mentioned yourself message' do + page.within('.js-todos-all') do + expect(page).to have_content("You mentioned yourself on issue #{issue.to_reference(full: true)}") + expect(page).not_to have_content('to yourself') + end + end + end + + context 'directly_addressed todo' do + before do + create(:todo, :directly_addressed, user: user, project: project, target: issue, author: user) + visit dashboard_todos_path + end + + it 'shows you directly addressed yourself message' do + page.within('.js-todos-all') do + expect(page).to have_content("You directly addressed yourself on issue #{issue.to_reference(full: true)}") + expect(page).not_to have_content('to yourself') + end + end + end + + context 'approval todo' do + let(:merge_request) { create(:merge_request) } + + before do + create(:todo, :approval_required, user: user, project: project, target: merge_request, author: user) + visit dashboard_todos_path + end + + it 'shows you set yourself as an approver message' do + page.within('.js-todos-all') do + expect(page).to have_content("You set yourself as an approver for merge request #{merge_request.to_reference(full: true)}") + expect(page).not_to have_content('to yourself') + end + end + end + end + + context 'User has done todos', js: true do + before do + create(:todo, :mentioned, :done, user: user, project: project, target: issue, author: author) + sign_in(user) + visit dashboard_todos_path(state: :done) + end + + it 'has the done todo present' do + expect(page).to have_selector('.todos-list .todo.todo-done', count: 1) + end + + describe 'restoring the todo' do + before do + within first('.todo') do + click_link 'Add todo' + end + end + + it 'is removed from the list' do + expect(page).not_to have_selector('.todos-list .todo.todo-done') + end + + it 'updates todo count' do + expect(page).to have_content 'To do 1' + expect(page).to have_content 'Done 0' + end + end + end + + context 'User has Todos with labels spanning multiple projects' do + before do + label1 = create(:label, project: project) + note1 = create(:note_on_issue, note: "Hello #{label1.to_reference(format: :name)}", noteable_id: issue.id, noteable_type: 'Issue', project: issue.project) + create(:todo, :mentioned, project: project, target: issue, user: user, note_id: note1.id) + + project2 = create(:project, :public) + label2 = create(:label, project: project2) + issue2 = create(:issue, project: project2) + note2 = create(:note_on_issue, note: "Test #{label2.to_reference(format: :name)}", noteable_id: issue2.id, noteable_type: 'Issue', project: project2) + create(:todo, :mentioned, project: project2, target: issue2, user: user, note_id: note2.id) + + gitlab_sign_in(user) + visit dashboard_todos_path + end + + it 'shows page with two Todos' do + expect(page).to have_selector('.todos-list .todo', count: 2) + end + end + + context 'User has multiple pages of Todos' do + before do + allow(Todo).to receive(:default_per_page).and_return(1) + + # Create just enough records to cause us to paginate + create_list(:todo, 2, :mentioned, user: user, project: project, target: issue, author: author) + + sign_in(user) + end + + it 'is paginated' do + visit dashboard_todos_path + + expect(page).to have_selector('.gl-pagination') + end + + it 'is has the right number of pages' do + visit dashboard_todos_path + + expect(page).to have_selector('.gl-pagination .page', count: 2) + end + + describe 'mark all as done', js: true do + before do + visit dashboard_todos_path + find('.js-todos-mark-all').trigger('click') + end + + it 'shows "All done" message!' do + expect(page).to have_content 'To do 0' + 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 + find('.js-todos-mark-all').trigger('click') + wait_for_requests + find('.js-todos-undo-all').trigger('click') + wait_for_requests + end + end + end + + context 'User has a Todo in a project pending deletion' do + before do + deleted_project = create(:project, :public, pending_delete: true) + create(:todo, :mentioned, user: user, project: deleted_project, target: issue, author: author) + create(:todo, :mentioned, user: user, project: deleted_project, target: issue, author: author, state: :done) + sign_in(user) + visit dashboard_todos_path + end + + it 'shows "All done" message' do + within('.todos-count') { expect(page).to have_content '0' } + expect(page).to have_content 'To do 0' + expect(page).to have_content 'Done 0' + expect(page).to have_selector('.todos-all-done', count: 1) + end + end + + context 'User has a Build Failed todo' do + let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author) } + + before do + sign_in(user) + visit dashboard_todos_path + end + + it 'shows the todo' do + expect(page).to have_content 'The build failed for merge request' + end + + it 'links to the pipelines for the merge request' do + href = pipelines_namespace_project_merge_request_path(project.namespace, project, todo.target) + + expect(page).to have_link "merge request #{todo.target.to_reference(full: true)}", href + end + end +end diff --git a/spec/features/groups/labels/subscription_spec.rb b/spec/features/groups/labels/subscription_spec.rb new file mode 100644 index 00000000000..8b891c52d08 --- /dev/null +++ b/spec/features/groups/labels/subscription_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +feature 'Labels subscription', feature: true do + let(:user) { create(:user) } + let(:group) { create(:group) } + let!(:feature) { create(:group_label, group: group, title: 'feature') } + + context 'when signed in' do + before do + group.add_developer(user) + gitlab_sign_in user + end + + scenario 'users can subscribe/unsubscribe to group labels', js: true do + visit group_labels_path(group) + + expect(page).to have_content('feature') + + within "#group_label_#{feature.id}" do + expect(page).not_to have_button 'Unsubscribe' + + click_button 'Subscribe' + + expect(page).not_to have_button 'Subscribe' + expect(page).to have_button 'Unsubscribe' + + click_button 'Unsubscribe' + + expect(page).to have_button 'Subscribe' + expect(page).not_to have_button 'Unsubscribe' + end + end + end + + context 'when not signed in' do + it 'users can not subscribe/unsubscribe to labels' do + visit group_labels_path(group) + + expect(page).to have_content 'feature' + expect(page).not_to have_button('Subscribe') + end + end + + def click_link_on_dropdown(text) + find('.dropdown-group-label').click + + page.within('.dropdown-group-label') do + find('a.js-subscribe-button', text: text).click + end + end +end diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index 53b8ba5b0f7..a8055b21cee 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -143,29 +143,8 @@ feature 'Login', feature: true do end context 'logging in via OAuth' do - def saml_config - OpenStruct.new(name: 'saml', label: 'saml', args: { - assertion_consumer_service_url: 'https://localhost:3443/users/auth/saml/callback', - idp_cert_fingerprint: '26:43:2C:47:AF:F0:6B:D0:07:9C:AD:A3:74:FE:5D:94:5F:4E:9E:52', - idp_sso_target_url: 'https://idp.example.com/sso/saml', - issuer: 'https://localhost:3443/', - name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient' - }) - end - - def stub_omniauth_config(messages) - Rails.application.env_config['devise.mapping'] = Devise.mappings[:user] - Rails.application.routes.disable_clear_and_finalize = true - Rails.application.routes.draw do - post '/users/auth/saml' => 'omniauth_callbacks#saml' - end - allow(Gitlab::OAuth::Provider).to receive_messages(providers: [:saml], config_for: saml_config) - allow(Gitlab.config.omniauth).to receive_messages(messages) - expect_any_instance_of(Object).to receive(:omniauth_authorize_path).with(:user, "saml").and_return('/users/auth/saml') - end - it 'shows 2FA prompt after OAuth login' do - stub_omniauth_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [saml_config]) + stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config]) user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: 'saml') gitlab_sign_in_via('saml', user, 'my-uid') diff --git a/spec/features/projects/no_password_spec.rb b/spec/features/projects/no_password_spec.rb new file mode 100644 index 00000000000..30a16e38e3c --- /dev/null +++ b/spec/features/projects/no_password_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +feature 'No Password Alert' do + let(:project) { create(:project, namespace: user.namespace) } + + context 'with internal auth enabled' do + before do + sign_in(user) + visit namespace_project_path(project.namespace, project) + end + + context 'when user has a password' do + let(:user) { create(:user) } + + it 'shows no alert' do + expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account" + end + end + + context 'when user has password automatically set' do + let(:user) { create(:user, password_automatically_set: true) } + + it 'shows a password alert' do + expect(page).to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account" + end + end + end + + context 'with internal auth disabled' do + let(:user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'saml') } + + before do + stub_application_setting(signin_enabled?: false) + stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config]) + end + + context 'when user has no personal access tokens' do + it 'has a personal access token alert' do + gitlab_sign_in_via('saml', user, 'my-uid') + visit namespace_project_path(project.namespace, project) + + expect(page).to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account" + end + end + + context 'when user has a personal access token' do + it 'shows no alert' do + create(:personal_access_token, user: user) + gitlab_sign_in_via('saml', user, 'my-uid') + visit namespace_project_path(project.namespace, project) + + expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account" + end + end + end + + context 'when user is ldap user' do + let(:user) { create(:omniauth_user, password_automatically_set: true) } + + before do + sign_in(user) + visit namespace_project_path(project.namespace, project) + end + + it 'shows no alert' do + expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you" + end + end +end diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index d310e7501ec..c7e2e3d8a34 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -33,6 +33,7 @@ describe 'Comments on personal snippets', :js, feature: true do expect(page).to have_selector('.note-emoji-button') end + find('body').click # close dropdown open_more_actions_dropdown(snippet_notes[1]) page.within("#notes-list li#note_#{snippet_notes[1].id}") do diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb deleted file mode 100644 index 41b32bdedc3..00000000000 --- a/spec/features/todos/todos_spec.rb +++ /dev/null @@ -1,355 +0,0 @@ -require 'spec_helper' - -describe 'Dashboard Todos', feature: true do - let(:user) { create(:user) } - let(:author) { create(:user) } - let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } - let(:issue) { create(:issue, due_date: Date.today) } - - describe 'GET /dashboard/todos' do - context 'User does not have todos' do - before do - gitlab_sign_in(user) - visit dashboard_todos_path - end - it 'shows "All done" message' do - expect(page).to have_content "Todos let you see what you should do next." - end - end - - context 'User has a todo', js: true do - before do - create(:todo, :mentioned, user: user, project: project, target: issue, author: author) - gitlab_sign_in(user) - visit dashboard_todos_path - end - - it 'has todo present' do - expect(page).to have_selector('.todos-list .todo', count: 1) - end - - it 'shows due date as today' do - within first('.todo') do - expect(page).to have_content 'Due today' - end - end - - shared_examples 'deleting the todo' do - before do - within first('.todo') do - click_link 'Done' - end - end - - it 'is marked as done-reversible in the list' do - expect(page).to have_selector('.todos-list .todo.todo-pending.done-reversible') - end - - it 'shows Undo button' do - expect(page).to have_selector('.js-undo-todo', visible: true) - expect(page).to have_selector('.js-done-todo', visible: false) - end - - it 'updates todo count' do - expect(page).to have_content 'To do 0' - expect(page).to have_content 'Done 1' - end - - it 'has not "All done" message' do - expect(page).not_to have_selector('.todos-all-done') - end - end - - shared_examples 'deleting and restoring the todo' do - before do - within first('.todo') do - click_link 'Done' - wait_for_requests - click_link 'Undo' - end - end - - it 'is marked back as pending in the list' do - expect(page).not_to have_selector('.todos-list .todo.todo-pending.done-reversible') - expect(page).to have_selector('.todos-list .todo.todo-pending') - end - - it 'shows Done button' do - expect(page).to have_selector('.js-undo-todo', visible: false) - expect(page).to have_selector('.js-done-todo', visible: true) - end - - it 'updates todo count' do - expect(page).to have_content 'To do 1' - expect(page).to have_content 'Done 0' - end - end - - it_behaves_like 'deleting the todo' - it_behaves_like 'deleting and restoring the todo' - - context 'todo is stale on the page' do - before do - todos = TodosFinder.new(user, state: :pending).execute - TodoService.new.mark_todos_as_done(todos, user) - end - - it_behaves_like 'deleting the todo' - it_behaves_like 'deleting and restoring the todo' - end - end - - context 'User created todos for themself' do - before do - gitlab_sign_in(user) - end - - context 'issue assigned todo' do - before do - create(:todo, :assigned, user: user, project: project, target: issue, author: user) - visit dashboard_todos_path - end - - it 'shows issue assigned to yourself message' do - page.within('.js-todos-all') do - expect(page).to have_content("You assigned issue #{issue.to_reference(full: true)} to yourself") - end - end - end - - context 'marked todo' do - before do - create(:todo, :marked, user: user, project: project, target: issue, author: user) - visit dashboard_todos_path - end - - it 'shows you added a todo message' do - page.within('.js-todos-all') do - expect(page).to have_content("You added a todo for issue #{issue.to_reference(full: true)}") - expect(page).not_to have_content('to yourself') - end - end - end - - context 'mentioned todo' do - before do - create(:todo, :mentioned, user: user, project: project, target: issue, author: user) - visit dashboard_todos_path - end - - it 'shows you mentioned yourself message' do - page.within('.js-todos-all') do - expect(page).to have_content("You mentioned yourself on issue #{issue.to_reference(full: true)}") - expect(page).not_to have_content('to yourself') - end - end - end - - context 'directly_addressed todo' do - before do - create(:todo, :directly_addressed, user: user, project: project, target: issue, author: user) - visit dashboard_todos_path - end - - it 'shows you directly addressed yourself message' do - page.within('.js-todos-all') do - expect(page).to have_content("You directly addressed yourself on issue #{issue.to_reference(full: true)}") - expect(page).not_to have_content('to yourself') - end - end - end - - context 'approval todo' do - let(:merge_request) { create(:merge_request) } - - before do - create(:todo, :approval_required, user: user, project: project, target: merge_request, author: user) - visit dashboard_todos_path - end - - it 'shows you set yourself as an approver message' do - page.within('.js-todos-all') do - expect(page).to have_content("You set yourself as an approver for merge request #{merge_request.to_reference(full: true)}") - expect(page).not_to have_content('to yourself') - end - end - end - end - - context 'User has done todos', js: true do - before do - create(:todo, :mentioned, :done, user: user, project: project, target: issue, author: author) - gitlab_sign_in(user) - visit dashboard_todos_path(state: :done) - end - - it 'has the done todo present' do - expect(page).to have_selector('.todos-list .todo.todo-done', count: 1) - end - - describe 'restoring the todo' do - before do - within first('.todo') do - click_link 'Add todo' - end - end - - it 'is removed from the list' do - expect(page).not_to have_selector('.todos-list .todo.todo-done') - end - - it 'updates todo count' do - expect(page).to have_content 'To do 1' - expect(page).to have_content 'Done 0' - end - end - end - - context 'User has Todos with labels spanning multiple projects' do - before do - label1 = create(:label, project: project) - note1 = create(:note_on_issue, note: "Hello #{label1.to_reference(format: :name)}", noteable_id: issue.id, noteable_type: 'Issue', project: issue.project) - create(:todo, :mentioned, project: project, target: issue, user: user, note_id: note1.id) - - project2 = create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) - label2 = create(:label, project: project2) - issue2 = create(:issue, project: project2) - note2 = create(:note_on_issue, note: "Test #{label2.to_reference(format: :name)}", noteable_id: issue2.id, noteable_type: 'Issue', project: project2) - create(:todo, :mentioned, project: project2, target: issue2, user: user, note_id: note2.id) - - gitlab_sign_in(user) - visit dashboard_todos_path - end - - it 'shows page with two Todos' do - expect(page).to have_selector('.todos-list .todo', count: 2) - end - end - - context 'User has multiple pages of Todos' do - before do - allow(Todo).to receive(:default_per_page).and_return(1) - - # Create just enough records to cause us to paginate - create_list(:todo, 2, :mentioned, user: user, project: project, target: issue, author: author) - - gitlab_sign_in(user) - end - - it 'is paginated' do - visit dashboard_todos_path - - expect(page).to have_selector('.gl-pagination') - end - - it 'is has the right number of pages' do - visit dashboard_todos_path - - expect(page).to have_selector('.gl-pagination .page', count: 2) - end - - describe 'mark all as done', js: true do - before do - visit dashboard_todos_path - find('.js-todos-mark-all').trigger('click') - end - - it 'shows "All done" message!' do - expect(page).to have_content 'To do 0' - 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 - find('.js-todos-mark-all').trigger('click') - wait_for_requests - find('.js-todos-undo-all').trigger('click') - wait_for_requests - end - end - end - - context 'User has a Todo in a project pending deletion' do - before do - deleted_project = create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC, pending_delete: true) - create(:todo, :mentioned, user: user, project: deleted_project, target: issue, author: author) - create(:todo, :mentioned, user: user, project: deleted_project, target: issue, author: author, state: :done) - gitlab_sign_in(user) - visit dashboard_todos_path - end - - it 'shows "All done" message' do - within('.todos-count') { expect(page).to have_content '0' } - expect(page).to have_content 'To do 0' - expect(page).to have_content 'Done 0' - expect(page).to have_selector('.todos-all-done', count: 1) - end - end - - context 'User has a Build Failed todo' do - let!(:todo) { create(:todo, :build_failed, user: user, project: project, author: author) } - - before do - gitlab_sign_in user - visit dashboard_todos_path - end - - it 'shows the todo' do - expect(page).to have_content 'The build failed for merge request' - end - - it 'links to the pipelines for the merge request' do - href = pipelines_namespace_project_merge_request_path(project.namespace, project, todo.target) - - expect(page).to have_link "merge request #{todo.target.to_reference(full: true)}", href - end - end - end -end diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb new file mode 100644 index 00000000000..661327d4432 --- /dev/null +++ b/spec/helpers/button_helper_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe ButtonHelper do + describe 'http_clone_button' do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:has_tooltip_class) { 'has-tooltip' } + + def element + element = helper.http_clone_button(project) + + Nokogiri::HTML::DocumentFragment.parse(element).first_element_child + end + + before do + allow(helper).to receive(:current_user).and_return(user) + end + + context 'with internal auth enabled' do + context 'when user has a password' do + it 'shows no tooltip' do + expect(element.attr('class')).not_to include(has_tooltip_class) + end + end + + context 'when user has password automatically set' do + let(:user) { create(:user, password_automatically_set: true) } + + it 'shows a password tooltip' do + expect(element.attr('class')).to include(has_tooltip_class) + expect(element.attr('data-title')).to eq('Set a password on your account to pull or push via HTTP.') + end + end + end + + context 'with internal auth disabled' do + before do + stub_application_setting(signin_enabled?: false) + end + + context 'when user has no personal access tokens' do + it 'has a personal access token tooltip ' do + expect(element.attr('class')).to include(has_tooltip_class) + expect(element.attr('data-title')).to eq('Create a personal access token on your account to pull or push via HTTP.') + end + end + + context 'when user has a personal access token' do + it 'shows no tooltip' do + create(:personal_access_token, user: user) + + expect(element.attr('class')).not_to include(has_tooltip_class) + end + end + end + + context 'when user is ldap user' do + let(:user) { create(:omniauth_user, password_automatically_set: true) } + + it 'shows no tooltip' do + expect(element.attr('class')).not_to include(has_tooltip_class) + end + end + end +end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 9a4086725d2..487d9800707 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -115,6 +115,82 @@ describe ProjectsHelper do end end + describe '#show_no_ssh_key_message?' do + let(:user) { create(:user) } + + before do + allow(helper).to receive(:current_user).and_return(user) + end + + context 'user has no keys' do + it 'returns true' do + expect(helper.show_no_ssh_key_message?).to be_truthy + end + end + + context 'user has an ssh key' do + it 'returns false' do + create(:personal_key, user: user) + + expect(helper.show_no_ssh_key_message?).to be_falsey + end + end + end + + describe '#show_no_password_message?' do + let(:user) { create(:user) } + + before do + allow(helper).to receive(:current_user).and_return(user) + end + + context 'user has password set' do + it 'returns false' do + expect(helper.show_no_password_message?).to be_falsey + end + end + + context 'user requires a password' do + let(:user) { create(:user, password_automatically_set: true) } + + it 'returns true' do + expect(helper.show_no_password_message?).to be_truthy + end + end + + context 'user requires a personal access token' do + it 'returns true' do + stub_application_setting(signin_enabled?: false) + + expect(helper.show_no_password_message?).to be_truthy + end + end + end + + describe '#link_to_set_password' do + before do + allow(helper).to receive(:current_user).and_return(user) + end + + context 'user requires a password' do + let(:user) { create(:user, password_automatically_set: true) } + + it 'returns link to set a password' do + expect(helper.link_to_set_password).to match %r{<a href="#{edit_profile_password_path}">set a password</a>} + end + end + + context 'user requires a personal access token' do + let(:user) { create(:user) } + + it 'returns link to create a personal access token' do + stub_application_setting(signin_enabled?: false) + + expect(helper.link_to_set_password).to match %r{<a href="#{profile_personal_access_tokens_path}">create a personal access token</a>} + end + end + end + describe 'link_to_member' do let(:group) { create(:group) } let(:project) { create(:empty_project, group: group) } diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js index 4bbaff561fc..291e19c9f3c 100644 --- a/spec/javascripts/vue_shared/components/markdown/field_spec.js +++ b/spec/javascripts/vue_shared/components/markdown/field_spec.js @@ -4,47 +4,33 @@ import fieldComponent from '~/vue_shared/components/markdown/field.vue'; describe('Markdown field component', () => { let vm; - beforeEach(() => { + beforeEach((done) => { vm = new Vue({ - render(createElement) { - return createElement( - fieldComponent, - { - props: { - markdownPreviewUrl: '/preview', - markdownDocs: '/docs', - }, - }, - [ - createElement('textarea', { - slot: 'textarea', - }), - ], - ); + data() { + return { + text: 'testing\n123', + }; }, - }); - }); - - it('creates a new instance of GL form', (done) => { - spyOn(gl, 'GLForm'); - vm.$mount(); - - Vue.nextTick(() => { - expect( - gl.GLForm, - ).toHaveBeenCalled(); - - done(); - }); + components: { + fieldComponent, + }, + template: ` + <field-component + marodown-preview-url="/preview" + markdown-docs="/docs" + > + <textarea + slot="textarea" + v-model="text"> + </textarea> + </field-component> + `, + }).$mount(); + + Vue.nextTick(done); }); describe('mounted', () => { - beforeEach((done) => { - vm.$mount(); - - Vue.nextTick(done); - }); - it('renders textarea inside backdrop', () => { expect( vm.$el.querySelector('.zen-backdrop textarea'), @@ -117,5 +103,52 @@ describe('Markdown field component', () => { }); }); }); + + describe('markdown buttons', () => { + it('converts single words', (done) => { + const textarea = vm.$el.querySelector('textarea'); + + textarea.setSelectionRange(0, 7); + vm.$el.querySelector('.js-md').click(); + + Vue.nextTick(() => { + expect( + textarea.value, + ).toContain('**testing**'); + + done(); + }); + }); + + it('converts a line', (done) => { + const textarea = vm.$el.querySelector('textarea'); + + textarea.setSelectionRange(0, 0); + vm.$el.querySelectorAll('.js-md')[4].click(); + + Vue.nextTick(() => { + expect( + textarea.value, + ).toContain('* testing'); + + done(); + }); + }); + + it('converts multiple lines', (done) => { + const textarea = vm.$el.querySelector('textarea'); + + textarea.setSelectionRange(0, 50); + vm.$el.querySelectorAll('.js-md')[4].click(); + + Vue.nextTick(() => { + expect( + textarea.value, + ).toContain('* testing\n* 123'); + + done(); + }); + }); + }); }); }); diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index 5e6206b96c7..cbf6c35356e 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -176,6 +176,10 @@ describe Gitlab::Database, lib: true do described_class.bulk_insert('test', rows) end + + it 'handles non-UTF-8 data' do + expect { described_class.bulk_insert('test', [{ a: "\255" }]) }.not_to raise_error + end end describe '.create_connection_pool' do diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index b47e1b56fa9..3c7c7562b46 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -37,6 +37,7 @@ describe Gitlab::UsageData do deploy_keys deployments environments + in_review_folder groups issues keys diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 879386b5437..4c88958264b 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -89,4 +89,25 @@ module LoginHelpers }) Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[:saml] end + + def mock_saml_config + OpenStruct.new(name: 'saml', label: 'saml', args: { + assertion_consumer_service_url: 'https://localhost:3443/users/auth/saml/callback', + idp_cert_fingerprint: '26:43:2C:47:AF:F0:6B:D0:07:9C:AD:A3:74:FE:5D:94:5F:4E:9E:52', + idp_sso_target_url: 'https://idp.example.com/sso/saml', + issuer: 'https://localhost:3443/', + name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient' + }) + end + + def stub_omniauth_saml_config(messages) + Rails.application.env_config['devise.mapping'] = Devise.mappings[:user] + Rails.application.routes.disable_clear_and_finalize = true + Rails.application.routes.draw do + post '/users/auth/saml' => 'omniauth_callbacks#saml' + end + allow(Gitlab::OAuth::Provider).to receive_messages(providers: [:saml], config_for: mock_saml_config) + stub_omniauth_setting(messages) + expect_any_instance_of(Object).to receive(:omniauth_authorize_path).with(:user, "saml").and_return('/users/auth/saml') + end end diff --git a/spec/support/stub_env.rb b/spec/support/stub_env.rb index 18597b5c71f..2999bcd9fb1 100644 --- a/spec/support/stub_env.rb +++ b/spec/support/stub_env.rb @@ -5,3 +5,11 @@ module StubENV allow(ENV).to receive(:[]).with(key).and_return(value) end end + +# It's possible that the state of the class variables are not reset across +# test runs. +RSpec.configure do |config| + config.after(:each) do + @env_already_stubbed = nil + end +end |