diff options
Diffstat (limited to 'spec')
13 files changed, 249 insertions, 48 deletions
diff --git a/spec/controllers/profiles/emails_controller_spec.rb b/spec/controllers/profiles/emails_controller_spec.rb index 246f8a6cd76..08552cc28fa 100644 --- a/spec/controllers/profiles/emails_controller_spec.rb +++ b/spec/controllers/profiles/emails_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Profiles::EmailsController do - let(:user) { create(:user) } + let_it_be(:user) { create(:user) } before do sign_in(user) @@ -16,36 +16,43 @@ RSpec.describe Profiles::EmailsController do end describe '#create' do - context 'when email address is valid' do - let(:email_params) { { email: "add_email@example.com" } } + let(:email) { 'add_email@example.com' } + let(:params) { { email: { email: email } } } - it 'sends an email confirmation' do - expect { post(:create, params: { email: email_params }) }.to change { ActionMailer::Base.deliveries.size } - end + subject { post(:create, params: params) } + + it 'sends an email confirmation' do + expect { subject }.to change { ActionMailer::Base.deliveries.size } end context 'when email address is invalid' do - let(:email_params) { { email: "test.@example.com" } } + let(:email) { 'invalid.@example.com' } it 'does not send an email confirmation' do - expect { post(:create, params: { email: email_params }) }.not_to change { ActionMailer::Base.deliveries.size } + expect { subject }.not_to change { ActionMailer::Base.deliveries.size } end end end describe '#resend_confirmation_instructions' do - let(:email_params) { { email: "add_email@example.com" } } + let_it_be(:email) { create(:email, user: user) } + let(:params) { { id: email.id } } + + subject { put(:resend_confirmation_instructions, params: params) } it 'resends an email confirmation' do - email = user.emails.create(email: 'add_email@example.com') + expect { subject }.to change { ActionMailer::Base.deliveries.size } - expect { put(:resend_confirmation_instructions, params: { id: email }) }.to change { ActionMailer::Base.deliveries.size } - expect(ActionMailer::Base.deliveries.last.to).to eq [email_params[:email]] - expect(ActionMailer::Base.deliveries.last.subject).to match "Confirmation instructions" + expect(ActionMailer::Base.deliveries.last.to).to eq [email.email] + expect(ActionMailer::Base.deliveries.last.subject).to match 'Confirmation instructions' end - it 'unable to resend an email confirmation' do - expect { put(:resend_confirmation_instructions, params: { id: 1 }) }.not_to change { ActionMailer::Base.deliveries.size } + context 'email does not exist' do + let(:params) { { id: non_existing_record_id } } + + it 'does not send an email confirmation' do + expect { subject }.not_to change { ActionMailer::Base.deliveries.size } + end end end end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 9bfd3319ff1..55c92fa353e 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -279,7 +279,8 @@ RSpec.describe "Admin::Users" do expect(page).to have_content(user.email) expect(page).to have_content(user.name) - expect(page).to have_content(user.id) + expect(page).to have_content("ID: #{user.id}") + expect(page).to have_content("Namespace ID: #{user.namespace_id}") expect(page).to have_button('Deactivate user') expect(page).to have_button('Block user') expect(page).to have_button('Delete user') diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index ed28ec6099d..a3eacd6147c 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -3,44 +3,53 @@ require 'spec_helper' RSpec.describe 'Tooltips on .timeago dates', :js do - let(:user) { create(:user) } - let(:project) { create(:project, name: 'test', namespace: user.namespace) } - let(:created_date) { Date.yesterday.to_time } - let(:expected_format) { created_date.in_time_zone.strftime('%b %-d, %Y %l:%M%P') } + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, name: 'test', namespace: user.namespace) } + let(:created_date) { 1.day.ago.beginning_of_minute - 1.hour } + + before_all do + project.add_maintainer(user) + end context 'on the activity tab' do before do - project.add_maintainer(user) - Event.create( project: project, author_id: user.id, action: :joined, updated_at: created_date, created_at: created_date) sign_in user visit user_activity_path(user) wait_for_requests - - page.find('.js-timeago').hover end it 'has the datetime formated correctly' do - expect(page).to have_selector('.local-timeago', text: expected_format) + expect(page).to have_selector('.js-timeago', text: '1 day ago') + + page.find('.js-timeago').hover + + expect(datetime_in_tooltip).to eq(created_date) end end context 'on the snippets tab' do before do - project.add_maintainer(user) create(:snippet, author: user, updated_at: created_date, created_at: created_date) sign_in user visit user_snippets_path(user) wait_for_requests - - page.find('.js-timeago.snippet-created-ago').hover end it 'has the datetime formated correctly' do - expect(page).to have_selector('.local-timeago', text: expected_format) + expect(page).to have_selector('.js-timeago.snippet-created-ago', text: '1 day ago') + + page.find('.js-timeago.snippet-created-ago').hover + + expect(datetime_in_tooltip).to eq(created_date) end end + + def datetime_in_tooltip + datetime_text = page.find('.local-timeago').text + DateTime.parse(datetime_text) + end end diff --git a/spec/frontend/design_management/components/design_todo_button_spec.js b/spec/frontend/design_management/components/design_todo_button_spec.js index 950876108ee..451c23f0fea 100644 --- a/spec/frontend/design_management/components/design_todo_button_spec.js +++ b/spec/frontend/design_management/components/design_todo_button_spec.js @@ -52,6 +52,7 @@ describe('Design management design todo button', () => { afterEach(() => { wrapper.destroy(); wrapper = null; + jest.clearAllMocks(); }); it('renders TodoButton component', () => { @@ -68,7 +69,14 @@ describe('Design management design todo button', () => { }); describe('when clicked', () => { + let dispatchEventSpy; + beforeEach(() => { + dispatchEventSpy = jest.spyOn(document, 'dispatchEvent'); + jest.spyOn(document, 'querySelector').mockReturnValue({ + innerText: 2, + }); + createComponent({ design: mockDesignWithPendingTodos }, { mountFn: mount }); wrapper.trigger('click'); return wrapper.vm.$nextTick(); @@ -86,6 +94,14 @@ describe('Design management design todo button', () => { expect(mutate).toHaveBeenCalledTimes(1); expect(mutate).toHaveBeenCalledWith(todoMarkDoneMutationVariables); }); + + it('calls dispatchDocumentEvent to update global To-Do counter correctly', () => { + const dispatchedEvent = dispatchEventSpy.mock.calls[0][0]; + + expect(dispatchEventSpy).toHaveBeenCalledTimes(1); + expect(dispatchedEvent.detail).toEqual({ count: 1 }); + expect(dispatchedEvent.type).toBe('todo:toggle'); + }); }); }); @@ -99,7 +115,14 @@ describe('Design management design todo button', () => { }); describe('when clicked', () => { + let dispatchEventSpy; + beforeEach(() => { + dispatchEventSpy = jest.spyOn(document, 'dispatchEvent'); + jest.spyOn(document, 'querySelector').mockReturnValue({ + innerText: 2, + }); + createComponent({}, { mountFn: mount }); wrapper.trigger('click'); return wrapper.vm.$nextTick(); @@ -112,6 +135,7 @@ describe('Design management design todo button', () => { variables: { atVersion: null, filenames: ['my-design.jpg'], + designId: '1', issueId: '1', issueIid: '10', projectPath: 'project-path', @@ -121,6 +145,14 @@ describe('Design management design todo button', () => { expect(mutate).toHaveBeenCalledTimes(1); expect(mutate).toHaveBeenCalledWith(createDesignTodoMutationVariables); }); + + it('calls dispatchDocumentEvent to update global To-Do counter correctly', () => { + const dispatchedEvent = dispatchEventSpy.mock.calls[0][0]; + + expect(dispatchEventSpy).toHaveBeenCalledTimes(1); + expect(dispatchedEvent.detail).toEqual({ count: 3 }); + expect(dispatchedEvent.type).toBe('todo:toggle'); + }); }); }); }); diff --git a/spec/frontend/header_spec.js b/spec/frontend/header_spec.js index 59a8ca2ed23..27305abfafa 100644 --- a/spec/frontend/header_spec.js +++ b/spec/frontend/header_spec.js @@ -4,7 +4,7 @@ import initTodoToggle, { initNavUserDropdownTracking } from '~/header'; describe('Header', () => { describe('Todos notification', () => { - const todosPendingCount = '.todos-count'; + const todosPendingCount = '.js-todos-count'; const fixtureTemplate = 'issues/open-issue.html'; function isTodosCountHidden() { diff --git a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap index 4b1346925cc..6aaefed92d0 100644 --- a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap +++ b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap @@ -40,7 +40,7 @@ exports[`packages_list_row renders 1`] = ` </div> <div - class="gl-text-gray-500 gl-mt-1 gl-min-h-6 gl-min-w-0 gl-flex-fill-1" + class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1 gl-min-h-6 gl-min-w-0 gl-flex-fill-1" > <div class="gl-display-flex" @@ -94,7 +94,7 @@ exports[`packages_list_row renders 1`] = ` class="gl-display-flex gl-flex-direction-column gl-sm-align-items-flex-end gl-justify-content-space-between gl-text-gray-500 gl-flex-shrink-0" > <div - class="gl-sm-text-body gl-sm-font-weight-bold gl-min-h-6" + class="gl-display-flex gl-align-items-center gl-sm-text-body gl-sm-font-weight-bold gl-min-h-6" > <publish-method-stub packageentity="[object Object]" @@ -102,11 +102,13 @@ exports[`packages_list_row renders 1`] = ` </div> <div - class="gl-mt-1 gl-min-h-6" + class="gl-display-flex gl-align-items-center gl-mt-1 gl-min-h-6" > - <gl-sprintf-stub - message="Created %{timestamp}" - /> + <span> + <gl-sprintf-stub + message="Created %{timestamp}" + /> + </span> </div> </div> </div> diff --git a/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap index 55ac86f9c49..9a0c52cee47 100644 --- a/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap +++ b/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap @@ -2,7 +2,7 @@ exports[`publish_method renders 1`] = ` <div - class="gl-display-flex gl-align-items-center gl-mb-2" + class="gl-display-flex gl-align-items-center" > <gl-icon-stub class="gl-mr-2" diff --git a/spec/frontend/tooltips/components/tooltips_spec.js b/spec/frontend/tooltips/components/tooltips_spec.js index 1a97c7c9111..0edc5248629 100644 --- a/spec/frontend/tooltips/components/tooltips_spec.js +++ b/spec/frontend/tooltips/components/tooltips_spec.js @@ -120,7 +120,7 @@ describe('tooltips/components/tooltips.vue', () => { wrapper.vm.addTooltips([target, createTooltipTarget()]); await wrapper.vm.$nextTick(); - wrapper.vm.dispose([target]); + wrapper.vm.dispose(target); await wrapper.vm.$nextTick(); expect(allTooltips()).toHaveLength(1); @@ -148,6 +148,48 @@ describe('tooltips/components/tooltips.vue', () => { }); }); + describe('triggerEvent', () => { + it('triggers a bootstrap-vue tooltip global event for the tooltip specified', async () => { + const target = createTooltipTarget(); + const event = 'hide'; + + buildWrapper(); + + wrapper.vm.addTooltips([target]); + + await wrapper.vm.$nextTick(); + + wrapper.vm.triggerEvent(target, event); + + expect(wrapper.find(GlTooltip).emitted(event)).toHaveLength(1); + }); + }); + + describe('fixTitle', () => { + it('updates tooltip content with the latest value the target title property', async () => { + const target = createTooltipTarget(); + const currentTitle = 'title'; + const newTitle = 'new title'; + + target.setAttribute('title', currentTitle); + + buildWrapper(); + + wrapper.vm.addTooltips([target]); + + await wrapper.vm.$nextTick(); + + expect(wrapper.find(GlTooltip).text()).toBe(currentTitle); + + target.setAttribute('title', newTitle); + wrapper.vm.fixTitle(target); + + await wrapper.vm.$nextTick(); + + expect(wrapper.find(GlTooltip).text()).toBe(newTitle); + }); + }); + it('disconnects mutation observer on beforeDestroy', () => { buildWrapper(); wrapper.vm.addTooltips([createTooltipTarget()]); diff --git a/spec/frontend/tooltips/index_spec.js b/spec/frontend/tooltips/index_spec.js index a304ffce0a5..2b75707caed 100644 --- a/spec/frontend/tooltips/index_spec.js +++ b/spec/frontend/tooltips/index_spec.js @@ -1,4 +1,4 @@ -import { initTooltips, dispose, destroy } from '~/tooltips'; +import { initTooltips, dispose, destroy, hide, show, enable, disable, fixTitle } from '~/tooltips'; describe('tooltips/index.js', () => { let tooltipsApp; @@ -80,4 +80,41 @@ describe('tooltips/index.js', () => { expect(document.querySelector('.gl-tooltip')).toBe(null); }); }); + + it.each` + methodName | method | event + ${'enable'} | ${enable} | ${'enable'} + ${'disable'} | ${disable} | ${'disable'} + ${'hide'} | ${hide} | ${'close'} + ${'show'} | ${show} | ${'open'} + `( + '$methodName calls triggerEvent in tooltip app with $event event', + async ({ method, event }) => { + const target = createTooltipTarget(); + + buildTooltipsApp(); + + await tooltipsApp.$nextTick(); + + jest.spyOn(tooltipsApp, 'triggerEvent'); + + method([target]); + + expect(tooltipsApp.triggerEvent).toHaveBeenCalledWith(target, event); + }, + ); + + it('fixTitle calls fixTitle in tooltip app with the target specified', async () => { + const target = createTooltipTarget(); + + buildTooltipsApp(); + + await tooltipsApp.$nextTick(); + + jest.spyOn(tooltipsApp, 'fixTitle'); + + fixTitle([target]); + + expect(tooltipsApp.fixTitle).toHaveBeenCalledWith(target); + }); }); diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 1f47ec4bf97..89a2a92ea57 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -198,6 +198,7 @@ RSpec.describe IssuablesHelper do initialDescriptionHtml: '<p dir="auto">issue text</p>', initialDescriptionText: 'issue text', initialTaskStatus: '0 of 0 tasks completed', + issueType: 'issue', iid: issue.iid.to_s } expect(helper.issuable_initial_data(issue)).to match(hash_including(expected_data)) diff --git a/spec/lib/gitlab/graphql/docs/renderer_spec.rb b/spec/lib/gitlab/graphql/docs/renderer_spec.rb index 81ef7fcda97..0f0127819fa 100644 --- a/spec/lib/gitlab/graphql/docs/renderer_spec.rb +++ b/spec/lib/gitlab/graphql/docs/renderer_spec.rb @@ -36,10 +36,10 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do specify do expectation = <<~DOC - ## ArrayTest + ### ArrayTest - | Name | Type | Description | - | --- | ---- | ---------- | + | Field | Type | Description | + | ----- | ---- | ----------- | | `foo` | String! => Array | A description | DOC @@ -59,10 +59,10 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do specify do expectation = <<~DOC - ## OrderingTest + ### OrderingTest - | Name | Type | Description | - | --- | ---- | ---------- | + | Field | Type | Description | + | ----- | ---- | ----------- | | `bar` | String! | A description of bar field | | `foo` | String! | A description of foo field | DOC @@ -82,15 +82,45 @@ RSpec.describe Gitlab::Graphql::Docs::Renderer do specify do expectation = <<~DOC - ## DeprecatedTest + ### DeprecatedTest - | Name | Type | Description | - | --- | ---- | ---------- | + | Field | Type | Description | + | ----- | ---- | ----------- | | `foo` **{warning-solid}** | String! | **Deprecated:** This is deprecated. Deprecated in 1.10 | DOC is_expected.to include(expectation) end end + + context 'A type with an emum field' do + let(:type) do + enum_type = Class.new(Types::BaseEnum) do + graphql_name 'MyEnum' + + value 'BAZ', description: 'A description of BAZ' + value 'BAR', description: 'A description of BAR', deprecation_reason: 'This is deprecated' + end + + Class.new(Types::BaseObject) do + graphql_name 'EnumTest' + + field :foo, enum_type, null: false, description: 'A description of foo field' + end + end + + specify do + expectation = <<~DOC + ### MyEnum + + | Value | Description | + | ----- | ----------- | + | `BAR` **{warning-solid}** | **Deprecated:** This is deprecated | + | `BAZ` | A description of BAZ | + DOC + + is_expected.to include(expectation) + end + end end end diff --git a/spec/rubocop/cop/static_translation_definition_spec.rb b/spec/rubocop/cop/static_translation_definition_spec.rb index b6c9f6a25df..f3185def3d7 100644 --- a/spec/rubocop/cop/static_translation_definition_spec.rb +++ b/spec/rubocop/cop/static_translation_definition_spec.rb @@ -40,6 +40,17 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition, type: :rubocop do ['C = n_("c")', 'n_("c")', 1], [ <<~CODE, + class MyClass + def self.translations + @cache ||= { hello: _("hello") } + end + end + CODE + '_("hello")', + 3 + ], + [ + <<~CODE, module MyModule A = { b: { @@ -79,6 +90,20 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition, type: :rubocop do 'CONSTANT_2 = s__("a")', 'CONSTANT_3 = n__("a")', <<~CODE, + class MyClass + def self.method + @cache ||= { hello: -> { _("hello") } } + end + end + CODE + <<~CODE, + class MyClass + def method + @cache ||= { hello: _("hello") } + end + end + CODE + <<~CODE, def method s_('a') end diff --git a/spec/workers/ci_platform_metrics_update_cron_worker_spec.rb b/spec/workers/ci_platform_metrics_update_cron_worker_spec.rb new file mode 100644 index 00000000000..0bb6822a0a5 --- /dev/null +++ b/spec/workers/ci_platform_metrics_update_cron_worker_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe CiPlatformMetricsUpdateCronWorker, type: :worker do + describe '#perform' do + subject { described_class.new.perform } + + it 'inserts new platform metrics' do + expect(CiPlatformMetric).to receive(:insert_auto_devops_platform_targets!).and_call_original + + subject + end + end +end |