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>2023-08-03 09:09:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-08-03 09:09:11 +0300
commite0a415ccb7a7e59c7a6c16841bdd1668d2ef0be5 (patch)
tree7a2019bcbc2bc1cee665f3ebbcd824b16d2680ce /spec
parentf7dd4c23f3a8c61d54f4589c7835e882c889f462 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/frontend/custom_emoji/components/form_spec.js116
-rw-r--r--spec/frontend/custom_emoji/mock_data.js16
-rw-r--r--spec/models/namespaces/project_namespace_spec.rb77
-rw-r--r--spec/models/project_spec.rb6
-rw-r--r--spec/services/projects/create_service_spec.rb4
6 files changed, 218 insertions, 5 deletions
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index bd207bc9a64..fdf60ca71f8 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -100,6 +100,10 @@ FactoryBot.define do
project.set_runners_token(evaluator.runners_token) if evaluator.runners_token.present?
end
+ to_create do |project|
+ project.project_namespace.save! if project.valid?
+ end
+
after(:create) do |project, evaluator|
# Normally the class Projects::CreateService is used for creating
# projects, and this class takes care of making sure the owner and current
diff --git a/spec/frontend/custom_emoji/components/form_spec.js b/spec/frontend/custom_emoji/components/form_spec.js
new file mode 100644
index 00000000000..c5010d93da4
--- /dev/null
+++ b/spec/frontend/custom_emoji/components/form_spec.js
@@ -0,0 +1,116 @@
+import Vue, { nextTick } from 'vue';
+import { GlAlert } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import Form from '~/custom_emoji/components/form.vue';
+import createCustomEmojiMutation from '~/custom_emoji/queries/create_custom_emoji.mutation.graphql';
+import { CREATED_CUSTOM_EMOJI, CREATED_CUSTOM_EMOJI_WITH_ERROR } from '../mock_data';
+
+let wrapper;
+let createCustomEmojiResponseSpy;
+
+function createMockApolloProvider(response) {
+ Vue.use(VueApollo);
+
+ createCustomEmojiResponseSpy = jest.fn().mockResolvedValue(response);
+
+ const requestHandlers = [[createCustomEmojiMutation, createCustomEmojiResponseSpy]];
+
+ return createMockApollo(requestHandlers);
+}
+
+function createComponent(response = CREATED_CUSTOM_EMOJI) {
+ const mockApollo = createMockApolloProvider(response);
+
+ return mountExtended(Form, {
+ provide: {
+ groupPath: 'gitlab-org',
+ },
+ apolloProvider: mockApollo,
+ });
+}
+
+const findCustomEmojiNameInput = () => wrapper.findByTestId('custom-emoji-name-input');
+const findCustomEmojiNameFormGroup = () => wrapper.findByTestId('custom-emoji-name-form-group');
+const findCustomEmojiUrlInput = () => wrapper.findByTestId('custom-emoji-url-input');
+const findCustomEmojiUrlFormGroup = () => wrapper.findByTestId('custom-emoji-url-form-group');
+const findCustomEmojiFrom = () => wrapper.findByTestId('custom-emoji-form');
+const findAlerts = () => wrapper.findAllComponents(GlAlert);
+const findSubmitBtn = () => wrapper.findByTestId('custom-emoji-form-submit-btn');
+
+function completeForm() {
+ findCustomEmojiNameInput().setValue('Test');
+ findCustomEmojiUrlInput().setValue('https://example.com');
+ findCustomEmojiFrom().trigger('submit');
+}
+
+describe('Custom emoji form component', () => {
+ describe('creates custom emoji', () => {
+ it('calls apollo mutation', async () => {
+ wrapper = createComponent();
+
+ completeForm();
+
+ await waitForPromises();
+
+ expect(createCustomEmojiResponseSpy).toHaveBeenCalledWith({
+ groupPath: 'gitlab-org',
+ url: 'https://example.com',
+ name: 'Test',
+ });
+ });
+
+ it('does not submit when form validation fails', async () => {
+ wrapper = createComponent();
+
+ findCustomEmojiFrom().trigger('submit');
+
+ await waitForPromises();
+
+ expect(createCustomEmojiResponseSpy).not.toHaveBeenCalled();
+ });
+
+ it.each`
+ findFormGroup | findInput | fieldName
+ ${findCustomEmojiNameFormGroup} | ${findCustomEmojiUrlInput} | ${'name'}
+ ${findCustomEmojiUrlFormGroup} | ${findCustomEmojiNameInput} | ${'URL'}
+ `('shows errors for empty $fieldName input', async ({ findFormGroup, findInput }) => {
+ wrapper = createComponent(CREATED_CUSTOM_EMOJI_WITH_ERROR);
+
+ findInput().setValue('Test');
+ findCustomEmojiFrom().trigger('submit');
+
+ await waitForPromises();
+
+ expect(findFormGroup().classes('is-invalid')).toBe(true);
+ });
+
+ it('displays errors when mutation fails', async () => {
+ wrapper = createComponent(CREATED_CUSTOM_EMOJI_WITH_ERROR);
+
+ completeForm();
+
+ await waitForPromises();
+
+ const alertMessages = findAlerts().wrappers.map((x) => x.text());
+
+ expect(alertMessages).toEqual(CREATED_CUSTOM_EMOJI_WITH_ERROR.data.createCustomEmoji.errors);
+ });
+
+ it('shows loading state when saving', async () => {
+ wrapper = createComponent();
+
+ completeForm();
+
+ await nextTick();
+
+ expect(findSubmitBtn().props('loading')).toBe(true);
+
+ await waitForPromises();
+
+ expect(findSubmitBtn().props('loading')).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/custom_emoji/mock_data.js b/spec/frontend/custom_emoji/mock_data.js
index 19ba7022bf1..9936274d71c 100644
--- a/spec/frontend/custom_emoji/mock_data.js
+++ b/spec/frontend/custom_emoji/mock_data.js
@@ -6,3 +6,19 @@ export const CUSTOM_EMOJI = [
createdAt: 'created-at',
},
];
+
+export const CREATED_CUSTOM_EMOJI = {
+ data: {
+ createCustomEmoji: {
+ errors: [],
+ },
+ },
+};
+
+export const CREATED_CUSTOM_EMOJI_WITH_ERROR = {
+ data: {
+ createCustomEmoji: {
+ errors: ['Test error'],
+ },
+ },
+};
diff --git a/spec/models/namespaces/project_namespace_spec.rb b/spec/models/namespaces/project_namespace_spec.rb
index 78403db7fa8..c635d6e54e7 100644
--- a/spec/models/namespaces/project_namespace_spec.rb
+++ b/spec/models/namespaces/project_namespace_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Namespaces::ProjectNamespace, type: :model do
describe 'relationships' do
- it { is_expected.to have_one(:project).with_foreign_key(:project_namespace_id).inverse_of(:project_namespace) }
+ it { is_expected.to have_one(:project).inverse_of(:project_namespace) }
specify do
project = create(:project)
@@ -32,4 +32,79 @@ RSpec.describe Namespaces::ProjectNamespace, type: :model do
expect { project.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
+
+ describe '.create_from_project!' do
+ context 'when namespace does not exist' do
+ it 'new project_namespace is not saved' do
+ expect_any_instance_of(described_class) do |instance|
+ expect(instance).not_to receive(:save!)
+ end
+
+ project = Project.new(namespace: nil)
+ described_class.create_from_project!(project)
+ end
+ end
+
+ context 'for new record when namespace exists' do
+ let(:project) { build(:project) }
+ let(:project_namespace) { project.project_namespace }
+
+ it 'syncs the project attributes to project namespace' do
+ project_name = 'project 1 name'
+ project.name = project_name
+
+ described_class.create_from_project!(project)
+ expect(project.project_namespace.name).to eq(project_name)
+ end
+
+ context 'when project has an unsaved project namespace' do
+ it 'saves the same project namespace' do
+ described_class.create_from_project!(project)
+
+ expect(project_namespace).to be_persisted
+ end
+ end
+ end
+ end
+
+ describe '#sync_attributes_from_project' do
+ context 'with existing project' do
+ let(:project) { create(:project) }
+ let(:project_namespace) { project.project_namespace }
+ let(:project_new_namespace) { create(:namespace) }
+ let(:project_new_path) { 'project-new-path' }
+ let(:project_new_name) { project_new_path.titleize }
+ let(:project_new_visibility_level) { Gitlab::VisibilityLevel::INTERNAL }
+ let(:project_shared_runners_enabled) { !project.shared_runners_enabled }
+
+ before do
+ project.name = project_new_name
+ project.path = project_new_path
+ project.visibility_level = project_new_visibility_level
+ project.namespace = project_new_namespace
+ project.shared_runners_enabled = project_shared_runners_enabled
+ end
+
+ it 'syncs the relevant keys from the project' do
+ project_namespace.sync_attributes_from_project(project)
+
+ expect(project_namespace.name).to eq(project_new_name)
+ expect(project_namespace.path).to eq(project_new_path)
+ expect(project_namespace.visibility_level).to eq(project_new_visibility_level)
+ expect(project_namespace.namespace).to eq(project_new_namespace)
+ expect(project_namespace.namespace_id).to eq(project_new_namespace.id)
+ expect(project_namespace.shared_runners_enabled).to eq(project_shared_runners_enabled)
+ end
+ end
+
+ it 'syncs visibility_level if project is new' do
+ project = build(:project)
+ project_namespace = project.project_namespace
+ project_namespace.visibility_level = Gitlab::VisibilityLevel::PUBLIC
+
+ project_namespace.sync_attributes_from_project(project)
+
+ expect(project_namespace.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 82cefc1a95c..d71ae75aefb 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:namespace) }
- it { is_expected.to belong_to(:project_namespace).class_name('Namespaces::ProjectNamespace').with_foreign_key('project_namespace_id') }
+ it { is_expected.to belong_to(:project_namespace).class_name('Namespaces::ProjectNamespace').with_foreign_key('project_namespace_id').inverse_of(:project) }
it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to belong_to(:pool_repository) }
it { is_expected.to have_many(:users) }
@@ -634,8 +634,8 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
it 'validates the visibility' do
- expect_any_instance_of(described_class).to receive(:visibility_level_allowed_as_fork).and_call_original
- expect_any_instance_of(described_class).to receive(:visibility_level_allowed_by_group).and_call_original
+ expect_any_instance_of(described_class).to receive(:visibility_level_allowed_as_fork).twice.and_call_original
+ expect_any_instance_of(described_class).to receive(:visibility_level_allowed_by_group).twice.and_call_original
create(:project)
end
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 8a737e4df56..683e438eb08 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -628,11 +628,13 @@ RSpec.describe Projects::CreateService, '#execute', feature_category: :groups_an
context 'repository creation' do
it 'synchronously creates the repository' do
expect_next_instance_of(Project) do |instance|
- expect(instance).to receive(:create_repository)
+ expect(instance).to receive(:create_repository).and_return(true)
end
project = create_project(user, opts)
+
expect(project).to be_valid
+ expect(project).to be_persisted
expect(project.owner).to eq(user)
expect(project.namespace).to eq(user.namespace)
expect(project.project_namespace).to be_in_sync_with_project(project)