diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-21 12:09:01 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-21 12:09:01 +0300 |
commit | a53d2c37c4934f564caa94543dd4cf5af1703e2d (patch) | |
tree | a028dc39771a4612a9845ab700a73af2d6f3f51b /spec | |
parent | 18b8435318887d3fc6e9f9d305967a953cdd7d3f (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
6 files changed, 286 insertions, 185 deletions
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index bcb05e1c718..4ab6b0ce506 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -3,102 +3,123 @@ require 'spec_helper' describe 'Project navbar' do - it_behaves_like 'verified navigation bar' do - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } - let(:structure) do - [ - { - nav_item: _('Project overview'), - nav_sub_items: [ - _('Details'), - _('Activity'), - _('Releases') - ] - }, - { - nav_item: _('Repository'), - nav_sub_items: [ - _('Files'), - _('Commits'), - _('Branches'), - _('Tags'), - _('Contributors'), - _('Graph'), - _('Compare'), - (_('Locked Files') if Gitlab.ee?) - ] - }, - { - nav_item: _('Issues'), - nav_sub_items: [ - _('List'), - _('Boards'), - _('Labels'), - _('Milestones') - ] - }, - { - nav_item: _('Merge Requests'), - nav_sub_items: [] - }, - { - nav_item: _('CI / CD'), - nav_sub_items: [ - _('Pipelines'), - _('Jobs'), - _('Artifacts'), - _('Schedules') - ] - }, - { - nav_item: _('Operations'), - nav_sub_items: [ - _('Metrics'), - _('Environments'), - _('Error Tracking'), - _('Serverless'), - _('Kubernetes') - ] - }, - { - nav_item: _('Analytics'), - nav_sub_items: [ - _('CI / CD Analytics'), - (_('Code Review') if Gitlab.ee?), - _('Repository Analytics'), - _('Value Stream Analytics') - ] - }, - { - nav_item: _('Wiki'), - nav_sub_items: [] - }, - { - nav_item: _('Snippets'), - nav_sub_items: [] - }, - { - nav_item: _('Settings'), - nav_sub_items: [ - _('General'), - _('Members'), - _('Integrations'), - _('Repository'), - _('CI / CD'), - _('Operations'), - (_('Audit Events') if Gitlab.ee?) - ].compact - } + let(:analytics_nav_item) do + { + nav_item: _('Analytics'), + nav_sub_items: [ + _('CI / CD Analytics'), + (_('Code Review') if Gitlab.ee?), + _('Repository Analytics'), + _('Value Stream Analytics') ] - end + } + end - before do - project.add_maintainer(user) - sign_in(user) + let(:structure) do + [ + { + nav_item: _('Project overview'), + nav_sub_items: [ + _('Details'), + _('Activity'), + _('Releases') + ] + }, + { + nav_item: _('Repository'), + nav_sub_items: [ + _('Files'), + _('Commits'), + _('Branches'), + _('Tags'), + _('Contributors'), + _('Graph'), + _('Compare'), + (_('Locked Files') if Gitlab.ee?) + ] + }, + { + nav_item: _('Issues'), + nav_sub_items: [ + _('List'), + _('Boards'), + _('Labels'), + _('Milestones') + ] + }, + { + nav_item: _('Merge Requests'), + nav_sub_items: [] + }, + { + nav_item: _('CI / CD'), + nav_sub_items: [ + _('Pipelines'), + _('Jobs'), + _('Artifacts'), + _('Schedules') + ] + }, + { + nav_item: _('Operations'), + nav_sub_items: [ + _('Metrics'), + _('Environments'), + _('Error Tracking'), + _('Serverless'), + _('Kubernetes') + ] + }, + analytics_nav_item, + { + nav_item: _('Wiki'), + nav_sub_items: [] + }, + { + nav_item: _('Snippets'), + nav_sub_items: [] + }, + { + nav_item: _('Settings'), + nav_sub_items: [ + _('General'), + _('Members'), + _('Integrations'), + _('Repository'), + _('CI / CD'), + _('Operations'), + (_('Audit Events') if Gitlab.ee?) + ].compact + } + ] + end + + before do + project.add_maintainer(user) + sign_in(user) + end + it_behaves_like 'verified navigation bar' do + before do visit project_path(project) end end + + if Gitlab.ee? + context 'when issues analytics is available' do + before do + stub_licensed_features(issues_analytics: true) + + analytics_nav_item[:nav_sub_items] << _('Issues Analytics') + analytics_nav_item[:nav_sub_items].sort! + + visit project_path(project) + end + + it_behaves_like 'verified navigation bar' + end + end end diff --git a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js new file mode 100644 index 00000000000..925699f5623 --- /dev/null +++ b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js @@ -0,0 +1,103 @@ +import { shallowMount } from '@vue/test-utils'; +import { trimText } from 'helpers/text_helper'; +import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue'; +import mockData from '../mock_data'; // can also use 'mockGroup', but not useful to test here + +const mockProject = mockData(); + +describe('FrequentItemsListItemComponent', () => { + let wrapper; + + const findTitle = () => wrapper.find({ ref: 'frequentItemsItemTitle' }); + const findAvatar = () => wrapper.find({ ref: 'frequentItemsItemAvatar' }); + const findAllTitles = () => wrapper.findAll({ ref: 'frequentItemsItemTitle' }); + const findNamespace = () => wrapper.find({ ref: 'frequentItemsItemNamespace' }); + const findAllAnchors = () => wrapper.findAll('a'); + const findAllNamespace = () => wrapper.findAll({ ref: 'frequentItemsItemNamespace' }); + const findAvatarContainer = () => wrapper.findAll({ ref: 'frequentItemsItemAvatarContainer' }); + const findAllMetadataContainers = () => + wrapper.findAll({ ref: 'frequentItemsItemMetadataContainer' }); + + const createComponent = (props = {}) => { + wrapper = shallowMount(frequentItemsListItemComponent, { + propsData: { + itemId: mockProject.id, + itemName: mockProject.name, + namespace: mockProject.namespace, + webUrl: mockProject.webUrl, + avatarUrl: mockProject.avatarUrl, + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('computed', () => { + describe('highlightedItemName', () => { + it('should enclose part of project name in <b> & </b> which matches with `matcher` prop', () => { + createComponent({ matcher: 'lab' }); + + expect(findTitle().element.innerHTML).toContain('<b>L</b><b>a</b><b>b</b>'); + }); + + it('should return project name as it is if `matcher` is not available', () => { + createComponent({ matcher: null }); + + expect(trimText(findTitle().text())).toBe(mockProject.name); + }); + }); + + describe('truncatedNamespace', () => { + it('should truncate project name from namespace string', () => { + createComponent({ namespace: 'platform / nokia-3310' }); + + expect(trimText(findNamespace().text())).toBe('platform'); + }); + + it('should truncate namespace string from the middle if it includes more than two groups in path', () => { + createComponent({ + namespace: 'platform / hardware / broadcom / Wifi Group / Mobile Chipset / nokia-3310', + }); + + expect(trimText(findNamespace().text())).toBe('platform / ... / Mobile Chipset'); + }); + }); + }); + + describe('template', () => { + beforeEach(() => { + createComponent(); + }); + + it('should render avatar if avatarUrl is present', () => { + wrapper.setProps({ avatarUrl: 'path/to/avatar.png' }); + + return wrapper.vm.$nextTick(() => { + expect(findAvatar().exists()).toBe(true); + }); + }); + + it('should not render avatar if avatarUrl is not present', () => { + expect(findAvatar().exists()).toBe(false); + }); + + it('renders root element with the right classes', () => { + expect(wrapper.classes('frequent-items-list-item-container')).toBe(true); + }); + + it.each` + name | selector | expected + ${'anchor'} | ${findAllAnchors} | ${1} + ${'avatar container'} | ${findAvatarContainer} | ${1} + ${'metadata container'} | ${findAllMetadataContainers} | ${1} + ${'title'} | ${findAllTitles} | ${1} + ${'namespace'} | ${findAllNamespace} | ${1} + `('should render $expected $name', ({ selector, expected }) => { + expect(selector()).toHaveLength(expected); + }); + }); +}); diff --git a/spec/frontend/frequent_items/mock_data.js b/spec/frontend/frequent_items/mock_data.js new file mode 100644 index 00000000000..81f34053543 --- /dev/null +++ b/spec/frontend/frequent_items/mock_data.js @@ -0,0 +1,9 @@ +import { TEST_HOST } from 'helpers/test_constants'; + +export default () => ({ + id: 1, + name: 'GitLab Community Edition', + namespace: 'gitlab-org / gitlab-ce', + webUrl: `${TEST_HOST}/gitlab-org/gitlab-foss`, + avatarUrl: null, +}); diff --git a/spec/javascripts/frequent_items/components/frequent_items_list_item_spec.js b/spec/javascripts/frequent_items/components/frequent_items_list_item_spec.js deleted file mode 100644 index e3f05e89a2d..00000000000 --- a/spec/javascripts/frequent_items/components/frequent_items_list_item_spec.js +++ /dev/null @@ -1,94 +0,0 @@ -import { shallowMount, createLocalVue } from '@vue/test-utils'; -import { trimText } from 'spec/helpers/text_helper'; -import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue'; -import { mockProject } from '../mock_data'; // can also use 'mockGroup', but not useful to test here - -const localVue = createLocalVue(); - -describe('FrequentItemsListItemComponent', () => { - let wrapper; - - const createComponent = (props = {}) => { - wrapper = shallowMount(localVue.extend(frequentItemsListItemComponent), { - propsData: { - itemId: mockProject.id, - itemName: mockProject.name, - namespace: mockProject.namespace, - webUrl: mockProject.webUrl, - avatarUrl: mockProject.avatarUrl, - ...props, - }, - localVue, - }); - }; - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - describe('computed', () => { - describe('hasAvatar', () => { - it('should return `true` or `false` if whether avatar is present or not', () => { - createComponent({ avatarUrl: 'path/to/avatar.png' }); - - expect(wrapper.vm.hasAvatar).toBe(true); - }); - - it('should return `false` if avatar is not present', () => { - createComponent({ avatarUrl: null }); - - expect(wrapper.vm.hasAvatar).toBe(false); - }); - }); - - describe('highlightedItemName', () => { - it('should enclose part of project name in <b> & </b> which matches with `matcher` prop', () => { - createComponent({ matcher: 'lab' }); - - expect(wrapper.find('.js-frequent-items-item-title').html()).toContain( - '<b>L</b><b>a</b><b>b</b>', - ); - }); - - it('should return project name as it is if `matcher` is not available', () => { - createComponent({ matcher: null }); - - expect(trimText(wrapper.find('.js-frequent-items-item-title').text())).toBe( - mockProject.name, - ); - }); - }); - - describe('truncatedNamespace', () => { - it('should truncate project name from namespace string', () => { - createComponent({ namespace: 'platform / nokia-3310' }); - - expect(trimText(wrapper.find('.js-frequent-items-item-namespace').text())).toBe('platform'); - }); - - it('should truncate namespace string from the middle if it includes more than two groups in path', () => { - createComponent({ - namespace: 'platform / hardware / broadcom / Wifi Group / Mobile Chipset / nokia-3310', - }); - - expect(trimText(wrapper.find('.js-frequent-items-item-namespace').text())).toBe( - 'platform / ... / Mobile Chipset', - ); - }); - }); - }); - - describe('template', () => { - it('should render component element', () => { - createComponent(); - - expect(wrapper.classes()).toContain('frequent-items-list-item-container'); - expect(wrapper.findAll('a').length).toBe(1); - expect(wrapper.findAll('.frequent-items-item-avatar-container').length).toBe(1); - expect(wrapper.findAll('.frequent-items-item-metadata-container').length).toBe(1); - expect(wrapper.findAll('.frequent-items-item-title').length).toBe(1); - expect(wrapper.findAll('.frequent-items-item-namespace').length).toBe(1); - }); - }); -}); diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index bb5475130cf..ce6e8c731e2 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1332,6 +1332,15 @@ describe Gitlab::Database::MigrationHelpers do end end end + + context 'with other_arguments option' do + it 'queues jobs correctly' do + model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.minutes, other_arguments: [1, 2]) + + expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['FooJob', [id1, id3, 1, 2]]) + expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.minutes.from_now.to_f) + end + end end context "when the model doesn't have an ID column" do diff --git a/spec/migrations/cleanup_optimistic_locking_nulls_spec.rb b/spec/migrations/cleanup_optimistic_locking_nulls_spec.rb new file mode 100644 index 00000000000..bec8435b2f0 --- /dev/null +++ b/spec/migrations/cleanup_optimistic_locking_nulls_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20200128210353_cleanup_optimistic_locking_nulls') + +describe CleanupOptimisticLockingNulls, :migration do + TABLES = %w(epics merge_requests issues).freeze + TABLES.each do |table| + let(table.to_sym) { table(table.to_sym) } + end + let(:tables) { TABLES.map { |t| method(t.to_sym).call } } + + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:users) { table(:users)} + + before do + namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) + users.create!(id: 123, username: 'author', projects_limit: 1000) + + # Create necessary rows + epics.create!(iid: 123, group_id: 123, author_id: 123, title: 'a', title_html: 'a') + merge_requests.create!(iid: 123, target_project_id: 123, source_project_id: 123, target_branch: 'master', source_branch: 'hmm', title: 'a', title_html: 'a') + issues.create!(iid: 123, project_id: 123, title: 'a', title_html: 'a') + + # Nullify `lock_version` column for all rows + # Needs to be done with a SQL fragment, otherwise Rails will coerce it to 0 + tables.each do |table| + table.update_all('lock_version = NULL') + end + end + + it 'correctly migrates nullified lock_version column', :sidekiq_inline do + tables.each do |table| + expect(table.where(lock_version: nil).count).to eq(1) + end + + tables.each do |table| + expect(table.where(lock_version: 0).count).to eq(0) + end + + migrate! + + tables.each do |table| + expect(table.where(lock_version: nil).count).to eq(0) + end + + tables.each do |table| + expect(table.where(lock_version: 0).count).to eq(1) + end + end +end |