diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-11 12:09:45 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-11 12:09:45 +0300 |
commit | c7ba7b997608a103a0a9165b2e5cef9530c4ef53 (patch) | |
tree | 3af88eaacba25539b97da4ad358418b6a69c11d7 /spec | |
parent | a031b1f4f34470fba578856dc7ab735a6f54733a (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
49 files changed, 618 insertions, 184 deletions
diff --git a/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb new file mode 100644 index 00000000000..30d2b79a92f --- /dev/null +++ b/spec/controllers/projects/design_management/designs/raw_images_controller_spec.rb @@ -0,0 +1,153 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::DesignManagement::Designs::RawImagesController do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:viewer) { issue.author } + let(:design_id) { design.id } + let(:sha) { design.versions.first.sha } + let(:filename) { design.filename } + + before do + enable_design_management + end + + describe 'GET #show' do + subject do + get(:show, + params: { + namespace_id: project.namespace, + project_id: project, + design_id: design_id, + sha: sha + }) + end + + before do + sign_in(viewer) + end + + context 'when the design is not an LFS file' do + let_it_be(:design) { create(:design, :with_file, issue: issue, versions_count: 2) } + + # For security, .svg images should only ever be served with Content-Disposition: attachment. + # If this specs ever fails we must assess whether we should be serving svg images. + # See https://gitlab.com/gitlab-org/gitlab/issues/12771 + it 'serves files with `Content-Disposition: attachment`' do + subject + + expect(response.header['Content-Disposition']).to eq('attachment') + expect(response).to have_gitlab_http_status(:ok) + end + + it 'serves files with Workhorse' do + subject + + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true" + expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:') + expect(response).to have_gitlab_http_status(:ok) + end + + it_behaves_like 'project cache control headers' + + context 'when the user does not have permission' do + let_it_be(:viewer) { create(:user) } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when design does not exist' do + let(:design_id) { 'foo' } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'sha param' do + let(:newest_version) { design.versions.ordered.first } + let(:oldest_version) { design.versions.ordered.last } + + shared_examples 'a successful request for sha' do + it do + expect_next_instance_of(DesignManagement::Repository) do |repository| + expect(repository).to receive(:blob_at).with(expected_ref, design.full_path).and_call_original + end + + subject + + expect(response).to have_gitlab_http_status(:ok) + end + end + + specify { expect(newest_version.sha).not_to eq(oldest_version.sha) } + + context 'when sha is the newest version sha' do + let(:sha) { newest_version.sha } + let(:expected_ref) { sha } + + it_behaves_like 'a successful request for sha' + end + + context 'when sha is the oldest version sha' do + let(:sha) { oldest_version.sha } + let(:expected_ref) { sha } + + it_behaves_like 'a successful request for sha' + end + + context 'when sha is nil' do + let(:sha) { nil } + let(:expected_ref) { 'master' } + + it_behaves_like 'a successful request for sha' + end + end + end + + context 'when the design is an LFS file' do + let_it_be(:design) { create(:design, :with_lfs_file, issue: issue) } + + # For security, .svg images should only ever be served with Content-Disposition: attachment. + # If this specs ever fails we must assess whether we should be serving svg images. + # See https://gitlab.com/gitlab-org/gitlab/issues/12771 + it 'serves files with `Content-Disposition: attachment`' do + subject + + expect(response.header['Content-Disposition']).to eq(%Q(attachment; filename=\"#{filename}\"; filename*=UTF-8''#{filename})) + end + + it 'sets appropriate caching headers' do + subject + + expect(response.header['ETag']).to be_present + expect(response.header['Cache-Control']).to eq("max-age=60, private") + end + end + + # Pass `skip_lfs_disabled_tests: true` to this shared example to disable + # the test scenarios for when LFS is disabled globally. + # + # When LFS is disabled then the design management feature also becomes disabled. + # When the feature is disabled, the `authorize :read_design` check within the + # controller will never authorize the user. Therefore #show will return a 403 and + # we cannot test the data that it serves. + it_behaves_like 'a controller that can serve LFS files', skip_lfs_disabled_tests: true do + let(:file) { fixture_file_upload('spec/fixtures/dk.png', '`/png') } + let(:lfs_pointer) { Gitlab::Git::LfsPointerFile.new(file.read) } + let(:design) { create(:design, :with_lfs_file, file: lfs_pointer.pointer, issue: issue) } + let(:lfs_oid) { project.design_repository.blob_at('HEAD', design.full_path).lfs_oid } + let(:filepath) { design.full_path } + end + end +end diff --git a/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb new file mode 100644 index 00000000000..9a3fee5b43a --- /dev/null +++ b/spec/controllers/projects/design_management/designs/resized_image_controller_spec.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::DesignManagement::Designs::ResizedImageController do + include DesignManagementTestHelpers + + let_it_be(:project) { create(:project, :private) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:viewer) { issue.author } + let_it_be(:size) { :v432x230 } + let(:design) { create(:design, :with_smaller_image_versions, issue: issue, versions_count: 2) } + let(:design_id) { design.id } + let(:sha) { design.versions.first.sha } + + before do + # TODO these tests are being temporarily skipped unless run in EE, + # as we are in the process of moving Design Management to FOSS in 13.0 + # in steps. In the current step the services have not yet been moved, + # and the `design` factory used in this test uses the `:with_smaller_image_versions` + # trait, which calls `GenerateImageVersionsService` to generate the + # smaller image versions. + # + # See https://gitlab.com/gitlab-org/gitlab/-/issues/212566#note_327724283. + skip 'See https://gitlab.com/gitlab-org/gitlab/-/issues/212566#note_327724283' unless Gitlab.ee? + + enable_design_management + end + + describe 'GET #show' do + subject do + get(:show, + params: { + namespace_id: project.namespace, + project_id: project, + design_id: design_id, + sha: sha, + id: size + }) + end + + before do + sign_in(viewer) + subject + end + + context 'when the user does not have permission' do + let_it_be(:viewer) { create(:user) } + + specify do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'Response headers' do + it 'completes the request successfully' do + expect(response).to have_gitlab_http_status(:ok) + end + + it 'sets Content-Disposition as attachment' do + filename = design.filename + + expect(response.header['Content-Disposition']).to eq(%Q(attachment; filename=\"#{filename}\"; filename*=UTF-8''#{filename})) + end + + it 'serves files with Workhorse' do + expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq 'true' + end + + it 'sets appropriate caching headers' do + expect(response.header['Cache-Control']).to eq('private') + expect(response.header['ETag']).to be_present + end + end + + context 'when design does not exist' do + let(:design_id) { 'foo' } + + specify do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when size is invalid' do + let_it_be(:size) { :foo } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + + describe 'sha param' do + let(:newest_version) { design.versions.ordered.first } + let(:oldest_version) { design.versions.ordered.last } + + # The design images generated by Factorybot are identical, so + # refer to the `ETag` header, which is uniquely generated from the Action + # (the record that represents the design at a specific version), to + # verify that the correct file is being returned. + def etag(action) + ActionDispatch::TestResponse.new.send(:generate_weak_etag, [action.cache_key, '']) + end + + specify { expect(newest_version.sha).not_to eq(oldest_version.sha) } + + context 'when sha is the newest version sha' do + let(:sha) { newest_version.sha } + + it 'serves the newest image' do + action = newest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is the oldest version sha' do + let(:sha) { oldest_version.sha } + + it 'serves the oldest image' do + action = oldest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is nil' do + let(:sha) { nil } + + it 'serves the newest image' do + action = newest_version.actions.first + + expect(response.header['ETag']).to eq(etag(action)) + expect(response).to have_gitlab_http_status(:ok) + end + end + + context 'when sha is not a valid version sha' do + let(:sha) { '570e7b2abdd848b95f2f578043fc23bd6f6fd24d' } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when design does not have a smaller image size available' do + let(:design) { create(:design, :with_file, issue: issue) } + + it 'returns a 404' do + expect(response).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 053932944bb..a22dc77997b 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -1719,6 +1719,33 @@ describe Projects::IssuesController do end end + describe 'GET #designs' do + context 'when project has moved' do + let(:new_project) { create(:project) } + let(:issue) { create(:issue, project: new_project) } + + before do + sign_in(user) + + project.route.destroy + new_project.redirect_routes.create!(path: project.full_path) + new_project.add_developer(user) + end + + it 'redirects from an old issue/designs correctly' do + get :designs, + params: { + namespace_id: project.namespace, + project_id: project, + id: issue + } + + expect(response).to redirect_to(designs_project_issue_path(new_project, issue)) + expect(response).to have_gitlab_http_status(:found) + end + end + end + context 'private project with token authentication' do let(:private_project) { create(:project, :private) } diff --git a/spec/frontend/alert_management/components/alert_management_list_spec.js b/spec/frontend/alert_management/components/alert_management_list_spec.js index cb2531663bd..d7170e71a96 100644 --- a/spec/frontend/alert_management/components/alert_management_list_spec.js +++ b/spec/frontend/alert_management/components/alert_management_list_spec.js @@ -9,6 +9,7 @@ import { GlIcon, GlTab, } from '@gitlab/ui'; +import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import AlertManagementList from '~/alert_management/components/alert_management_list.vue'; import { ALERTS_STATUS_TABS } from '../../../../app/assets/javascripts/alert_management/constants'; @@ -24,6 +25,7 @@ describe('AlertManagementList', () => { const findStatusDropdown = () => wrapper.find(GlNewDropdown); const findStatusFilterTabs = () => wrapper.findAll(GlTab); const findNumberOfAlertsBadge = () => wrapper.findAll(GlBadge); + const findDateFields = () => wrapper.findAll(TimeAgo); function mountComponent({ props = { @@ -198,5 +200,45 @@ describe('AlertManagementList', () => { ).toBe(true); }); }); + + describe('handle date fields', () => { + it('should display time ago dates when values provided', () => { + mountComponent({ + props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, + data: { + alerts: [ + { + iid: 1, + startedAt: '2020-03-17T23:18:14.996Z', + endedAt: '2020-04-17T23:18:14.996Z', + severity: 'high', + }, + ], + errored: false, + }, + loading: false, + }); + expect(findDateFields().length).toBe(2); + }); + + it('should not display time ago dates when values not provided', () => { + mountComponent({ + props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, + data: { + alerts: [ + { + iid: 1, + startedAt: null, + endedAt: null, + severity: 'high', + }, + ], + errored: false, + }, + loading: false, + }); + expect(findDateFields().exists()).toBe(false); + }); + }); }); }); diff --git a/spec/frontend/ci_variable_list/services/mock_data.js b/spec/frontend/ci_variable_list/services/mock_data.js index 09c6cd9de21..7dab33050d9 100644 --- a/spec/frontend/ci_variable_list/services/mock_data.js +++ b/spec/frontend/ci_variable_list/services/mock_data.js @@ -8,7 +8,7 @@ export default { protected: false, secret_value: 'test_val', value: 'test_val', - variable_type: 'Var', + variable_type: 'Variable', }, ], @@ -44,7 +44,7 @@ export default { protected: false, secret_value: 'test_val', value: 'test_val', - variable_type: 'Var', + variable_type: 'Variable', }, { environment_scope: 'All (default)', @@ -104,7 +104,7 @@ export default { id: 28, key: 'goku_var', value: 'goku_val', - variable_type: 'Var', + variable_type: 'Variable', protected: true, masked: true, environment_scope: 'staging', @@ -114,7 +114,7 @@ export default { id: 25, key: 'test_var_4', value: 'test_val_4', - variable_type: 'Var', + variable_type: 'Variable', protected: false, masked: false, environment_scope: 'production', @@ -134,7 +134,7 @@ export default { id: 24, key: 'test_var_3', value: 'test_val_3', - variable_type: 'Var', + variable_type: 'Variable', protected: false, masked: false, environment_scope: 'All (default)', @@ -144,7 +144,7 @@ export default { id: 26, key: 'test_var_5', value: 'test_val_5', - variable_type: 'Var', + variable_type: 'Variable', protected: false, masked: false, environment_scope: 'production', diff --git a/spec/frontend/ci_variable_list/store/mutations_spec.js b/spec/frontend/ci_variable_list/store/mutations_spec.js index 8652359f3df..ce0792d0353 100644 --- a/spec/frontend/ci_variable_list/store/mutations_spec.js +++ b/spec/frontend/ci_variable_list/store/mutations_spec.js @@ -47,7 +47,7 @@ describe('CI variable list mutations', () => { describe('CLEAR_MODAL', () => { it('should clear modal state ', () => { const modalState = { - variable_type: 'Var', + variable_type: 'Variable', key: '', secret_value: '', protected: false, diff --git a/spec/frontend/ide/services/index_spec.js b/spec/frontend/ide/services/index_spec.js index 658ad37d7f2..f4d4122bd5a 100644 --- a/spec/frontend/ide/services/index_spec.js +++ b/spec/frontend/ide/services/index_spec.js @@ -221,4 +221,37 @@ describe('IDE services', () => { }); }); }); + + describe('getFiles', () => { + let mock; + let relativeUrlRoot; + const TEST_RELATIVE_URL_ROOT = 'blah-blah'; + + beforeEach(() => { + jest.spyOn(axios, 'get'); + relativeUrlRoot = gon.relative_url_root; + gon.relative_url_root = TEST_RELATIVE_URL_ROOT; + + mock = new MockAdapter(axios); + + mock + .onGet(`${TEST_RELATIVE_URL_ROOT}/${TEST_PROJECT_ID}/-/files/${TEST_COMMIT_SHA}`) + .reply(200, [TEST_FILE_PATH]); + }); + + afterEach(() => { + mock.restore(); + gon.relative_url_root = relativeUrlRoot; + }); + + it('initates the api call based on the passed path and commit hash', () => { + return services.getFiles(TEST_PROJECT_ID, TEST_COMMIT_SHA).then(({ data }) => { + expect(axios.get).toHaveBeenCalledWith( + `${gon.relative_url_root}/${TEST_PROJECT_ID}/-/files/${TEST_COMMIT_SHA}`, + expect.any(Object), + ); + expect(data).toEqual([TEST_FILE_PATH]); + }); + }); + }); }); diff --git a/spec/javascripts/image_diff/helpers/badge_helper_spec.js b/spec/frontend/image_diff/helpers/badge_helper_spec.js index b3001d45e3c..c970ccc535d 100644 --- a/spec/javascripts/image_diff/helpers/badge_helper_spec.js +++ b/spec/frontend/image_diff/helpers/badge_helper_spec.js @@ -66,7 +66,7 @@ describe('badge helper', () => { }); it('should set the badge text', () => { - expect(buttonEl.innerText).toEqual(badgeText); + expect(buttonEl.textContent).toEqual(badgeText); }); it('should set the button coordinates', () => { @@ -120,7 +120,7 @@ describe('badge helper', () => { }); it('should update badge number', () => { - expect(avatarBadgeEl.innerText).toEqual(badgeNumber.toString()); + expect(avatarBadgeEl.textContent).toEqual(badgeNumber.toString()); }); it('should remove hidden class', () => { diff --git a/spec/javascripts/image_diff/helpers/comment_indicator_helper_spec.js b/spec/frontend/image_diff/helpers/comment_indicator_helper_spec.js index 8e3e7f1222e..395bb7de362 100644 --- a/spec/javascripts/image_diff/helpers/comment_indicator_helper_spec.js +++ b/spec/frontend/image_diff/helpers/comment_indicator_helper_spec.js @@ -128,8 +128,8 @@ describe('commentIndicatorHelper', () => { currentTarget: containerEl.querySelector('button'), }; - spyOn(event, 'stopPropagation'); - spyOn(textAreaEl, 'focus'); + jest.spyOn(event, 'stopPropagation').mockImplementation(() => {}); + jest.spyOn(textAreaEl, 'focus').mockImplementation(() => {}); commentIndicatorHelper.commentIndicatorOnClick(event); }); diff --git a/spec/javascripts/image_diff/helpers/dom_helper_spec.js b/spec/frontend/image_diff/helpers/dom_helper_spec.js index ffe712af2dd..9357d626bbe 100644 --- a/spec/javascripts/image_diff/helpers/dom_helper_spec.js +++ b/spec/frontend/image_diff/helpers/dom_helper_spec.js @@ -44,7 +44,7 @@ describe('domHelper', () => { }); it('should update avatar badge number', () => { - expect(discussionEl.querySelector('.badge').innerText).toEqual(badgeNumber.toString()); + expect(discussionEl.querySelector('.badge').textContent).toEqual(badgeNumber.toString()); }); }); @@ -60,7 +60,7 @@ describe('domHelper', () => { }); it('should update discussion badge number', () => { - expect(discussionEl.querySelector('.badge').innerText).toEqual(badgeNumber.toString()); + expect(discussionEl.querySelector('.badge').textContent).toEqual(badgeNumber.toString()); }); }); diff --git a/spec/javascripts/image_diff/helpers/utils_helper_spec.js b/spec/frontend/image_diff/helpers/utils_helper_spec.js index 3b6378be883..3b6378be883 100644 --- a/spec/javascripts/image_diff/helpers/utils_helper_spec.js +++ b/spec/frontend/image_diff/helpers/utils_helper_spec.js diff --git a/spec/javascripts/image_diff/image_badge_spec.js b/spec/frontend/image_diff/image_badge_spec.js index a1589d7b7a0..a11b50ead47 100644 --- a/spec/javascripts/image_diff/image_badge_spec.js +++ b/spec/frontend/image_diff/image_badge_spec.js @@ -71,7 +71,7 @@ describe('ImageBadge', () => { describe('imageEl property is provided and not browser property', () => { beforeEach(() => { - spyOn(imageDiffHelper, 'resizeCoordinatesToImageElement').and.returnValue(true); + jest.spyOn(imageDiffHelper, 'resizeCoordinatesToImageElement').mockReturnValue(true); }); it('should generate browser property', () => { diff --git a/spec/javascripts/image_diff/image_diff_spec.js b/spec/frontend/image_diff/image_diff_spec.js index 21e7b8e2e9b..c15718b5106 100644 --- a/spec/javascripts/image_diff/image_diff_spec.js +++ b/spec/frontend/image_diff/image_diff_spec.js @@ -75,7 +75,7 @@ describe('ImageDiff', () => { describe('init', () => { beforeEach(() => { - spyOn(ImageDiff.prototype, 'bindEvents').and.callFake(() => {}); + jest.spyOn(ImageDiff.prototype, 'bindEvents').mockImplementation(() => {}); imageDiff = new ImageDiff(element); imageDiff.init(); }); @@ -97,19 +97,19 @@ describe('ImageDiff', () => { let imageEl; beforeEach(() => { - spyOn(imageDiffHelper, 'toggleCollapsed').and.callFake(() => {}); - spyOn(imageDiffHelper, 'commentIndicatorOnClick').and.callFake(() => {}); - spyOn(imageDiffHelper, 'removeCommentIndicator').and.callFake(() => {}); - spyOn(ImageDiff.prototype, 'imageClicked').and.callFake(() => {}); - spyOn(ImageDiff.prototype, 'addBadge').and.callFake(() => {}); - spyOn(ImageDiff.prototype, 'removeBadge').and.callFake(() => {}); - spyOn(ImageDiff.prototype, 'renderBadges').and.callFake(() => {}); + jest.spyOn(imageDiffHelper, 'toggleCollapsed').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'commentIndicatorOnClick').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'removeCommentIndicator').mockImplementation(() => {}); + jest.spyOn(ImageDiff.prototype, 'imageClicked').mockImplementation(() => {}); + jest.spyOn(ImageDiff.prototype, 'addBadge').mockImplementation(() => {}); + jest.spyOn(ImageDiff.prototype, 'removeBadge').mockImplementation(() => {}); + jest.spyOn(ImageDiff.prototype, 'renderBadges').mockImplementation(() => {}); imageEl = element.querySelector('.diff-file .js-image-frame img'); }); describe('default', () => { beforeEach(() => { - spyOn(imageUtility, 'isImageLoaded').and.returnValue(false); + jest.spyOn(imageUtility, 'isImageLoaded').mockReturnValue(false); imageDiff = new ImageDiff(element); imageDiff.imageEl = imageEl; imageDiff.bindEvents(); @@ -130,7 +130,7 @@ describe('ImageDiff', () => { describe('image not loaded', () => { beforeEach(() => { - spyOn(imageUtility, 'isImageLoaded').and.returnValue(false); + jest.spyOn(imageUtility, 'isImageLoaded').mockReturnValue(false); imageDiff = new ImageDiff(element); imageDiff.imageEl = imageEl; imageDiff.bindEvents(); @@ -146,7 +146,7 @@ describe('ImageDiff', () => { describe('canCreateNote', () => { beforeEach(() => { - spyOn(imageUtility, 'isImageLoaded').and.returnValue(false); + jest.spyOn(imageUtility, 'isImageLoaded').mockReturnValue(false); imageDiff = new ImageDiff(element, { canCreateNote: true, }); @@ -185,7 +185,7 @@ describe('ImageDiff', () => { describe('canCreateNote is false', () => { beforeEach(() => { - spyOn(imageUtility, 'isImageLoaded').and.returnValue(false); + jest.spyOn(imageUtility, 'isImageLoaded').mockReturnValue(false); imageDiff = new ImageDiff(element); imageDiff.imageEl = imageEl; imageDiff.bindEvents(); @@ -202,12 +202,12 @@ describe('ImageDiff', () => { describe('imageClicked', () => { beforeEach(() => { - spyOn(imageDiffHelper, 'getTargetSelection').and.returnValue({ + jest.spyOn(imageDiffHelper, 'getTargetSelection').mockReturnValue({ actual: {}, browser: {}, }); - spyOn(imageDiffHelper, 'setPositionDataAttribute').and.callFake(() => {}); - spyOn(imageDiffHelper, 'showCommentIndicator').and.callFake(() => {}); + jest.spyOn(imageDiffHelper, 'setPositionDataAttribute').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'showCommentIndicator').mockImplementation(() => {}); imageDiff = new ImageDiff(element); imageDiff.imageClicked({ detail: { @@ -231,7 +231,7 @@ describe('ImageDiff', () => { describe('renderBadges', () => { beforeEach(() => { - spyOn(ImageDiff.prototype, 'renderBadge').and.callFake(() => {}); + jest.spyOn(ImageDiff.prototype, 'renderBadge').mockImplementation(() => {}); imageDiff = new ImageDiff(element); imageDiff.renderBadges(); }); @@ -239,7 +239,7 @@ describe('ImageDiff', () => { it('should call renderBadge for each discussionEl', () => { const discussionEls = element.querySelectorAll('.note-container .discussion-notes .notes'); - expect(imageDiff.renderBadge.calls.count()).toEqual(discussionEls.length); + expect(imageDiff.renderBadge.mock.calls.length).toEqual(discussionEls.length); }); }); @@ -247,9 +247,9 @@ describe('ImageDiff', () => { let discussionEls; beforeEach(() => { - spyOn(imageDiffHelper, 'addImageBadge').and.callFake(() => {}); - spyOn(imageDiffHelper, 'addImageCommentBadge').and.callFake(() => {}); - spyOn(imageDiffHelper, 'generateBadgeFromDiscussionDOM').and.returnValue({ + jest.spyOn(imageDiffHelper, 'addImageBadge').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'addImageCommentBadge').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'generateBadgeFromDiscussionDOM').mockReturnValue({ browser: {}, noteId: 'noteId', }); @@ -282,9 +282,9 @@ describe('ImageDiff', () => { describe('addBadge', () => { beforeEach(() => { - spyOn(imageDiffHelper, 'addImageBadge').and.callFake(() => {}); - spyOn(imageDiffHelper, 'addAvatarBadge').and.callFake(() => {}); - spyOn(imageDiffHelper, 'updateDiscussionBadgeNumber').and.callFake(() => {}); + jest.spyOn(imageDiffHelper, 'addImageBadge').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'addAvatarBadge').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'updateDiscussionBadgeNumber').mockImplementation(() => {}); imageDiff = new ImageDiff(element); imageDiff.imageFrameEl = element.querySelector('.diff-file .js-image-frame'); imageDiff.addBadge({ @@ -320,8 +320,8 @@ describe('ImageDiff', () => { beforeEach(() => { const { imageMeta } = mockData; - spyOn(imageDiffHelper, 'updateDiscussionBadgeNumber').and.callFake(() => {}); - spyOn(imageDiffHelper, 'updateDiscussionAvatarBadgeNumber').and.callFake(() => {}); + jest.spyOn(imageDiffHelper, 'updateDiscussionBadgeNumber').mockImplementation(() => {}); + jest.spyOn(imageDiffHelper, 'updateDiscussionAvatarBadgeNumber').mockImplementation(() => {}); imageDiff = new ImageDiff(element); imageDiff.imageBadges = [imageMeta, imageMeta, imageMeta]; imageDiff.imageFrameEl = element.querySelector('.diff-file .js-image-frame'); @@ -336,8 +336,8 @@ describe('ImageDiff', () => { it('should update next imageBadgeEl value', () => { const imageBadgeEls = imageDiff.imageFrameEl.querySelectorAll('.badge'); - expect(imageBadgeEls[0].innerText).toEqual('1'); - expect(imageBadgeEls[1].innerText).toEqual('2'); + expect(imageBadgeEls[0].textContent).toEqual('1'); + expect(imageBadgeEls[1].textContent).toEqual('2'); expect(imageBadgeEls.length).toEqual(2); }); diff --git a/spec/javascripts/image_diff/mock_data.js b/spec/frontend/image_diff/mock_data.js index a0d1732dd0a..a0d1732dd0a 100644 --- a/spec/javascripts/image_diff/mock_data.js +++ b/spec/frontend/image_diff/mock_data.js diff --git a/spec/javascripts/image_diff/replaced_image_diff_spec.js b/spec/frontend/image_diff/replaced_image_diff_spec.js index 62e7c8b6c6a..f2a7b7f8406 100644 --- a/spec/javascripts/image_diff/replaced_image_diff_spec.js +++ b/spec/frontend/image_diff/replaced_image_diff_spec.js @@ -76,8 +76,8 @@ describe('ReplacedImageDiff', () => { describe('init', () => { beforeEach(() => { - spyOn(ReplacedImageDiff.prototype, 'bindEvents').and.callFake(() => {}); - spyOn(ReplacedImageDiff.prototype, 'generateImageEls').and.callFake(() => {}); + jest.spyOn(ReplacedImageDiff.prototype, 'bindEvents').mockImplementation(() => {}); + jest.spyOn(ReplacedImageDiff.prototype, 'generateImageEls').mockImplementation(() => {}); replacedImageDiff = new ReplacedImageDiff(element); replacedImageDiff.init(); @@ -140,7 +140,7 @@ describe('ReplacedImageDiff', () => { describe('generateImageEls', () => { beforeEach(() => { - spyOn(ReplacedImageDiff.prototype, 'bindEvents').and.callFake(() => {}); + jest.spyOn(ReplacedImageDiff.prototype, 'bindEvents').mockImplementation(() => {}); replacedImageDiff = new ReplacedImageDiff(element, { canCreateNote: false, @@ -163,7 +163,7 @@ describe('ReplacedImageDiff', () => { describe('bindEvents', () => { beforeEach(() => { - spyOn(ImageDiff.prototype, 'bindEvents').and.callFake(() => {}); + jest.spyOn(ImageDiff.prototype, 'bindEvents').mockImplementation(() => {}); replacedImageDiff = new ReplacedImageDiff(element); setupViewModesEls(); @@ -176,7 +176,7 @@ describe('ReplacedImageDiff', () => { }); it('should register click eventlistener to 2-up view mode', done => { - spyOn(ReplacedImageDiff.prototype, 'changeView').and.callFake(viewMode => { + jest.spyOn(ReplacedImageDiff.prototype, 'changeView').mockImplementation(viewMode => { expect(viewMode).toEqual(viewTypes.TWO_UP); done(); }); @@ -186,7 +186,7 @@ describe('ReplacedImageDiff', () => { }); it('should register click eventlistener to swipe view mode', done => { - spyOn(ReplacedImageDiff.prototype, 'changeView').and.callFake(viewMode => { + jest.spyOn(ReplacedImageDiff.prototype, 'changeView').mockImplementation(viewMode => { expect(viewMode).toEqual(viewTypes.SWIPE); done(); }); @@ -196,7 +196,7 @@ describe('ReplacedImageDiff', () => { }); it('should register click eventlistener to onion skin view mode', done => { - spyOn(ReplacedImageDiff.prototype, 'changeView').and.callFake(viewMode => { + jest.spyOn(ReplacedImageDiff.prototype, 'changeView').mockImplementation(viewMode => { expect(viewMode).toEqual(viewTypes.SWIPE); done(); }); @@ -247,7 +247,7 @@ describe('ReplacedImageDiff', () => { describe('changeView', () => { beforeEach(() => { replacedImageDiff = new ReplacedImageDiff(element); - spyOn(imageDiffHelper, 'removeCommentIndicator').and.returnValue({ + jest.spyOn(imageDiffHelper, 'removeCommentIndicator').mockReturnValue({ removed: false, }); setupImageFrameEls(); @@ -265,13 +265,12 @@ describe('ReplacedImageDiff', () => { describe('valid viewType', () => { beforeEach(() => { - jasmine.clock().install(); - spyOn(ReplacedImageDiff.prototype, 'renderNewView').and.callFake(() => {}); + jest.spyOn(ReplacedImageDiff.prototype, 'renderNewView').mockImplementation(() => {}); replacedImageDiff.changeView(viewTypes.ONION_SKIN); }); afterEach(() => { - jasmine.clock().uninstall(); + jest.clearAllTimers(); }); it('should call removeCommentIndicator', () => { @@ -287,7 +286,7 @@ describe('ReplacedImageDiff', () => { }); it('should call renderNewView', () => { - jasmine.clock().tick(251); + jest.advanceTimersByTime(251); expect(replacedImageDiff.renderNewView).toHaveBeenCalled(); }); @@ -300,7 +299,7 @@ describe('ReplacedImageDiff', () => { }); it('should call renderBadges', () => { - spyOn(ReplacedImageDiff.prototype, 'renderBadges').and.callFake(() => {}); + jest.spyOn(ReplacedImageDiff.prototype, 'renderBadges').mockImplementation(() => {}); replacedImageDiff.renderNewView({ removed: false, @@ -326,14 +325,16 @@ describe('ReplacedImageDiff', () => { }); it('should pass showCommentIndicator normalized indicator values', done => { - spyOn(imageDiffHelper, 'showCommentIndicator').and.callFake(() => {}); - spyOn(imageDiffHelper, 'resizeCoordinatesToImageElement').and.callFake((imageEl, meta) => { - expect(meta.x).toEqual(indicator.x); - expect(meta.y).toEqual(indicator.y); - expect(meta.width).toEqual(indicator.image.width); - expect(meta.height).toEqual(indicator.image.height); - done(); - }); + jest.spyOn(imageDiffHelper, 'showCommentIndicator').mockImplementation(() => {}); + jest + .spyOn(imageDiffHelper, 'resizeCoordinatesToImageElement') + .mockImplementation((imageEl, meta) => { + expect(meta.x).toEqual(indicator.x); + expect(meta.y).toEqual(indicator.y); + expect(meta.width).toEqual(indicator.image.width); + expect(meta.height).toEqual(indicator.image.height); + done(); + }); replacedImageDiff.renderNewView(indicator); }); @@ -341,13 +342,13 @@ describe('ReplacedImageDiff', () => { const normalized = { normalized: true, }; - spyOn(imageDiffHelper, 'resizeCoordinatesToImageElement').and.returnValue(normalized); - spyOn(imageDiffHelper, 'showCommentIndicator').and.callFake( - (imageFrameEl, normalizedIndicator) => { + jest.spyOn(imageDiffHelper, 'resizeCoordinatesToImageElement').mockReturnValue(normalized); + jest + .spyOn(imageDiffHelper, 'showCommentIndicator') + .mockImplementation((imageFrameEl, normalizedIndicator) => { expect(normalizedIndicator).toEqual(normalized); done(); - }, - ); + }); replacedImageDiff.renderNewView(indicator); }); }); diff --git a/spec/javascripts/vue_shared/components/ci_badge_link_spec.js b/spec/frontend/vue_shared/components/ci_badge_link_spec.js index 367e07d3ad3..f656bb0b60d 100644 --- a/spec/javascripts/vue_shared/components/ci_badge_link_spec.js +++ b/spec/frontend/vue_shared/components/ci_badge_link_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import ciBadge from '~/vue_shared/components/ci_badge_link.vue'; describe('CI Badge Link Component', () => { diff --git a/spec/javascripts/vue_shared/components/ci_icon_spec.js b/spec/frontend/vue_shared/components/ci_icon_spec.js index 9486d7d4f23..63afe631063 100644 --- a/spec/javascripts/vue_shared/components/ci_icon_spec.js +++ b/spec/frontend/vue_shared/components/ci_icon_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import ciIcon from '~/vue_shared/components/ci_icon.vue'; describe('CI Icon component', () => { diff --git a/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js b/spec/frontend/vue_shared/components/content_viewer/content_viewer_spec.js index fbe9337ecf4..b0563f2f6de 100644 --- a/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js +++ b/spec/frontend/vue_shared/components/content_viewer/content_viewer_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; import MockAdapter from 'axios-mock-adapter'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import waitForPromises from 'spec/helpers/wait_for_promises'; +import mountComponent from 'helpers/vue_mount_component_helper'; +import waitForPromises from 'helpers/wait_for_promises'; import { GREEN_BOX_IMAGE_URL } from 'spec/test_constants'; import axios from '~/lib/utils/axios_utils'; import contentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; @@ -96,7 +96,7 @@ describe('ContentViewer', () => { it('markdown preview receives the file path as a parameter', done => { mock = new MockAdapter(axios); - spyOn(axios, 'post').and.callThrough(); + jest.spyOn(axios, 'post'); mock.onPost(`${gon.relative_url_root}/testproject/preview_markdown`).reply(200, { body: '<b>testing</b>', }); @@ -114,7 +114,7 @@ describe('ContentViewer', () => { expect(axios.post).toHaveBeenCalledWith( `${gon.relative_url_root}/testproject/preview_markdown`, { path: 'foo/test.md', text: '* Test' }, - jasmine.any(Object), + expect.any(Object), ); }) .then(done) diff --git a/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js b/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js index a8acecdd3fc..636508be6b6 100644 --- a/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js +++ b/spec/frontend/vue_shared/components/diff_viewer/diff_viewer_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import { GREEN_BOX_IMAGE_URL, RED_BOX_IMAGE_URL } from 'spec/test_constants'; import diffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; @@ -32,7 +32,7 @@ describe('DiffViewer', () => { createComponent({ ...requiredProps, projectPath: '' }); - setTimeout(() => { + setImmediate(() => { expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe( `//-/raw/DEF/${RED_BOX_IMAGE_URL}`, ); @@ -53,7 +53,7 @@ describe('DiffViewer', () => { oldPath: 'testold.abc', }); - setTimeout(() => { + setImmediate(() => { expect(vm.$el.querySelector('.deleted .file-info').textContent.trim()).toContain( 'testold.abc', ); diff --git a/spec/javascripts/vue_shared/components/dropdown/dropdown_button_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js index b00fa785a0e..892a96b76fd 100644 --- a/spec/javascripts/vue_shared/components/dropdown/dropdown_button_spec.js +++ b/spec/frontend/vue_shared/components/dropdown/dropdown_button_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper'; +import { mountComponentWithSlots } from 'helpers/vue_mount_component_helper'; import dropdownButtonComponent from '~/vue_shared/components/dropdown/dropdown_button.vue'; const defaultLabel = 'Select'; @@ -74,7 +74,7 @@ describe('DropdownButtonComponent', () => { }, ); - expect(vm.$el).not.toContainElement('.dropdown-toggle-text'); + expect(vm.$el.querySelector('.dropdown-toggle-text')).toBeNull(); expect(vm.$el).toHaveText('Lorem Ipsum Dolar'); }); }); diff --git a/spec/javascripts/vue_shared/components/dropdown/dropdown_hidden_input_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_hidden_input_spec.js index 402de2a8788..30b8e869aab 100644 --- a/spec/javascripts/vue_shared/components/dropdown/dropdown_hidden_input_spec.js +++ b/spec/frontend/vue_shared/components/dropdown/dropdown_hidden_input_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import dropdownHiddenInputComponent from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; import { mockLabels } from './mock_data'; diff --git a/spec/javascripts/vue_shared/components/dropdown/mock_data.js b/spec/frontend/vue_shared/components/dropdown/mock_data.js index b09d42da401..b09d42da401 100644 --- a/spec/javascripts/vue_shared/components/dropdown/mock_data.js +++ b/spec/frontend/vue_shared/components/dropdown/mock_data.js diff --git a/spec/javascripts/vue_shared/components/file_finder/item_spec.js b/spec/frontend/vue_shared/components/file_finder/item_spec.js index e18d0a46223..63f2614106d 100644 --- a/spec/javascripts/vue_shared/components/file_finder/item_spec.js +++ b/spec/frontend/vue_shared/components/file_finder/item_spec.js @@ -1,7 +1,7 @@ import Vue from 'vue'; -import { file } from 'spec/ide/helpers'; +import { file } from 'jest/ide/helpers'; import ItemComponent from '~/vue_shared/components/file_finder/item.vue'; -import createComponent from '../../../helpers/vue_mount_component_helper'; +import createComponent from 'helpers/vue_mount_component_helper'; describe('File finder item spec', () => { const Component = Vue.extend(ItemComponent); @@ -75,7 +75,7 @@ describe('File finder item spec', () => { }); it('emits event when clicked', () => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.click(); diff --git a/spec/javascripts/vue_shared/components/filtered_search_dropdown_spec.js b/spec/frontend/vue_shared/components/filtered_search_dropdown_spec.js index 0bb4a04557b..87cafa0bb8c 100644 --- a/spec/javascripts/vue_shared/components/filtered_search_dropdown_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_dropdown_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import component from '~/vue_shared/components/filtered_search_dropdown.vue'; describe('Filtered search dropdown', () => { @@ -125,7 +125,7 @@ describe('Filtered search dropdown', () => { describe('on click create button', () => { it('emits createItem event with the filter', done => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$nextTick(() => { vm.$el.querySelector('.js-dropdown-create-button').click(); diff --git a/spec/javascripts/vue_shared/components/gl_countdown_spec.js b/spec/frontend/vue_shared/components/gl_countdown_spec.js index 929ffe219f4..365c9fad478 100644 --- a/spec/javascripts/vue_shared/components/gl_countdown_spec.js +++ b/spec/frontend/vue_shared/components/gl_countdown_spec.js @@ -1,4 +1,4 @@ -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import Vue from 'vue'; import GlCountdown from '~/vue_shared/components/gl_countdown.vue'; @@ -8,13 +8,12 @@ describe('GlCountdown', () => { let now = '2000-01-01T00:00:00Z'; beforeEach(() => { - spyOn(Date, 'now').and.callFake(() => new Date(now).getTime()); - jasmine.clock().install(); + jest.spyOn(Date, 'now').mockImplementation(() => new Date(now).getTime()); }); afterEach(() => { vm.$destroy(); - jasmine.clock().uninstall(); + jest.clearAllTimers(); }); describe('when there is time remaining', () => { @@ -29,16 +28,16 @@ describe('GlCountdown', () => { }); it('displays remaining time', () => { - expect(vm.$el).toContainText('01:02:03'); + expect(vm.$el.textContent).toContain('01:02:03'); }); it('updates remaining time', done => { now = '2000-01-01T00:00:01Z'; - jasmine.clock().tick(1000); + jest.advanceTimersByTime(1000); Vue.nextTick() .then(() => { - expect(vm.$el).toContainText('01:02:02'); + expect(vm.$el.textContent).toContain('01:02:02'); done(); }) .catch(done.fail); @@ -57,19 +56,26 @@ describe('GlCountdown', () => { }); it('displays 00:00:00', () => { - expect(vm.$el).toContainText('00:00:00'); + expect(vm.$el.textContent).toContain('00:00:00'); }); }); describe('when an invalid date is passed', () => { + beforeEach(() => { + Vue.config.warnHandler = jest.fn(); + }); + + afterEach(() => { + Vue.config.warnHandler = null; + }); + it('throws a validation error', () => { - spyOn(Vue.config, 'warnHandler').and.stub(); vm = mountComponent(Component, { endDateString: 'this is invalid', }); expect(Vue.config.warnHandler).toHaveBeenCalledTimes(1); - const [errorMessage] = Vue.config.warnHandler.calls.argsFor(0); + const [errorMessage] = Vue.config.warnHandler.mock.calls[0]; expect(errorMessage).toMatch(/^Invalid prop: .* "endDateString"/); }); diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/frontend/vue_shared/components/header_ci_component_spec.js index b1abc972e1d..216563165d6 100644 --- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js +++ b/spec/frontend/vue_shared/components/header_ci_component_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent, { mountComponentWithSlots } from 'spec/helpers/vue_mount_component_helper'; +import mountComponent, { mountComponentWithSlots } from 'helpers/vue_mount_component_helper'; import headerCi from '~/vue_shared/components/header_ci_component.vue'; describe('Header CI Component', () => { diff --git a/spec/javascripts/vue_shared/components/markdown/toolbar_spec.js b/spec/frontend/vue_shared/components/markdown/toolbar_spec.js index a87998aa72f..e7c31014bfc 100644 --- a/spec/javascripts/vue_shared/components/markdown/toolbar_spec.js +++ b/spec/frontend/vue_shared/components/markdown/toolbar_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import toolbar from '~/vue_shared/components/markdown/toolbar.vue'; describe('toolbar', () => { diff --git a/spec/javascripts/vue_shared/components/navigation_tabs_spec.js b/spec/frontend/vue_shared/components/navigation_tabs_spec.js index beb980a6556..561456d614e 100644 --- a/spec/javascripts/vue_shared/components/navigation_tabs_spec.js +++ b/spec/frontend/vue_shared/components/navigation_tabs_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import navigationTabs from '~/vue_shared/components/navigation_tabs.vue'; describe('navigation tabs component', () => { @@ -56,7 +56,7 @@ describe('navigation tabs component', () => { }); it('should trigger onTabClick', () => { - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); vm.$el.querySelector('.js-pipelines-tab-pending').click(); expect(vm.$emit).toHaveBeenCalledWith('onChangeTab', 'pending'); diff --git a/spec/javascripts/vue_shared/components/pikaday_spec.js b/spec/frontend/vue_shared/components/pikaday_spec.js index b787ba7596f..867bf88ff50 100644 --- a/spec/javascripts/vue_shared/components/pikaday_spec.js +++ b/spec/frontend/vue_shared/components/pikaday_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import datePicker from '~/vue_shared/components/pikaday.vue'; describe('datePicker', () => { @@ -20,7 +20,7 @@ describe('datePicker', () => { }); it('should toggle when dropdown is clicked', () => { - const hidePicker = jasmine.createSpy(); + const hidePicker = jest.fn(); vm.$on('hidePicker', hidePicker); vm.$el.querySelector('.dropdown-menu-toggle').click(); diff --git a/spec/javascripts/vue_shared/components/project_avatar/default_spec.js b/spec/frontend/vue_shared/components/project_avatar/default_spec.js index 2ec19ebf80e..090f8b69213 100644 --- a/spec/javascripts/vue_shared/components/project_avatar/default_spec.js +++ b/spec/frontend/vue_shared/components/project_avatar/default_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; -import { projectData } from 'spec/ide/mock_data'; +import mountComponent from 'helpers/vue_mount_component_helper'; +import { projectData } from 'jest/ide/mock_data'; import { TEST_HOST } from 'spec/test_constants'; import { getFirstCharacterCapitalized } from '~/lib/utils/text_utility'; import ProjectAvatarDefault from '~/vue_shared/components/project_avatar/default.vue'; @@ -48,8 +48,8 @@ describe('ProjectAvatarDefault component', () => { vm.$nextTick() .then(() => { - expect(vm.$el).toContainElement('.avatar'); - expect(vm.$el).not.toContainElement('.identicon'); + expect(vm.$el.querySelector('.avatar')).not.toBeNull(); + expect(vm.$el.querySelector('.identicon')).toBeNull(); expect(vm.$el.querySelector('img')).toHaveAttr('src', avatarUrl); }) .then(done) diff --git a/spec/javascripts/vue_shared/components/project_selector/project_list_item_spec.js b/spec/frontend/vue_shared/components/project_selector/project_list_item_spec.js index e73fb97b741..eb1d9e93634 100644 --- a/spec/javascripts/vue_shared/components/project_selector/project_list_item_spec.js +++ b/spec/frontend/vue_shared/components/project_selector/project_list_item_spec.js @@ -1,5 +1,5 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { trimText } from 'spec/helpers/text_helper'; +import { trimText } from 'helpers/text_helper'; import ProjectListItem from '~/vue_shared/components/project_selector/project_list_item.vue'; const localVue = createLocalVue(); @@ -9,7 +9,7 @@ describe('ProjectListItem component', () => { let wrapper; let vm; let options; - loadJSONFixtures('static/projects.json'); + const project = getJSONFixture('static/projects.json')[0]; beforeEach(() => { @@ -44,7 +44,7 @@ describe('ProjectListItem component', () => { wrapper = shallowMount(Component, options); ({ vm } = wrapper); - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); wrapper.vm.onClick(); expect(wrapper.vm.$emit).toHaveBeenCalledWith('click'); @@ -95,7 +95,7 @@ describe('ProjectListItem component', () => { }); it('prevents search query and project name XSS', () => { - const alertSpy = spyOn(window, 'alert'); + const alertSpy = jest.spyOn(window, 'alert'); options.propsData.project.name = "my-xss-pro<script>alert('XSS');</script>ject"; options.propsData.matcher = "pro<script>alert('XSS');</script>"; diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js index d90fafb6bf7..9db86fa775f 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/base_spec.js @@ -4,10 +4,7 @@ import { shallowMount } from '@vue/test-utils'; import LabelsSelect from '~/labels_select'; import BaseComponent from '~/vue_shared/components/sidebar/labels_select/base.vue'; -import { - mockConfig, - mockLabels, -} from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data'; +import { mockConfig, mockLabels } from './mock_data'; const createComponent = (config = mockConfig) => shallowMount(BaseComponent, { diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js index a4121448492..d02d924bd2b 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_button_spec.js @@ -3,10 +3,7 @@ import Vue from 'vue'; import mountComponent from 'helpers/vue_mount_component_helper'; import dropdownButtonComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_button.vue'; -import { - mockConfig, - mockLabels, -} from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data'; +import { mockConfig, mockLabels } from './mock_data'; const componentConfig = { ...mockConfig, diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js index d0299523137..edec3b138b3 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js @@ -3,7 +3,7 @@ import Vue from 'vue'; import mountComponent from 'helpers/vue_mount_component_helper'; import dropdownCreateLabelComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue'; -import { mockSuggestedColors } from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data'; +import { mockSuggestedColors } from './mock_data'; const createComponent = headerTitle => { const Component = Vue.extend(dropdownCreateLabelComponent); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js index 784bbaf8e6a..7e9e242a4f5 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js @@ -3,7 +3,7 @@ import Vue from 'vue'; import mountComponent from 'helpers/vue_mount_component_helper'; import dropdownFooterComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_footer.vue'; -import { mockConfig } from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data'; +import { mockConfig } from './mock_data'; const createComponent = ( labelsWebUrl = mockConfig.labelsWebUrl, diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js index 887c04268d1..e09f0006359 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed_spec.js @@ -3,7 +3,7 @@ import Vue from 'vue'; import mountComponent from 'helpers/vue_mount_component_helper'; import dropdownValueCollapsedComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue'; -import { mockLabels } from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data'; +import { mockLabels } from './mock_data'; const createComponent = (labels = mockLabels) => { const Component = Vue.extend(dropdownValueCollapsedComponent); diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js index 06355c0dd65..c33cffb421d 100644 --- a/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js @@ -2,10 +2,7 @@ import { mount } from '@vue/test-utils'; import DropdownValueComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_value.vue'; import { GlLabel } from '@gitlab/ui'; -import { - mockConfig, - mockLabels, -} from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data'; +import { mockConfig, mockLabels } from './mock_data'; const createComponent = ( labels = mockLabels, diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select/mock_data.js index 6564c012e67..6564c012e67 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js +++ b/spec/frontend/vue_shared/components/sidebar/labels_select/mock_data.js diff --git a/spec/javascripts/vue_shared/components/stacked_progress_bar_spec.js b/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js index 3e044f47a3f..bc86ee5a0c6 100644 --- a/spec/javascripts/vue_shared/components/stacked_progress_bar_spec.js +++ b/spec/frontend/vue_shared/components/stacked_progress_bar_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import stackedProgressBarComponent from '~/vue_shared/components/stacked_progress_bar.vue'; const createComponent = config => { diff --git a/spec/javascripts/vue_shared/components/tabs/tab_spec.js b/spec/frontend/vue_shared/components/tabs/tab_spec.js index 8437fe37738..8cf07a9177c 100644 --- a/spec/javascripts/vue_shared/components/tabs/tab_spec.js +++ b/spec/frontend/vue_shared/components/tabs/tab_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import Tab from '~/vue_shared/components/tabs/tab.vue'; describe('Tab component', () => { diff --git a/spec/javascripts/vue_shared/components/tabs/tabs_spec.js b/spec/frontend/vue_shared/components/tabs/tabs_spec.js index 50ba18cd338..49d92094b34 100644 --- a/spec/javascripts/vue_shared/components/tabs/tabs_spec.js +++ b/spec/frontend/vue_shared/components/tabs/tabs_spec.js @@ -5,28 +5,23 @@ import Tab from '~/vue_shared/components/tabs/tab.vue'; describe('Tabs component', () => { let vm; - beforeEach(done => { + beforeEach(() => { vm = new Vue({ components: { Tabs, Tab, }, - template: ` - <div> - <tabs> - <tab title="Testing" active> - First tab - </tab> - <tab> - <template slot="title">Test slot</template> - Second tab - </tab> - </tabs> - </div> - `, + render(h) { + return h('div', [ + h('tabs', [ + h('tab', { attrs: { title: 'Testing', active: true } }, 'First tab'), + h('tab', [h('template', { slot: 'title' }, 'Test slot'), 'Second tab']), + ]), + ]); + }, }).$mount(); - setTimeout(done); + return vm.$nextTick(); }); describe('tab links', () => { @@ -46,14 +41,12 @@ describe('Tabs component', () => { expect(vm.$el.querySelector('a').classList).toContain('active'); }); - it('updates active class on click', done => { + it('updates active class on click', () => { vm.$el.querySelectorAll('a')[1].click(); - setTimeout(() => { + return vm.$nextTick(() => { expect(vm.$el.querySelector('a').classList).not.toContain('active'); expect(vm.$el.querySelectorAll('a')[1].classList).toContain('active'); - - done(); }); }); }); diff --git a/spec/javascripts/vue_shared/components/toggle_button_spec.js b/spec/frontend/vue_shared/components/toggle_button_spec.js index ea0a89a3ab5..83bbb37a89a 100644 --- a/spec/javascripts/vue_shared/components/toggle_button_spec.js +++ b/spec/frontend/vue_shared/components/toggle_button_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import mountComponent from 'helpers/vue_mount_component_helper'; import toggleButton from '~/vue_shared/components/toggle_button.vue'; describe('Toggle Button', () => { @@ -42,7 +42,7 @@ describe('Toggle Button', () => { value: true, }); - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); }); it('renders is checked class', () => { @@ -72,7 +72,7 @@ describe('Toggle Button', () => { value: true, disabledInput: true, }); - spyOn(vm, '$emit'); + jest.spyOn(vm, '$emit').mockImplementation(() => {}); }); it('renders disabled button', () => { diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_svg_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_svg_spec.js new file mode 100644 index 00000000000..ee6c2e2cc46 --- /dev/null +++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_svg_spec.js @@ -0,0 +1,27 @@ +import { shallowMount } from '@vue/test-utils'; +import UserAvatarSvg from '~/vue_shared/components/user_avatar/user_avatar_svg.vue'; + +describe('User Avatar Svg Component', () => { + describe('Initialization', () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(UserAvatarSvg, { + propsData: { + size: 99, + svg: + '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M1.707 15.707C1.077z"/></svg>', + }, + }); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('should have <svg> as a child element', () => { + expect(wrapper.element.tagName).toEqual('svg'); + expect(wrapper.html()).toContain('<path'); + }); + }); +}); diff --git a/spec/javascripts/ide/stores/actions/tree_spec.js b/spec/javascripts/ide/stores/actions/tree_spec.js index fabe44ce333..2201a3b4b57 100644 --- a/spec/javascripts/ide/stores/actions/tree_spec.js +++ b/spec/javascripts/ide/stores/actions/tree_spec.js @@ -30,6 +30,7 @@ describe('Multi-file store tree actions', () => { store.state.currentBranchId = 'master'; store.state.projects.abcproject = { web_url: '', + path_with_namespace: 'foo/abcproject', }; }); @@ -57,7 +58,7 @@ describe('Multi-file store tree actions', () => { store .dispatch('getFiles', basicCallParameters) .then(() => { - expect(service.getFiles).toHaveBeenCalledWith('', '12345678'); + expect(service.getFiles).toHaveBeenCalledWith('foo/abcproject', '12345678'); done(); }) diff --git a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_svg_spec.js b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_svg_spec.js deleted file mode 100644 index 31644416439..00000000000 --- a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_svg_spec.js +++ /dev/null @@ -1,29 +0,0 @@ -import Vue from 'vue'; -import avatarSvg from 'icons/_icon_random.svg'; -import UserAvatarSvg from '~/vue_shared/components/user_avatar/user_avatar_svg.vue'; - -const UserAvatarSvgComponent = Vue.extend(UserAvatarSvg); - -describe('User Avatar Svg Component', function() { - describe('Initialization', function() { - beforeEach(function() { - this.propsData = { - size: 99, - svg: avatarSvg, - }; - - this.userAvatarSvg = new UserAvatarSvgComponent({ - propsData: this.propsData, - }).$mount(); - }); - - it('should return a defined Vue component', function() { - expect(this.userAvatarSvg).toBeDefined(); - }); - - it('should have <svg> as a child element', function() { - expect(this.userAvatarSvg.$el.tagName).toEqual('svg'); - expect(this.userAvatarSvg.$el.innerHTML).toContain('<path'); - }); - }); -}); diff --git a/spec/lib/gitlab/git/attributes_parser_spec.rb b/spec/lib/gitlab/git/attributes_parser_spec.rb index 94b7a086e59..45db4acd3ac 100644 --- a/spec/lib/gitlab/git/attributes_parser_spec.rb +++ b/spec/lib/gitlab/git/attributes_parser_spec.rb @@ -75,6 +75,14 @@ describe Gitlab::Git::AttributesParser, :seed_helper do expect(subject.attributes('test.foo')).to eq({}) end end + + context 'when attributes data has binary data' do + let(:data) { "\xFF\xFE*\u0000.\u0000c\u0000s".b } + + it 'returns an empty Hash' do + expect(subject.attributes('test.foo')).to eq({}) + end + end end describe '#patterns' do diff --git a/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb b/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb index 85a5b1dacc7..11cf14523c2 100644 --- a/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb +++ b/spec/lib/gitlab/graphql/pagination/externally_paginated_array_connection_spec.rb @@ -19,6 +19,20 @@ describe Gitlab::Graphql::Pagination::ExternallyPaginatedArrayConnection do it_behaves_like 'connection with paged nodes' do let(:paged_nodes_size) { values.size } end + + context 'when after or before is specified, they are ignored' do + # after and before are not used to filter the array, as they + # were already used to directly fetch the external array + it_behaves_like 'connection with paged nodes' do + let(:arguments) { { after: next_cursor } } + let(:paged_nodes_size) { values.size } + end + + it_behaves_like 'connection with paged nodes' do + let(:arguments) { { before: prev_cursor } } + let(:paged_nodes_size) { values.size } + end + end end describe '#start_cursor' do diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb index 555b7f04f86..95782c1f674 100644 --- a/spec/models/design_management/design_spec.rb +++ b/spec/models/design_management/design_spec.rb @@ -380,15 +380,8 @@ describe DesignManagement::Design do end end - # TODO these tests are being temporarily skipped unless run in EE, - # as we are in the process of moving Design Management to FOSS in 13.0 - # in steps. In the current step the routes have not yet been moved. - # - # See https://gitlab.com/gitlab-org/gitlab/-/issues/212566#note_327724283. describe '#note_etag_key' do it 'returns a correct etag key' do - skip 'See https://gitlab.com/gitlab-org/gitlab/-/issues/212566#note_327724283' unless Gitlab.ee? - design = create(:design) expect(design.note_etag_key).to eq( diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index cbbd0dae2eb..4fe612c1d0e 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -852,4 +852,20 @@ describe 'project routing' do it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/serverless", "/gitlab/gitlabhq/-/serverless" end end + + describe Projects::DesignManagement::Designs::RawImagesController, 'routing' do + it 'to #show' do + expect(get('/gitlab/gitlabhq/-/design_management/designs/1/raw_image')).to route_to('projects/design_management/designs/raw_images#show', namespace_id: 'gitlab', project_id: 'gitlabhq', design_id: '1') + expect(get('/gitlab/gitlabhq/-/design_management/designs/1/c6f00aa50b80887ada30a6fe517670be9f8f9ece/raw_image')).to route_to('projects/design_management/designs/raw_images#show', namespace_id: 'gitlab', project_id: 'gitlabhq', design_id: '1', sha: 'c6f00aa50b80887ada30a6fe517670be9f8f9ece') + end + end + + describe Projects::DesignManagement::Designs::ResizedImageController, 'routing' do + it 'to #show' do + expect(get('/gitlab/gitlabhq/-/design_management/designs/1/resized_image/v432x230')).to route_to('projects/design_management/designs/resized_image#show', namespace_id: 'gitlab', project_id: 'gitlabhq', design_id: '1', id: 'v432x230') + expect(get('/gitlab/gitlabhq/-/design_management/designs/1/c6f00aa50b80887ada30a6fe517670be9f8f9ece/resized_image/v432x230')).to route_to('projects/design_management/designs/resized_image#show', namespace_id: 'gitlab', project_id: 'gitlabhq', design_id: '1', sha: 'c6f00aa50b80887ada30a6fe517670be9f8f9ece', id: 'v432x230') + expect(get('/gitlab/gitlabhq/-/design_management/designs/1/invalid/resized_image/v432x230')).to route_to('application#route_not_found', unmatched_route: 'gitlab/gitlabhq/-/design_management/designs/1/invalid/resized_image/v432x230') + expect(get('/gitlab/gitlabhq/-/design_management/designs/1/c6f00aa50b80887ada30a6fe517670be9f8f9ece/resized_image/small')).to route_to('application#route_not_found', unmatched_route: 'gitlab/gitlabhq/-/design_management/designs/1/c6f00aa50b80887ada30a6fe517670be9f8f9ece/resized_image/small') + end + end end |