diff options
Diffstat (limited to 'spec')
-rw-r--r-- | spec/frontend/diffs/components/diff_file_row_spec.js | 25 | ||||
-rw-r--r-- | spec/frontend/ide/components/ide_file_row_spec.js | 25 | ||||
-rw-r--r-- | spec/frontend/monitoring/components/dashboard_spec.js | 48 | ||||
-rw-r--r-- | spec/frontend/monitoring/components/panel_type_spec.js (renamed from spec/frontend/monitoring/panel_type_spec.js) | 27 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/file_tree_spec.js | 88 | ||||
-rw-r--r-- | spec/javascripts/vue_shared/components/file_row_spec.js | 7 | ||||
-rw-r--r-- | spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb | 82 |
7 files changed, 265 insertions, 37 deletions
diff --git a/spec/frontend/diffs/components/diff_file_row_spec.js b/spec/frontend/diffs/components/diff_file_row_spec.js new file mode 100644 index 00000000000..3e95d1d55bd --- /dev/null +++ b/spec/frontend/diffs/components/diff_file_row_spec.js @@ -0,0 +1,25 @@ +import { shallowMount } from '@vue/test-utils'; +import DiffFileRow from '~/diffs/components/diff_file_row.vue'; +import FileRow from '~/vue_shared/components/file_row.vue'; + +describe('Diff File Row component', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(DiffFileRow, { + propsData: { ...props }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders file row component', () => { + createComponent({ + level: 4, + file: {}, + }); + expect(wrapper.find(FileRow).exists()).toEqual(true); + }); +}); diff --git a/spec/frontend/ide/components/ide_file_row_spec.js b/spec/frontend/ide/components/ide_file_row_spec.js new file mode 100644 index 00000000000..7531bc3e144 --- /dev/null +++ b/spec/frontend/ide/components/ide_file_row_spec.js @@ -0,0 +1,25 @@ +import { shallowMount } from '@vue/test-utils'; +import IdeFileRow from '~/ide/components/ide_file_row.vue'; +import FileRow from '~/vue_shared/components/file_row.vue'; + +describe('Ide File Row component', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(IdeFileRow, { + propsData: { ...props }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders file row component', () => { + createComponent({ + level: 4, + file: {}, + }); + expect(wrapper.find(FileRow).exists()).toEqual(true); + }); +}); diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js index 70b2c9cf527..7a039d46d39 100644 --- a/spec/frontend/monitoring/components/dashboard_spec.js +++ b/spec/frontend/monitoring/components/dashboard_spec.js @@ -1,5 +1,5 @@ import { shallowMount, createLocalVue, mount } from '@vue/test-utils'; -import { GlDropdownItem, GlButton, GlToast } from '@gitlab/ui'; +import { GlDropdownItem, GlButton } from '@gitlab/ui'; import VueDraggable from 'vuedraggable'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; @@ -10,6 +10,7 @@ import Dashboard from '~/monitoring/components/dashboard.vue'; import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue'; import DashboardsDropdown from '~/monitoring/components/dashboards_dropdown.vue'; import GroupEmptyState from '~/monitoring/components/group_empty_state.vue'; +import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue'; import { createStore } from '~/monitoring/stores'; import * as types from '~/monitoring/stores/mutation_types'; import { setupComponentStore, propsData } from '../init_utils'; @@ -540,37 +541,36 @@ describe('Dashboard', () => { }); }); - // https://gitlab.com/gitlab-org/gitlab-ce/issues/66922 - // eslint-disable-next-line jest/no-disabled-tests - describe.skip('link to chart', () => { + describe('Clipboard text in panels', () => { const currentDashboard = 'TEST_DASHBOARD'; - localVue.use(GlToast); - const link = () => wrapper.find('.js-chart-link'); - const clipboardText = () => link().element.dataset.clipboardText; + + const getClipboardTextAt = i => + wrapper + .findAll(PanelType) + .at(i) + .props('clipboardText'); beforeEach(done => { createShallowWrapper({ hasMetrics: true, currentDashboard }); - setTimeout(done); - }); + setupComponentStore(wrapper); - it('adds a copy button to the dropdown', () => { - expect(link().text()).toContain('Generate link to chart'); + wrapper.vm.$nextTick(done); }); it('contains a link to the dashboard', () => { - expect(clipboardText()).toContain(`dashboard=${currentDashboard}`); - expect(clipboardText()).toContain(`group=`); - expect(clipboardText()).toContain(`title=`); - expect(clipboardText()).toContain(`y_label=`); + expect(getClipboardTextAt(0)).toContain(`dashboard=${currentDashboard}`); + expect(getClipboardTextAt(0)).toContain(`group=`); + expect(getClipboardTextAt(0)).toContain(`title=`); + expect(getClipboardTextAt(0)).toContain(`y_label=`); }); - it('undefined parameter is stripped', done => { + it('strips the undefined parameter', done => { wrapper.setProps({ currentDashboard: undefined }); wrapper.vm.$nextTick(() => { - expect(clipboardText()).not.toContain(`dashboard=`); - expect(clipboardText()).toContain(`y_label=`); + expect(getClipboardTextAt(0)).not.toContain(`dashboard=`); + expect(getClipboardTextAt(0)).toContain(`y_label=`); done(); }); }); @@ -579,18 +579,10 @@ describe('Dashboard', () => { wrapper.setProps({ currentDashboard: null }); wrapper.vm.$nextTick(() => { - expect(clipboardText()).not.toContain(`dashboard=`); - expect(clipboardText()).toContain(`y_label=`); + expect(getClipboardTextAt(0)).not.toContain(`dashboard=`); + expect(getClipboardTextAt(0)).toContain(`y_label=`); done(); }); }); - - it('creates a toast when clicked', () => { - jest.spyOn(wrapper.vm.$toast, 'show').and.stub(); - - link().vm.$emit('click'); - - expect(wrapper.vm.$toast.show).toHaveBeenCalled(); - }); }); }); diff --git a/spec/frontend/monitoring/panel_type_spec.js b/spec/frontend/monitoring/components/panel_type_spec.js index 730d67f79d8..6d8bd1d3a30 100644 --- a/spec/frontend/monitoring/panel_type_spec.js +++ b/spec/frontend/monitoring/components/panel_type_spec.js @@ -3,22 +3,29 @@ import AxiosMockAdapter from 'axios-mock-adapter'; import { setTestTimeout } from 'helpers/timeout'; import invalidUrl from '~/lib/utils/invalid_url'; import axios from '~/lib/utils/axios_utils'; + import PanelType from '~/monitoring/components/panel_type.vue'; import EmptyChart from '~/monitoring/components/charts/empty_chart.vue'; import TimeSeriesChart from '~/monitoring/components/charts/time_series.vue'; import AnomalyChart from '~/monitoring/components/charts/anomaly.vue'; -import { graphDataPrometheusQueryRange } from '../../javascripts/monitoring/mock_data'; -import { anomalyMockGraphData } from '../../frontend/monitoring/mock_data'; +import { anomalyMockGraphData, graphDataPrometheusQueryRange } from 'jest/monitoring/mock_data'; import { createStore } from '~/monitoring/stores'; global.IS_EE = true; global.URL.createObjectURL = jest.fn(); +const mocks = { + $toast: { + show: jest.fn(), + }, +}; + describe('Panel Type component', () => { let axiosMock; let store; let state; let wrapper; + const exampleText = 'example_text'; const createWrapper = props => { @@ -27,6 +34,7 @@ describe('Panel Type component', () => { ...props, }, store, + mocks, }); }; @@ -88,7 +96,7 @@ describe('Panel Type component', () => { }); it('sets no clipboard copy link on dropdown by default', () => { - const link = () => wrapper.find('.js-chart-link'); + const link = () => wrapper.find({ ref: 'copyChartLink' }); expect(link().exists()).toBe(false); }); @@ -196,6 +204,7 @@ describe('Panel Type component', () => { }); describe('when cliboard data is available', () => { + const link = () => wrapper.find({ ref: 'copyChartLink' }); const clipboardText = 'A value to copy.'; beforeEach(() => { @@ -210,11 +219,19 @@ describe('Panel Type component', () => { }); it('sets clipboard text on the dropdown', () => { - const link = () => wrapper.find('.js-chart-link'); - expect(link().exists()).toBe(true); expect(link().element.dataset.clipboardText).toBe(clipboardText); }); + + it('adds a copy button to the dropdown', () => { + expect(link().text()).toContain('Generate link to chart'); + }); + + it('opens a toast on click', () => { + link().vm.$emit('click'); + + expect(wrapper.vm.$toast.show).toHaveBeenCalled(); + }); }); describe('when downloading metrics data as CSV', () => { diff --git a/spec/frontend/vue_shared/components/file_tree_spec.js b/spec/frontend/vue_shared/components/file_tree_spec.js new file mode 100644 index 00000000000..38979d9d844 --- /dev/null +++ b/spec/frontend/vue_shared/components/file_tree_spec.js @@ -0,0 +1,88 @@ +import { pick } from 'lodash'; +import { shallowMount } from '@vue/test-utils'; +import FileTree from '~/vue_shared/components/file_tree.vue'; + +const MockFileRow = { + name: 'MockFileRow', + render() { + return this.$slots.default; + }, +}; + +const TEST_LEVEL = 4; +const TEST_EXTA_ARGS = { + foo: 'lorem-ipsum', + bar: 'zoo', +}; + +describe('File Tree component', () => { + let wrapper; + + const createComponent = (props = {}) => { + wrapper = shallowMount(FileTree, { + propsData: { level: TEST_LEVEL, fileRowComponent: MockFileRow, ...props }, + attrs: { ...TEST_EXTA_ARGS }, + }); + }; + + const findFileRow = () => wrapper.find(MockFileRow); + const findChildrenTrees = () => wrapper.findAll(FileTree).wrappers.slice(1); + const findChildrenTreeProps = () => + findChildrenTrees().map(x => ({ + ...x.props(), + ...pick(x.attributes(), Object.keys(TEST_EXTA_ARGS)), + })); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('file row component', () => { + beforeEach(() => { + createComponent({ file: {} }); + }); + + it('renders file row component', () => { + expect(findFileRow().exists()).toEqual(true); + }); + + it('contains the required attribute keys', () => { + const fileRow = findFileRow(); + + // Checking strings b/c value in attributes are always strings + expect(fileRow.attributes()).toEqual({ + file: {}.toString(), + level: TEST_LEVEL.toString(), + ...TEST_EXTA_ARGS, + }); + }); + }); + + describe('file tree', () => { + const createChildren = () => [{ id: 1 }, { id: 2 }]; + const createChildrenExpectation = (props = {}) => + createChildren().map(file => ({ + fileRowComponent: MockFileRow, + file, + ...TEST_EXTA_ARGS, + ...props, + })); + + it.each` + key | value | desc | expectedChildren + ${'isHeader'} | ${true} | ${'is shown if file is header'} | ${createChildrenExpectation({ level: 0 })} + ${'opened'} | ${true} | ${'is shown if file is open'} | ${createChildrenExpectation({ level: TEST_LEVEL + 1 })} + ${'isHeader'} | ${false} | ${'is hidden if file is header'} | ${[]} + ${'opened'} | ${false} | ${'is hidden if file is open'} | ${[]} + `('$desc', ({ key, value, expectedChildren }) => { + createComponent({ + file: { + [key]: value, + tree: createChildren(), + }, + }); + + expect(findChildrenTreeProps()).toEqual(expectedChildren); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/file_row_spec.js b/spec/javascripts/vue_shared/components/file_row_spec.js index 2d80099fafe..071a09f8b93 100644 --- a/spec/javascripts/vue_shared/components/file_row_spec.js +++ b/spec/javascripts/vue_shared/components/file_row_spec.js @@ -19,7 +19,6 @@ describe('File row component', () => { const findNewDropdown = () => vm.$el.querySelector('.ide-new-btn .dropdown'); const findNewDropdownButton = () => vm.$el.querySelector('.ide-new-btn .dropdown button'); - const findFileRow = () => vm.$el.querySelector('.file-row'); it('renders name', () => { createComponent({ @@ -42,7 +41,7 @@ describe('File row component', () => { }); spyOn(vm, '$emit').and.stub(); - vm.$el.querySelector('.file-row').click(); + vm.$el.click(); expect(vm.$emit).toHaveBeenCalledWith('toggleTreeOpen', vm.file.path); }); @@ -87,7 +86,7 @@ describe('File row component', () => { level: 0, }); - expect(vm.$el.querySelector('.js-file-row-header')).not.toBe(null); + expect(vm.$el.classList).toContain('js-file-row-header'); }); describe('new dropdown', () => { @@ -138,7 +137,7 @@ describe('File row component', () => { }); it('closes when row triggers mouseleave', () => { - findFileRow().dispatchEvent(new Event('mouseleave')); + vm.$el.dispatchEvent(new Event('mouseleave')); expect(vm.dropdownOpen).toBe(false); }); diff --git a/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb new file mode 100644 index 00000000000..f90e1a1ebab --- /dev/null +++ b/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +shared_examples 'resource mentions migration' do |migration_class, resource_class| + it 'migrates resource mentions' do + join = migration_class::JOIN + conditions = migration_class::QUERY_CONDITIONS + + expect do + subject.perform(resource_class.name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id)) + end.to change { user_mentions.count }.by(1) + + user_mention = user_mentions.last + expect(user_mention.mentioned_users_ids.sort).to eq(mentioned_users.pluck(:id).sort) + expect(user_mention.mentioned_groups_ids.sort).to eq([group.id]) + expect(user_mention.mentioned_groups_ids.sort).not_to include(inaccessible_group.id) + + # check that performing the same job twice does not fail and does not change counts + expect do + subject.perform(resource_class.name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id)) + end.to change { user_mentions.count }.by(0) + end +end + +shared_examples 'resource notes mentions migration' do |migration_class, resource_class| + before do + note1.becomes(Note).save! + note2.becomes(Note).save! + note3.becomes(Note).save! + # note4.becomes(Note).save(validate: false) + end + + it 'migrates mentions from note' do + join = migration_class::JOIN + conditions = migration_class::QUERY_CONDITIONS + + # there are 4 notes for each noteable_type, but one does not have mentions and + # another one's noteable_id points to an inexistent resource + expect(notes.where(noteable_type: resource_class.to_s).count).to eq 4 + + expect do + subject.perform(resource_class.name, join, conditions, true, Note.minimum(:id), Note.maximum(:id)) + end.to change { user_mentions.count }.by(2) + + # check that the user_mention for regular note is created + user_mention = user_mentions.first + expect(Note.find(user_mention.note_id).system).to be false + expect(user_mention.mentioned_users_ids.sort).to eq(users.pluck(:id).sort) + expect(user_mention.mentioned_groups_ids.sort).to eq([group.id]) + expect(user_mention.mentioned_groups_ids.sort).not_to include(inaccessible_group.id) + + # check that the user_mention for system note is created + user_mention = user_mentions.second + expect(Note.find(user_mention.note_id).system).to be true + expect(user_mention.mentioned_users_ids.sort).to eq(users.pluck(:id).sort) + expect(user_mention.mentioned_groups_ids.sort).to eq([group.id]) + expect(user_mention.mentioned_groups_ids.sort).not_to include(inaccessible_group.id) + + # check that performing the same job twice does not fail and does not change counts + expect do + subject.perform(resource_class.name, join, conditions, true, Note.minimum(:id), Note.maximum(:id)) + end.to change { user_mentions.count }.by(0) + end +end + +shared_examples 'schedules resource mentions migration' do |resource_class, is_for_notes| + it 'schedules background migrations' do + Sidekiq::Testing.fake! do + Timecop.freeze do + migrate! + + migration = described_class::MIGRATION + join = described_class::JOIN + conditions = described_class::QUERY_CONDITIONS + + expect(migration).to be_scheduled_delayed_migration(2.minutes, resource_class.name, join, conditions, is_for_notes, resource1.id, resource1.id) + expect(migration).to be_scheduled_delayed_migration(4.minutes, resource_class.name, join, conditions, is_for_notes, resource2.id, resource2.id) + expect(migration).to be_scheduled_delayed_migration(6.minutes, resource_class.name, join, conditions, is_for_notes, resource3.id, resource3.id) + expect(BackgroundMigrationWorker.jobs.size).to eq 3 + end + end + end +end |