diff options
author | Sean McGivern <sean@gitlab.com> | 2016-10-17 10:56:55 +0100 |
---|---|---|
committer | Sean McGivern <sean@gitlab.com> | 2016-10-17 10:56:55 +0100 |
commit | 86dcb79be37f5759dfeaa26283ed8bf031b38d54 (patch) | |
tree | 70869aeaa6bfbdcaada873cfd3e4054c62d3e25a /spec | |
parent | 26e327ea93140f6400b965b845958ff50461718c (diff) | |
parent | 052de0600c6b137e6f9df08250b4cf5f38280295 (diff) | |
download | gitlab-ce-86dcb79be37f5759dfeaa26283ed8bf031b38d54.tar.gz |
Merge branch 'master' into merge-conflicts-editor-2
Diffstat (limited to 'spec')
37 files changed, 682 insertions, 129 deletions
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 3fe90375b92..d6980471ea4 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -911,4 +911,34 @@ describe Projects::MergeRequestsController do post_assign_issues end end + + describe 'GET ci_environments_status' do + context 'when the environment is from a forked project' do + let!(:forked) { create(:project) } + let!(:environment) { create(:environment, project: forked) } + let!(:deployment) { create(:deployment, environment: environment, sha: forked.commit.id, ref: 'master') } + let(:json_response) { JSON.parse(response.body) } + let(:admin) { create(:admin) } + + let(:merge_request) do + create(:forked_project_link, forked_to_project: forked, + forked_from_project: project) + + create(:merge_request, source_project: forked, target_project: project) + end + + before do + forked.team << [user, :master] + + get :ci_environments_status, + namespace_id: merge_request.project.namespace.to_param, + project_id: merge_request.project.to_param, + id: merge_request.iid, format: 'json' + end + + it 'links to the environment on that project' do + expect(json_response.first['url']).to match /#{forked.path_with_namespace}/ + end + end + end end diff --git a/spec/features/compare_spec.rb b/spec/features/compare_spec.rb index 33dfd0d5b62..43eb4000e58 100644 --- a/spec/features/compare_spec.rb +++ b/spec/features/compare_spec.rb @@ -44,7 +44,7 @@ describe "Compare", js: true do def select_using_dropdown(dropdown_type, selection) dropdown = find(".js-compare-#{dropdown_type}-dropdown") dropdown.find(".compare-dropdown-toggle").click - dropdown.fill_in("Filter by branch/tag", with: selection) - click_link selection + dropdown.fill_in("Filter by Git revision", with: selection) + find_link(selection, visible: true).click end end diff --git a/spec/features/groups/members/owner_manages_access_requests_spec.rb b/spec/features/groups/members/owner_manages_access_requests_spec.rb index 10d3713f19f..d811b05b0c3 100644 --- a/spec/features/groups/members/owner_manages_access_requests_spec.rb +++ b/spec/features/groups/members/owner_manages_access_requests_spec.rb @@ -41,7 +41,7 @@ feature 'Groups > Members > Owner manages access requests', feature: true do def expect_visible_access_request(group, user) expect(group.requesters.exists?(user_id: user)).to be_truthy - expect(page).to have_content "#{group.name} access requests 1" + expect(page).to have_content "Users requesting access to #{group.name} 1" expect(page).to have_content user.name end end diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index c54ec2563ad..13bfe90302c 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -11,67 +11,99 @@ feature 'Group', feature: true do end end - describe 'creating a group with space in group path' do - it 'renders new group form with validation errors' do - visit new_group_path - fill_in 'Group path', with: 'space group' + describe 'create a group' do + before { visit new_group_path } - click_button 'Create group' + describe 'with space in group path' do + it 'renders new group form with validation errors' do + fill_in 'Group path', with: 'space group' + click_button 'Create group' - expect(current_path).to eq(groups_path) - expect(page).to have_namespace_error_message + expect(current_path).to eq(groups_path) + expect(page).to have_namespace_error_message + end end - end - - describe 'creating a group with .atom at end of group path' do - it 'renders new group form with validation errors' do - visit new_group_path - fill_in 'Group path', with: 'atom_group.atom' - click_button 'Create group' + describe 'with .atom at end of group path' do + it 'renders new group form with validation errors' do + fill_in 'Group path', with: 'atom_group.atom' + click_button 'Create group' - expect(current_path).to eq(groups_path) - expect(page).to have_namespace_error_message + expect(current_path).to eq(groups_path) + expect(page).to have_namespace_error_message + end + end + + describe 'with .git at end of group path' do + it 'renders new group form with validation errors' do + fill_in 'Group path', with: 'git_group.git' + click_button 'Create group' + + expect(current_path).to eq(groups_path) + expect(page).to have_namespace_error_message + end end end - - describe 'creating a group with .git at end of group path' do - it 'renders new group form with validation errors' do - visit new_group_path - fill_in 'Group path', with: 'git_group.git' - click_button 'Create group' + describe 'group edit' do + let(:group) { create(:group) } + let(:path) { edit_group_path(group) } + let(:new_name) { 'new-name' } + + before { visit path } + + it 'saves new settings' do + fill_in 'group_name', with: new_name + click_button 'Save group' + + expect(page).to have_content 'successfully updated' + expect(find('#group_name').value).to eq(new_name) - expect(current_path).to eq(groups_path) - expect(page).to have_namespace_error_message + page.within ".navbar-gitlab" do + expect(page).to have_content new_name + end + end + + it 'removes group' do + click_link 'Remove Group' + + expect(page).to have_content "scheduled for deletion" end end - describe 'description' do + describe 'group page with markdown description' do let(:group) { create(:group) } let(:path) { group_path(group) } it 'parses Markdown' do group.update_attribute(:description, 'This is **my** group') + visit path + expect(page).to have_css('.description > p > strong') end it 'passes through html-pipeline' do group.update_attribute(:description, 'This group is the :poop:') + visit path + expect(page).to have_css('.description > p > img') end it 'sanitizes unwanted tags' do group.update_attribute(:description, '# Group Description') + visit path + expect(page).not_to have_css('.description h1') end it 'permits `rel` attribute on links' do group.update_attribute(:description, 'https://google.com/') + visit path + expect(page).to have_css('.description a[rel]') end end diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index 2523b4b7898..996f39ea06d 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -29,7 +29,7 @@ feature 'Login', feature: true do describe 'with two-factor authentication' do def enter_code(code) - fill_in 'Two-Factor Authentication code', with: code + fill_in 'user_otp_attempt', with: code click_button 'Verify code' end diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb index 4d5d4aa121a..a506624b30d 100644 --- a/spec/features/merge_requests/created_from_fork_spec.rb +++ b/spec/features/merge_requests/created_from_fork_spec.rb @@ -45,7 +45,7 @@ feature 'Merge request created from fork' do page.within('.merge-request-tabs') { click_link 'Builds' } wait_for_ajax - page.within('table.builds') do + page.within('table.ci-table') do expect(page).to have_content 'rspec' expect(page).to have_content 'spinach' end 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 cb3cea3fd51..7b8af555f0e 100644 --- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb @@ -20,7 +20,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do login_with(user) visit namespace_project_merge_request_path(project.namespace, project, merge_request) end - + after do wait_for_ajax end @@ -34,7 +34,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do expect(page).to have_content 'Your commands have been executed!' expect(merge_request.reload.work_in_progress?).to eq true - end + end it 'removes the WIP: prefix from the title' do merge_request.title = merge_request.wip_title @@ -45,7 +45,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do expect(page).to have_content 'Your commands have been executed!' expect(merge_request.reload.work_in_progress?).to eq false - end + end end context 'when the current user cannot toggle the WIP prefix' do diff --git a/spec/features/merge_requests/widget_deployments_spec.rb b/spec/features/merge_requests/widget_deployments_spec.rb new file mode 100644 index 00000000000..8e23ec50d4a --- /dev/null +++ b/spec/features/merge_requests/widget_deployments_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +feature 'Widget Deployments Header', feature: true, js: true do + include WaitForAjax + + describe 'when deployed to an environment' do + let(:project) { merge_request.target_project } + let(:merge_request) { create(:merge_request, :merged) } + let(:environment) { create(:environment, project: project) } + let!(:deployment) do + create(:deployment, environment: environment, sha: project.commit('master').id) + end + + before do + login_as :admin + visit namespace_project_merge_request_path(project.namespace, project, merge_request) + end + + it 'displays that the environment is deployed' do + wait_for_ajax + + expect(page).to have_content("Deployed to #{environment.name}") + expect(find('.ci_widget > span > span')['data-title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium)) + end + end +end diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index cd79c4f512d..d886909ce85 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -15,6 +15,7 @@ feature 'issuable templates', feature: true, js: true do let(:template_content) { 'this is a test "bug" template' } let(:longtemplate_content) { %Q(this\n\n\n\n\nis\n\n\n\n\na\n\n\n\n\nbug\n\n\n\n\ntemplate) } let(:issue) { create(:issue, author: user, assignee: user, project: project) } + let(:description_addition) { ' appending to description' } background do project.repository.commit_file(user, '.gitlab/issue_templates/bug.md', template_content, 'added issue template', 'master', false) @@ -26,7 +27,26 @@ feature 'issuable templates', feature: true, js: true do scenario 'user selects "bug" template' do select_template 'bug' wait_for_ajax - preview_template(template_content) + preview_template + save_changes + end + + scenario 'user selects "bug" template and then "no template"' do + select_template 'bug' + wait_for_ajax + select_option 'No template' + wait_for_ajax + preview_template('') + save_changes('') + end + + scenario 'user selects "bug" template, edits description and then selects "reset template"' do + select_template 'bug' + wait_for_ajax + find_field('issue_description').send_keys(description_addition) + preview_template(template_content + description_addition) + select_option 'Reset template' + preview_template save_changes end @@ -37,7 +57,7 @@ feature 'issuable templates', feature: true, js: true do wait_for_ajax end_height = page.evaluate_script('$(".markdown-area").outerHeight()') - + expect(end_height).not_to eq(start_height) end end @@ -75,7 +95,7 @@ feature 'issuable templates', feature: true, js: true do scenario 'user selects "feature-proposal" template' do select_template 'feature-proposal' wait_for_ajax - preview_template(template_content) + preview_template save_changes end end @@ -102,25 +122,31 @@ feature 'issuable templates', feature: true, js: true do scenario 'user selects template' do select_template 'feature-proposal' wait_for_ajax - preview_template(template_content) + preview_template save_changes end end end end - def preview_template(expected_content) + def preview_template(expected_content = template_content) click_link 'Preview' expect(page).to have_content expected_content + click_link 'Write' end - def save_changes + def save_changes(expected_content = template_content) click_button "Save changes" - expect(page).to have_content template_content + expect(page).to have_content expected_content end def select_template(name) first('.js-issuable-selector').click first('.js-issuable-selector-wrap .dropdown-content a', text: name).click end + + def select_option(name) + first('.js-issuable-selector').click + first('.js-issuable-selector-wrap .dropdown-footer-list a', text: name).click + end end diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb new file mode 100644 index 00000000000..cc2f695211c --- /dev/null +++ b/spec/features/projects/members/group_links_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +feature 'Projects > Members > Anonymous user sees members', feature: true, js: true do + include WaitForAjax + + let(:user) { create(:user) } + let(:group) { create(:group, :public) } + let(:project) { create(:empty_project, :public) } + + background do + project.team << [user, :master] + @group_link = create(:project_group_link, project: project, group: group) + + login_as(user) + visit namespace_project_project_members_path(project.namespace, project) + end + + it 'updates group access level' do + select 'Guest', from: "member_access_level_#{group.id}" + wait_for_ajax + + visit namespace_project_project_members_path(project.namespace, project) + + expect(page).to have_select("member_access_level_#{group.id}", selected: 'Guest') + end + + it 'updates expiry date' do + tomorrow = Date.today + 3 + + fill_in "member_expires_at_#{group.id}", with: tomorrow.strftime("%F") + wait_for_ajax + + page.within(find('li.group_member')) do + expect(page).to have_content('Expires in') + end + end + + it 'deletes group link' do + page.within(first('.group_member')) do + find('.btn-remove').click + end + wait_for_ajax + + expect(page).not_to have_selector('.group_member') + end + + context 'search' do + it 'finds no results' do + page.within '.member-search-form' do + fill_in 'search', with: 'testing 123' + find('.member-search-btn').click + end + + expect(page).not_to have_selector('.group_member') + end + + it 'finds results' do + page.within '.member-search-form' do + fill_in 'search', with: group.name + find('.member-search-btn').click + end + + expect(page).to have_selector('.group_member', count: 1) + end + end +end diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index 430c384ac2e..27a83fdcd1f 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' feature 'Projects > Members > Master adds member with expiration date', feature: true, js: true do + include WaitForAjax include Select2Helper include ActiveSupport::Testing::TimeHelpers @@ -20,7 +21,7 @@ feature 'Projects > Members > Master adds member with expiration date', feature: page.within '.users-project-form' do select2(new_member.id, from: '#user_ids', multiple: true) fill_in 'expires_at', with: '2016-08-10' - click_on 'Add users to project' + click_on 'Add to project' end page.within '.project_member:first-child' do @@ -35,9 +36,8 @@ feature 'Projects > Members > Master adds member with expiration date', feature: visit namespace_project_project_members_path(project.namespace, project) page.within '.project_member:first-child' do - click_on 'Edit' - fill_in 'Access expiration date', with: '2016-08-09' - click_on 'Save' + find('.js-access-expiration-date').set '2016-08-09' + wait_for_ajax expect(page).to have_content('Expires in 3 days') end end diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index f7fcd9b6731..d15376931c3 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -41,7 +41,7 @@ feature 'Projects > Members > Master manages access requests', feature: true do def expect_visible_access_request(project, user) expect(project.requesters.exists?(user_id: user)).to be_truthy - expect(page).to have_content "#{project.name} access requests 1" + expect(page).to have_content "Users requesting access to #{project.name} 1" expect(page).to have_content user.name end end diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb index a752c1d7235..65544f79eba 100644 --- a/spec/features/signup_spec.rb +++ b/spec/features/signup_spec.rb @@ -14,7 +14,7 @@ feature 'Signup', feature: true do fill_in 'new_user_username', with: user.username fill_in 'new_user_email', with: user.email fill_in 'new_user_password', with: user.password - click_button "Sign up" + click_button "Register" expect(current_path).to eq users_almost_there_path expect(page).to have_content("Please check your email to confirm your account") @@ -33,7 +33,7 @@ feature 'Signup', feature: true do fill_in 'new_user_username', with: user.username fill_in 'new_user_email', with: user.email fill_in 'new_user_password', with: user.password - click_button "Sign up" + click_button "Register" expect(current_path).to eq dashboard_projects_path expect(page).to have_content("Welcome! You have signed up successfully.") @@ -52,7 +52,7 @@ feature 'Signup', feature: true do fill_in 'new_user_username', with: user.username fill_in 'new_user_email', with: existing_user.email fill_in 'new_user_password', with: user.password - click_button "Sign up" + click_button "Register" expect(current_path).to eq user_registration_path expect(page).to have_content("error prohibited this user from being saved") @@ -69,7 +69,7 @@ feature 'Signup', feature: true do fill_in 'new_user_username', with: user.username fill_in 'new_user_email', with: existing_user.email fill_in 'new_user_password', with: user.password - click_button "Sign up" + click_button "Register" expect(current_path).to eq user_registration_path expect(page.body).not_to match(/#{user.password}/) diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index ff6933dc8d9..b750f27ea72 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -160,7 +160,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: login_with(user) @u2f_device.respond_to_u2f_authentication - click_on "Login Via U2F Device" + click_on "Sign in via U2F device" expect(page.body).to match('We heard back from your U2F device') click_on "Authenticate via U2F Device" @@ -174,7 +174,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: login_with(user) @u2f_device.respond_to_u2f_authentication - click_on "Login Via U2F Device" + click_on "Sign in via U2F device" expect(page.body).to match('We heard back from your U2F device') click_on "Authenticate via U2F Device" @@ -186,7 +186,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: login_with(user, remember: true) @u2f_device.respond_to_u2f_authentication - click_on "Login Via U2F Device" + click_on "Sign in via U2F device" expect(page.body).to match('We heard back from your U2F device') within 'div#js-authenticate-u2f' do @@ -209,7 +209,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: # Try authenticating user with the old U2F device login_as(current_user) @u2f_device.respond_to_u2f_authentication - click_on "Login Via U2F Device" + click_on "Sign in via U2F device" expect(page.body).to match('We heard back from your U2F device') click_on "Authenticate via U2F Device" @@ -230,7 +230,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: # Try authenticating user with the same U2F device login_as(current_user) @u2f_device.respond_to_u2f_authentication - click_on "Login Via U2F Device" + click_on "Sign in via U2F device" expect(page.body).to match('We heard back from your U2F device') click_on "Authenticate via U2F Device" @@ -244,7 +244,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: unregistered_device = FakeU2fDevice.new(page, FFaker::Name.first_name) login_as(user) unregistered_device.respond_to_u2f_authentication - click_on "Login Via U2F Device" + click_on "Sign in via U2F device" expect(page.body).to match('We heard back from your U2F device') click_on "Authenticate via U2F Device" @@ -271,7 +271,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: [first_device, second_device].each do |device| login_as(user) device.respond_to_u2f_authentication - click_on "Login Via U2F Device" + click_on "Sign in via U2F device" expect(page.body).to match('We heard back from your U2F device') click_on "Authenticate via U2F Device" diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index 6498b7317b4..ec4c4d62f53 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -1,15 +1,16 @@ require 'spec_helper' -feature 'Users', feature: true do +feature 'Users', feature: true, js: true do let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') } scenario 'GET /users/sign_in creates a new user account' do visit new_user_session_path + click_link 'Register' fill_in 'new_user_name', with: 'Name Surname' fill_in 'new_user_username', with: 'Great' fill_in 'new_user_email', with: 'name@mail.com' fill_in 'new_user_password', with: 'password1234' - expect { click_button 'Sign up' }.to change { User.count }.by(1) + expect { click_button 'Register' }.to change { User.count }.by(1) end scenario 'Successful user signin invalidates password reset token' do @@ -31,11 +32,12 @@ feature 'Users', feature: true do scenario 'Should show one error if email is already taken' do visit new_user_session_path + click_link 'Register' fill_in 'new_user_name', with: 'Another user name' fill_in 'new_user_username', with: 'anotheruser' fill_in 'new_user_email', with: user.email fill_in 'new_user_password', with: '12341234' - expect { click_button 'Sign up' }.to change { User.count }.by(0) + expect { click_button 'Register' }.to change { User.count }.by(0) expect(page).to have_text('Email has already been taken') expect(number_of_errors_on_page(page)).to be(1), 'errors on page:\n #{errors_on_page page}' end @@ -51,6 +53,28 @@ feature 'Users', feature: true do end end + feature 'username validation' do + include WaitForAjax + let(:loading_icon) { '.fa.fa-spinner' } + let(:username_input) { 'new_user_username' } + + before(:each) do + visit new_user_session_path + click_link 'Register' + end + scenario 'shows an error border if the username already exists' do + fill_in username_input, with: user.username + wait_for_ajax + expect(find('.username')).to have_css '.gl-field-error-outline' + end + + scenario 'doesn\'t show an error border if the username is available' do + fill_in username_input, with: 'new-user' + wait_for_ajax + expect(find('#new_user_username')).not_to have_css '.gl-field-error-outline' + end + end + def errors_on_page(page) page.find('#error_explanation').find('ul').all('li').map{ |item| item.text }.join("\n") end diff --git a/spec/javascripts/fixtures/gl_field_errors.html.haml b/spec/javascripts/fixtures/gl_field_errors.html.haml new file mode 100644 index 00000000000..2526e5e33a5 --- /dev/null +++ b/spec/javascripts/fixtures/gl_field_errors.html.haml @@ -0,0 +1,15 @@ +%form.show-gl-field-errors{action: 'submit', method: 'post'} + .form-group + %input.required-text{required: true, type: 'text'} Text + .form-group + %input.email{type: 'email', title: 'Please provide a valid email address.', required: true } Email + .form-group + %input.password{type: 'password', required: true} Password + .form-group + %input.alphanumeric{type: 'text', pattern: '[a-zA-Z0-9]', required: true} Alphanumeric + .form-group + %input.hidden{ type:'hidden' } + .form-group + %input.custom.no-gl-field-errors{ type:'text' } Custom, do not validate + .form-group + %input.submit{type: 'submit'} Submit diff --git a/spec/javascripts/gl_field_errors_spec.js.es6 b/spec/javascripts/gl_field_errors_spec.js.es6 new file mode 100644 index 00000000000..36feb2b2aa5 --- /dev/null +++ b/spec/javascripts/gl_field_errors_spec.js.es6 @@ -0,0 +1,111 @@ +//= require jquery +//= require gl_field_errors + +((global) => { + fixture.preload('gl_field_errors.html'); + + describe('GL Style Field Errors', function() { + beforeEach(function() { + fixture.load('gl_field_errors.html'); + const $form = this.$form = $('form.show-gl-field-errors'); + this.fieldErrors = new global.GlFieldErrors($form); + }); + + it('should properly initialize the form', function() { + expect(this.$form).toBeDefined(); + expect(this.$form.length).toBe(1); + expect(this.fieldErrors).toBeDefined(); + const inputs = this.fieldErrors.state.inputs; + expect(inputs.length).toBe(5); + }); + + it('should ignore elements with custom error handling', function() { + const customErrorFlag = 'no-gl-field-errors'; + const customErrorElem = $(`.${customErrorFlag}`); + + expect(customErrorElem.length).toBe(1); + + const customErrors = this.fieldErrors.state.inputs.filter((input) => { + return input.inputElement.hasClass(customErrorFlag); + }); + expect(customErrors.length).toBe(0); + }); + + it('should not show any errors before submit attempt', function() { + this.$form.find('.email').val('not-a-valid-email').keyup(); + this.$form.find('.text-required').val('').keyup(); + this.$form.find('.alphanumberic').val('?---*').keyup(); + + const errorsShown = this.$form.find('.gl-field-error-outline'); + expect(errorsShown.length).toBe(0); + }); + + it('should show errors when input valid is submitted', function() { + this.$form.find('.email').val('not-a-valid-email').keyup(); + this.$form.find('.text-required').val('').keyup(); + this.$form.find('.alphanumberic').val('?---*').keyup(); + + this.$form.submit(); + + const errorsShown = this.$form.find('.gl-field-error-outline'); + expect(errorsShown.length).toBe(4); + }); + + it('should properly track validity state on input after invalid submission attempt', function() { + this.$form.submit(); + + const emailInputModel = this.fieldErrors.state.inputs[1]; + const fieldState = emailInputModel.state; + const emailInputElement = emailInputModel.inputElement; + + // No input + expect(emailInputElement).toHaveClass('gl-field-error-outline'); + expect(fieldState.empty).toBe(true); + expect(fieldState.valid).toBe(false); + + // Then invalid input + emailInputElement.val('not-a-valid-email').keyup(); + expect(emailInputElement).toHaveClass('gl-field-error-outline'); + expect(fieldState.empty).toBe(false); + expect(fieldState.valid).toBe(false); + + // Then valid input + emailInputElement.val('email@gitlab.com').keyup(); + expect(emailInputElement).not.toHaveClass('gl-field-error-outline'); + expect(fieldState.empty).toBe(false); + expect(fieldState.valid).toBe(true); + + // Then invalid input + emailInputElement.val('not-a-valid-email').keyup(); + expect(emailInputElement).toHaveClass('gl-field-error-outline'); + expect(fieldState.empty).toBe(false); + expect(fieldState.valid).toBe(false); + + // Then empty input + emailInputElement.val('').keyup(); + expect(emailInputElement).toHaveClass('gl-field-error-outline'); + expect(fieldState.empty).toBe(true); + expect(fieldState.valid).toBe(false); + + // Then valid input + emailInputElement.val('email@gitlab.com').keyup(); + expect(emailInputElement).not.toHaveClass('gl-field-error-outline'); + expect(fieldState.empty).toBe(false); + expect(fieldState.valid).toBe(true); + }); + + it('should properly infer error messages', function() { + this.$form.submit(); + const trackedInputs = this.fieldErrors.state.inputs; + const inputHasTitle = trackedInputs[1]; + const hasTitleErrorElem = inputHasTitle.inputElement.siblings('.gl-field-error'); + const inputNoTitle = trackedInputs[2]; + const noTitleErrorElem = inputNoTitle.inputElement.siblings('.gl-field-error'); + + expect(noTitleErrorElem.text()).toBe('This field is required.'); + expect(hasTitleErrorElem.text()).toBe('Please provide a valid email address.'); + }); + + }); + +})(window.gl || (window.gl = {})); diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 395032a7416..96ee5235acf 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -1,5 +1,6 @@ /*= require merge_request_tabs */ +//= require breakpoints (function() { describe('MergeRequestTabs', function() { diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js index 17b32914ec3..c9175e2b704 100644 --- a/spec/javascripts/merge_request_widget_spec.js +++ b/spec/javascripts/merge_request_widget_spec.js @@ -1,5 +1,5 @@ - /*= require merge_request_widget */ +/*= require lib/utils/jquery.timeago.js */ (function() { describe('MergeRequestWidget', function() { @@ -8,6 +8,7 @@ window.notify = function() {}; this.opts = { ci_status_url: "http://sampledomain.local/ci/getstatus", + ci_environments_status_url: "http://sampledomain.local/ci/getenvironmentsstatus", ci_status: "", ci_message: { normal: "Build {{status}} for \"{{title}}\"", @@ -20,17 +21,48 @@ gitlab_icon: "gitlab_logo.png", builds_path: "http://sampledomain.local/sampleBuildsPath" }; - this["class"] = new MergeRequestWidget(this.opts); - return this.ciStatusData = { - "title": "Sample MR title", - "sha": "12a34bc5", - "status": "success", - "coverage": 98 - }; + this["class"] = new window.gl.MergeRequestWidget(this.opts); }); + + describe('getCIEnvironmentsStatus', function() { + beforeEach(function() { + this.ciEnvironmentsStatusData = [{ + created_at: '2016-09-12T13:38:30.636Z', + environment_id: 1, + environment_name: 'env1', + external_url: 'https://test-url.com', + external_url_formatted: 'test-url.com' + }]; + + spyOn(jQuery, 'getJSON').and.callFake((req, cb) => { + cb(this.ciEnvironmentsStatusData); + }); + }); + + it('should call renderEnvironments when the environments property is set', function() { + const spy = spyOn(this.class, 'renderEnvironments').and.stub(); + this.class.getCIEnvironmentsStatus(); + expect(spy).toHaveBeenCalledWith(this.ciEnvironmentsStatusData); + }); + + it('should not call renderEnvironments when the environments property is not set', function() { + this.ciEnvironmentsStatusData = null; + const spy = spyOn(this.class, 'renderEnvironments').and.stub(); + this.class.getCIEnvironmentsStatus(); + expect(spy).not.toHaveBeenCalled(); + }); + }); + return describe('getCIStatus', function() { beforeEach(function() { - return spyOn(jQuery, 'getJSON').and.callFake((function(_this) { + this.ciStatusData = { + "title": "Sample MR title", + "sha": "12a34bc5", + "status": "success", + "coverage": 98 + }; + + spyOn(jQuery, 'getJSON').and.callFake((function(_this) { return function(req, cb) { return cb(_this.ciStatusData); }; @@ -61,10 +93,10 @@ this["class"].getCIStatus(false); return expect(spy).not.toHaveBeenCalled(); }); - return it('should not display a notification on the first check after the widget has been created', function() { + it('should not display a notification on the first check after the widget has been created', function() { var spy; spy = spyOn(window, 'notify'); - this["class"] = new MergeRequestWidget(this.opts); + this["class"] = new window.gl.MergeRequestWidget(this.opts); this["class"].getCIStatus(true); return expect(spy).not.toHaveBeenCalled(); }); diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index 7ce3884f844..784b43d4846 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -21,7 +21,7 @@ setupButton = this.container.find("#js-login-u2f-device"); setupMessage = this.container.find("p"); expect(setupMessage.text()).toContain('Insert your security key'); - expect(setupButton.text()).toBe('Login Via U2F Device'); + expect(setupButton.text()).toBe('Sign in via U2F device'); setupButton.trigger('click'); inProgressMessage = this.container.find("p"); expect(inProgressMessage.text()).toContain("Trying to communicate with your device"); diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 6b1867a44e1..e172ee8e590 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -64,6 +64,23 @@ describe Environment, models: true do end end + describe '#first_deployment_for' do + let(:project) { create(:project) } + let!(:environment) { create(:environment, project: project) } + let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } + let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } + let(:head_commit) { project.commit } + let(:commit) { project.commit.parent } + + it 'returns deployment id for the environment' do + expect(environment.first_deployment_for(commit)).to eq deployment1 + end + + it 'return nil when no deployment is found' do + expect(environment.first_deployment_for(head_commit)).to eq nil + end + end + describe '#environment_type' do subject { environment.environment_type } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 308a00db9cd..67dbcc362f6 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -228,7 +228,6 @@ describe Project, models: true do describe 'Respond to' do it { is_expected.to respond_to(:url_to_repo) } it { is_expected.to respond_to(:repo_exists?) } - it { is_expected.to respond_to(:update_merge_requests) } it { is_expected.to respond_to(:execute_hooks) } it { is_expected.to respond_to(:owner) } it { is_expected.to respond_to(:path_with_namespace) } @@ -389,26 +388,6 @@ describe Project, models: true do end end - describe '#update_merge_requests' do - let(:project) { create(:project) } - let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - let(:key) { create(:key, user_id: project.owner.id) } - let(:prev_commit_id) { merge_request.commits.last.id } - let(:commit_id) { merge_request.commits.first.id } - - it 'closes merge request if last commit from source branch was pushed to target branch' do - project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.target_branch}", key.user) - merge_request.reload - expect(merge_request.merged?).to be_truthy - end - - it 'updates merge request commits with new one if pushed to source branch' do - project.update_merge_requests(prev_commit_id, commit_id, "refs/heads/#{merge_request.source_branch}", key.user) - merge_request.reload - expect(merge_request.diff_head_sha).to eq(commit_id) - end - end - describe '.find_with_namespace' do context 'with namespace' do before do diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 4b80efbe12b..f977cf73673 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -7,15 +7,18 @@ describe Repository, models: true do let(:project) { create(:project) } let(:repository) { project.repository } let(:user) { create(:user) } + let(:commit_options) do author = repository.user_to_committer(user) { message: 'Test message', committer: author, author: author } end + let(:merge_commit) do merge_request = create(:merge_request, source_branch: 'feature', target_branch: 'master', source_project: project) merge_commit_id = repository.merge(user, merge_request, commit_options) repository.commit(merge_commit_id) end + let(:author_email) { FFaker::Internet.email } # I have to remove periods from the end of the name @@ -90,6 +93,26 @@ describe Repository, models: true do end end + describe '#ref_name_for_sha' do + context 'ref found' do + it 'returns the ref' do + allow_any_instance_of(Gitlab::Popen).to receive(:popen). + and_return(["b8d95eb4969eefacb0a58f6a28f6803f8070e7b9 commit\trefs/environments/production/77\n", 0]) + + expect(repository.ref_name_for_sha('bla', '0' * 40)).to eq 'refs/environments/production/77' + end + end + + context 'ref not found' do + it 'returns nil' do + allow_any_instance_of(Gitlab::Popen).to receive(:popen). + and_return(["", 0]) + + expect(repository.ref_name_for_sha('bla', '0' * 40)).to eq nil + end + end + end + describe '#last_commit_for_path' do subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id } diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 5a1ed7d4a25..27f0fd22ae6 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -412,9 +412,10 @@ describe 'Git HTTP requests', lib: true do context "when the params are anything else" do let(:params) { { service: 'git-implode-pack' } } + before { get path, params } - it "fails to find a route" do - expect { get(path, params) }.to raise_error(ActionController::RoutingError) + it "redirects to the sign-in page" do + expect(response).to redirect_to(new_user_session_path) end end end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 0ee1c811dfb..488dc1a63b0 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -270,6 +270,12 @@ describe "Groups", "routing" do expect(get('/1')).to route_to('groups#show', id: '1') end + + it "also display group#show with dot in the path" do + allow(Group).to receive(:find_by_path).and_return(true) + + expect(get('/group.with.dot')).to route_to('groups#show', id: 'group.with.dot') + end end describe HealthCheckController, 'routing' do diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index 343b4385bf2..5fe56e7725f 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -84,11 +84,22 @@ describe CreateDeploymentService, services: true do expect(subject).to be_persisted end end + + context 'when project was removed' do + let(:project) { nil } + + it 'does not create deployment or environment' do + expect { subject }.not_to raise_error + + expect(Environment.count).to be_zero + expect(Deployment.count).to be_zero + end + end end describe 'processing of builds' do let(:environment) { nil } - + shared_examples 'does not create environment and deployment' do it 'does not create a new environment' do expect { subject }.not_to change { Environment.count } @@ -133,12 +144,12 @@ describe CreateDeploymentService, services: true do context 'without environment specified' do let(:build) { create(:ci_build, project: project) } - + it_behaves_like 'does not create environment and deployment' do subject { build.success } end end - + context 'when environment is specified' do let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline, environment: 'production', options: options) } diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 8e3e12114f2..dd2a9e9903a 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -184,8 +184,8 @@ describe GitPushService, services: true do context "Updates merge requests" do it "when pushing a new branch for the first time" do - expect(project).to receive(:update_merge_requests). - with(@blankrev, 'newrev', 'refs/heads/master', user) + expect(UpdateMergeRequestsWorker).to receive(:perform_async). + with(project.id, user.id, @blankrev, 'newrev', 'refs/heads/master') execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) end end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 5b4e4908add..e515bc9f89c 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -62,7 +62,8 @@ describe MergeRequests::RefreshService, services: true do it { expect(@merge_request.notes).not_to be_empty } it { expect(@merge_request).to be_open } - it { expect(@merge_request.merge_when_build_succeeds).to be_falsey} + it { expect(@merge_request.merge_when_build_succeeds).to be_falsey } + it { expect(@merge_request.diff_head_sha).to eq(@newrev) } it { expect(@fork_merge_request).to be_open } it { expect(@fork_merge_request.notes).to be_empty } it { expect(@build_failed_todo).to be_done } diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 243d671c521..2e3fd5118ef 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -17,6 +17,7 @@ module TestEnv 'markdown' => '0ed8c6c', 'lfs' => 'be93687', 'master' => 'b83d6e3', + 'merge-test' => '5937ac0', "'test'" => 'e56497b', 'orphaned-branch' => '45127a9', 'binary-encoding' => '7b1cf43', diff --git a/spec/views/projects/merge_requests/_heading.html.haml_spec.rb b/spec/views/projects/merge_requests/_heading.html.haml_spec.rb deleted file mode 100644 index 86980f59cd8..00000000000 --- a/spec/views/projects/merge_requests/_heading.html.haml_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -describe 'projects/merge_requests/widget/_heading' do - include Devise::Test::ControllerHelpers - - context 'when released to an environment' do - let(:project) { merge_request.target_project } - let(:merge_request) { create(:merge_request, :merged) } - let(:environment) { create(:environment, project: project) } - let!(:deployment) do - create(:deployment, environment: environment, sha: project.commit('master').id) - end - - before do - assign(:merge_request, merge_request) - assign(:project, project) - - allow(view).to receive(:can?).and_return(true) - - render - end - - it 'displays that the environment is deployed' do - expect(rendered).to match("Deployed to") - expect(rendered).to match("#{environment.name}") - end - end -end diff --git a/spec/workers/build_coverage_worker_spec.rb b/spec/workers/build_coverage_worker_spec.rb new file mode 100644 index 00000000000..ba20488f663 --- /dev/null +++ b/spec/workers/build_coverage_worker_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe BuildCoverageWorker do + describe '#perform' do + context 'when build exists' do + let!(:build) { create(:ci_build) } + + it 'updates code coverage' do + expect_any_instance_of(Ci::Build) + .to receive(:update_coverage) + + described_class.new.perform(build.id) + end + end + + context 'when build does not exist' do + it 'does not raise exception' do + expect { described_class.new.perform(123) } + .not_to raise_error + end + end + end +end diff --git a/spec/workers/build_finished_worker_spec.rb b/spec/workers/build_finished_worker_spec.rb new file mode 100644 index 00000000000..2868167c7d4 --- /dev/null +++ b/spec/workers/build_finished_worker_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe BuildFinishedWorker do + describe '#perform' do + context 'when build exists' do + let(:build) { create(:ci_build) } + + it 'calculates coverage and calls hooks' do + expect(BuildCoverageWorker) + .to receive(:new).ordered.and_call_original + expect(BuildHooksWorker) + .to receive(:new).ordered.and_call_original + + expect_any_instance_of(BuildCoverageWorker) + .to receive(:perform) + expect_any_instance_of(BuildHooksWorker) + .to receive(:perform) + + described_class.new.perform(build.id) + end + end + + context 'when build does not exist' do + it 'does not raise exception' do + expect { described_class.new.perform(123) } + .not_to raise_error + end + end + end +end diff --git a/spec/workers/build_hooks_worker_spec.rb b/spec/workers/build_hooks_worker_spec.rb new file mode 100644 index 00000000000..97654a93f5c --- /dev/null +++ b/spec/workers/build_hooks_worker_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe BuildHooksWorker do + describe '#perform' do + context 'when build exists' do + let!(:build) { create(:ci_build) } + + it 'calls build hooks' do + expect_any_instance_of(Ci::Build) + .to receive(:execute_hooks) + + described_class.new.perform(build.id) + end + end + + context 'when build does not exist' do + it 'does not raise exception' do + expect { described_class.new.perform(123) } + .not_to raise_error + end + end + end +end diff --git a/spec/workers/build_success_worker_spec.rb b/spec/workers/build_success_worker_spec.rb new file mode 100644 index 00000000000..dba70883130 --- /dev/null +++ b/spec/workers/build_success_worker_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe BuildSuccessWorker do + describe '#perform' do + context 'when build exists' do + context 'when build belogs to the environment' do + let!(:build) { create(:ci_build, environment: 'production') } + + it 'executes deployment service' do + expect_any_instance_of(CreateDeploymentService) + .to receive(:execute) + + described_class.new.perform(build.id) + end + end + + context 'when build is not associated with project' do + let!(:build) { create(:ci_build, project: nil) } + + it 'does not create deployment' do + expect_any_instance_of(CreateDeploymentService) + .not_to receive(:execute) + + described_class.new.perform(build.id) + end + end + end + + context 'when build does not exist' do + it 'does not raise exception' do + expect { described_class.new.perform(123) } + .not_to raise_error + end + end + end +end diff --git a/spec/workers/pipeline_hooks_worker_spec.rb b/spec/workers/pipeline_hooks_worker_spec.rb new file mode 100644 index 00000000000..035e329839f --- /dev/null +++ b/spec/workers/pipeline_hooks_worker_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe PipelineHooksWorker do + describe '#perform' do + context 'when pipeline exists' do + let(:pipeline) { create(:ci_pipeline) } + + it 'executes hooks for the pipeline' do + expect_any_instance_of(Ci::Pipeline) + .to receive(:execute_hooks) + + described_class.new.perform(pipeline.id) + end + end + + context 'when pipeline does not exist' do + it 'does not raise exception' do + expect { described_class.new.perform(123) } + .not_to raise_error + end + end + end +end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index ffeaafe654a..984acdade36 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -92,7 +92,13 @@ describe PostReceive do allow(Project).to receive(:find_with_namespace).and_return(project) expect(project).to receive(:execute_hooks).twice expect(project).to receive(:execute_services).twice - expect(project).to receive(:update_merge_requests) + + PostReceive.new.perform(pwd(project), key_id, base64_changes) + end + + it "enqueues a UpdateMergeRequestsWorker job" do + allow(Project).to receive(:find_with_namespace).and_return(project) + expect(UpdateMergeRequestsWorker).to receive(:perform_async).with(project.id, project.owner.id, any_args) PostReceive.new.perform(pwd(project), key_id, base64_changes) end diff --git a/spec/workers/update_merge_requests_worker_spec.rb b/spec/workers/update_merge_requests_worker_spec.rb new file mode 100644 index 00000000000..c78a69eda67 --- /dev/null +++ b/spec/workers/update_merge_requests_worker_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe UpdateMergeRequestsWorker do + include RepoHelpers + + let(:project) { create(:project) } + let(:user) { create(:user) } + + subject { described_class.new } + + describe '#perform' do + let(:oldrev) { "123456" } + let(:newrev) { "789012" } + let(:ref) { "refs/heads/test" } + + def perform + subject.perform(project.id, user.id, oldrev, newrev, ref) + end + + it 'executes MergeRequests::RefreshService with expected values' do + expect(MergeRequests::RefreshService).to receive(:new).with(project, user).and_call_original + expect_any_instance_of(MergeRequests::RefreshService).to receive(:execute).with(oldrev, newrev, ref) + + perform + end + + it 'executes SystemHooksService with expected values' do + push_data = double('push_data') + expect(Gitlab::DataBuilder::Push).to receive(:build).with(project, user, oldrev, newrev, ref, []).and_return(push_data) + + system_hook_service = double('system_hook_service') + expect(SystemHooksService).to receive(:new).and_return(system_hook_service) + expect(system_hook_service).to receive(:execute_hooks).with(push_data, :push_hooks) + + perform + end + end +end |