Subject: The message subject! @all
Mime-Version: 1.0
diff --git a/spec/frontend/batch_comments/components/preview_dropdown_spec.js b/spec/frontend/batch_comments/components/preview_dropdown_spec.js
index bf3bbf4de26..079b64225e4 100644
--- a/spec/frontend/batch_comments/components/preview_dropdown_spec.js
+++ b/spec/frontend/batch_comments/components/preview_dropdown_spec.js
@@ -1,8 +1,15 @@
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+import { visitUrl } from '~/lib/utils/url_utility';
import PreviewDropdown from '~/batch_comments/components/preview_dropdown.vue';
+jest.mock('~/lib/utils/url_utility', () => ({
+ visitUrl: jest.fn(),
+ setUrlParams: jest.requireActual('~/lib/utils/url_utility').setUrlParams,
+}));
+
Vue.use(Vuex);
let wrapper;
@@ -27,6 +34,11 @@ function factory({ viewDiffsFileByFile = false, draftsCount = 1, sortedDrafts =
actions: { scrollToDraft },
getters: { draftsCount: () => draftsCount, sortedDrafts: () => sortedDrafts },
},
+ notes: {
+ getters: {
+ getNoteableData: () => ({ diff_head_sha: '123' }),
+ },
+ },
},
});
@@ -67,5 +79,19 @@ describe('Batch comments preview dropdown', () => {
expect(scrollToDraft).toHaveBeenCalledWith(expect.anything(), { id: 1 });
});
+
+ it('changes window location to navigate to commit', async () => {
+ factory({
+ viewDiffsFileByFile: false,
+ sortedDrafts: [{ id: 1, position: { head_sha: '1234' } }],
+ });
+
+ wrapper.findByTestId('preview-item').vm.$emit('click');
+
+ await nextTick();
+
+ expect(scrollToDraft).not.toHaveBeenCalled();
+ expect(visitUrl).toHaveBeenCalledWith(`${TEST_HOST}/?commit_id=1234#note_1`);
+ });
});
});
diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js
index 8e499844406..7cf101a5e59 100644
--- a/spec/frontend/lib/utils/common_utils_spec.js
+++ b/spec/frontend/lib/utils/common_utils_spec.js
@@ -88,6 +88,28 @@ describe('common_utils', () => {
expectGetElementIdToHaveBeenCalledWith('user-content-definição');
});
+ it(`does not scroll when ${commonUtils.NO_SCROLL_TO_HASH_CLASS} is set on target`, () => {
+ jest.spyOn(window, 'scrollBy');
+
+ document.body.innerHTML += `
+
+ `;
+
+ window.history.pushState({}, null, '#test');
+ commonUtils.handleLocationHash();
+ jest.runOnlyPendingTimers();
+
+ try {
+ expect(window.scrollBy).not.toHaveBeenCalled();
+ } finally {
+ document.getElementById('parent').remove();
+ }
+ });
+
it('scrolls element into view', () => {
document.body.innerHTML += `
diff --git a/spec/frontend/tabs/index_spec.js b/spec/frontend/tabs/index_spec.js
index 67e3d707adb..1d61d38a488 100644
--- a/spec/frontend/tabs/index_spec.js
+++ b/spec/frontend/tabs/index_spec.js
@@ -1,9 +1,16 @@
-import { GlTabsBehavior, TAB_SHOWN_EVENT } from '~/tabs';
+import { GlTabsBehavior, TAB_SHOWN_EVENT, HISTORY_TYPE_HASH } from '~/tabs';
import { ACTIVE_PANEL_CLASS, ACTIVE_TAB_CLASSES } from '~/tabs/constants';
+import { getLocationHash } from '~/lib/utils/url_utility';
+import { NO_SCROLL_TO_HASH_CLASS } from '~/lib/utils/common_utils';
import { getFixture, setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import setWindowLocation from 'helpers/set_window_location_helper';
const tabsFixture = getFixture('tabs/tabs.html');
+global.CSS = {
+ escape: (val) => val,
+};
+
describe('GlTabsBehavior', () => {
let glTabs;
let tabShownEventSpy;
@@ -41,6 +48,7 @@ describe('GlTabsBehavior', () => {
});
expect(panel.classList.contains(ACTIVE_PANEL_CLASS)).toBe(true);
+ expect(panel.classList.contains(NO_SCROLL_TO_HASH_CLASS)).toBe(true);
};
const expectInactiveTabAndPanel = (name) => {
@@ -67,6 +75,7 @@ describe('GlTabsBehavior', () => {
});
expect(panel.classList.contains(ACTIVE_PANEL_CLASS)).toBe(false);
+ expect(panel.classList.contains(NO_SCROLL_TO_HASH_CLASS)).toBe(true);
};
const expectGlTabShownEvent = (name) => {
@@ -263,4 +272,98 @@ describe('GlTabsBehavior', () => {
expectInactiveTabAndPanel('foo');
});
});
+
+ describe('using history=hash', () => {
+ const defaultTab = 'foo';
+ let tab;
+ let tabsEl;
+
+ beforeEach(() => {
+ setHTMLFixture(tabsFixture);
+ tabsEl = findByTestId('tabs');
+ });
+
+ afterEach(() => {
+ glTabs.destroy();
+ resetHTMLFixture();
+ });
+
+ describe('when a hash exists onInit', () => {
+ beforeEach(() => {
+ tab = 'bar';
+ setWindowLocation(`http://foo.com/index#${tab}`);
+ glTabs = new GlTabsBehavior(tabsEl, { history: HISTORY_TYPE_HASH });
+ });
+
+ it('sets the active tab to the hash and preserves hash', () => {
+ expectActiveTabAndPanel(tab);
+ expect(getLocationHash()).toBe(tab);
+ });
+ });
+
+ describe('when a hash does not exist onInit', () => {
+ beforeEach(() => {
+ setWindowLocation(`http://foo.com/index`);
+ glTabs = new GlTabsBehavior(tabsEl, { history: HISTORY_TYPE_HASH });
+ });
+
+ it('sets the active tab to the first tab and sets hash', () => {
+ expectActiveTabAndPanel(defaultTab);
+ expect(getLocationHash()).toBe(defaultTab);
+ });
+ });
+
+ describe('clicking on an inactive tab', () => {
+ beforeEach(() => {
+ tab = 'qux';
+ setWindowLocation(`http://foo.com/index`);
+ glTabs = new GlTabsBehavior(tabsEl, { history: HISTORY_TYPE_HASH });
+
+ findTab(tab).click();
+ });
+
+ it('changes the tabs and updates the hash', () => {
+ expectInactiveTabAndPanel(defaultTab);
+ expectActiveTabAndPanel(tab);
+ expect(getLocationHash()).toBe(tab);
+ });
+ });
+
+ describe('keyboard navigation', () => {
+ const secondTab = 'bar';
+
+ beforeEach(() => {
+ setWindowLocation(`http://foo.com/index`);
+ glTabs = new GlTabsBehavior(tabsEl, { history: HISTORY_TYPE_HASH });
+ });
+
+ it.each(['ArrowRight', 'ArrowDown'])(
+ 'pressing %s moves to next tab and updates hash',
+ (code) => {
+ expectActiveTabAndPanel(defaultTab);
+
+ triggerKeyDown(code, glTabs.activeTab);
+
+ expectInactiveTabAndPanel(defaultTab);
+ expectActiveTabAndPanel(secondTab);
+ expect(getLocationHash()).toBe(secondTab);
+ },
+ );
+
+ it.each(['ArrowLeft', 'ArrowUp'])(
+ 'pressing %s moves to previous tab and updates hash',
+ (code) => {
+ // First, make the 2nd tab active
+ findTab(secondTab).click();
+ expectActiveTabAndPanel(secondTab);
+
+ triggerKeyDown(code, glTabs.activeTab);
+
+ expectInactiveTabAndPanel(secondTab);
+ expectActiveTabAndPanel(defaultTab);
+ expect(getLocationHash()).toBe(defaultTab);
+ },
+ );
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/markdown/field_spec.js b/spec/frontend/vue_shared/components/markdown/field_spec.js
index b3376f26a25..85a135d2b89 100644
--- a/spec/frontend/vue_shared/components/markdown/field_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/field_spec.js
@@ -67,11 +67,6 @@ describe('Markdown field component', () => {
enablePreview,
restrictedToolBarItems,
},
- provide: {
- glFeatures: {
- contactsAutocomplete: true,
- },
- },
},
);
}
diff --git a/spec/lib/backup/gitaly_backup_spec.rb b/spec/lib/backup/gitaly_backup_spec.rb
index ab198fcbe1f..3a9c4dfe3fb 100644
--- a/spec/lib/backup/gitaly_backup_spec.rb
+++ b/spec/lib/backup/gitaly_backup_spec.rb
@@ -16,8 +16,8 @@ RSpec.describe Backup::GitalyBackup do
let(:expected_env) do
{
- 'SSL_CERT_FILE' => OpenSSL::X509::DEFAULT_CERT_FILE,
- 'SSL_CERT_DIR' => OpenSSL::X509::DEFAULT_CERT_DIR
+ 'SSL_CERT_FILE' => Gitlab::X509::Certificate.default_cert_file,
+ 'SSL_CERT_DIR' => Gitlab::X509::Certificate.default_cert_dir
}.merge(ENV)
end
diff --git a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
index 6e7806c5d53..d0aba70081b 100644
--- a/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/service_desk_handler_spec.rb
@@ -52,14 +52,6 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
expect(new_issue.issue_email_participants.first.email).to eq(author_email)
end
- it 'attaches existing CRM contact' do
- contact = create(:contact, group: group, email: author_email)
- receiver.execute
- new_issue = Issue.last
-
- expect(new_issue.issue_customer_relations_contacts.last.contact).to eq(contact)
- end
-
it 'sends thank you email' do
expect { receiver.execute }.to have_enqueued_job.on_queue('mailers')
end
@@ -77,6 +69,16 @@ RSpec.describe Gitlab::Email::Handler::ServiceDeskHandler do
context 'when everything is fine' do
it_behaves_like 'a new issue request'
+ it 'attaches existing CRM contacts' do
+ contact = create(:contact, group: group, email: author_email)
+ contact2 = create(:contact, group: group, email: "cc@example.com")
+ contact3 = create(:contact, group: group, email: "kk@example.org")
+ receiver.execute
+ new_issue = Issue.last
+
+ expect(new_issue.issue_customer_relations_contacts.map(&:contact)).to contain_exactly(contact, contact2, contact3)
+ end
+
context 'with legacy incoming email address' do
let(:email_raw) { fixture_file('emails/service_desk_legacy.eml') }
diff --git a/spec/lib/gitlab/version_info_spec.rb b/spec/lib/gitlab/version_info_spec.rb
index f81e3aa070a..a77d51fab88 100644
--- a/spec/lib/gitlab/version_info_spec.rb
+++ b/spec/lib/gitlab/version_info_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
+require 'fast_spec_helper'
RSpec.describe 'Gitlab::VersionInfo' do
before do
@@ -13,7 +13,7 @@ RSpec.describe 'Gitlab::VersionInfo' do
@v2_0_0 = Gitlab::VersionInfo.new(2, 0, 0)
end
- context '>' do
+ describe '>' do
it { expect(@v2_0_0).to be > @v1_1_0 }
it { expect(@v1_1_0).to be > @v1_0_1 }
it { expect(@v1_0_1).to be > @v1_0_0 }
@@ -21,12 +21,12 @@ RSpec.describe 'Gitlab::VersionInfo' do
it { expect(@v0_1_0).to be > @v0_0_1 }
end
- context '>=' do
+ describe '>=' do
it { expect(@v2_0_0).to be >= Gitlab::VersionInfo.new(2, 0, 0) }
it { expect(@v2_0_0).to be >= @v1_1_0 }
end
- context '<' do
+ describe '<' do
it { expect(@v0_0_1).to be < @v0_1_0 }
it { expect(@v0_1_0).to be < @v1_0_0 }
it { expect(@v1_0_0).to be < @v1_0_1 }
@@ -34,29 +34,29 @@ RSpec.describe 'Gitlab::VersionInfo' do
it { expect(@v1_1_0).to be < @v2_0_0 }
end
- context '<=' do
+ describe '<=' do
it { expect(@v0_0_1).to be <= Gitlab::VersionInfo.new(0, 0, 1) }
it { expect(@v0_0_1).to be <= @v0_1_0 }
end
- context '==' do
+ describe '==' do
it { expect(@v0_0_1).to eq(Gitlab::VersionInfo.new(0, 0, 1)) }
it { expect(@v0_1_0).to eq(Gitlab::VersionInfo.new(0, 1, 0)) }
it { expect(@v1_0_0).to eq(Gitlab::VersionInfo.new(1, 0, 0)) }
end
- context '!=' do
+ describe '!=' do
it { expect(@v0_0_1).not_to eq(@v0_1_0) }
end
- context 'unknown' do
+ describe '.unknown' do
it { expect(@unknown).not_to be @v0_0_1 }
it { expect(@unknown).not_to be Gitlab::VersionInfo.new }
it { expect {@unknown > @v0_0_1}.to raise_error(ArgumentError) }
it { expect {@unknown < @v0_0_1}.to raise_error(ArgumentError) }
end
- context 'parse' do
+ describe '.parse' do
it { expect(Gitlab::VersionInfo.parse("1.0.0")).to eq(@v1_0_0) }
it { expect(Gitlab::VersionInfo.parse("1.0.0.1")).to eq(@v1_0_0) }
it { expect(Gitlab::VersionInfo.parse("1.0.0-ee")).to eq(@v1_0_0) }
@@ -66,8 +66,37 @@ RSpec.describe 'Gitlab::VersionInfo' do
it { expect(Gitlab::VersionInfo.parse("git 1.0b1")).not_to be_valid }
end
- context 'to_s' do
+ describe '.to_s' do
it { expect(@v1_0_0.to_s).to eq("1.0.0") }
it { expect(@unknown.to_s).to eq("Unknown") }
end
+
+ describe '.hash' do
+ it { expect(Gitlab::VersionInfo.parse("1.0.0").hash).to eq(@v1_0_0.hash) }
+ it { expect(Gitlab::VersionInfo.parse("1.0.0.1").hash).to eq(@v1_0_0.hash) }
+ it { expect(Gitlab::VersionInfo.parse("1.0.1b1").hash).to eq(@v1_0_1.hash) }
+ end
+
+ describe '.eql?' do
+ it { expect(Gitlab::VersionInfo.parse("1.0.0").eql?(@v1_0_0)).to be_truthy }
+ it { expect(Gitlab::VersionInfo.parse("1.0.0.1").eql?(@v1_0_0)).to be_truthy }
+ it { expect(@v1_0_1.eql?(@v1_0_0)).to be_falsey }
+ it { expect(@v1_1_0.eql?(@v1_0_0)).to be_falsey }
+ it { expect(@v1_0_0.eql?(@v1_0_0)).to be_truthy }
+ it { expect([@v1_0_0, @v1_1_0, @v1_0_0].uniq).to eq [@v1_0_0, @v1_1_0] }
+ end
+
+ describe '.same_minor_version?' do
+ it { expect(@v0_1_0.same_minor_version?(@v0_0_1)).to be_falsey }
+ it { expect(@v1_0_1.same_minor_version?(@v1_0_0)).to be_truthy }
+ it { expect(@v1_0_0.same_minor_version?(@v1_0_1)).to be_truthy }
+ it { expect(@v1_1_0.same_minor_version?(@v1_0_0)).to be_falsey }
+ it { expect(@v2_0_0.same_minor_version?(@v1_0_0)).to be_falsey }
+ end
+
+ describe '.without_patch' do
+ it { expect(@v0_1_0.without_patch).to eq(@v0_1_0) }
+ it { expect(@v1_0_0.without_patch).to eq(@v1_0_0) }
+ it { expect(@v1_0_1.without_patch).to eq(@v1_0_0) }
+ end
end
diff --git a/spec/lib/gitlab/x509/certificate_spec.rb b/spec/lib/gitlab/x509/certificate_spec.rb
index 2dc30cc871d..d919b99de2a 100644
--- a/spec/lib/gitlab/x509/certificate_spec.rb
+++ b/spec/lib/gitlab/x509/certificate_spec.rb
@@ -116,9 +116,69 @@ RSpec.describe Gitlab::X509::Certificate do
end
end
+ describe '.default_cert_dir' do
+ before do
+ described_class.reset_default_cert_paths
+ end
+
+ after(:context) do
+ described_class.reset_default_cert_paths
+ end
+
+ context 'when SSL_CERT_DIR env variable is not set' do
+ before do
+ stub_env('SSL_CERT_DIR', nil)
+ end
+
+ it 'returns default directory from OpenSSL' do
+ expect(described_class.default_cert_dir).to eq(OpenSSL::X509::DEFAULT_CERT_DIR)
+ end
+ end
+
+ context 'when SSL_CERT_DIR env variable is set' do
+ before do
+ stub_env('SSL_CERT_DIR', '/tmp/foo/certs')
+ end
+
+ it 'returns specified directory' do
+ expect(described_class.default_cert_dir).to eq('/tmp/foo/certs')
+ end
+ end
+ end
+
+ describe '.default_cert_file' do
+ before do
+ described_class.reset_default_cert_paths
+ end
+
+ after(:context) do
+ described_class.reset_default_cert_paths
+ end
+
+ context 'when SSL_CERT_FILE env variable is not set' do
+ before do
+ stub_env('SSL_CERT_FILE', nil)
+ end
+
+ it 'returns default file from OpenSSL' do
+ expect(described_class.default_cert_file).to eq(OpenSSL::X509::DEFAULT_CERT_FILE)
+ end
+ end
+
+ context 'when SSL_CERT_FILE env variable is set' do
+ before do
+ stub_env('SSL_CERT_FILE', '/tmp/foo/cert.pem')
+ end
+
+ it 'returns specified file' do
+ expect(described_class.default_cert_file).to eq('/tmp/foo/cert.pem')
+ end
+ end
+ end
+
describe '.ca_certs_paths' do
it 'returns all files specified by OpenSSL defaults' do
- cert_paths = Dir["#{OpenSSL::X509::DEFAULT_CERT_DIR}/*"]
+ cert_paths = Dir["#{described_class.default_cert_dir}/*"]
expect(described_class.ca_certs_paths).to match_array(cert_paths + [sample_cert])
end
diff --git a/spec/lib/gitlab/x509/signature_spec.rb b/spec/lib/gitlab/x509/signature_spec.rb
index 0e34d5393d6..5626e49bfe1 100644
--- a/spec/lib/gitlab/x509/signature_spec.rb
+++ b/spec/lib/gitlab/x509/signature_spec.rb
@@ -107,7 +107,7 @@ RSpec.describe Gitlab::X509::Signature do
f.print certificate.to_pem
end
- stub_const("OpenSSL::X509::DEFAULT_CERT_FILE", file_path)
+ allow(Gitlab::X509::Certificate).to receive(:default_cert_file).and_return(file_path)
allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 47fd1622306..1d58a31bd6e 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -788,20 +788,6 @@ RSpec.describe 'project routing' do
it 'to #test' do
expect(put('/gitlab/gitlabhq/-/settings/integrations/acme/test')).to route_to('projects/settings/integrations#test', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'acme')
end
-
- context 'legacy routes' do
- it 'to #edit' do
- expect(get('/gitlab/gitlabhq/-/integrations/acme/edit')).to route_to('projects/settings/integrations#edit', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'acme')
- end
-
- it 'to #update' do
- expect(put('/gitlab/gitlabhq/-/integrations/acme')).to route_to('projects/settings/integrations#update', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'acme')
- end
-
- it 'to #test' do
- expect(put('/gitlab/gitlabhq/-/integrations/acme/test')).to route_to('projects/settings/integrations#test', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'acme')
- end
- end
end
describe Projects::Settings::IntegrationHookLogsController do
@@ -812,16 +798,6 @@ RSpec.describe 'project routing' do
it 'to #retry' do
expect(post('/gitlab/gitlabhq/-/settings/integrations/acme/hook_logs/log/retry')).to route_to('projects/settings/integration_hook_logs#retry', namespace_id: 'gitlab', project_id: 'gitlabhq', integration_id: 'acme', id: 'log')
end
-
- context 'legacy routes' do
- it 'to #show' do
- expect(get('/gitlab/gitlabhq/-/integrations/acme/hook_logs/log')).to route_to('projects/settings/integration_hook_logs#show', namespace_id: 'gitlab', project_id: 'gitlabhq', integration_id: 'acme', id: 'log')
- end
-
- it 'to #retry' do
- expect(post('/gitlab/gitlabhq/-/integrations/acme/hook_logs/log/retry')).to route_to('projects/settings/integration_hook_logs#retry', namespace_id: 'gitlab', project_id: 'gitlabhq', integration_id: 'acme', id: 'log')
- end
- end
end
describe Projects::TemplatesController, 'routing' do