summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/diffs/components/diff_file_row_spec.js25
-rw-r--r--spec/frontend/ide/components/ide_file_row_spec.js25
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js48
-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.js88
-rw-r--r--spec/javascripts/vue_shared/components/file_row_spec.js7
-rw-r--r--spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb82
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