Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-08-13 00:10:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-13 00:10:33 +0300
commit8cdf31a1f97786973eb60564ef667e8416d1b1c8 (patch)
treeda2c8f275dc32269bfadda39b74deb28137366c9 /spec
parentbf1990164b801489b4475504701eefb66146e724 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/finders/packages/pypi/packages_finder_spec.rb10
-rw-r--r--spec/frontend/content_editor/components/content_editor_spec.js162
-rw-r--r--spec/frontend/content_editor/extensions/attachment_spec.js10
-rw-r--r--spec/frontend/content_editor/services/content_editor_spec.js12
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_form_spec.js5
-rw-r--r--spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb62
-rw-r--r--spec/requests/api/pypi_packages_spec.rb8
-rw-r--r--spec/support/shared_contexts/lib/api/helpers/packages/dependency_proxy_helpers_shared_context.rb9
-rw-r--r--spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb29
11 files changed, 237 insertions, 77 deletions
diff --git a/spec/finders/packages/pypi/packages_finder_spec.rb b/spec/finders/packages/pypi/packages_finder_spec.rb
index a69c2317261..1a44fb99009 100644
--- a/spec/finders/packages/pypi/packages_finder_spec.rb
+++ b/spec/finders/packages/pypi/packages_finder_spec.rb
@@ -14,14 +14,14 @@ RSpec.describe Packages::Pypi::PackagesFinder do
let(:package_name) { package2.name }
- describe 'execute!' do
- subject { described_class.new(user, scope, package_name: package_name).execute! }
+ describe 'execute' do
+ subject { described_class.new(user, scope, package_name: package_name).execute }
shared_examples 'when no package is found' do
context 'non-existing package' do
let(:package_name) { 'none' }
- it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+ it { expect(subject).to be_empty }
end
end
@@ -29,7 +29,7 @@ RSpec.describe Packages::Pypi::PackagesFinder do
context 'non-existing package' do
let(:package_name) { package2.name.upcase.tr('-', '.') }
- it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+ it { expect(subject).to be_empty }
end
end
@@ -45,7 +45,7 @@ RSpec.describe Packages::Pypi::PackagesFinder do
context 'within a group' do
let(:scope) { group }
- it { expect { subject }.to raise_error(ActiveRecord::RecordNotFound) }
+ it { expect(subject).to be_empty }
context 'user with access to only one project' do
before do
diff --git a/spec/frontend/content_editor/components/content_editor_spec.js b/spec/frontend/content_editor/components/content_editor_spec.js
index 5b6794cbc66..d516baf6f0f 100644
--- a/spec/frontend/content_editor/components/content_editor_spec.js
+++ b/spec/frontend/content_editor/components/content_editor_spec.js
@@ -1,93 +1,175 @@
-import { GlAlert } from '@gitlab/ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import { EditorContent } from '@tiptap/vue-2';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ContentEditor from '~/content_editor/components/content_editor.vue';
+import ContentEditorError from '~/content_editor/components/content_editor_error.vue';
+import ContentEditorProvider from '~/content_editor/components/content_editor_provider.vue';
+import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue';
import TopToolbar from '~/content_editor/components/top_toolbar.vue';
-import { createContentEditor } from '~/content_editor/services/create_content_editor';
+import {
+ LOADING_CONTENT_EVENT,
+ LOADING_SUCCESS_EVENT,
+ LOADING_ERROR_EVENT,
+} from '~/content_editor/constants';
+import { emitEditorEvent } from '../test_utils';
jest.mock('~/emoji');
describe('ContentEditor', () => {
let wrapper;
- let editor;
+ let contentEditor;
+ let renderMarkdown;
+ const uploadsPath = '/uploads';
const findEditorElement = () => wrapper.findByTestId('content-editor');
- const findErrorAlert = () => wrapper.findComponent(GlAlert);
+ const findEditorContent = () => wrapper.findComponent(EditorContent);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+
+ const createWrapper = (propsData = {}) => {
+ renderMarkdown = jest.fn();
- const createWrapper = async (contentEditor) => {
wrapper = shallowMountExtended(ContentEditor, {
propsData: {
- contentEditor,
+ renderMarkdown,
+ uploadsPath,
+ ...propsData,
+ },
+ stubs: {
+ EditorStateObserver,
+ ContentEditorProvider,
+ },
+ listeners: {
+ initialized(editor) {
+ contentEditor = editor;
+ },
},
});
};
- beforeEach(() => {
- editor = createContentEditor({ renderMarkdown: () => true });
- });
-
afterEach(() => {
wrapper.destroy();
});
- it('renders editor content component and attaches editor instance', () => {
- createWrapper(editor);
+ it('triggers initialized event and provides contentEditor instance as event data', () => {
+ createWrapper();
- const editorContent = wrapper.findComponent(EditorContent);
+ expect(contentEditor).not.toBeFalsy();
+ });
- expect(editorContent.props().editor).toBe(editor.tiptapEditor);
+ it('renders EditorContent component and provides tiptapEditor instance', () => {
+ createWrapper();
+
+ const editorContent = findEditorContent();
+
+ expect(editorContent.props().editor).toBe(contentEditor.tiptapEditor);
expect(editorContent.classes()).toContain('md');
});
+ it('renders ContentEditorProvider component', () => {
+ createWrapper();
+
+ expect(wrapper.findComponent(ContentEditorProvider).exists()).toBe(true);
+ });
+
it('renders top toolbar component', () => {
- createWrapper(editor);
+ createWrapper();
expect(wrapper.findComponent(TopToolbar).exists()).toBe(true);
});
- it.each`
- isFocused | classes
- ${true} | ${['md-area', 'is-focused']}
- ${false} | ${['md-area']}
- `(
- 'has $classes class selectors when tiptapEditor.isFocused = $isFocused',
- ({ isFocused, classes }) => {
- editor.tiptapEditor.isFocused = isFocused;
- createWrapper(editor);
+ it('adds is-focused class when focus event is emitted', async () => {
+ createWrapper();
- expect(findEditorElement().classes()).toStrictEqual(classes);
- },
- );
-
- it('adds isFocused class when tiptapEditor is focused', () => {
- editor.tiptapEditor.isFocused = true;
- createWrapper(editor);
+ await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'focus' });
expect(findEditorElement().classes()).toContain('is-focused');
});
- describe('displaying error', () => {
- const error = 'Content Editor error';
+ it('removes is-focused class when blur event is emitted', async () => {
+ createWrapper();
+
+ await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'focus' });
+ await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'blur' });
+
+ expect(findEditorElement().classes()).not.toContain('is-focused');
+ });
+
+ it('emits change event when document is updated', async () => {
+ createWrapper();
+
+ await emitEditorEvent({ tiptapEditor: contentEditor.tiptapEditor, event: 'update' });
+
+ expect(wrapper.emitted('change')).toEqual([
+ [
+ {
+ empty: contentEditor.empty,
+ },
+ ],
+ ]);
+ });
+
+ it('renders content_editor_error component', () => {
+ createWrapper();
+
+ expect(wrapper.findComponent(ContentEditorError).exists()).toBe(true);
+ });
+ describe('when loading content', () => {
beforeEach(async () => {
- createWrapper(editor);
+ createWrapper();
- editor.tiptapEditor.emit('error', error);
+ contentEditor.emit(LOADING_CONTENT_EVENT);
await nextTick();
});
- it('displays error notifications from the tiptap editor', () => {
- expect(findErrorAlert().text()).toBe(error);
+ it('displays loading indicator', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('hides EditorContent component', () => {
+ expect(findEditorContent().exists()).toBe(false);
});
+ });
- it('allows dismissing an error alert', async () => {
- findErrorAlert().vm.$emit('dismiss');
+ describe('when loading content succeeds', () => {
+ beforeEach(async () => {
+ createWrapper();
+ contentEditor.emit(LOADING_CONTENT_EVENT);
+ await nextTick();
+ contentEditor.emit(LOADING_SUCCESS_EVENT);
await nextTick();
+ });
+
+ it('hides loading indicator', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('displays EditorContent component', () => {
+ expect(findEditorContent().exists()).toBe(true);
+ });
+ });
+
+ describe('when loading content fails', () => {
+ const error = 'error';
+
+ beforeEach(async () => {
+ createWrapper();
+
+ contentEditor.emit(LOADING_CONTENT_EVENT);
+ await nextTick();
+ contentEditor.emit(LOADING_ERROR_EVENT, error);
+ await nextTick();
+ });
+
+ it('hides loading indicator', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
- expect(findErrorAlert().exists()).toBe(false);
+ it('displays EditorContent component', () => {
+ expect(findEditorContent().exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/content_editor/extensions/attachment_spec.js b/spec/frontend/content_editor/extensions/attachment_spec.js
index d87a1459b50..1334b1ddaad 100644
--- a/spec/frontend/content_editor/extensions/attachment_spec.js
+++ b/spec/frontend/content_editor/extensions/attachment_spec.js
@@ -10,7 +10,7 @@ import httpStatus from '~/lib/utils/http_status';
import { loadMarkdownApiResult } from '../markdown_processing_examples';
import { createTestEditor, createDocBuilder } from '../test_utils';
-describe('content_editor/extensions/image', () => {
+describe('content_editor/extensions/attachment', () => {
let tiptapEditor;
let eq;
let doc;
@@ -144,8 +144,8 @@ describe('content_editor/extensions/image', () => {
it('emits an error event that includes an error message', (done) => {
tiptapEditor.commands.uploadAttachment({ file: imageFile });
- tiptapEditor.on('error', (message) => {
- expect(message).toBe('An error occurred while uploading the image. Please try again.');
+ tiptapEditor.on('error', ({ error }) => {
+ expect(error).toBe('An error occurred while uploading the image. Please try again.');
done();
});
});
@@ -224,8 +224,8 @@ describe('content_editor/extensions/image', () => {
it('emits an error event that includes an error message', (done) => {
tiptapEditor.commands.uploadAttachment({ file: attachmentFile });
- tiptapEditor.on('error', (message) => {
- expect(message).toBe('An error occurred while uploading the file. Please try again.');
+ tiptapEditor.on('error', ({ error }) => {
+ expect(error).toBe('An error occurred while uploading the file. Please try again.');
done();
});
});
diff --git a/spec/frontend/content_editor/services/content_editor_spec.js b/spec/frontend/content_editor/services/content_editor_spec.js
index 8580d3249b9..e48687f1548 100644
--- a/spec/frontend/content_editor/services/content_editor_spec.js
+++ b/spec/frontend/content_editor/services/content_editor_spec.js
@@ -13,10 +13,22 @@ describe('content_editor/services/content_editor', () => {
beforeEach(() => {
const tiptapEditor = createTestEditor();
+ jest.spyOn(tiptapEditor, 'destroy');
+
serializer = { deserialize: jest.fn() };
contentEditor = new ContentEditor({ tiptapEditor, serializer });
});
+ describe('.dispose', () => {
+ it('destroys the tiptapEditor', () => {
+ expect(contentEditor.tiptapEditor.destroy).not.toHaveBeenCalled();
+
+ contentEditor.dispose();
+
+ expect(contentEditor.tiptapEditor.destroy).toHaveBeenCalled();
+ });
+ });
+
describe('when setSerializedContent succeeds', () => {
beforeEach(() => {
serializer.deserialize.mockResolvedValueOnce('');
diff --git a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
index 97cb70dbd62..082a8977710 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -352,11 +352,6 @@ describe('WikiForm', () => {
await waitForPromises();
});
- it('editor is shown in a perpetual loading state', () => {
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- expect(wrapper.findComponent(ContentEditor).exists()).toBe(false);
- });
-
it('disables the submit button', () => {
expect(findSubmitButton().props('disabled')).toBe(true);
});
diff --git a/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb b/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
index 99b52236771..ae0c0f53acd 100644
--- a/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
let_it_be(:helper) { Class.new.include(described_class).new }
- describe 'redirect_registry_request' do
+ describe '#redirect_registry_request' do
using RSpec::Parameterized::TableSyntax
let(:options) { {} }
@@ -13,7 +13,7 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
subject { helper.redirect_registry_request(forward_to_registry, package_type, options) { helper.fallback } }
before do
- allow(helper).to receive(:options).and_return(for: API::NpmInstancePackages)
+ allow(helper).to receive(:options).and_return(for: described_class)
end
shared_examples 'executing fallback' do
@@ -34,38 +34,66 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
subject
- expect_snowplow_event(category: 'API::NpmInstancePackages', action: 'npm_request_forward')
+ expect_snowplow_event(category: described_class.to_s, action: "#{package_type}_request_forward")
end
end
- context 'with npm packages' do
- let(:package_type) { :npm }
+ %i[npm pypi].each do |forwardable_package_type|
+ context "with #{forwardable_package_type} packages" do
+ include_context 'dependency proxy helpers context'
- where(:application_setting, :forward_to_registry, :example_name) do
- true | true | 'executing redirect'
- true | false | 'executing fallback'
- false | true | 'executing fallback'
- false | false | 'executing fallback'
- end
+ let(:package_type) { forwardable_package_type }
- with_them do
- before do
- stub_application_setting(npm_package_requests_forwarding: application_setting)
+ where(:application_setting, :forward_to_registry, :example_name) do
+ true | true | 'executing redirect'
+ true | false | 'executing fallback'
+ false | true | 'executing fallback'
+ false | false | 'executing fallback'
end
- it_behaves_like params[:example_name]
+ with_them do
+ before do
+ allow_fetch_application_setting(attribute: "#{forwardable_package_type}_package_requests_forwarding", return_value: application_setting)
+ end
+
+ it_behaves_like params[:example_name]
+ end
end
end
- context 'with non-forwardable packages' do
+ context 'with non-forwardable package type' do
let(:forward_to_registry) { true }
before do
stub_application_setting(npm_package_requests_forwarding: true)
+ stub_application_setting(pypi_package_requests_forwarding: true)
end
- Packages::Package.package_types.keys.without('npm').each do |pkg_type|
+ Packages::Package.package_types.keys.without('npm', 'pypi').each do |pkg_type|
context "#{pkg_type}" do
+ let(:package_type) { pkg_type.to_sym }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(ArgumentError, "Can't find application setting for package_type #{package_type}")
+ end
+ end
+ end
+ end
+
+ describe '#registry_url' do
+ subject { helper.registry_url(package_type, package_name: 'test') }
+
+ where(:package_type, :expected_result) do
+ :npm | 'https://registry.npmjs.org/test'
+ :pypi | 'https://pypi.org/simple/test/'
+ end
+
+ with_them do
+ it { is_expected.to eq(expected_result) }
+ end
+
+ Packages::Package.package_types.keys.without('npm', 'pypi').each do |pkg_type|
+ context "with non-forwardable package type #{pkg_type}" do
let(:package_type) { pkg_type }
it 'raises an error' do
diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb
index a3200ef6a5b..8df2460a2b6 100644
--- a/spec/requests/api/pypi_packages_spec.rb
+++ b/spec/requests/api/pypi_packages_spec.rb
@@ -23,7 +23,8 @@ RSpec.describe API::PypiPackages do
subject { get api(url), headers: headers }
describe 'GET /api/v4/groups/:id/-/packages/pypi/simple/:package_name' do
- let(:url) { "/groups/#{group.id}/-/packages/pypi/simple/#{package.name}" }
+ let(:package_name) { package.name }
+ let(:url) { "/groups/#{group.id}/-/packages/pypi/simple/#{package_name}" }
let(:snowplow_gitlab_standard_context) { {} }
it_behaves_like 'pypi simple API endpoint'
@@ -40,7 +41,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'deploy token for package GET requests'
context 'with group path as id' do
- let(:url) { "/groups/#{CGI.escape(group.full_path)}/-/packages/pypi/simple/#{package.name}" }
+ let(:url) { "/groups/#{CGI.escape(group.full_path)}/-/packages/pypi/simple/#{package_name}"}
it_behaves_like 'deploy token for package GET requests'
end
@@ -60,7 +61,8 @@ RSpec.describe API::PypiPackages do
end
describe 'GET /api/v4/projects/:id/packages/pypi/simple/:package_name' do
- let(:url) { "/projects/#{project.id}/packages/pypi/simple/#{package.name}" }
+ let(:package_name) { package.name }
+ let(:url) { "/projects/#{project.id}/packages/pypi/simple/#{package_name}" }
let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace } }
it_behaves_like 'pypi simple API endpoint'
diff --git a/spec/support/shared_contexts/lib/api/helpers/packages/dependency_proxy_helpers_shared_context.rb b/spec/support/shared_contexts/lib/api/helpers/packages/dependency_proxy_helpers_shared_context.rb
new file mode 100644
index 00000000000..7c8b6250d24
--- /dev/null
+++ b/spec/support/shared_contexts/lib/api/helpers/packages/dependency_proxy_helpers_shared_context.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'dependency proxy helpers context' do
+ def allow_fetch_application_setting(attribute:, return_value:)
+ attributes = double
+ allow(::Gitlab::CurrentSettings.current_application_settings).to receive(:attributes).and_return(attributes)
+ allow(attributes).to receive(:fetch).with(attribute, false).and_return(return_value)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
index c15c59e1a1d..0390e60747f 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_shared_examples.rb
@@ -46,6 +46,8 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
end
shared_examples 'handling all conditions' do
+ include_context 'dependency proxy helpers context'
+
where(:auth, :package_name_type, :request_forward, :visibility, :user_role, :expected_result, :expected_status) do
nil | :scoped_naming_convention | true | :public | nil | :accept | :ok
nil | :scoped_naming_convention | false | :public | nil | :accept | :ok
@@ -243,7 +245,7 @@ RSpec.shared_examples 'handling get metadata requests' do |scope: :project|
project.send("add_#{user_role}", user) if user_role
project.update!(visibility: visibility.to_s)
package.update!(name: package_name) unless package_name == 'non-existing-package'
- stub_application_setting(npm_package_requests_forwarding: request_forward)
+ allow_fetch_application_setting(attribute: "npm_package_requests_forwarding", return_value: request_forward)
end
example_name = "#{params[:expected_result]} metadata request"
diff --git a/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb b/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb
index e6b3dc74b74..86b6975bf9f 100644
--- a/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/npm_packages_tags_shared_examples.rb
@@ -10,9 +10,10 @@ end
RSpec.shared_examples 'accept package tags request' do |status:|
using RSpec::Parameterized::TableSyntax
+ include_context 'dependency proxy helpers context'
before do
- stub_application_setting(npm_package_requests_forwarding: false)
+ allow_fetch_application_setting(attribute: "npm_package_requests_forwarding", return_value: false)
end
context 'with valid package name' do
diff --git a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
index 8a351226123..ed6d9ed43c8 100644
--- a/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb
@@ -228,6 +228,35 @@ RSpec.shared_examples 'pypi simple API endpoint' do
it_behaves_like 'PyPI package versions', :developer, :success
end
+
+ context 'package request forward' do
+ include_context 'dependency proxy helpers context'
+
+ where(:forward, :package_in_project, :shared_examples_name, :expected_status) do
+ true | true | 'PyPI package versions' | :success
+ true | false | 'process PyPI api request' | :redirect
+ false | true | 'PyPI package versions' | :success
+ false | false | 'process PyPI api request' | :not_found
+ end
+
+ with_them do
+ let_it_be(:package) { create(:pypi_package, project: project, name: 'foobar') }
+
+ let(:package_name) do
+ if package_in_project
+ 'foobar'
+ else
+ 'barfoo'
+ end
+ end
+
+ before do
+ allow_fetch_application_setting(attribute: "pypi_package_requests_forwarding", return_value: forward)
+ end
+
+ it_behaves_like params[:shared_examples_name], :reporter, params[:expected_status]
+ end
+ end
end
RSpec.shared_examples 'pypi file download endpoint' do