diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-04 15:11:19 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-04 15:11:19 +0000 |
commit | 770adf92515e4311dfb42d89750d32a1e0628913 (patch) | |
tree | 574db6e5e92af5c1a0ffe87be345fffa24bb95f7 /spec | |
parent | d5d47b45ddddcef0f8fc80a35ca7a8a2a0765fd1 (diff) | |
download | gitlab-ce-770adf92515e4311dfb42d89750d32a1e0628913.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
95 files changed, 513 insertions, 366 deletions
diff --git a/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb b/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb index 4e9d021fa5d..4724a8eb5c7 100644 --- a/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb +++ b/spec/finders/merge_requests/oldest_per_commit_finder_spec.rb @@ -6,12 +6,20 @@ RSpec.describe MergeRequests::OldestPerCommitFinder do describe '#execute' do it 'returns a Hash mapping commit SHAs to their oldest merge requests' do project = create(:project) + sha1 = Digest::SHA1.hexdigest('foo') + sha2 = Digest::SHA1.hexdigest('bar') + sha3 = Digest::SHA1.hexdigest('baz') mr1 = create(:merge_request, :merged, target_project: project) mr2 = create(:merge_request, :merged, target_project: project) + mr3 = create( + :merge_request, + :merged, + target_project: project, + merge_commit_sha: sha3 + ) + mr1_diff = create(:merge_request_diff, merge_request: mr1) mr2_diff = create(:merge_request_diff, merge_request: mr2) - sha1 = Digest::SHA1.hexdigest('foo') - sha2 = Digest::SHA1.hexdigest('bar') create(:merge_request_diff_commit, merge_request_diff: mr1_diff, sha: sha1) create(:merge_request_diff_commit, merge_request_diff: mr2_diff, sha: sha1) @@ -22,11 +30,16 @@ RSpec.describe MergeRequests::OldestPerCommitFinder do relative_order: 1 ) - commits = [double(:commit, id: sha1), double(:commit, id: sha2)] + commits = [ + double(:commit, id: sha1), + double(:commit, id: sha2), + double(:commit, id: sha3) + ] expect(described_class.new(project).execute(commits)).to eq( sha1 => mr1, - sha2 => mr2 + sha2 => mr2, + sha3 => mr3 ) end @@ -42,5 +55,45 @@ RSpec.describe MergeRequests::OldestPerCommitFinder do expect(described_class.new(mr.target_project).execute(commits)) .to be_empty end + + it 'includes the merge request for a merge commit' do + project = create(:project) + sha = Digest::SHA1.hexdigest('foo') + mr = create( + :merge_request, + :merged, + target_project: project, + merge_commit_sha: sha + ) + + commits = [double(:commit, id: sha)] + + # This expectation is set so we're certain that the merge commit SHAs (if + # a matching merge request is found) aren't also used for finding MRs + # according to diffs. + expect(MergeRequestDiffCommit) + .not_to receive(:oldest_merge_request_id_per_commit) + + expect(described_class.new(project).execute(commits)).to eq(sha => mr) + end + + it 'includes the oldest merge request when a merge commit is present in a newer merge request' do + project = create(:project) + sha = Digest::SHA1.hexdigest('foo') + mr1 = create( + :merge_request, + :merged, + target_project: project, merge_commit_sha: sha + ) + + mr2 = create(:merge_request, :merged, target_project: project) + mr_diff = create(:merge_request_diff, merge_request: mr2) + + create(:merge_request_diff_commit, merge_request_diff: mr_diff, sha: sha) + + commits = [double(:commit, id: sha)] + + expect(described_class.new(project).execute(commits)).to eq(sha => mr1) + end end end diff --git a/spec/frontend/.eslintrc.yml b/spec/frontend/.eslintrc.yml index d0e585e844a..145e6c8961a 100644 --- a/spec/frontend/.eslintrc.yml +++ b/spec/frontend/.eslintrc.yml @@ -14,7 +14,6 @@ settings: globals: getJSONFixture: false loadFixtures: false - preloadFixtures: false setFixtures: false rules: jest/expect-expect: diff --git a/spec/frontend/__helpers__/fake_date/fixtures.js b/spec/frontend/__helpers__/fake_date/fixtures.js new file mode 100644 index 00000000000..fcf9d4a9c64 --- /dev/null +++ b/spec/frontend/__helpers__/fake_date/fixtures.js @@ -0,0 +1,4 @@ +import { useFakeDate } from './jest'; + +// Also see spec/support/helpers/javascript_fixtures_helpers.rb +export const useFixturesFakeDate = () => useFakeDate(2015, 6, 3, 10); diff --git a/spec/frontend/__helpers__/fake_date/index.js b/spec/frontend/__helpers__/fake_date/index.js index 3d1b124ce79..9d00349bd26 100644 --- a/spec/frontend/__helpers__/fake_date/index.js +++ b/spec/frontend/__helpers__/fake_date/index.js @@ -1,2 +1,3 @@ export * from './fake_date'; export * from './jest'; +export * from './fixtures'; diff --git a/spec/frontend/alert_management/components/alert_management_table_spec.js b/spec/frontend/alert_management/components/alert_management_table_spec.js index cea665aa50d..233585735b6 100644 --- a/spec/frontend/alert_management/components/alert_management_table_spec.js +++ b/spec/frontend/alert_management/components/alert_management_table_spec.js @@ -2,6 +2,8 @@ import { GlTable, GlAlert, GlLoadingIcon, GlDropdown, GlIcon, GlAvatar } from '@ import { mount } from '@vue/test-utils'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import mockAlerts from 'jest/vue_shared/alert_details/mocks/alerts.json'; import AlertManagementTable from '~/alert_management/components/alert_management_table.vue'; import { visitUrl } from '~/lib/utils/url_utility'; @@ -18,19 +20,18 @@ describe('AlertManagementTable', () => { let wrapper; let mock; - const findAlertsTable = () => wrapper.find(GlTable); + const findAlertsTable = () => wrapper.findComponent(GlTable); const findAlerts = () => wrapper.findAll('table tbody tr'); - const findAlert = () => wrapper.find(GlAlert); - const findLoader = () => wrapper.find(GlLoadingIcon); - const findStatusDropdown = () => wrapper.find(GlDropdown); - const findDateFields = () => wrapper.findAll(TimeAgo); - const findSearch = () => wrapper.find(FilteredSearchBar); - const findSeverityColumnHeader = () => - wrapper.find('[data-testid="alert-management-severity-sort"]'); - const findFirstIDField = () => wrapper.findAll('[data-testid="idField"]').at(0); - const findAssignees = () => wrapper.findAll('[data-testid="assigneesField"]'); - const findSeverityFields = () => wrapper.findAll('[data-testid="severityField"]'); - const findIssueFields = () => wrapper.findAll('[data-testid="issueField"]'); + const findAlert = () => wrapper.findComponent(GlAlert); + const findLoader = () => wrapper.findComponent(GlLoadingIcon); + const findStatusDropdown = () => wrapper.findComponent(GlDropdown); + const findDateFields = () => wrapper.findAllComponents(TimeAgo); + const findSearch = () => wrapper.findComponent(FilteredSearchBar); + const findSeverityColumnHeader = () => wrapper.findByTestId('alert-management-severity-sort'); + const findFirstIDField = () => wrapper.findAllByTestId('idField').at(0); + const findAssignees = () => wrapper.findAllByTestId('assigneesField'); + const findSeverityFields = () => wrapper.findAllByTestId('severityField'); + const findIssueFields = () => wrapper.findAllByTestId('issueField'); const alertsCount = { open: 24, triggered: 20, @@ -40,29 +41,34 @@ describe('AlertManagementTable', () => { }; function mountComponent({ provide = {}, data = {}, loading = false, stubs = {} } = {}) { - wrapper = mount(AlertManagementTable, { - provide: { - ...defaultProvideValues, - alertManagementEnabled: true, - userCanEnableAlertManagement: true, - ...provide, - }, - data() { - return data; - }, - mocks: { - $apollo: { - mutate: jest.fn(), - query: jest.fn(), - queries: { - alerts: { - loading, + wrapper = extendedWrapper( + mount(AlertManagementTable, { + provide: { + ...defaultProvideValues, + alertManagementEnabled: true, + userCanEnableAlertManagement: true, + ...provide, + }, + data() { + return data; + }, + mocks: { + $apollo: { + mutate: jest.fn(), + query: jest.fn(), + queries: { + alerts: { + loading, + }, }, }, }, - }, - stubs, - }); + stubs, + directives: { + GlTooltip: createMockDirective(), + }, + }), + ); } beforeEach(() => { @@ -72,7 +78,6 @@ describe('AlertManagementTable', () => { afterEach(() => { if (wrapper) { wrapper.destroy(); - wrapper = null; } mock.restore(); }); @@ -241,9 +246,14 @@ describe('AlertManagementTable', () => { expect(findIssueFields().at(0).text()).toBe('None'); }); - it('renders a link when one exists', () => { - expect(findIssueFields().at(1).text()).toBe('#1'); - expect(findIssueFields().at(1).attributes('href')).toBe('/gitlab-org/gitlab/-/issues/1'); + it('renders a link when one exists with the issue state and title tooltip', () => { + const issueField = findIssueFields().at(1); + const tooltip = getBinding(issueField.element, 'gl-tooltip'); + + expect(issueField.text()).toBe(`#1 (closed)`); + expect(issueField.attributes('href')).toBe('/gitlab-org/gitlab/-/issues/1'); + expect(issueField.attributes('title')).toBe('My test issue'); + expect(tooltip).not.toBe(undefined); }); }); diff --git a/spec/frontend/authentication/u2f/authenticate_spec.js b/spec/frontend/authentication/u2f/authenticate_spec.js index bf50ee88035..153d4be56af 100644 --- a/spec/frontend/authentication/u2f/authenticate_spec.js +++ b/spec/frontend/authentication/u2f/authenticate_spec.js @@ -8,8 +8,6 @@ describe('U2FAuthenticate', () => { let container; let component; - preloadFixtures('u2f/authenticate.html'); - beforeEach(() => { loadFixtures('u2f/authenticate.html'); u2fDevice = new MockU2FDevice(); diff --git a/spec/frontend/authentication/u2f/register_spec.js b/spec/frontend/authentication/u2f/register_spec.js index 9cbadbc2fef..a814144ac7a 100644 --- a/spec/frontend/authentication/u2f/register_spec.js +++ b/spec/frontend/authentication/u2f/register_spec.js @@ -8,8 +8,6 @@ describe('U2FRegister', () => { let container; let component; - preloadFixtures('u2f/register.html'); - beforeEach((done) => { loadFixtures('u2f/register.html'); u2fDevice = new MockU2FDevice(); diff --git a/spec/frontend/authentication/webauthn/authenticate_spec.js b/spec/frontend/authentication/webauthn/authenticate_spec.js index 0a82adfd0ee..8b27560bbbe 100644 --- a/spec/frontend/authentication/webauthn/authenticate_spec.js +++ b/spec/frontend/authentication/webauthn/authenticate_spec.js @@ -13,7 +13,6 @@ const mockResponse = { }; describe('WebAuthnAuthenticate', () => { - preloadFixtures('webauthn/authenticate.html'); useMockNavigatorCredentials(); let fallbackElement; diff --git a/spec/frontend/authentication/webauthn/register_spec.js b/spec/frontend/authentication/webauthn/register_spec.js index 1de952d176d..43cd3d7ca34 100644 --- a/spec/frontend/authentication/webauthn/register_spec.js +++ b/spec/frontend/authentication/webauthn/register_spec.js @@ -5,7 +5,6 @@ import MockWebAuthnDevice from './mock_webauthn_device'; import { useMockNavigatorCredentials } from './util'; describe('WebAuthnRegister', () => { - preloadFixtures('webauthn/register.html'); useMockNavigatorCredentials(); const mockResponse = { diff --git a/spec/frontend/awards_handler_spec.js b/spec/frontend/awards_handler_spec.js index edd17cfd810..988f5c98e2b 100644 --- a/spec/frontend/awards_handler_spec.js +++ b/spec/frontend/awards_handler_spec.js @@ -60,7 +60,6 @@ describe('AwardsHandler', () => { u: '6.0', }, }; - preloadFixtures('snippets/show.html'); const openAndWaitForEmojiMenu = (sel = '.js-add-award') => { $(sel).eq(0).click(); diff --git a/spec/frontend/behaviors/quick_submit_spec.js b/spec/frontend/behaviors/quick_submit_spec.js index d3d65892aff..86a85831c6b 100644 --- a/spec/frontend/behaviors/quick_submit_spec.js +++ b/spec/frontend/behaviors/quick_submit_spec.js @@ -6,8 +6,6 @@ describe('Quick Submit behavior', () => { const keydownEvent = (options = { keyCode: 13, metaKey: true }) => $.Event('keydown', options); - preloadFixtures('snippets/show.html'); - beforeEach(() => { loadFixtures('snippets/show.html'); diff --git a/spec/frontend/behaviors/requires_input_spec.js b/spec/frontend/behaviors/requires_input_spec.js index 0f27f89d6dc..bb22133ae44 100644 --- a/spec/frontend/behaviors/requires_input_spec.js +++ b/spec/frontend/behaviors/requires_input_spec.js @@ -3,7 +3,6 @@ import '~/behaviors/requires_input'; describe('requiresInput', () => { let submitButton; - preloadFixtures('branches/new_branch.html'); beforeEach(() => { loadFixtures('branches/new_branch.html'); diff --git a/spec/frontend/behaviors/shortcuts/shortcuts_issuable_spec.js b/spec/frontend/behaviors/shortcuts/shortcuts_issuable_spec.js index 94ba1615c89..26d38b115b6 100644 --- a/spec/frontend/behaviors/shortcuts/shortcuts_issuable_spec.js +++ b/spec/frontend/behaviors/shortcuts/shortcuts_issuable_spec.js @@ -13,8 +13,6 @@ describe('ShortcutsIssuable', () => { const snippetShowFixtureName = 'snippets/show.html'; const mrShowFixtureName = 'merge_requests/merge_request_of_current_user.html'; - preloadFixtures(snippetShowFixtureName, mrShowFixtureName); - beforeAll((done) => { initCopyAsGFM(); diff --git a/spec/frontend/blob/blob_file_dropzone_spec.js b/spec/frontend/blob/blob_file_dropzone_spec.js index 95520577e9a..e387ab7c18a 100644 --- a/spec/frontend/blob/blob_file_dropzone_spec.js +++ b/spec/frontend/blob/blob_file_dropzone_spec.js @@ -7,7 +7,6 @@ jest.mock('~/projects/upload_file_experiment', () => ({ })); describe('BlobFileDropzone', () => { - preloadFixtures('blob/show.html'); let dropzone; let replaceFileButton; diff --git a/spec/frontend/blob/sketch/index_spec.js b/spec/frontend/blob/sketch/index_spec.js index a24e7de9037..7424897b22c 100644 --- a/spec/frontend/blob/sketch/index_spec.js +++ b/spec/frontend/blob/sketch/index_spec.js @@ -4,8 +4,6 @@ import SketchLoader from '~/blob/sketch'; jest.mock('jszip'); describe('Sketch viewer', () => { - preloadFixtures('static/sketch_viewer.html'); - beforeEach(() => { loadFixtures('static/sketch_viewer.html'); }); diff --git a/spec/frontend/blob/viewer/index_spec.js b/spec/frontend/blob/viewer/index_spec.js index d793b5eb190..e4f145ae81b 100644 --- a/spec/frontend/blob/viewer/index_spec.js +++ b/spec/frontend/blob/viewer/index_spec.js @@ -16,8 +16,6 @@ describe('Blob viewer', () => { setTestTimeout(2000); - preloadFixtures('blob/show_readme.html'); - beforeEach(() => { $.fn.extend(jQueryMock); mock = new MockAdapter(axios); diff --git a/spec/frontend/bootstrap_linked_tabs_spec.js b/spec/frontend/bootstrap_linked_tabs_spec.js index 2d8939e6480..30fb140bc69 100644 --- a/spec/frontend/bootstrap_linked_tabs_spec.js +++ b/spec/frontend/bootstrap_linked_tabs_spec.js @@ -1,8 +1,6 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs'; describe('Linked Tabs', () => { - preloadFixtures('static/linked_tabs.html'); - beforeEach(() => { loadFixtures('static/linked_tabs.html'); }); diff --git a/spec/frontend/ci_variable_list/ci_variable_list/ci_variable_list_spec.js b/spec/frontend/ci_variable_list/ci_variable_list/ci_variable_list_spec.js index ad1bdec1735..1bca21b1d57 100644 --- a/spec/frontend/ci_variable_list/ci_variable_list/ci_variable_list_spec.js +++ b/spec/frontend/ci_variable_list/ci_variable_list/ci_variable_list_spec.js @@ -4,9 +4,6 @@ import VariableList from '~/ci_variable_list/ci_variable_list'; const HIDE_CLASS = 'hide'; describe('VariableList', () => { - preloadFixtures('pipeline_schedules/edit.html'); - preloadFixtures('pipeline_schedules/edit_with_variables.html'); - let $wrapper; let variableList; diff --git a/spec/frontend/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js b/spec/frontend/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js index 4982b68fa81..eee1362440d 100644 --- a/spec/frontend/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js +++ b/spec/frontend/ci_variable_list/ci_variable_list/native_form_variable_list_spec.js @@ -2,8 +2,6 @@ import $ from 'jquery'; import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list'; describe('NativeFormVariableList', () => { - preloadFixtures('pipeline_schedules/edit.html'); - let $wrapper; beforeEach(() => { diff --git a/spec/frontend/collapsed_sidebar_todo_spec.js b/spec/frontend/collapsed_sidebar_todo_spec.js index ef53cc9e103..7c659822672 100644 --- a/spec/frontend/collapsed_sidebar_todo_spec.js +++ b/spec/frontend/collapsed_sidebar_todo_spec.js @@ -14,9 +14,6 @@ describe('Issuable right sidebar collapsed todo toggle', () => { const jsonFixtureName = 'todos/todos.json'; let mock; - preloadFixtures(fixtureName); - preloadFixtures(jsonFixtureName); - beforeEach(() => { const todoData = getJSONFixture(jsonFixtureName); new Sidebar(); diff --git a/spec/frontend/commit/pipelines/pipelines_spec.js b/spec/frontend/commit/pipelines/pipelines_spec.js index 3d6debda520..c8c8f6408b7 100644 --- a/spec/frontend/commit/pipelines/pipelines_spec.js +++ b/spec/frontend/commit/pipelines/pipelines_spec.js @@ -17,8 +17,6 @@ describe('Pipelines table in Commits and Merge requests', () => { errorStateSvgPath: 'foo', }; - preloadFixtures(jsonFixtureName); - const findRunPipelineBtn = () => vm.$el.querySelector('[data-testid="run_pipeline_button"]'); const findRunPipelineBtnMobile = () => vm.$el.querySelector('[data-testid="run_pipeline_button_mobile"]'); diff --git a/spec/frontend/create_item_dropdown_spec.js b/spec/frontend/create_item_dropdown_spec.js index 7314eb5eee8..56c09cd731e 100644 --- a/spec/frontend/create_item_dropdown_spec.js +++ b/spec/frontend/create_item_dropdown_spec.js @@ -20,8 +20,6 @@ const DROPDOWN_ITEM_DATA = [ ]; describe('CreateItemDropdown', () => { - preloadFixtures('static/create_item_dropdown.html'); - let $wrapperEl; let createItemDropdown; diff --git a/spec/frontend/deprecated_jquery_dropdown_spec.js b/spec/frontend/deprecated_jquery_dropdown_spec.js index 6070532a1bf..7858f88f8c3 100644 --- a/spec/frontend/deprecated_jquery_dropdown_spec.js +++ b/spec/frontend/deprecated_jquery_dropdown_spec.js @@ -10,8 +10,6 @@ jest.mock('~/lib/utils/url_utility', () => ({ })); describe('deprecatedJQueryDropdown', () => { - preloadFixtures('static/deprecated_jquery_dropdown.html'); - const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-item'; const SEARCH_INPUT_SELECTOR = '.dropdown-input-field'; diff --git a/spec/frontend/diffs/mock_data/diff_with_commit.js b/spec/frontend/diffs/mock_data/diff_with_commit.js index d646294ee84..f3b39bd3577 100644 --- a/spec/frontend/diffs/mock_data/diff_with_commit.js +++ b/spec/frontend/diffs/mock_data/diff_with_commit.js @@ -1,7 +1,5 @@ const FIXTURE = 'merge_request_diffs/with_commit.json'; -preloadFixtures(FIXTURE); - export default function getDiffWithCommit() { return getJSONFixture(FIXTURE); } diff --git a/spec/frontend/filtered_search/dropdown_user_spec.js b/spec/frontend/filtered_search/dropdown_user_spec.js index 0e2d2ee6c09..961587f7146 100644 --- a/spec/frontend/filtered_search/dropdown_user_spec.js +++ b/spec/frontend/filtered_search/dropdown_user_spec.js @@ -78,7 +78,6 @@ describe('Dropdown User', () => { describe('hideCurrentUser', () => { const fixtureTemplate = 'issues/issue_list.html'; - preloadFixtures(fixtureTemplate); let dropdown; let authorFilterDropdownElement; diff --git a/spec/frontend/filtered_search/dropdown_utils_spec.js b/spec/frontend/filtered_search/dropdown_utils_spec.js index 32d1f909d0b..49e14f58630 100644 --- a/spec/frontend/filtered_search/dropdown_utils_spec.js +++ b/spec/frontend/filtered_search/dropdown_utils_spec.js @@ -5,7 +5,6 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered describe('Dropdown Utils', () => { const issueListFixture = 'issues/issue_list.html'; - preloadFixtures(issueListFixture); describe('getEscapedText', () => { it('should return same word when it has no space', () => { diff --git a/spec/frontend/filtered_search/visual_token_value_spec.js b/spec/frontend/filtered_search/visual_token_value_spec.js index a2082271efe..772fa7d07ed 100644 --- a/spec/frontend/filtered_search/visual_token_value_spec.js +++ b/spec/frontend/filtered_search/visual_token_value_spec.js @@ -133,8 +133,6 @@ describe('Filtered Search Visual Tokens', () => { const jsonFixtureName = 'labels/project_labels.json'; const dummyEndpoint = '/dummy/endpoint'; - preloadFixtures(jsonFixtureName); - let labelData; beforeAll(() => { diff --git a/spec/frontend/gl_field_errors_spec.js b/spec/frontend/gl_field_errors_spec.js index a1737211252..ada3b34e6b1 100644 --- a/spec/frontend/gl_field_errors_spec.js +++ b/spec/frontend/gl_field_errors_spec.js @@ -8,8 +8,6 @@ describe('GL Style Field Errors', () => { testContext = {}; }); - preloadFixtures('static/gl_field_errors.html'); - beforeEach(() => { loadFixtures('static/gl_field_errors.html'); const $form = $('form.gl-show-field-errors'); diff --git a/spec/frontend/header_spec.js b/spec/frontend/header_spec.js index 27305abfafa..4ca6d7259bd 100644 --- a/spec/frontend/header_spec.js +++ b/spec/frontend/header_spec.js @@ -15,7 +15,6 @@ describe('Header', () => { $(document).trigger('todo:toggle', newCount); } - preloadFixtures(fixtureTemplate); beforeEach(() => { initTodoToggle(); loadFixtures(fixtureTemplate); diff --git a/spec/frontend/integrations/integration_settings_form_spec.js b/spec/frontend/integrations/integration_settings_form_spec.js index 348b942703f..cbb2ef380ba 100644 --- a/spec/frontend/integrations/integration_settings_form_spec.js +++ b/spec/frontend/integrations/integration_settings_form_spec.js @@ -7,7 +7,6 @@ jest.mock('~/vue_shared/plugins/global_toast'); describe('IntegrationSettingsForm', () => { const FIXTURE = 'services/edit_service.html'; - preloadFixtures(FIXTURE); beforeEach(() => { loadFixtures(FIXTURE); diff --git a/spec/frontend/issue_spec.js b/spec/frontend/issue_spec.js index 970fdacd492..952ef54d286 100644 --- a/spec/frontend/issue_spec.js +++ b/spec/frontend/issue_spec.js @@ -8,11 +8,6 @@ describe('Issue', () => { let testContext; let mock; - beforeAll(() => { - preloadFixtures('issues/closed-issue.html'); - preloadFixtures('issues/open-issue.html'); - }); - beforeEach(() => { mock = new MockAdapter(axios); mock.onGet(/(.*)\/related_branches$/).reply(200, {}); diff --git a/spec/frontend/line_highlighter_spec.js b/spec/frontend/line_highlighter_spec.js index 8318f63ab3e..b5a0adc9d49 100644 --- a/spec/frontend/line_highlighter_spec.js +++ b/spec/frontend/line_highlighter_spec.js @@ -7,7 +7,6 @@ import LineHighlighter from '~/line_highlighter'; describe('LineHighlighter', () => { const testContext = {}; - preloadFixtures('static/line_highlighter.html'); const clickLine = (number, eventData = {}) => { if ($.isEmptyObject(eventData)) { return $(`#L${number}`).click(); diff --git a/spec/frontend/merge_request_spec.js b/spec/frontend/merge_request_spec.js index 84647a108b2..0b7ed349507 100644 --- a/spec/frontend/merge_request_spec.js +++ b/spec/frontend/merge_request_spec.js @@ -9,7 +9,6 @@ describe('MergeRequest', () => { describe('task lists', () => { let mock; - preloadFixtures('merge_requests/merge_request_with_task_list.html'); beforeEach(() => { loadFixtures('merge_requests/merge_request_with_task_list.html'); diff --git a/spec/frontend/merge_request_tabs_spec.js b/spec/frontend/merge_request_tabs_spec.js index fd2c240aff3..23e9bf8b447 100644 --- a/spec/frontend/merge_request_tabs_spec.js +++ b/spec/frontend/merge_request_tabs_spec.js @@ -21,11 +21,6 @@ describe('MergeRequestTabs', () => { $.extend(stubLocation, defaults, stubs || {}); }; - preloadFixtures( - 'merge_requests/merge_request_with_task_list.html', - 'merge_requests/diff_comment.html', - ); - beforeEach(() => { initMrPage(); diff --git a/spec/frontend/mini_pipeline_graph_dropdown_spec.js b/spec/frontend/mini_pipeline_graph_dropdown_spec.js index 3ff34c967e4..ccd5a4ea142 100644 --- a/spec/frontend/mini_pipeline_graph_dropdown_spec.js +++ b/spec/frontend/mini_pipeline_graph_dropdown_spec.js @@ -5,8 +5,6 @@ import axios from '~/lib/utils/axios_utils'; import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown'; describe('Mini Pipeline Graph Dropdown', () => { - preloadFixtures('static/mini_dropdown_graph.html'); - beforeEach(() => { loadFixtures('static/mini_dropdown_graph.html'); }); diff --git a/spec/frontend/new_branch_spec.js b/spec/frontend/new_branch_spec.js index 7e6b8a78d4f..66b28a8c0dc 100644 --- a/spec/frontend/new_branch_spec.js +++ b/spec/frontend/new_branch_spec.js @@ -9,8 +9,6 @@ describe('Branch', () => { }); describe('create a new branch', () => { - preloadFixtures('branches/new_branch.html'); - function fillNameWith(value) { $('.js-branch-name').val(value).trigger('blur'); } diff --git a/spec/frontend/notes/components/diff_discussion_header_spec.js b/spec/frontend/notes/components/diff_discussion_header_spec.js index fdc89522901..fa34a5e8d39 100644 --- a/spec/frontend/notes/components/diff_discussion_header_spec.js +++ b/spec/frontend/notes/components/diff_discussion_header_spec.js @@ -6,14 +6,10 @@ import createStore from '~/notes/stores'; import mockDiffFile from '../../diffs/mock_data/diff_discussions'; import { discussionMock } from '../mock_data'; -const discussionWithTwoUnresolvedNotes = 'merge_requests/resolved_diff_discussion.json'; - describe('diff_discussion_header component', () => { let store; let wrapper; - preloadFixtures(discussionWithTwoUnresolvedNotes); - beforeEach(() => { window.mrTabs = {}; store = createStore(); diff --git a/spec/frontend/notes/components/noteable_discussion_spec.js b/spec/frontend/notes/components/noteable_discussion_spec.js index 34df39bf1c7..dd65351ef88 100644 --- a/spec/frontend/notes/components/noteable_discussion_spec.js +++ b/spec/frontend/notes/components/noteable_discussion_spec.js @@ -24,8 +24,6 @@ describe('noteable_discussion component', () => { let wrapper; let originalGon; - preloadFixtures(discussionWithTwoUnresolvedNotes); - beforeEach(() => { window.mrTabs = {}; store = createStore(); diff --git a/spec/frontend/notes/stores/getters_spec.js b/spec/frontend/notes/stores/getters_spec.js index 4ebfc679310..4d2f86a1ecf 100644 --- a/spec/frontend/notes/stores/getters_spec.js +++ b/spec/frontend/notes/stores/getters_spec.js @@ -26,8 +26,6 @@ const createDiscussionNeighborParams = (discussionId, diffOrder, step) => ({ describe('Getters Notes Store', () => { let state; - preloadFixtures(discussionWithTwoUnresolvedNotes); - beforeEach(() => { state = { discussions: [individualNote], diff --git a/spec/frontend/oauth_remember_me_spec.js b/spec/frontend/oauth_remember_me_spec.js index 910676a97ed..70bda1d9f9e 100644 --- a/spec/frontend/oauth_remember_me_spec.js +++ b/spec/frontend/oauth_remember_me_spec.js @@ -6,8 +6,6 @@ describe('OAuthRememberMe', () => { return $(`#oauth-container .oauth-login${selector}`).parent('form').attr('action'); }; - preloadFixtures('static/oauth_remember_me.html'); - beforeEach(() => { loadFixtures('static/oauth_remember_me.html'); diff --git a/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js index 2c76adf761f..71c9da238b4 100644 --- a/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js +++ b/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js @@ -14,8 +14,6 @@ describe('Abuse Reports', () => { const findMessage = (searchText) => $messages.filter((index, element) => element.innerText.indexOf(searchText) > -1).first(); - preloadFixtures(FIXTURE); - beforeEach(() => { loadFixtures(FIXTURE); new AbuseReports(); // eslint-disable-line no-new diff --git a/spec/frontend/pages/admin/application_settings/account_and_limits_spec.js b/spec/frontend/pages/admin/application_settings/account_and_limits_spec.js index 8816609d1d2..9f326dc33c0 100644 --- a/spec/frontend/pages/admin/application_settings/account_and_limits_spec.js +++ b/spec/frontend/pages/admin/application_settings/account_and_limits_spec.js @@ -8,7 +8,6 @@ describe('AccountAndLimits', () => { const FIXTURE = 'application_settings/accounts_and_limit.html'; let $userDefaultExternal; let $userInternalRegex; - preloadFixtures(FIXTURE); beforeEach(() => { loadFixtures(FIXTURE); diff --git a/spec/frontend/pages/admin/users/new/index_spec.js b/spec/frontend/pages/admin/users/new/index_spec.js index 60482860e84..ec9fe487030 100644 --- a/spec/frontend/pages/admin/users/new/index_spec.js +++ b/spec/frontend/pages/admin/users/new/index_spec.js @@ -7,8 +7,6 @@ describe('UserInternalRegexHandler', () => { let $userEmail; let $warningMessage; - preloadFixtures(FIXTURE); - beforeEach(() => { loadFixtures(FIXTURE); // eslint-disable-next-line no-new diff --git a/spec/frontend/pages/dashboard/todos/index/todos_spec.js b/spec/frontend/pages/dashboard/todos/index/todos_spec.js index fb612f17669..de8b29d54fc 100644 --- a/spec/frontend/pages/dashboard/todos/index/todos_spec.js +++ b/spec/frontend/pages/dashboard/todos/index/todos_spec.js @@ -14,7 +14,6 @@ const TEST_COUNT_BIG = 2000; const TEST_DONE_COUNT_BIG = 7300; describe('Todos', () => { - preloadFixtures('todos/todos.html'); let todoItem; let mock; diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js index de63409b181..2a3b07f95f2 100644 --- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js +++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js @@ -6,8 +6,6 @@ import TimezoneDropdown, { } from '~/pages/projects/pipeline_schedules/shared/components/timezone_dropdown'; describe('Timezone Dropdown', () => { - preloadFixtures('pipeline_schedules/edit.html'); - let $inputEl = null; let $dropdownEl = null; let $wrapper = null; diff --git a/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js b/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js index 8632c852720..e39a3904613 100644 --- a/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js +++ b/spec/frontend/pages/sessions/new/preserve_url_fragment_spec.js @@ -6,8 +6,6 @@ describe('preserve_url_fragment', () => { return $(`.omniauth-container ${selector}`).parent('form').attr('action'); }; - preloadFixtures('sessions/new.html'); - beforeEach(() => { loadFixtures('sessions/new.html'); }); diff --git a/spec/frontend/pages/sessions/new/signin_tabs_memoizer_spec.js b/spec/frontend/pages/sessions/new/signin_tabs_memoizer_spec.js index f04c16d2ddb..6aa725fbd7d 100644 --- a/spec/frontend/pages/sessions/new/signin_tabs_memoizer_spec.js +++ b/spec/frontend/pages/sessions/new/signin_tabs_memoizer_spec.js @@ -18,8 +18,6 @@ describe('SigninTabsMemoizer', () => { return memo; } - preloadFixtures(fixtureTemplate); - beforeEach(() => { loadFixtures(fixtureTemplate); diff --git a/spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js b/spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js index 5eeccd78265..ef8ca574e59 100644 --- a/spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js +++ b/spec/frontend/pipeline_editor/components/header/pipeline_editor_header_spec.js @@ -3,7 +3,7 @@ import PipelineEditorHeader from '~/pipeline_editor/components/header/pipeline_e import PipelineStatus from '~/pipeline_editor/components/header/pipeline_status.vue'; import ValidationSegment from '~/pipeline_editor/components/header/validation_segment.vue'; -import { mockLintResponse } from '../../mock_data'; +import { mockCiYml, mockLintResponse } from '../../mock_data'; describe('Pipeline editor header', () => { let wrapper; @@ -19,8 +19,9 @@ describe('Pipeline editor header', () => { ...mockProvide, ...provide, }, - props: { + propsData: { ciConfigData: mockLintResponse, + ciFileContent: mockCiYml, isCiConfigDataLoading: false, }, }); diff --git a/spec/frontend/pipeline_editor/components/header/validation_segment_spec.js b/spec/frontend/pipeline_editor/components/header/validation_segment_spec.js index cf1d89e1d7c..274c2d1b8da 100644 --- a/spec/frontend/pipeline_editor/components/header/validation_segment_spec.js +++ b/spec/frontend/pipeline_editor/components/header/validation_segment_spec.js @@ -7,9 +7,9 @@ import ValidationSegment, { i18n, } from '~/pipeline_editor/components/header/validation_segment.vue'; import { CI_CONFIG_STATUS_INVALID } from '~/pipeline_editor/constants'; -import { mockYmlHelpPagePath, mergeUnwrappedCiConfig } from '../../mock_data'; +import { mockYmlHelpPagePath, mergeUnwrappedCiConfig, mockCiYml } from '../../mock_data'; -describe('~/pipeline_editor/components/info/validation_segment.vue', () => { +describe('Validation segment component', () => { let wrapper; const createComponent = (props = {}) => { @@ -20,6 +20,7 @@ describe('~/pipeline_editor/components/info/validation_segment.vue', () => { }, propsData: { ciConfig: mergeUnwrappedCiConfig(), + ciFileContent: mockCiYml, loading: false, ...props, }, @@ -42,6 +43,20 @@ describe('~/pipeline_editor/components/info/validation_segment.vue', () => { expect(wrapper.text()).toBe(i18n.loading); }); + describe('when config is empty', () => { + beforeEach(() => { + createComponent({ ciFileContent: '' }); + }); + + it('has check icon', () => { + expect(findIcon().props('name')).toBe('check'); + }); + + it('shows a message for empty state', () => { + expect(findValidationMsg().text()).toBe(i18n.empty); + }); + }); + describe('when config is valid', () => { beforeEach(() => { createComponent({}); @@ -61,7 +76,7 @@ describe('~/pipeline_editor/components/info/validation_segment.vue', () => { }); }); - describe('when config is not valid', () => { + describe('when config is invalid', () => { beforeEach(() => { createComponent({ ciConfig: mergeUnwrappedCiConfig({ diff --git a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js index 2210fc87f68..b444d9dcfea 100644 --- a/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js +++ b/spec/frontend/pipeline_editor/components/ui/pipeline_editor_empty_state_spec.js @@ -1,42 +1,79 @@ -import { GlSprintf } from '@gitlab/ui'; +import { GlButton, GlSprintf } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue'; describe('Pipeline editor empty state', () => { let wrapper; const defaultProvide = { + glFeatures: { + pipelineEditorEmptyStateAction: false, + }, emptyStateIllustrationPath: 'my/svg/path', }; - const createComponent = () => { + const createComponent = ({ provide } = {}) => { wrapper = shallowMount(PipelineEditorEmptyState, { - provide: defaultProvide, + provide: { ...defaultProvide, ...provide }, }); }; const findSvgImage = () => wrapper.find('img'); const findTitle = () => wrapper.find('h1'); + const findConfirmButton = () => wrapper.findComponent(GlButton); const findDescription = () => wrapper.findComponent(GlSprintf); - beforeEach(() => { - createComponent(); - }); - afterEach(() => { wrapper.destroy(); }); - it('renders an svg image', () => { - expect(findSvgImage().exists()).toBe(true); - }); + describe('template', () => { + beforeEach(() => { + createComponent(); + }); - it('renders a title', () => { - expect(findTitle().exists()).toBe(true); - expect(findTitle().text()).toBe(wrapper.vm.$options.i18n.title); + it('renders an svg image', () => { + expect(findSvgImage().exists()).toBe(true); + }); + + it('renders a title', () => { + expect(findTitle().exists()).toBe(true); + expect(findTitle().text()).toBe(wrapper.vm.$options.i18n.title); + }); + + it('renders a description', () => { + expect(findDescription().exists()).toBe(true); + expect(findDescription().html()).toContain(wrapper.vm.$options.i18n.body); + }); + + describe('with feature flag off', () => { + it('does not renders a CTA button', () => { + expect(findConfirmButton().exists()).toBe(false); + }); + }); }); - it('renders a description', () => { - expect(findDescription().exists()).toBe(true); - expect(findDescription().html()).toContain(wrapper.vm.$options.i18n.body); + describe('with feature flag on', () => { + beforeEach(() => { + createComponent({ + provide: { + glFeatures: { + pipelineEditorEmptyStateAction: true, + }, + }, + }); + }); + + it('renders a CTA button', () => { + expect(findConfirmButton().exists()).toBe(true); + expect(findConfirmButton().text()).toBe(wrapper.vm.$options.i18n.btnText); + }); + + it('emits an event when clicking on the CTA', async () => { + const expectedEvent = 'createEmptyConfigFile'; + expect(wrapper.emitted(expectedEvent)).toBeUndefined(); + + await findConfirmButton().vm.$emit('click'); + expect(wrapper.emitted(expectedEvent)).toHaveLength(1); + }); }); }); diff --git a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js index 0dfd123db75..887d296222f 100644 --- a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js +++ b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js @@ -7,6 +7,7 @@ import httpStatusCodes from '~/lib/utils/http_status'; import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue'; import TextEditor from '~/pipeline_editor/components/editor/text_editor.vue'; +import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue'; import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue'; import { COMMIT_SUCCESS, COMMIT_FAILURE, LOAD_FAILURE_UNKNOWN } from '~/pipeline_editor/constants'; import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.graphql'; @@ -30,6 +31,9 @@ const MockEditorLite = { const mockProvide = { ciConfigPath: mockCiConfigPath, defaultBranch: mockDefaultBranch, + glFeatures: { + pipelineEditorEmptyStateAction: false, + }, projectFullPath: mockProjectFullPath, }; @@ -40,14 +44,17 @@ describe('Pipeline editor app component', () => { let mockBlobContentData; let mockCiConfigData; - const createComponent = ({ blobLoading = false, options = {} } = {}) => { + const createComponent = ({ blobLoading = false, options = {}, provide = {} } = {}) => { wrapper = shallowMount(PipelineEditorApp, { - provide: mockProvide, + provide: { ...mockProvide, ...provide }, stubs: { GlTabs, GlButton, CommitForm, + PipelineEditorHome, + PipelineEditorTabs, EditorLite: MockEditorLite, + PipelineEditorEmptyState, }, mocks: { $apollo: { @@ -65,7 +72,7 @@ describe('Pipeline editor app component', () => { }); }; - const createComponentWithApollo = ({ props = {} } = {}) => { + const createComponentWithApollo = ({ props = {}, provide = {} } = {}) => { const handlers = [[getCiConfigData, mockCiConfigData]]; const resolvers = { Query: { @@ -86,7 +93,7 @@ describe('Pipeline editor app component', () => { apolloProvider: mockApollo, }; - createComponent({ props, options }); + createComponent({ props, provide, options }); }; const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); @@ -94,6 +101,8 @@ describe('Pipeline editor app component', () => { const findEditorHome = () => wrapper.findComponent(PipelineEditorHome); const findTextEditor = () => wrapper.findComponent(TextEditor); const findEmptyState = () => wrapper.findComponent(PipelineEditorEmptyState); + const findEmptyStateButton = () => + wrapper.findComponent(PipelineEditorEmptyState).findComponent(GlButton); beforeEach(() => { mockBlobContentData = jest.fn(); @@ -105,7 +114,6 @@ describe('Pipeline editor app component', () => { mockCiConfigData.mockReset(); wrapper.destroy(); - wrapper = null; }); it('displays a loading icon if the blob query is loading', () => { @@ -196,6 +204,34 @@ describe('Pipeline editor app component', () => { }); }); + describe('when landing on the empty state with feature flag on', () => { + it('user can click on CTA button and see an empty editor', async () => { + mockBlobContentData.mockRejectedValueOnce({ + response: { + status: httpStatusCodes.NOT_FOUND, + }, + }); + + createComponentWithApollo({ + provide: { + glFeatures: { + pipelineEditorEmptyStateAction: true, + }, + }, + }); + + await waitForPromises(); + + expect(findEmptyState().exists()).toBe(true); + expect(findTextEditor().exists()).toBe(false); + + await findEmptyStateButton().vm.$emit('click'); + + expect(findEmptyState().exists()).toBe(false); + expect(findTextEditor().exists()).toBe(true); + }); + }); + describe('when the user commits', () => { const updateFailureMessage = 'The GitLab CI configuration could not be updated.'; diff --git a/spec/frontend/pipelines/pipelines_table_row_spec.js b/spec/frontend/pipelines/pipelines_table_row_spec.js index 56da636bb3d..26767cd3805 100644 --- a/spec/frontend/pipelines/pipelines_table_row_spec.js +++ b/spec/frontend/pipelines/pipelines_table_row_spec.js @@ -19,8 +19,6 @@ describe('Pipelines Table Row', () => { let pipelineWithoutAuthor; let pipelineWithoutCommit; - preloadFixtures(jsonFixtureName); - beforeEach(() => { const { pipelines } = getJSONFixture(jsonFixtureName); diff --git a/spec/frontend/pipelines/pipelines_table_spec.js b/spec/frontend/pipelines/pipelines_table_spec.js index 4f4d71e5dab..d72ea7b42a6 100644 --- a/spec/frontend/pipelines/pipelines_table_spec.js +++ b/spec/frontend/pipelines/pipelines_table_spec.js @@ -52,8 +52,6 @@ describe('Pipelines Table', () => { const findTimeAgoTh = () => wrapper.findByTestId('timeago-th'); const findActionsTh = () => wrapper.findByTestId('actions-th'); - preloadFixtures(jsonFixtureName); - beforeEach(() => { const { pipelines } = getJSONFixture(jsonFixtureName); pipeline = pipelines.find((p) => p.user !== null && p.commit !== null); diff --git a/spec/frontend/pipelines_spec.js b/spec/frontend/pipelines_spec.js index 6d4d634c575..add91fbcc23 100644 --- a/spec/frontend/pipelines_spec.js +++ b/spec/frontend/pipelines_spec.js @@ -1,8 +1,6 @@ import Pipelines from '~/pipelines'; describe('Pipelines', () => { - preloadFixtures('static/pipeline_graph.html'); - beforeEach(() => { loadFixtures('static/pipeline_graph.html'); }); diff --git a/spec/frontend/project_select_combo_button_spec.js b/spec/frontend/project_select_combo_button_spec.js index c47db71b4ac..5cdc3d174a1 100644 --- a/spec/frontend/project_select_combo_button_spec.js +++ b/spec/frontend/project_select_combo_button_spec.js @@ -10,8 +10,6 @@ describe('Project Select Combo Button', () => { testContext = {}; }); - preloadFixtures(fixturePath); - beforeEach(() => { testContext.defaults = { label: 'Select project to create issue', diff --git a/spec/frontend/prometheus_metrics/custom_metrics_spec.js b/spec/frontend/prometheus_metrics/custom_metrics_spec.js index 3e3d4ee361a..20593351ee5 100644 --- a/spec/frontend/prometheus_metrics/custom_metrics_spec.js +++ b/spec/frontend/prometheus_metrics/custom_metrics_spec.js @@ -9,7 +9,6 @@ describe('PrometheusMetrics', () => { const customMetricsEndpoint = 'http://test.host/frontend-fixtures/services-project/prometheus/metrics'; let mock; - preloadFixtures(FIXTURE); beforeEach(() => { mock = new MockAdapter(axios); diff --git a/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js b/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js index 722a5274ad4..a703dc0a66f 100644 --- a/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js +++ b/spec/frontend/prometheus_metrics/prometheus_metrics_spec.js @@ -6,7 +6,6 @@ import { metrics2 as metrics, missingVarMetrics } from './mock_data'; describe('PrometheusMetrics', () => { const FIXTURE = 'services/prometheus/prometheus_service.html'; - preloadFixtures(FIXTURE); beforeEach(() => { loadFixtures(FIXTURE); diff --git a/spec/frontend/read_more_spec.js b/spec/frontend/read_more_spec.js index d1d01272403..16f0d7fb075 100644 --- a/spec/frontend/read_more_spec.js +++ b/spec/frontend/read_more_spec.js @@ -3,8 +3,6 @@ import initReadMore from '~/read_more'; describe('Read more click-to-expand functionality', () => { const fixtureName = 'projects/overview.html'; - preloadFixtures(fixtureName); - beforeEach(() => { loadFixtures(fixtureName); }); diff --git a/spec/frontend/right_sidebar_spec.js b/spec/frontend/right_sidebar_spec.js index f3719b28baa..8699e1cf420 100644 --- a/spec/frontend/right_sidebar_spec.js +++ b/spec/frontend/right_sidebar_spec.js @@ -27,7 +27,6 @@ const assertSidebarState = (state) => { describe('RightSidebar', () => { describe('fixture tests', () => { const fixtureName = 'issues/open-issue.html'; - preloadFixtures(fixtureName); let mock; beforeEach(() => { diff --git a/spec/frontend/search/highlight_blob_search_result_spec.js b/spec/frontend/search/highlight_blob_search_result_spec.js index c1b0c7d794b..6908bcbd283 100644 --- a/spec/frontend/search/highlight_blob_search_result_spec.js +++ b/spec/frontend/search/highlight_blob_search_result_spec.js @@ -4,8 +4,6 @@ const fixture = 'search/blob_search_result.html'; const searchKeyword = 'Send'; // spec/frontend/fixtures/search.rb#79 describe('search/highlight_blob_search_result', () => { - preloadFixtures(fixture); - beforeEach(() => loadFixtures(fixture)); it('highlights lines with search term occurrence', () => { diff --git a/spec/frontend/search_autocomplete_spec.js b/spec/frontend/search_autocomplete_spec.js index a9fbe0fe552..5aca07d59e4 100644 --- a/spec/frontend/search_autocomplete_spec.js +++ b/spec/frontend/search_autocomplete_spec.js @@ -105,7 +105,6 @@ describe('Search autocomplete dropdown', () => { expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created"); }; - preloadFixtures('static/search_autocomplete.html'); beforeEach(() => { loadFixtures('static/search_autocomplete.html'); diff --git a/spec/frontend/settings_panels_spec.js b/spec/frontend/settings_panels_spec.js index 8666106d3c6..6b739617b97 100644 --- a/spec/frontend/settings_panels_spec.js +++ b/spec/frontend/settings_panels_spec.js @@ -2,8 +2,6 @@ import $ from 'jquery'; import initSettingsPanels, { isExpanded } from '~/settings_panels'; describe('Settings Panels', () => { - preloadFixtures('groups/edit.html'); - beforeEach(() => { loadFixtures('groups/edit.html'); }); diff --git a/spec/frontend/shortcuts_spec.js b/spec/frontend/shortcuts_spec.js index 1650dd2c1ca..fc5eeee9687 100644 --- a/spec/frontend/shortcuts_spec.js +++ b/spec/frontend/shortcuts_spec.js @@ -20,8 +20,6 @@ describe('Shortcuts', () => { target, }); - preloadFixtures(fixtureName); - beforeEach(() => { loadFixtures(fixtureName); diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js index b6b29faef79..9b95ed6b816 100644 --- a/spec/frontend/test_setup.js +++ b/spec/frontend/test_setup.js @@ -44,11 +44,6 @@ Object.assign(global, { getJSONFixture, loadFixtures: loadHTMLFixture, setFixtures: setHTMLFixture, - - // The following functions fill the fixtures cache in Karma. - // This is not necessary in Jest because we make no Ajax request. - loadJSONFixtures() {}, - preloadFixtures() {}, }); // custom-jquery-matchers was written for an old Jest version, we need to make it compatible diff --git a/spec/frontend/user_popovers_spec.js b/spec/frontend/user_popovers_spec.js index 5c6053f413f..745b66fd700 100644 --- a/spec/frontend/user_popovers_spec.js +++ b/spec/frontend/user_popovers_spec.js @@ -3,7 +3,6 @@ import initUserPopovers from '~/user_popovers'; describe('User Popovers', () => { const fixtureTemplate = 'merge_requests/merge_request_with_mentions.html'; - preloadFixtures(fixtureTemplate); const selector = '.js-user-link, .gfm-project_member'; const findFixtureLinks = () => { diff --git a/spec/frontend/vue_shared/alert_details/alert_details_spec.js b/spec/frontend/vue_shared/alert_details/alert_details_spec.js index ce410a8b3e7..20301e1bc88 100644 --- a/spec/frontend/vue_shared/alert_details/alert_details_spec.js +++ b/spec/frontend/vue_shared/alert_details/alert_details_spec.js @@ -89,7 +89,7 @@ describe('AlertDetails', () => { const findIncidentCreationAlert = () => wrapper.findByTestId('incidentCreationError'); const findEnvironmentName = () => wrapper.findByTestId('environmentName'); const findEnvironmentPath = () => wrapper.findByTestId('environmentPath'); - const findDetailsTable = () => wrapper.find(AlertDetailsTable); + const findDetailsTable = () => wrapper.findComponent(AlertDetailsTable); const findMetricsTab = () => wrapper.findByTestId('metrics'); describe('Alert details', () => { @@ -192,23 +192,21 @@ describe('AlertDetails', () => { describe('Create incident from alert', () => { it('should display "View incident" button that links the incident page when incident exists', () => { - const issueIid = '3'; + const iid = '3'; mountComponent({ - data: { alert: { ...mockAlert, issueIid }, sidebarStatus: false }, + data: { alert: { ...mockAlert, issue: { iid } }, sidebarStatus: false }, }); expect(findViewIncidentBtn().exists()).toBe(true); - expect(findViewIncidentBtn().attributes('href')).toBe( - joinPaths(projectIssuesPath, issueIid), - ); + expect(findViewIncidentBtn().attributes('href')).toBe(joinPaths(projectIssuesPath, iid)); expect(findCreateIncidentBtn().exists()).toBe(false); }); it('should display "Create incident" button when incident doesn\'t exist yet', () => { - const issueIid = null; + const issue = null; mountComponent({ mountMethod: mount, - data: { alert: { ...mockAlert, issueIid } }, + data: { alert: { ...mockAlert, issue } }, }); return wrapper.vm.$nextTick().then(() => { diff --git a/spec/frontend/vue_shared/alert_details/mocks/alerts.json b/spec/frontend/vue_shared/alert_details/mocks/alerts.json index 5267a4fe50d..007557e234a 100644 --- a/spec/frontend/vue_shared/alert_details/mocks/alerts.json +++ b/spec/frontend/vue_shared/alert_details/mocks/alerts.json @@ -21,7 +21,7 @@ "endedAt": "2020-04-17T23:18:14.996Z", "status": "ACKNOWLEDGED", "assignees": { "nodes": [{ "username": "root", "avatarUrl": "/url", "name": "root" }] }, - "issueIid": "1", + "issue": { "state" : "closed", "iid": "1", "title": "My test issue" }, "notes": { "nodes": [ { diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js index a6c5e23ae14..650d204201e 100644 --- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js +++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js @@ -18,7 +18,6 @@ const DEFAULT_PROPS = { describe('User Popover Component', () => { const fixtureTemplate = 'merge_requests/diff_comment.html'; - preloadFixtures(fixtureTemplate); let wrapper; diff --git a/spec/frontend/zen_mode_spec.js b/spec/frontend/zen_mode_spec.js index 5cc1d2200d3..bf4b57d8afb 100644 --- a/spec/frontend/zen_mode_spec.js +++ b/spec/frontend/zen_mode_spec.js @@ -13,8 +13,6 @@ describe('ZenMode', () => { let dropzoneForElementSpy; const fixtureName = 'snippets/show.html'; - preloadFixtures(fixtureName); - function enterZen() { $('.notes-form .js-zen-enter').click(); } diff --git a/spec/graphql/types/alert_management/alert_type_spec.rb b/spec/graphql/types/alert_management/alert_type_spec.rb index 82b48a20708..9ff01418c9a 100644 --- a/spec/graphql/types/alert_management/alert_type_spec.rb +++ b/spec/graphql/types/alert_management/alert_type_spec.rb @@ -10,7 +10,8 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do it 'exposes the expected fields' do expected_fields = %i[ iid - issue_iid + issueIid + issue title description severity diff --git a/spec/lib/sentry/api_urls_spec.rb b/spec/lib/error_tracking/sentry_client/api_urls_spec.rb index d56b4397e1c..bd701748dc2 100644 --- a/spec/lib/sentry/api_urls_spec.rb +++ b/spec/lib/error_tracking/sentry_client/api_urls_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' -RSpec.describe Sentry::ApiUrls do +RSpec.describe ErrorTracking::SentryClient::ApiUrls do let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project/' } let(:token) { 'test-token' } let(:issue_id) { '123456' } let(:issue_id_with_reserved_chars) { '123$%' } let(:escaped_issue_id) { '123%24%25' } - let(:api_urls) { Sentry::ApiUrls.new(sentry_url) } + let(:api_urls) { described_class.new(sentry_url) } # Sentry API returns 404 if there are extra slashes in the URL! shared_examples 'correct url with extra slashes' do diff --git a/spec/lib/sentry/client/event_spec.rb b/spec/lib/error_tracking/sentry_client/event_spec.rb index 07ed331c44c..64e674f1e9b 100644 --- a/spec/lib/sentry/client/event_spec.rb +++ b/spec/lib/error_tracking/sentry_client/event_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sentry::Client do +RSpec.describe ErrorTracking::SentryClient do include SentryClientHelpers let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } diff --git a/spec/lib/sentry/client/issue_link_spec.rb b/spec/lib/error_tracking/sentry_client/issue_link_spec.rb index fe3abe7cb23..f86d328ef89 100644 --- a/spec/lib/sentry/client/issue_link_spec.rb +++ b/spec/lib/error_tracking/sentry_client/issue_link_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Sentry::Client::IssueLink do +RSpec.describe ErrorTracking::SentryClient::IssueLink do include SentryClientHelpers let_it_be(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } diff --git a/spec/lib/sentry/client/issue_spec.rb b/spec/lib/error_tracking/sentry_client/issue_spec.rb index dedef905c95..e54296c58e0 100644 --- a/spec/lib/sentry/client/issue_spec.rb +++ b/spec/lib/error_tracking/sentry_client/issue_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -RSpec.describe Sentry::Client::Issue do +RSpec.describe ErrorTracking::SentryClient::Issue do include SentryClientHelpers let(:token) { 'test-token' } let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' } - let(:client) { Sentry::Client.new(sentry_url, token) } + let(:client) { ErrorTracking::SentryClient.new(sentry_url, token) } let(:issue_id) { 11 } describe '#list_issues' do @@ -136,7 +136,7 @@ RSpec.describe Sentry::Client::Issue do subject { client.list_issues(issue_status: issue_status, limit: limit, sort: 'fish') } it 'throws an error' do - expect { subject }.to raise_error(Sentry::Client::BadRequestError, 'Invalid value for sort param') + expect { subject }.to raise_error(ErrorTracking::SentryClient::BadRequestError, 'Invalid value for sort param') end end @@ -164,7 +164,7 @@ RSpec.describe Sentry::Client::Issue do end it 'raises exception' do - expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"') + expect { subject }.to raise_error(ErrorTracking::SentryClient::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"') end end @@ -173,7 +173,7 @@ RSpec.describe Sentry::Client::Issue do deep_size = double('Gitlab::Utils::DeepSize', valid?: false) allow(Gitlab::Utils::DeepSize).to receive(:new).with(sentry_api_response).and_return(deep_size) - expect { subject }.to raise_error(Sentry::Client::ResponseInvalidSizeError, 'Sentry API response is too big. Limit is 1 MB.') + expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError, 'Sentry API response is too big. Limit is 1 MB.') end end diff --git a/spec/lib/sentry/pagination_parser_spec.rb b/spec/lib/error_tracking/sentry_client/pagination_parser_spec.rb index c4ed24827bb..c4b771d5b93 100644 --- a/spec/lib/sentry/pagination_parser_spec.rb +++ b/spec/lib/error_tracking/sentry_client/pagination_parser_spec.rb @@ -2,7 +2,7 @@ require 'fast_spec_helper' -RSpec.describe Sentry::PaginationParser do +RSpec.describe ErrorTracking::SentryClient::PaginationParser do describe '.parse' do subject { described_class.parse(headers) } diff --git a/spec/lib/sentry/client/projects_spec.rb b/spec/lib/error_tracking/sentry_client/projects_spec.rb index ea2c5ccb81e..247f9c1c085 100644 --- a/spec/lib/sentry/client/projects_spec.rb +++ b/spec/lib/error_tracking/sentry_client/projects_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -RSpec.describe Sentry::Client::Projects do +RSpec.describe ErrorTracking::SentryClient::Projects do include SentryClientHelpers let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } let(:token) { 'test-token' } - let(:client) { Sentry::Client.new(sentry_url, token) } + let(:client) { ErrorTracking::SentryClient.new(sentry_url, token) } let(:projects_sample_response) do Gitlab::Utils.deep_indifferent_access( Gitlab::Json.parse(fixture_file('sentry/list_projects_sample_response.json')) @@ -44,7 +44,7 @@ RSpec.describe Sentry::Client::Projects do end it 'raises exception' do - expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "slug"') + expect { subject }.to raise_error(ErrorTracking::SentryClient::MissingKeysError, 'Sentry API response is missing keys. key not found: "slug"') end end diff --git a/spec/lib/sentry/client/repo_spec.rb b/spec/lib/error_tracking/sentry_client/repo_spec.rb index 956c0b6eee1..9a1c7a69c3d 100644 --- a/spec/lib/sentry/client/repo_spec.rb +++ b/spec/lib/error_tracking/sentry_client/repo_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -RSpec.describe Sentry::Client::Repo do +RSpec.describe ErrorTracking::SentryClient::Repo do include SentryClientHelpers let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } let(:token) { 'test-token' } - let(:client) { Sentry::Client.new(sentry_url, token) } + let(:client) { ErrorTracking::SentryClient.new(sentry_url, token) } let(:repos_sample_response) { Gitlab::Json.parse(fixture_file('sentry/repos_sample_response.json')) } describe '#repos' do diff --git a/spec/lib/sentry/client_spec.rb b/spec/lib/error_tracking/sentry_client_spec.rb index cddcb6e98fa..9ffd756f057 100644 --- a/spec/lib/sentry/client_spec.rb +++ b/spec/lib/error_tracking/sentry_client_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' -RSpec.describe Sentry::Client do +RSpec.describe ErrorTracking::SentryClient do let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' } let(:token) { 'test-token' } - subject { Sentry::Client.new(sentry_url, token) } + subject { described_class.new(sentry_url, token) } it { is_expected.to respond_to :projects } it { is_expected.to respond_to :list_issues } diff --git a/spec/mailers/emails/merge_requests_spec.rb b/spec/mailers/emails/merge_requests_spec.rb index 5ab0265203e..1a61d3c4362 100644 --- a/spec/mailers/emails/merge_requests_spec.rb +++ b/spec/mailers/emails/merge_requests_spec.rb @@ -6,7 +6,8 @@ require 'email_spec' RSpec.describe Emails::MergeRequests do include EmailSpec::Matchers - let_it_be(:recipient) { create(:user) } + include_context 'gitlab email notification' + let_it_be(:current_user) { create(:user) } let_it_be(:assignee, reload: true) { create(:user, email: 'assignee@example.com', name: 'John Doe') } let_it_be(:reviewer, reload: true) { create(:user, email: 'reviewer@example.com', name: 'Jane Doe') } @@ -20,6 +21,42 @@ RSpec.describe Emails::MergeRequests do description: 'Awesome description') end + let(:recipient) { assignee } + + describe '#merged_merge_request_email' do + let(:merge_author) { assignee } + + subject { Notify.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) } + + it_behaves_like 'a multiple recipients email' + it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do + let(:model) { merge_request } + end + + it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like 'an unsubscribeable thread' + it_behaves_like 'appearance header and footer enabled' + it_behaves_like 'appearance header and footer not enabled' + + it 'is sent as the merge author' do + sender = subject.header[:from].addrs[0] + expect(sender.display_name).to eq(merge_author.name) + expect(sender.address).to eq(gitlab_sender) + end + + it 'has the correct subject and body' do + aggregate_failures do + is_expected.to have_referable_subject(merge_request, reply: true) + is_expected.to have_body_text('merged') + is_expected.to have_body_text(project_merge_request_path(project, merge_request)) + is_expected.to have_link(merge_request.to_reference, href: project_merge_request_url(merge_request.target_project, merge_request)) + + expect(subject.text_part).to have_content(assignee.name) + expect(subject.text_part).to have_content(reviewer.name) + end + end + end + describe "#merge_when_pipeline_succeeds_email" do let(:title) { "Merge request #{merge_request.to_reference} was scheduled to merge after pipeline succeeds by #{current_user.name}" } diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index a965980271b..762c57615b8 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -495,37 +495,6 @@ RSpec.describe Notify do end end - describe 'that are merged' do - let(:merge_author) { create(:user) } - - subject { described_class.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) } - - it_behaves_like 'a multiple recipients email' - it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do - let(:model) { merge_request } - end - - it_behaves_like 'it should show Gmail Actions View Merge request link' - it_behaves_like 'an unsubscribeable thread' - it_behaves_like 'appearance header and footer enabled' - it_behaves_like 'appearance header and footer not enabled' - - it 'is sent as the merge author' do - sender = subject.header[:from].addrs[0] - expect(sender.display_name).to eq(merge_author.name) - expect(sender.address).to eq(gitlab_sender) - end - - it 'has the correct subject and body' do - aggregate_failures do - is_expected.to have_referable_subject(merge_request, reply: true) - is_expected.to have_body_text('merged') - is_expected.to have_body_text(project_merge_request_path(project, merge_request)) - is_expected.to have_link(merge_request.to_reference, href: project_merge_request_url(merge_request.target_project, merge_request)) - end - end - end - describe 'that are unmergeable' do let_it_be(:merge_request) do create(:merge_request, :conflict, diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb index 6c9dc061430..17ab4d5954c 100644 --- a/spec/models/bulk_imports/entity_spec.rb +++ b/spec/models/bulk_imports/entity_spec.rb @@ -189,20 +189,4 @@ RSpec.describe BulkImports::Entity, type: :model do expect(entity.next_page_for(:relation)).to eq('nextPage') end end - - describe 'caching', :clean_gitlab_redis_cache do - let(:entity) { create(:bulk_import_entity, :started) } - - it 'removes entity cache keys' do - cache_key = "bulk_import:#{entity.bulk_import.id}:entity:#{entity.id}:relation:1" - - Gitlab::Redis::Cache.with do |redis| - redis.set(cache_key, 1) - - expect(redis).to receive(:del).with(cache_key) - end - - entity.finish! - end - end end diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb index 72ed11f6c74..3ae0666f7d0 100644 --- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb +++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb @@ -111,7 +111,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do describe '#sentry_client' do it 'returns sentry client' do - expect(subject.sentry_client).to be_a(Sentry::Client) + expect(subject.sentry_client).to be_a(ErrorTracking::SentryClient) end end @@ -152,7 +152,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do end end - context 'when sentry client raises Sentry::Client::Error' do + context 'when sentry client raises ErrorTracking::SentryClient::Error' do let(:sentry_client) { spy(:sentry_client) } before do @@ -160,7 +160,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do allow(subject).to receive(:sentry_client).and_return(sentry_client) allow(sentry_client).to receive(:list_issues).with(opts) - .and_raise(Sentry::Client::Error, 'error message') + .and_raise(ErrorTracking::SentryClient::Error, 'error message') end it 'returns error' do @@ -171,7 +171,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do end end - context 'when sentry client raises Sentry::Client::MissingKeysError' do + context 'when sentry client raises ErrorTracking::SentryClient::MissingKeysError' do let(:sentry_client) { spy(:sentry_client) } before do @@ -179,7 +179,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do allow(subject).to receive(:sentry_client).and_return(sentry_client) allow(sentry_client).to receive(:list_issues).with(opts) - .and_raise(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"') + .and_raise(ErrorTracking::SentryClient::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"') end it 'returns error' do @@ -190,7 +190,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do end end - context 'when sentry client raises Sentry::Client::ResponseInvalidSizeError' do + context 'when sentry client raises ErrorTracking::SentryClient::ResponseInvalidSizeError' do let(:sentry_client) { spy(:sentry_client) } let(:error_msg) {"Sentry API response is too big. Limit is #{Gitlab::Utils::DeepSize.human_default_max_size}."} @@ -199,7 +199,7 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do allow(subject).to receive(:sentry_client).and_return(sentry_client) allow(sentry_client).to receive(:list_issues).with(opts) - .and_raise(Sentry::Client::ResponseInvalidSizeError, error_msg) + .and_raise(ErrorTracking::SentryClient::ResponseInvalidSizeError, error_msg) end it 'returns error' do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index f22ee7b1686..551da6d0471 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -2885,11 +2885,6 @@ RSpec.describe MergeRequest, factory_default: :keep do describe '#mergeable?' do subject { build_stubbed(:merge_request) } - it 'returns false if still preparing' do - expect(subject).to receive(:preparing?) { true } - expect(subject.mergeable?).to be_falsey - end - it 'returns false if #mergeable_state? is false' do expect(subject).to receive(:mergeable_state?) { false } @@ -3080,7 +3075,6 @@ RSpec.describe MergeRequest, factory_default: :keep do subject { build(:merge_request, merge_status: status) } where(:status, :public_status) do - 'preparing' | 'checking' 'cannot_be_merged_rechecking' | 'checking' 'checking' | 'checking' 'cannot_be_merged' | 'cannot_be_merged' @@ -4136,13 +4130,6 @@ RSpec.describe MergeRequest, factory_default: :keep do include_examples 'for an valid state transition' end - context 'when the status is preparing' do - let(:merge_status) { :preparing } - let(:expected_merge_status) { 'unchecked' } - - include_examples 'for an valid state transition' - end - context 'when the status is can_be_merged' do let(:merge_status) { :can_be_merged } let(:expected_merge_status) { 'unchecked' } diff --git a/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb index 6141a172253..f637ca98353 100644 --- a/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb +++ b/spec/requests/api/graphql/mutations/alert_management/alerts/create_alert_issue_spec.rb @@ -20,7 +20,9 @@ RSpec.describe 'Create an alert issue from an alert' do errors alert { iid - issueIid + issue { + iid + } } issue { iid @@ -46,7 +48,7 @@ RSpec.describe 'Create an alert issue from an alert' do expect(mutation_response.slice('alert', 'issue')).to eq( 'alert' => { 'iid' => alert.iid.to_s, - 'issueIid' => new_issue.iid.to_s + 'issue' => { 'iid' => new_issue.iid.to_s } }, 'issue' => { 'iid' => new_issue.iid.to_s, diff --git a/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb new file mode 100644 index 00000000000..9724de4fedb --- /dev/null +++ b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'getting Alert Management Alert Issue' do + include GraphqlHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:current_user) { create(:user) } + let(:payload) { {} } + let(:query) { 'avg(metric) > 1.0' } + + let(:fields) do + <<~QUERY + nodes { + iid + issue { + iid + state + } + } + QUERY + end + + let(:graphql_query) do + graphql_query_for( + 'project', + { 'fullPath' => project.full_path }, + query_graphql_field('alertManagementAlerts', {}, fields) + ) + end + + let(:alerts) { graphql_data.dig('project', 'alertManagementAlerts', 'nodes') } + let(:first_alert) { alerts.first } + + before do + project.add_developer(current_user) + end + + context 'with gitlab alert' do + before do + create(:alert_management_alert, :with_issue, project: project, payload: payload) + end + + it 'includes the correct alert issue payload data' do + post_graphql(graphql_query, current_user: current_user) + + expect(first_alert).to include('issue' => { "iid" => "1", "state" => "opened" }) + end + end + + describe 'performance' do + let(:first_n) { var('Int') } + let(:params) { { first: first_n } } + let(:limited_query) { with_signature([first_n], query) } + + context 'with gitlab alert' do + before do + create(:alert_management_alert, :with_issue, project: project, payload: payload) + end + + it 'avoids N+1 queries' do + base_count = ActiveRecord::QueryRecorder.new do + post_graphql(limited_query, current_user: current_user, variables: first_n.with(1)) + end + + expect { post_graphql(limited_query, current_user: current_user) }.not_to exceed_query_limit(base_count) + end + end + end +end diff --git a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb index 8deed75a466..fe77d9dc86d 100644 --- a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb +++ b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb @@ -7,7 +7,7 @@ RSpec.describe 'getting Alert Management Alerts' do let_it_be(:payload) { { 'custom' => { 'alert' => 'payload' }, 'runbook' => 'runbook' } } let_it_be(:project) { create(:project, :repository) } let_it_be(:current_user) { create(:user) } - let_it_be(:resolved_alert) { create(:alert_management_alert, :all_fields, :resolved, project: project, issue: nil, severity: :low).present } + let_it_be(:resolved_alert) { create(:alert_management_alert, :all_fields, :resolved, project: project, severity: :low).present } let_it_be(:triggered_alert) { create(:alert_management_alert, :all_fields, project: project, severity: :critical, payload: payload).present } let_it_be(:other_project_alert) { create(:alert_management_alert, :all_fields).present } @@ -60,7 +60,6 @@ RSpec.describe 'getting Alert Management Alerts' do it 'returns the correct properties of the alerts' do expect(first_alert).to include( 'iid' => triggered_alert.iid.to_s, - 'issueIid' => triggered_alert.issue_iid.to_s, 'title' => triggered_alert.title, 'description' => triggered_alert.description, 'severity' => triggered_alert.severity.upcase, @@ -82,7 +81,6 @@ RSpec.describe 'getting Alert Management Alerts' do expect(second_alert).to include( 'iid' => resolved_alert.iid.to_s, - 'issueIid' => resolved_alert.issue_iid.to_s, 'status' => 'RESOLVED', 'endedAt' => resolved_alert.ended_at.strftime('%Y-%m-%dT%H:%M:%SZ') ) diff --git a/spec/requests/api/invitations_spec.rb b/spec/requests/api/invitations_spec.rb index 2ea237469b1..a40eae8fdaf 100644 --- a/spec/requests/api/invitations_spec.rb +++ b/spec/requests/api/invitations_spec.rb @@ -3,14 +3,14 @@ require 'spec_helper' RSpec.describe API::Invitations do - let(:maintainer) { create(:user, username: 'maintainer_user') } - let(:developer) { create(:user) } - let(:access_requester) { create(:user) } - let(:stranger) { create(:user) } + let_it_be(:maintainer) { create(:user, username: 'maintainer_user') } + let_it_be(:developer) { create(:user) } + let_it_be(:access_requester) { create(:user) } + let_it_be(:stranger) { create(:user) } let(:email) { 'email1@example.com' } let(:email2) { 'email2@example.com' } - let(:project) do + let_it_be(:project) do create(:project, :public, creator_id: maintainer.id, namespace: maintainer.namespace) do |project| project.add_developer(developer) project.add_maintainer(maintainer) @@ -18,7 +18,7 @@ RSpec.describe API::Invitations do end end - let!(:group) do + let_it_be(:group, reload: true) do create(:group, :public) do |group| group.add_developer(developer) group.add_owner(maintainer) diff --git a/spec/services/members/invite_service_spec.rb b/spec/services/members/invite_service_spec.rb index 08cdf0d3ae1..cced93896a5 100644 --- a/spec/services/members/invite_service_spec.rb +++ b/spec/services/members/invite_service_spec.rb @@ -2,76 +2,155 @@ require 'spec_helper' -RSpec.describe Members::InviteService do - let(:project) { create(:project) } - let(:user) { create(:user) } - let(:project_user) { create(:user) } - - before do - project.add_maintainer(user) +RSpec.describe Members::InviteService, :aggregate_failures do + let_it_be(:project) { create(:project) } + let_it_be(:user) { project.owner } + let_it_be(:project_user) { create(:user) } + let(:params) { {} } + let(:base_params) { { access_level: Gitlab::Access::GUEST } } + + subject(:result) { described_class.new(user, base_params.merge(params)).execute(project) } + + context 'when email is previously unused by current members' do + let(:params) { { email: 'email@example.org' } } + + it 'successfully creates a member' do + expect { result }.to change(ProjectMember, :count).by(1) + expect(result[:status]).to eq(:success) + end end - it 'adds an existing user to members' do - params = { email: project_user.email.to_s, access_level: Gitlab::Access::GUEST } - result = described_class.new(user, params).execute(project) + context 'when emails are passed as an array' do + let(:params) { { email: %w[email@example.org email2@example.org] } } - expect(result[:status]).to eq(:success) - expect(project.users).to include project_user + it 'successfully creates members' do + expect { result }.to change(ProjectMember, :count).by(2) + expect(result[:status]).to eq(:success) + end end - it 'creates a new user for an unknown email address' do - params = { email: 'email@example.org', access_level: Gitlab::Access::GUEST } - result = described_class.new(user, params).execute(project) + context 'when emails are passed as an empty string' do + let(:params) { { email: '' } } - expect(result[:status]).to eq(:success) + it 'returns an error' do + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq('Email cannot be blank') + end end - it 'limits the number of emails to 100' do - emails = Array.new(101).map { |n| "email#{n}@example.com" } - params = { email: emails, access_level: Gitlab::Access::GUEST } + context 'when email param is not included' do + it 'returns an error' do + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq('Email cannot be blank') + end + end - result = described_class.new(user, params).execute(project) + context 'when email is not a valid email' do + let(:params) { { email: '_bogus_' } } - expect(result[:status]).to eq(:error) - expect(result[:message]).to eq('Too many users specified (limit is 100)') + it 'returns an error' do + expect { result }.not_to change(ProjectMember, :count) + expect(result[:status]).to eq(:error) + expect(result[:message]['_bogus_']).to eq("Invite email is invalid") + end end - it 'does not invite an invalid email' do - params = { email: project_user.id.to_s, access_level: Gitlab::Access::GUEST } - result = described_class.new(user, params).execute(project) + context 'when duplicate email addresses are passed' do + let(:params) { { email: 'email@example.org,email@example.org' } } + + it 'only creates one member per unique address' do + expect { result }.to change(ProjectMember, :count).by(1) + expect(result[:status]).to eq(:success) + end + end - expect(result[:status]).to eq(:error) - expect(result[:message][project_user.id.to_s]).to eq("Invite email is invalid") - expect(project.users).not_to include project_user + context 'when observing email limits' do + let_it_be(:emails) { Array(1..101).map { |n| "email#{n}@example.com" } } + + context 'when over the allowed default limit of emails' do + let(:params) { { email: emails } } + + it 'limits the number of emails to 100' do + expect { result }.not_to change(ProjectMember, :count) + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq('Too many users specified (limit is 100)') + end + end + + context 'when over the allowed custom limit of emails' do + let(:params) { { email: 'email@example.org,email2@example.org', limit: 1 } } + + it 'limits the number of emails to the limit supplied' do + expect { result }.not_to change(ProjectMember, :count) + expect(result[:status]).to eq(:error) + expect(result[:message]).to eq('Too many users specified (limit is 1)') + end + end + + context 'when limit allowed is disabled via limit param' do + let(:params) { { email: emails, limit: -1 } } + + it 'does not limit number of emails' do + expect { result }.to change(ProjectMember, :count).by(101) + expect(result[:status]).to eq(:success) + end + end end - it 'does not invite to an invalid access level' do - params = { email: project_user.email, access_level: -1 } - result = described_class.new(user, params).execute(project) + context 'when email belongs to an existing user' do + let(:params) { { email: project_user.email } } - expect(result[:status]).to eq(:error) - expect(result[:message][project_user.email]).to eq("Access level is not included in the list") + it 'adds an existing user to members' do + expect { result }.to change(ProjectMember, :count).by(1) + expect(result[:status]).to eq(:success) + expect(project.users).to include project_user + end end - it 'does not add a member with an existing invite' do - invited_member = create(:project_member, :invited, project: project) + context 'when access level is not valid' do + let(:params) { { email: project_user.email, access_level: -1 } } - params = { email: invited_member.invite_email, - access_level: Gitlab::Access::GUEST } - result = described_class.new(user, params).execute(project) + it 'returns an error' do + expect { result }.not_to change(ProjectMember, :count) + expect(result[:status]).to eq(:error) + expect(result[:message][project_user.email]).to eq("Access level is not included in the list") + end + end + + context 'when invite already exists for an included email' do + let!(:invited_member) { create(:project_member, :invited, project: project) } + let(:params) { { email: "#{invited_member.invite_email},#{project_user.email}" } } - expect(result[:status]).to eq(:error) - expect(result[:message][invited_member.invite_email]).to eq("Member already invited to #{project.name}") + it 'adds new email and returns an error for the already invited email' do + expect { result }.to change(ProjectMember, :count).by(1) + expect(result[:status]).to eq(:error) + expect(result[:message][invited_member.invite_email]).to eq("Member already invited to #{project.name}") + expect(project.users).to include project_user + end end - it 'does not add a member with an access_request' do - requested_member = create(:project_member, :access_request, project: project) + context 'when access request already exists for an included email' do + let!(:requested_member) { create(:project_member, :access_request, project: project) } + let(:params) { { email: "#{requested_member.user.email},#{project_user.email}" } } + + it 'adds new email and returns an error for the already invited email' do + expect { result }.to change(ProjectMember, :count).by(1) + expect(result[:status]).to eq(:error) + expect(result[:message][requested_member.user.email]) + .to eq("Member cannot be invited because they already requested to join #{project.name}") + expect(project.users).to include project_user + end + end - params = { email: requested_member.user.email, - access_level: Gitlab::Access::GUEST } - result = described_class.new(user, params).execute(project) + context 'when email is already a member on the project' do + let!(:existing_member) { create(:project_member, :guest, project: project) } + let(:params) { { email: "#{existing_member.user.email},#{project_user.email}" } } - expect(result[:status]).to eq(:error) - expect(result[:message][requested_member.user.email]).to eq("Member cannot be invited because they already requested to join #{project.name}") + it 'adds new email and returns an error for the already invited email' do + expect { result }.to change(ProjectMember, :count).by(1) + expect(result[:status]).to eq(:error) + expect(result[:message][existing_member.user.email]).to eq("Already a member of #{project.name}") + expect(project.users).to include project_user + end end end diff --git a/spec/services/merge_requests/after_create_service_spec.rb b/spec/services/merge_requests/after_create_service_spec.rb index 22af346634f..f21feb70bc5 100644 --- a/spec/services/merge_requests/after_create_service_spec.rb +++ b/spec/services/merge_requests/after_create_service_spec.rb @@ -67,27 +67,5 @@ RSpec.describe MergeRequests::AfterCreateService do it_behaves_like 'records an onboarding progress action', :merge_request_created do let(:namespace) { merge_request.target_project.namespace } end - - context 'when merge request is in unchecked state' do - before do - merge_request.mark_as_unchecked! - execute_service - end - - it 'does not change its state' do - expect(merge_request.reload).to be_unchecked - end - end - - context 'when merge request is in preparing state' do - before do - merge_request.mark_as_preparing! - execute_service - end - - it 'marks the merge request as unchecked' do - expect(merge_request.reload).to be_unchecked - end - end end end diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index e63e678bdd8..4f47a22b07c 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -67,10 +67,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do expect(Event.where(attributes).count).to eq(1) end - it 'sets the merge_status to preparing' do - expect(merge_request.reload).to be_preparing - end - describe 'when marked with /wip' do context 'in title and in description' do let(:opts) do diff --git a/spec/services/repositories/changelog_service_spec.rb b/spec/services/repositories/changelog_service_spec.rb index 4ec692d678a..91bc248b20a 100644 --- a/spec/services/repositories/changelog_service_spec.rb +++ b/spec/services/repositories/changelog_service_spec.rb @@ -76,7 +76,7 @@ RSpec.describe Repositories::ChangelogService do recorder = ActiveRecord::QueryRecorder.new { service.execute } changelog = project.repository.blob_at('master', 'CHANGELOG.md')&.data - expect(recorder.count).to eq(10) + expect(recorder.count).to eq(11) expect(changelog).to include('Title 1', 'Title 2') end diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb index 2224af88ab9..09425c3742a 100644 --- a/spec/support/helpers/javascript_fixtures_helpers.rb +++ b/spec/support/helpers/javascript_fixtures_helpers.rb @@ -12,6 +12,7 @@ module JavaScriptFixturesHelpers included do |base| base.around do |example| # pick an arbitrary date from the past, so tests are not time dependent + # Also see spec/frontend/__helpers__/fake_date/jest.js Timecop.freeze(Time.utc(2015, 7, 3, 10)) { example.run } raise NoMethodError.new('You need to set `response` for the fixture generator! This will automatically happen with `type: :controller` or `type: :request`.', 'response') unless respond_to?(:response) diff --git a/spec/support/shared_contexts/features/error_tracking_shared_context.rb b/spec/support/shared_contexts/features/error_tracking_shared_context.rb index 1f4eb3a6df9..f04111e0ce0 100644 --- a/spec/support/shared_contexts/features/error_tracking_shared_context.rb +++ b/spec/support/shared_contexts/features/error_tracking_shared_context.rb @@ -9,7 +9,7 @@ RSpec.shared_context 'sentry error tracking context feature' do let_it_be(:issue_response) { Gitlab::Json.parse(issue_response_body) } let_it_be(:event_response_body) { fixture_file('sentry/issue_latest_event_sample_response.json') } let_it_be(:event_response) { Gitlab::Json.parse(event_response_body) } - let(:sentry_api_urls) { Sentry::ApiUrls.new(project_error_tracking_settings.api_url) } + let(:sentry_api_urls) { ErrorTracking::SentryClient::ApiUrls.new(project_error_tracking_settings.api_url) } let(:issue_id) { issue_response['id'] } let(:issue_seen) { 1.year.ago.utc } let(:formatted_issue_seen) { issue_seen.strftime("%Y-%m-%d %-l:%M:%S%p %Z") } diff --git a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb index 4221708b55c..d73c7b6848d 100644 --- a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb +++ b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb @@ -26,7 +26,7 @@ RSpec.shared_examples 'no Sentry redirects' do |http_method| end it 'does not follow redirects' do - expect { subject }.to raise_exception(Sentry::Client::Error, 'Sentry response status code: 302') + expect { subject }.to raise_exception(ErrorTracking::SentryClient::Error, 'Sentry response status code: 302') expect(redirect_req_stub).to have_been_requested expect(redirected_req_stub).not_to have_been_requested end @@ -53,7 +53,7 @@ RSpec.shared_examples 'maps Sentry exceptions' do |http_method| it do expect { subject } - .to raise_exception(Sentry::Client::Error, message) + .to raise_exception(ErrorTracking::SentryClient::Error, message) end end end diff --git a/spec/workers/error_tracking_issue_link_worker_spec.rb b/spec/workers/error_tracking_issue_link_worker_spec.rb index 5be568c2dad..90e747c8788 100644 --- a/spec/workers/error_tracking_issue_link_worker_spec.rb +++ b/spec/workers/error_tracking_issue_link_worker_spec.rb @@ -20,7 +20,7 @@ RSpec.describe ErrorTrackingIssueLinkWorker do describe '#perform' do it 'creates a link between an issue and a Sentry issue in Sentry' do - expect_next_instance_of(Sentry::Client) do |client| + expect_next_instance_of(ErrorTracking::SentryClient) do |client| expect(client).to receive(:repos).with('sentry-org').and_return([repo]) expect(client) .to receive(:create_issue_link) @@ -33,8 +33,8 @@ RSpec.describe ErrorTrackingIssueLinkWorker do shared_examples_for 'makes no external API requests' do it 'takes no action' do - expect_any_instance_of(Sentry::Client).not_to receive(:repos) - expect_any_instance_of(Sentry::Client).not_to receive(:create_issue_link) + expect_any_instance_of(ErrorTracking::SentryClient).not_to receive(:repos) + expect_any_instance_of(ErrorTracking::SentryClient).not_to receive(:create_issue_link) expect(subject).to be nil end @@ -42,7 +42,7 @@ RSpec.describe ErrorTrackingIssueLinkWorker do shared_examples_for 'attempts to create a link via plugin' do it 'takes no action' do - expect_next_instance_of(Sentry::Client) do |client| + expect_next_instance_of(ErrorTracking::SentryClient) do |client| expect(client).to receive(:repos).with('sentry-org').and_return([repo]) expect(client) .to receive(:create_issue_link) @@ -98,8 +98,8 @@ RSpec.describe ErrorTrackingIssueLinkWorker do context 'when Sentry repos request errors' do it 'falls back to creating a link via plugin' do - expect_next_instance_of(Sentry::Client) do |client| - expect(client).to receive(:repos).with('sentry-org').and_raise(Sentry::Client::Error) + expect_next_instance_of(ErrorTracking::SentryClient) do |client| + expect(client).to receive(:repos).with('sentry-org').and_raise(ErrorTracking::SentryClient::Error) expect(client) .to receive(:create_issue_link) .with(nil, sentry_issue.sentry_issue_identifier, issue) |