diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-25 15:08:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-25 15:08:50 +0000 |
commit | e06d0e779673d745972863302858105aad9032e5 (patch) | |
tree | 0ff35b27a949a164f586613004b4abfe33e7d20e /spec | |
parent | f7dae0cdcb70ecb71c1d65f099e9d96b27a4548c (diff) | |
download | gitlab-ce-e06d0e779673d745972863302858105aad9032e5.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/features/boards/sidebar_spec.rb | 10 | ||||
-rw-r--r-- | spec/features/container_registry_spec.rb | 75 | ||||
-rw-r--r-- | spec/features/groups/container_registry_spec.rb | 93 | ||||
-rw-r--r-- | spec/features/issuables/issuable_list_spec.rb | 8 | ||||
-rw-r--r-- | spec/features/issues/filtered_search/filter_issues_spec.rb | 2 | ||||
-rw-r--r-- | spec/features/labels_hierarchy_spec.rb | 6 | ||||
-rw-r--r-- | spec/features/projects/container_registry_spec.rb | 161 | ||||
-rw-r--r-- | spec/frontend/lib/utils/unit_format/formatter_factory_spec.js | 200 | ||||
-rw-r--r-- | spec/frontend/lib/utils/unit_format/index_spec.js | 117 | ||||
-rw-r--r-- | spec/helpers/labels_helper_spec.rb | 12 | ||||
-rw-r--r-- | spec/helpers/markup_helper_spec.rb | 4 | ||||
-rw-r--r-- | spec/lib/banzai/filter/label_reference_filter_spec.rb | 26 | ||||
-rw-r--r-- | spec/services/resource_events/change_milestone_service_spec.rb | 62 | ||||
-rw-r--r-- | spec/support/shared_examples/services/resource_events/change_milestone_service_shared_examples.rb | 46 |
14 files changed, 656 insertions, 166 deletions
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index c7edb574f19..e54c11f657d 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -277,7 +277,7 @@ describe 'Issue Boards', :js do wait_for_requests page.within('.value') do - expect(page).to have_selector('.badge', count: 2) + expect(page).to have_selector('.gl-label-text', count: 2) expect(page).to have_content(development.title) expect(page).to have_content(stretch.title) end @@ -299,7 +299,7 @@ describe 'Issue Boards', :js do find('.dropdown-menu-close-icon').click page.within('.value') do - expect(page).to have_selector('.badge', count: 3) + expect(page).to have_selector('.gl-label-text', count: 3) expect(page).to have_content(bug.title) end end @@ -328,7 +328,7 @@ describe 'Issue Boards', :js do find('.dropdown-menu-close-icon').click page.within('.value') do - expect(page).to have_selector('.badge', count: 4) + expect(page).to have_selector('.gl-label-text', count: 4) expect(page).to have_content(bug.title) expect(page).to have_content(regression.title) end @@ -357,13 +357,13 @@ describe 'Issue Boards', :js do find('.dropdown-menu-close-icon').click page.within('.value') do - expect(page).to have_selector('.badge', count: 1) + expect(page).to have_selector('.gl-label-text', count: 1) expect(page).not_to have_content(stretch.title) end end # 'Development' label does not show since the card is in a 'Development' list label - expect(card).to have_selector('.badge', count: 0) + expect(card).to have_selector('.gl-label-text', count: 0) expect(card).not_to have_content(stretch.title) end diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb deleted file mode 100644 index 881cad1864b..00000000000 --- a/spec/features/container_registry_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe 'Container Registry', :js do - let(:user) { create(:user) } - let(:project) { create(:project) } - - let(:container_repository) do - create(:container_repository, name: 'my/image') - end - - before do - sign_in(user) - project.add_developer(user) - stub_container_registry_config(enabled: true) - stub_container_registry_tags(repository: :any, tags: []) - stub_feature_flags(vue_container_registry_explorer: false) - end - - it 'has a page title set' do - visit_container_registry - expect(page).to have_title(_('Container Registry')) - end - - context 'when there are no image repositories' do - it 'user visits container registry main page' do - visit_container_registry - - expect(page).to have_content 'no container images' - end - end - - context 'when there are image repositories' do - before do - stub_container_registry_tags(repository: %r{my/image}, tags: %w[latest], with_manifest: true) - project.container_repositories << container_repository - end - - it 'user wants to see multi-level container repository' do - visit_container_registry - - expect(page).to have_content('my/image') - end - - it 'user removes entire container repository', :sidekiq_might_not_need_inline do - visit_container_registry - - expect_any_instance_of(ContainerRepository).to receive(:delete_tags!).and_return(true) - - click_on(class: 'js-remove-repo') - expect(find('.modal .modal-title')).to have_content 'Remove repository' - find('.modal .modal-footer .btn-danger').click - end - - it 'user removes a specific tag from container repository' do - visit_container_registry - - find('.js-toggle-repo').click - wait_for_requests - - service = double('service') - expect(service).to receive(:execute).with(container_repository) { { status: :success } } - expect(Projects::ContainerRepository::DeleteTagsService).to receive(:new).with(container_repository.project, user, tags: ['latest']) { service } - - click_on(class: 'js-delete-registry-row', visible: false) - expect(find('.modal .modal-title')).to have_content 'Remove tag' - find('.modal .modal-footer .btn-danger').click - end - end - - def visit_container_registry - visit project_container_registry_index_path(project) - end -end diff --git a/spec/features/groups/container_registry_spec.rb b/spec/features/groups/container_registry_spec.rb new file mode 100644 index 00000000000..7e3c1728f3c --- /dev/null +++ b/spec/features/groups/container_registry_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Container Registry', :js do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:project) { create(:project, namespace: group) } + + let(:container_repository) do + create(:container_repository, name: 'my/image') + end + + before do + group.add_owner(user) + sign_in(user) + stub_container_registry_config(enabled: true) + stub_container_registry_tags(repository: :any, tags: []) + end + + it 'has a page title set' do + visit_container_registry + + expect(page).to have_title _('Container Registry') + end + + context 'when there are no image repositories' do + it 'list page has no container title' do + visit_container_registry + + expect(page).to have_content _('There are no container images available in this group') + end + end + + context 'when there are image repositories' do + before do + stub_container_registry_tags(repository: %r{my/image}, tags: %w[latest], with_manifest: true) + project.container_repositories << container_repository + end + + it 'list page has a list of images' do + visit_container_registry + + expect(page).to have_content 'my/image' + end + + it 'image repository delete is disabled' do + visit_container_registry + + delete_btn = find('[title="Remove repository"]') + expect(delete_btn).to be_disabled + end + + it 'navigates to repo details' do + visit_container_registry_details('my/image') + + expect(page).to have_content 'latest' + end + + describe 'image repo details' do + before do + visit_container_registry_details 'my/image' + end + + it 'shows the details breadcrumb' do + expect(find('.breadcrumbs')).to have_link 'my/image' + end + + it 'shows the image title' do + expect(page).to have_content 'my/image tags' + end + + it 'user removes a specific tag from container repository' do + service = double('service') + expect(service).to receive(:execute).with(container_repository) { { status: :success } } + expect(Projects::ContainerRepository::DeleteTagsService).to receive(:new).with(container_repository.project, user, tags: ['latest']) { service } + + click_on(class: 'js-delete-registry') + expect(find('.modal .modal-title')).to have_content _('Remove tag') + find('.modal .modal-footer .btn-danger').click + end + end + end + + def visit_container_registry + visit group_container_registries_path(group) + end + + def visit_container_registry_details(name) + visit_container_registry + click_link(name) + end +end diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index bcc05d313ad..7014a51ccdc 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -41,10 +41,10 @@ describe 'issuable list' do visit_issuable_list(issuable_type) - expect(all('.label-link')[0].text).to have_content('B') - expect(all('.label-link')[1].text).to have_content('X') - expect(all('.label-link')[2].text).to have_content('a') - expect(all('.label-link')[3].text).to have_content('z') + expect(all('.gl-label-text')[0].text).to have_content('B') + expect(all('.gl-label-text')[1].text).to have_content('X') + expect(all('.gl-label-text')[2].text).to have_content('a') + expect(all('.gl-label-text')[3].text).to have_content('z') end end diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index ee5773f1484..a518831ea2b 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -332,7 +332,7 @@ describe 'Filter issues', :js do context 'issue label clicked' do it 'filters and displays in search bar' do - find('.issues-list .issue .issuable-main-info .issuable-info a .badge', text: multiple_words_label.title).click + find('.issues-list .issue .issuable-main-info .issuable-info a .gl-label-text', text: multiple_words_label.title).click expect_issues_list_count(1) expect_tokens([label_token("\"#{multiple_words_label.title}\"")]) diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb index c1a2e22a0c2..c66d858a019 100644 --- a/spec/features/labels_hierarchy_spec.rb +++ b/spec/features/labels_hierarchy_spec.rb @@ -161,9 +161,9 @@ describe 'Labels Hierarchy', :js do find('.btn-success').click expect(page.find('.issue-details h2.title')).to have_content('new created issue') - expect(page).to have_selector('span.badge', text: grandparent_group_label.title) - expect(page).to have_selector('span.badge', text: parent_group_label.title) - expect(page).to have_selector('span.badge', text: project_label_1.title) + expect(page).to have_selector('span.gl-label-text', text: grandparent_group_label.title) + expect(page).to have_selector('span.gl-label-text', text: parent_group_label.title) + expect(page).to have_selector('span.gl-label-text', text: project_label_1.title) end end diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb new file mode 100644 index 00000000000..02b2d03a880 --- /dev/null +++ b/spec/features/projects/container_registry_spec.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Container Registry', :js do + let(:user) { create(:user) } + let(:project) { create(:project) } + + let(:container_repository) do + create(:container_repository, name: 'my/image') + end + + before do + sign_in(user) + project.add_developer(user) + stub_container_registry_config(enabled: true) + stub_container_registry_tags(repository: :any, tags: []) + end + + describe 'Registry explorer is off' do + before do + stub_feature_flags(vue_container_registry_explorer: false) + end + + it 'has a page title set' do + visit_container_registry + + expect(page).to have_title _('Container Registry') + end + + context 'when there are no image repositories' do + it 'user visits container registry main page' do + visit_container_registry + + expect(page).to have_content _('no container images') + end + end + + context 'when there are image repositories' do + before do + stub_container_registry_tags(repository: %r{my/image}, tags: %w[latest], with_manifest: true) + project.container_repositories << container_repository + end + + it 'user wants to see multi-level container repository' do + visit_container_registry + + expect(page).to have_content 'my/image' + end + + it 'user removes entire container repository', :sidekiq_might_not_need_inline do + visit_container_registry + + expect_any_instance_of(ContainerRepository).to receive(:delete_tags!).and_return(true) + + click_on(class: 'js-remove-repo') + expect(find('.modal .modal-title')).to have_content _('Remove repository') + find('.modal .modal-footer .btn-danger').click + end + + it 'user removes a specific tag from container repository' do + visit_container_registry + + find('.js-toggle-repo').click + wait_for_requests + + service = double('service') + expect(service).to receive(:execute).with(container_repository) { { status: :success } } + expect(Projects::ContainerRepository::DeleteTagsService).to receive(:new).with(container_repository.project, user, tags: ['latest']) { service } + + click_on(class: 'js-delete-registry-row', visible: false) + expect(find('.modal .modal-title')).to have_content _('Remove tag') + find('.modal .modal-footer .btn-danger').click + end + end + end + + describe 'Registry explorer is on' do + it 'has a page title set' do + visit_container_registry + + expect(page).to have_title _('Container Registry') + end + + context 'when there are no image repositories' do + it 'list page has no container title' do + visit_container_registry + + expect(page).to have_content _('There are no container images stored for this project') + end + + it 'list page has quickstart' do + visit_container_registry + + expect(page).to have_content _('Quick Start') + end + end + + context 'when there are image repositories' do + before do + stub_container_registry_tags(repository: %r{my/image}, tags: %w[latest], with_manifest: true) + project.container_repositories << container_repository + end + + it 'list page has a list of images' do + visit_container_registry + + expect(page).to have_content 'my/image' + end + + it 'user removes entire container repository', :sidekiq_might_not_need_inline do + visit_container_registry + + expect_any_instance_of(ContainerRepository).to receive(:delete_tags!).and_return(true) + + find('[title="Remove repository"]').click + expect(find('.modal .modal-title')).to have_content _('Remove repository') + find('.modal .modal-footer .btn-danger').click + end + + it 'navigates to repo details' do + visit_container_registry_details('my/image') + + expect(page).to have_content 'latest' + end + + describe 'image repo details' do + before do + visit_container_registry_details 'my/image' + end + + it 'shows the details breadcrumb' do + expect(find('.breadcrumbs')).to have_link 'my/image' + end + + it 'shows the image title' do + expect(page).to have_content 'my/image tags' + end + + it 'user removes a specific tag from container repository' do + service = double('service') + expect(service).to receive(:execute).with(container_repository) { { status: :success } } + expect(Projects::ContainerRepository::DeleteTagsService).to receive(:new).with(container_repository.project, user, tags: ['latest']) { service } + + click_on(class: 'js-delete-registry') + expect(find('.modal .modal-title')).to have_content _('Remove tag') + find('.modal .modal-footer .btn-danger').click + end + end + end + end + + def visit_container_registry + visit project_container_registry_index_path(project) + end + + def visit_container_registry_details(name) + visit_container_registry + click_link(name) + end +end diff --git a/spec/frontend/lib/utils/unit_format/formatter_factory_spec.js b/spec/frontend/lib/utils/unit_format/formatter_factory_spec.js new file mode 100644 index 00000000000..071ecde6a6d --- /dev/null +++ b/spec/frontend/lib/utils/unit_format/formatter_factory_spec.js @@ -0,0 +1,200 @@ +import { + numberFormatter, + suffixFormatter, + scaledSIFormatter, +} from '~/lib/utils/unit_format/formatter_factory'; + +describe('unit_format/formatter_factory', () => { + describe('numberFormatter', () => { + let formatNumber; + beforeEach(() => { + formatNumber = numberFormatter(); + }); + + it('formats a integer', () => { + expect(formatNumber(1)).toEqual('1'); + expect(formatNumber(100)).toEqual('100'); + expect(formatNumber(1000)).toEqual('1,000'); + expect(formatNumber(10000)).toEqual('10,000'); + expect(formatNumber(1000000)).toEqual('1,000,000'); + }); + + it('formats a floating point number', () => { + expect(formatNumber(0.1)).toEqual('0.1'); + expect(formatNumber(0.1, 0)).toEqual('0'); + expect(formatNumber(0.1, 2)).toEqual('0.10'); + expect(formatNumber(0.1, 3)).toEqual('0.100'); + + expect(formatNumber(12.345)).toEqual('12.345'); + expect(formatNumber(12.345, 2)).toEqual('12.35'); + expect(formatNumber(12.345, 4)).toEqual('12.3450'); + }); + + it('formats a large integer with a length limit', () => { + expect(formatNumber(10 ** 7, undefined)).toEqual('10,000,000'); + expect(formatNumber(10 ** 7, undefined, 9)).toEqual('1.00e+7'); + expect(formatNumber(10 ** 7, undefined, 10)).toEqual('10,000,000'); + }); + }); + + describe('suffixFormatter', () => { + let formatSuffix; + beforeEach(() => { + formatSuffix = suffixFormatter('pop.', undefined); + }); + + it('formats a integer', () => { + expect(formatSuffix(1)).toEqual('1pop.'); + expect(formatSuffix(100)).toEqual('100pop.'); + expect(formatSuffix(1000)).toEqual('1,000pop.'); + expect(formatSuffix(10000)).toEqual('10,000pop.'); + expect(formatSuffix(1000000)).toEqual('1,000,000pop.'); + }); + + it('formats a floating point number', () => { + expect(formatSuffix(0.1)).toEqual('0.1pop.'); + expect(formatSuffix(0.1, 0)).toEqual('0pop.'); + expect(formatSuffix(0.1, 2)).toEqual('0.10pop.'); + expect(formatSuffix(0.1, 3)).toEqual('0.100pop.'); + + expect(formatSuffix(12.345)).toEqual('12.345pop.'); + expect(formatSuffix(12.345, 2)).toEqual('12.35pop.'); + expect(formatSuffix(12.345, 4)).toEqual('12.3450pop.'); + }); + + it('formats a negative integer', () => { + expect(formatSuffix(-1)).toEqual('-1pop.'); + expect(formatSuffix(-100)).toEqual('-100pop.'); + expect(formatSuffix(-1000)).toEqual('-1,000pop.'); + expect(formatSuffix(-10000)).toEqual('-10,000pop.'); + expect(formatSuffix(-1000000)).toEqual('-1,000,000pop.'); + }); + + it('formats a floating point nugative number', () => { + expect(formatSuffix(-0.1)).toEqual('-0.1pop.'); + expect(formatSuffix(-0.1, 0)).toEqual('-0pop.'); + expect(formatSuffix(-0.1, 2)).toEqual('-0.10pop.'); + expect(formatSuffix(-0.1, 3)).toEqual('-0.100pop.'); + + expect(formatSuffix(-12.345)).toEqual('-12.345pop.'); + expect(formatSuffix(-12.345, 2)).toEqual('-12.35pop.'); + expect(formatSuffix(-12.345, 4)).toEqual('-12.3450pop.'); + }); + + it('formats a large integer', () => { + expect(formatSuffix(10 ** 7)).toEqual('10,000,000pop.'); + expect(formatSuffix(10 ** 10)).toEqual('10,000,000,000pop.'); + }); + + it('formats a large integer with a length limit', () => { + expect(formatSuffix(10 ** 7, undefined, 10)).toEqual('1.00e+7pop.'); + expect(formatSuffix(10 ** 10, undefined, 10)).toEqual('1.00e+10pop.'); + }); + }); + + describe('scaledSIFormatter', () => { + describe('scaled format', () => { + let formatScaled; + + beforeEach(() => { + formatScaled = scaledSIFormatter('B'); + }); + + it('formats bytes', () => { + expect(formatScaled(12.345)).toEqual('12.345B'); + expect(formatScaled(12.345, 0)).toEqual('12B'); + expect(formatScaled(12.345, 1)).toEqual('12.3B'); + expect(formatScaled(12.345, 2)).toEqual('12.35B'); + }); + + it('formats bytes in a scale', () => { + expect(formatScaled(1)).toEqual('1B'); + expect(formatScaled(10)).toEqual('10B'); + expect(formatScaled(10 ** 2)).toEqual('100B'); + expect(formatScaled(10 ** 3)).toEqual('1kB'); + expect(formatScaled(10 ** 4)).toEqual('10kB'); + expect(formatScaled(10 ** 5)).toEqual('100kB'); + expect(formatScaled(10 ** 6)).toEqual('1MB'); + expect(formatScaled(10 ** 7)).toEqual('10MB'); + expect(formatScaled(10 ** 8)).toEqual('100MB'); + expect(formatScaled(10 ** 9)).toEqual('1GB'); + expect(formatScaled(10 ** 10)).toEqual('10GB'); + expect(formatScaled(10 ** 11)).toEqual('100GB'); + }); + }); + + describe('scaled format with offset', () => { + let formatScaled; + + beforeEach(() => { + // formats gigabytes + formatScaled = scaledSIFormatter('B', 3); + }); + + it('formats floating point numbers', () => { + expect(formatScaled(12.345)).toEqual('12.345GB'); + expect(formatScaled(12.345, 0)).toEqual('12GB'); + expect(formatScaled(12.345, 1)).toEqual('12.3GB'); + expect(formatScaled(12.345, 2)).toEqual('12.35GB'); + }); + + it('formats large numbers scaled', () => { + expect(formatScaled(1)).toEqual('1GB'); + expect(formatScaled(1, 1)).toEqual('1.0GB'); + expect(formatScaled(10)).toEqual('10GB'); + expect(formatScaled(10 ** 2)).toEqual('100GB'); + expect(formatScaled(10 ** 3)).toEqual('1TB'); + expect(formatScaled(10 ** 4)).toEqual('10TB'); + expect(formatScaled(10 ** 5)).toEqual('100TB'); + expect(formatScaled(10 ** 6)).toEqual('1PB'); + expect(formatScaled(10 ** 7)).toEqual('10PB'); + expect(formatScaled(10 ** 8)).toEqual('100PB'); + expect(formatScaled(10 ** 9)).toEqual('1EB'); + }); + + it('formatting of too large numbers is not suported', () => { + // formatting YB is out of range + expect(() => scaledSIFormatter('B', 9)).toThrow(); + }); + }); + + describe('scaled format with negative offset', () => { + let formatScaled; + + beforeEach(() => { + formatScaled = scaledSIFormatter('g', -1); + }); + + it('formats floating point numbers', () => { + expect(formatScaled(12.345)).toEqual('12.345mg'); + expect(formatScaled(12.345, 0)).toEqual('12mg'); + expect(formatScaled(12.345, 1)).toEqual('12.3mg'); + expect(formatScaled(12.345, 2)).toEqual('12.35mg'); + }); + + it('formats large numbers scaled', () => { + expect(formatScaled(1)).toEqual('1mg'); + expect(formatScaled(1, 1)).toEqual('1.0mg'); + expect(formatScaled(10)).toEqual('10mg'); + expect(formatScaled(10 ** 2)).toEqual('100mg'); + expect(formatScaled(10 ** 3)).toEqual('1g'); + expect(formatScaled(10 ** 4)).toEqual('10g'); + expect(formatScaled(10 ** 5)).toEqual('100g'); + expect(formatScaled(10 ** 6)).toEqual('1kg'); + expect(formatScaled(10 ** 7)).toEqual('10kg'); + expect(formatScaled(10 ** 8)).toEqual('100kg'); + }); + + it('formats negative numbers scaled', () => { + expect(formatScaled(-12.345)).toEqual('-12.345mg'); + expect(formatScaled(-12.345, 0)).toEqual('-12mg'); + expect(formatScaled(-12.345, 1)).toEqual('-12.3mg'); + expect(formatScaled(-12.345, 2)).toEqual('-12.35mg'); + + expect(formatScaled(-10)).toEqual('-10mg'); + expect(formatScaled(-100)).toEqual('-100mg'); + expect(formatScaled(-(10 ** 4))).toEqual('-10g'); + }); + }); + }); +}); diff --git a/spec/frontend/lib/utils/unit_format/index_spec.js b/spec/frontend/lib/utils/unit_format/index_spec.js new file mode 100644 index 00000000000..e0991f2909b --- /dev/null +++ b/spec/frontend/lib/utils/unit_format/index_spec.js @@ -0,0 +1,117 @@ +import { getFormatter, SUPPORTED_FORMATS } from '~/lib/utils/unit_format'; + +describe('unit_format', () => { + describe('when a supported format is provided, the returned function formats', () => { + it('numbers, by default', () => { + expect(getFormatter()(1)).toEqual('1'); + }); + + it('numbers', () => { + const formatNumber = getFormatter(SUPPORTED_FORMATS.number); + + expect(formatNumber(1)).toEqual('1'); + expect(formatNumber(100)).toEqual('100'); + expect(formatNumber(1000)).toEqual('1,000'); + expect(formatNumber(10000)).toEqual('10,000'); + expect(formatNumber(1000000)).toEqual('1,000,000'); + }); + + it('percent', () => { + const formatPercent = getFormatter(SUPPORTED_FORMATS.percent); + + expect(formatPercent(1)).toEqual('100%'); + expect(formatPercent(1, 2)).toEqual('100.00%'); + + expect(formatPercent(0.1)).toEqual('10%'); + expect(formatPercent(0.5)).toEqual('50%'); + + expect(formatPercent(0.888888)).toEqual('89%'); + expect(formatPercent(0.888888, 2)).toEqual('88.89%'); + expect(formatPercent(0.888888, 5)).toEqual('88.88880%'); + + expect(formatPercent(2)).toEqual('200%'); + expect(formatPercent(10)).toEqual('1,000%'); + }); + + it('percentunit', () => { + const formatPercentHundred = getFormatter(SUPPORTED_FORMATS.percentHundred); + + expect(formatPercentHundred(1)).toEqual('1%'); + expect(formatPercentHundred(1, 2)).toEqual('1.00%'); + + expect(formatPercentHundred(88.8888)).toEqual('89%'); + expect(formatPercentHundred(88.8888, 2)).toEqual('88.89%'); + expect(formatPercentHundred(88.8888, 5)).toEqual('88.88880%'); + + expect(formatPercentHundred(100)).toEqual('100%'); + expect(formatPercentHundred(100, 2)).toEqual('100.00%'); + + expect(formatPercentHundred(200)).toEqual('200%'); + expect(formatPercentHundred(1000)).toEqual('1,000%'); + }); + + it('seconds', () => { + expect(getFormatter(SUPPORTED_FORMATS.seconds)(1)).toEqual('1s'); + }); + + it('miliseconds', () => { + const formatMiliseconds = getFormatter(SUPPORTED_FORMATS.miliseconds); + + expect(formatMiliseconds(1)).toEqual('1ms'); + expect(formatMiliseconds(100)).toEqual('100ms'); + expect(formatMiliseconds(1000)).toEqual('1,000ms'); + expect(formatMiliseconds(10000)).toEqual('10,000ms'); + expect(formatMiliseconds(1000000)).toEqual('1,000,000ms'); + }); + + it('bytes', () => { + const formatBytes = getFormatter(SUPPORTED_FORMATS.bytes); + + expect(formatBytes(1)).toEqual('1B'); + expect(formatBytes(1, 1)).toEqual('1.0B'); + + expect(formatBytes(10)).toEqual('10B'); + expect(formatBytes(10 ** 2)).toEqual('100B'); + expect(formatBytes(10 ** 3)).toEqual('1kB'); + expect(formatBytes(10 ** 4)).toEqual('10kB'); + expect(formatBytes(10 ** 5)).toEqual('100kB'); + expect(formatBytes(10 ** 6)).toEqual('1MB'); + expect(formatBytes(10 ** 7)).toEqual('10MB'); + expect(formatBytes(10 ** 8)).toEqual('100MB'); + expect(formatBytes(10 ** 9)).toEqual('1GB'); + expect(formatBytes(10 ** 10)).toEqual('10GB'); + expect(formatBytes(10 ** 11)).toEqual('100GB'); + }); + + it('kilobytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.kilobytes)(1)).toEqual('1kB'); + expect(getFormatter(SUPPORTED_FORMATS.kilobytes)(1, 1)).toEqual('1.0kB'); + }); + + it('megabytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.megabytes)(1)).toEqual('1MB'); + expect(getFormatter(SUPPORTED_FORMATS.megabytes)(1, 1)).toEqual('1.0MB'); + }); + + it('gigabytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.gigabytes)(1)).toEqual('1GB'); + expect(getFormatter(SUPPORTED_FORMATS.gigabytes)(1, 1)).toEqual('1.0GB'); + }); + + it('terabytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.terabytes)(1)).toEqual('1TB'); + expect(getFormatter(SUPPORTED_FORMATS.terabytes)(1, 1)).toEqual('1.0TB'); + }); + + it('petabytes', () => { + expect(getFormatter(SUPPORTED_FORMATS.petabytes)(1)).toEqual('1PB'); + expect(getFormatter(SUPPORTED_FORMATS.petabytes)(1, 1)).toEqual('1.0PB'); + }); + }); + + describe('when get formatter format is incorrect', () => { + it('formatter fails', () => { + expect(() => getFormatter('not-supported')(1)).toThrow(); + }); + }); +}); diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index f5771405687..322390c3840 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -56,7 +56,7 @@ describe LabelsHelper do context 'without subject' do it "uses the label's project" do - expect(link_to_label(label_presenter)).to match %r{<a href="/#{label.project.full_path}/issues\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter)).to match %r{<a.*href="/#{label.project.full_path}/issues\?label_name%5B%5D=#{label.name}".*>.*</a>}m end end @@ -65,7 +65,7 @@ describe LabelsHelper do let(:subject) { build(:project, namespace: namespace, name: 'bar3') } it 'links to project issues page' do - expect(link_to_label(label_presenter)).to match %r{<a href="/foo3/bar3/issues\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter)).to match %r{<a.*href="/foo3/bar3/issues\?label_name%5B%5D=#{label.name}".*>.*</a>}m end end @@ -73,7 +73,7 @@ describe LabelsHelper do let(:subject) { build(:group, name: 'bar') } it 'links to group issues page' do - expect(link_to_label(label_presenter)).to match %r{<a href="/groups/bar/-/issues\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter)).to match %r{<a.*href="/groups/bar/-/issues\?label_name%5B%5D=#{label.name}".*>.*</a>}m end end @@ -81,7 +81,7 @@ describe LabelsHelper do ['issue', :issue].each do |type| context "set to #{type}" do it 'links to correct page' do - expect(link_to_label(label_presenter, type: type)).to match %r{<a href="/#{label.project.full_path}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter, type: type)).to match %r{<a.*href="/#{label.project.full_path}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}".*>.*</a>}m end end end @@ -89,7 +89,7 @@ describe LabelsHelper do ['merge_request', :merge_request].each do |type| context "set to #{type}" do it 'links to correct page' do - expect(link_to_label(label_presenter, type: type)).to match %r{<a href="/#{label.project.full_path}/-/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label_presenter, type: type)).to match %r{<a.*href="/#{label.project.full_path}/-/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}".*>.*</a>}m end end end @@ -113,7 +113,7 @@ describe LabelsHelper do context 'without block' do it 'uses render_colored_label as the link content' do expect(self).to receive(:render_colored_label) - .with(label_presenter, tooltip: true).and_return('Foo') + .with(label_presenter).and_return('Foo') expect(link_to_label(label_presenter)).to match('Foo') end end diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 3fb36e540b6..c22e20f0e73 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -537,8 +537,10 @@ describe MarkupHelper do it 'does not style a label that can not be accessed by current_user' do project = create(:project, :private) + label = create_and_format_label(project) - expect(create_and_format_label(project)).to eq("<p>#{label_title}</p>") + expect(label).to include("~label_1") + expect(label).not_to match(/span class=.*style=.*/) end end diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 82df5064896..5a672de13d7 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -28,7 +28,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'includes default classes' do doc = reference_filter("Label #{reference}") - expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label has-tooltip' + expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label has-tooltip gl-link gl-label-link' end it 'includes a data-project attribute' do @@ -66,12 +66,12 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'label span element' do it 'includes default classes' do doc = reference_filter("Label #{reference}") - expect(doc.css('a span').first.attr('class')).to eq 'badge color-label has-tooltip' + expect(doc.css('a span').first.attr('class')).to include 'gl-label-text' end it 'includes a style attribute' do doc = reference_filter("Label #{reference}") - expect(doc.css('a span').first.attr('style')).to match(/\Abackground-color: #\h{6}; color: #\h{6}\z/) + expect(doc.css('a span').first.attr('style')).to match(/\Abackground-color: #\h{6}\z/) end end @@ -85,7 +85,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\))) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>#{label.name}</span></a></span>\.\))) end it 'ignores invalid label IDs' do @@ -109,7 +109,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}).") - expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\)\.)) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>#{label.name}</span></a></span>\)\.)) end it 'ignores invalid label names' do @@ -133,7 +133,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}).") - expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\)\.)) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>#{label.name}</span></a></span>\)\.)) end it 'ignores invalid label names' do @@ -158,7 +158,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'does not include trailing punctuation', :aggregate_failures do ['.', ', ok?', '...', '?', '!', ': is that ok?'].each do |trailing_punctuation| doc = filter("Label #{reference}#{trailing_punctuation}") - expect(doc.to_html).to match(%r(<a.+><span.+>\?g\.fm&</span></a>#{Regexp.escape(trailing_punctuation)})) + expect(doc.to_html).to match(%r(<span.+><a.+><span.+>\?g\.fm&</span></a></span>#{Regexp.escape(trailing_punctuation)})) end end @@ -184,7 +184,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\))) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>#{label.name}</span></a></span>\.\))) end it 'ignores invalid label names' do @@ -208,7 +208,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\))) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>#{label.name}</span></a></span>\.\))) end it 'ignores invalid label names' do @@ -232,7 +232,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(<a.+><span.+>g\.fm & references\?</span></a>\.\))) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>g\.fm & references\?</span></a></span>\.\))) end it 'ignores invalid label names' do @@ -320,7 +320,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(<a.+>Label</a>\.\))) + expect(doc.to_html).to match(%r(\(<span.+><a.+>Label</a></span>\.\))) end it 'includes a data-project attribute' do @@ -358,7 +358,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(<a.+><span.+>#{group_label.name}</span></a>\.\))) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>#{group_label.name}</span></a></span>\.\))) end it 'ignores invalid label names' do @@ -381,7 +381,7 @@ describe Banzai::Filter::LabelReferenceFilter do it 'links with adjacent text' do doc = reference_filter("Label (#{reference}.)") - expect(doc.to_html).to match(%r(\(<a.+><span.+>#{group_label.name}</span></a>\.\))) + expect(doc.to_html).to match(%r(\(<span.+><a.+><span.+>#{group_label.name}</span></a></span>\.\))) end it 'ignores invalid label names' do diff --git a/spec/services/resource_events/change_milestone_service_spec.rb b/spec/services/resource_events/change_milestone_service_spec.rb index c6b4f8e1b7e..bc634fadadd 100644 --- a/spec/services/resource_events/change_milestone_service_spec.rb +++ b/spec/services/resource_events/change_milestone_service_spec.rb @@ -3,65 +3,11 @@ require 'spec_helper' describe ResourceEvents::ChangeMilestoneService do - shared_examples 'milestone events creator' do - let_it_be(:user) { create(:user) } - - let_it_be(:milestone) { create(:milestone) } - - context 'when milestone is present' do - before do - resource.milestone = milestone - end - - let(:service) { described_class.new(resource: resource, user: user, created_at: created_at_time) } - - it 'creates the expected event record' do - expect { service.execute }.to change { ResourceMilestoneEvent.count }.from(0).to(1) - - events = ResourceMilestoneEvent.all - - expect(events.size).to eq(1) - expect_event_record(events.first, action: 'add', milestone: milestone, state: 'opened') - end - end - - context 'when milestones is not present' do - before do - resource.milestone = nil - end - - let(:service) { described_class.new(resource: resource, user: user, created_at: created_at_time) } - - it 'creates the expected event records' do - expect { service.execute }.to change { ResourceMilestoneEvent.count }.from(0).to(1) - - expect_event_record(ResourceMilestoneEvent.first, action: 'remove', milestone: nil, state: 'opened') - end - end - - def expect_event_record(event, expected_attrs) - expect(event.action).to eq(expected_attrs[:action]) - expect(event.state).to eq(expected_attrs[:state]) - expect(event.user).to eq(user) - expect(event.issue).to eq(resource) if resource.is_a?(Issue) - expect(event.issue).to be_nil unless resource.is_a?(Issue) - expect(event.merge_request).to eq(resource) if resource.is_a?(MergeRequest) - expect(event.merge_request).to be_nil unless resource.is_a?(MergeRequest) - expect(event.milestone).to eq(expected_attrs[:milestone]) - expect(event.created_at).to eq(created_at_time) - end - end - - let_it_be(:merge_request) { create(:merge_request) } - let_it_be(:issue) { create(:issue) } - - let!(:created_at_time) { Time.utc(2019, 12, 30) } - - it_behaves_like 'milestone events creator' do - let(:resource) { issue } + it_behaves_like 'a milestone events creator' do + let(:resource) { create(:issue) } end - it_behaves_like 'milestone events creator' do - let(:resource) { merge_request } + it_behaves_like 'a milestone events creator' do + let(:resource) { create(:merge_request) } end end diff --git a/spec/support/shared_examples/services/resource_events/change_milestone_service_shared_examples.rb b/spec/support/shared_examples/services/resource_events/change_milestone_service_shared_examples.rb new file mode 100644 index 00000000000..77f64e5e8f8 --- /dev/null +++ b/spec/support/shared_examples/services/resource_events/change_milestone_service_shared_examples.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +shared_examples 'a milestone events creator' do + let_it_be(:user) { create(:user) } + + let(:created_at_time) { Time.utc(2019, 12, 30) } + let(:service) { described_class.new(resource, user, created_at: created_at_time) } + + context 'when milestone is present' do + let_it_be(:milestone) { create(:milestone) } + + before do + resource.milestone = milestone + end + + it 'creates the expected event record' do + expect { service.execute }.to change { ResourceMilestoneEvent.count }.by(1) + + expect_event_record(ResourceMilestoneEvent.last, action: 'add', milestone: milestone, state: 'opened') + end + end + + context 'when milestones is not present' do + before do + resource.milestone = nil + end + + it 'creates the expected event records' do + expect { service.execute }.to change { ResourceMilestoneEvent.count }.by(1) + + expect_event_record(ResourceMilestoneEvent.last, action: 'remove', milestone: nil, state: 'opened') + end + end + + def expect_event_record(event, expected_attrs) + expect(event.action).to eq(expected_attrs[:action]) + expect(event.state).to eq(expected_attrs[:state]) + expect(event.user).to eq(user) + expect(event.issue).to eq(resource) if resource.is_a?(Issue) + expect(event.issue).to be_nil unless resource.is_a?(Issue) + expect(event.merge_request).to eq(resource) if resource.is_a?(MergeRequest) + expect(event.merge_request).to be_nil unless resource.is_a?(MergeRequest) + expect(event.milestone).to eq(expected_attrs[:milestone]) + expect(event.created_at).to eq(created_at_time) + end +end |