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-02-16 12:10:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-16 12:10:11 +0300
commitb1a0a71628cb4531f3b9a2999f5aa4d22f6ac5fb (patch)
treeaf69c74ae863c73a051297ce5b6b8462460102e9 /spec
parent0e0890828e6574c6bbc3fd2518fe8ffb5a3dd13e (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/features/boards/issue_ordering_spec.rb35
-rw-r--r--spec/frontend/boards/board_list_spec.js16
-rw-r--r--spec/frontend/work_items/components/notes/work_item_add_note_spec.js (renamed from spec/frontend/work_items/components/work_item_comment_form_spec.js)104
-rw-r--r--spec/frontend/work_items/components/notes/work_item_comment_form_spec.js164
-rw-r--r--spec/frontend/work_items/components/notes/work_item_comment_locked_spec.js (renamed from spec/frontend/work_items/components/work_item_comment_locked_spec.js)2
-rw-r--r--spec/frontend/work_items/components/notes/work_item_discussion_spec.js23
-rw-r--r--spec/frontend/work_items/components/notes/work_item_note_actions_spec.js23
-rw-r--r--spec/frontend/work_items/components/notes/work_item_note_spec.js248
-rw-r--r--spec/frontend/work_items/components/work_item_notes_spec.js12
-rw-r--r--spec/frontend/work_items/mock_data.js46
-rw-r--r--spec/models/environment_spec.rb28
11 files changed, 567 insertions, 134 deletions
diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb
index f1ee7a8fde7..8aecaab42c2 100644
--- a/spec/features/boards/issue_ordering_spec.rb
+++ b/spec/features/boards/issue_ordering_spec.rb
@@ -130,6 +130,41 @@ RSpec.describe 'Issue Boards', :js, feature_category: :team_planning do
end
end
+ context 'ordering in list using move to position' do
+ let(:move_to_position) { find('[data-testid="board-move-to-position"]') }
+
+ before do
+ visit project_board_path(project, board)
+ wait_for_requests
+ end
+
+ it 'moves to end of list' do
+ expect(all('.board-card').first).to have_content(issue3.title)
+
+ page.within(find('.board:nth-child(2)')) do
+ first('.board-card').hover
+ move_to_position.click
+
+ click_button 'Move to end of list'
+ end
+
+ expect(all('.board-card').last).to have_content(issue3.title)
+ end
+
+ it 'moves to start of list' do
+ expect(all('.board-card').last).to have_content(issue1.title)
+
+ page.within(find('.board:nth-child(2)')) do
+ all('.board-card').last.hover
+ move_to_position.click
+
+ click_button 'Move to start of list'
+ end
+
+ expect(all('.board-card').first).to have_content(issue1.title)
+ end
+ end
+
context 'ordering when changing list' do
let(:label2) { create(:label, project: project) }
let!(:list2) { create(:list, board: board, label: label2, position: 1) }
diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js
index 543186a8009..fc8dbf8dc3a 100644
--- a/spec/frontend/boards/board_list_spec.js
+++ b/spec/frontend/boards/board_list_spec.js
@@ -1,6 +1,6 @@
import Draggable from 'vuedraggable';
import { nextTick } from 'vue';
-import { DraggableItemTypes } from 'ee_else_ce/boards/constants';
+import { DraggableItemTypes, ListType } from 'ee_else_ce/boards/constants';
import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame';
import waitForPromises from 'helpers/wait_for_promises';
import createComponent from 'jest/boards/board_list_helper';
@@ -107,6 +107,20 @@ describe('Board list component', () => {
});
});
+ describe('when ListType is Closed', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ listProps: {
+ listType: ListType.closed,
+ },
+ });
+ });
+
+ it('Board card move to position is not visible', () => {
+ expect(findMoveToPositionComponent().exists()).toBe(false);
+ });
+ });
+
describe('load more issues', () => {
const actions = {
fetchItemsForList: jest.fn(),
diff --git a/spec/frontend/work_items/components/work_item_comment_form_spec.js b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
index bef7efa2536..2a65e91a906 100644
--- a/spec/frontend/work_items/components/work_item_comment_form_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_add_note_spec.js
@@ -5,21 +5,23 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking } from 'helpers/tracking_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { updateDraft } from '~/lib/utils/autosave';
-import MarkdownField from '~/vue_shared/components/markdown/field.vue';
-import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
-import WorkItemCommentForm from '~/work_items/components/work_item_comment_form.vue';
-import WorkItemCommentLocked from '~/work_items/components/work_item_comment_locked.vue';
+import { clearDraft } from '~/lib/utils/autosave';
+import { config } from '~/graphql_shared/issuable_client';
+import WorkItemAddNote from '~/work_items/components/notes/work_item_add_note.vue';
+import WorkItemCommentLocked from '~/work_items/components/notes/work_item_comment_locked.vue';
+import WorkItemCommentForm from '~/work_items/components/notes/work_item_comment_form.vue';
import createNoteMutation from '~/work_items/graphql/notes/create_work_item_note.mutation.graphql';
import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
+import workItemNotesQuery from '~/work_items/graphql/notes/work_item_notes.query.graphql';
import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import {
workItemResponseFactory,
workItemQueryResponse,
projectWorkItemResponse,
createWorkItemNoteResponse,
-} from '../mock_data';
+ mockWorkItemNotesResponse,
+} from '../../mock_data';
jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
jest.mock('~/lib/utils/autosave');
@@ -35,18 +37,7 @@ describe('WorkItemCommentForm', () => {
const workItemByIidResponseHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
let workItemResponseHandler;
- const findMarkdownEditor = () => wrapper.findComponent(MarkdownEditor);
-
- const setText = (newText) => {
- return findMarkdownEditor().vm.$emit('input', newText);
- };
-
- const clickSave = () =>
- wrapper
- .findAllComponents(GlButton)
- .filter((button) => button.text().startsWith('Comment'))
- .at(0)
- .vm.$emit('click', {});
+ const findCommentForm = () => wrapper.findComponent(WorkItemCommentForm);
const createComponent = async ({
mutationHandler = mutationSuccessHandler,
@@ -65,13 +56,28 @@ describe('WorkItemCommentForm', () => {
window.gon.current_user_avatar_url = 'avatar.png';
}
- const { id } = workItemQueryResponse.data.workItem;
- wrapper = shallowMount(WorkItemCommentForm, {
- apolloProvider: createMockApollo([
+ const apolloProvider = createMockApollo(
+ [
[workItemQuery, workItemResponseHandler],
[createNoteMutation, mutationHandler],
[workItemByIidQuery, workItemByIidResponseHandler],
- ]),
+ ],
+ {},
+ { ...config.cacheConfig },
+ );
+
+ apolloProvider.clients.defaultClient.writeQuery({
+ query: workItemNotesQuery,
+ variables: {
+ id: workItemId,
+ pageSize: 100,
+ },
+ data: mockWorkItemNotesResponse.data,
+ });
+
+ const { id } = workItemQueryResponse.data.workItem;
+ wrapper = shallowMount(WorkItemAddNote, {
+ apolloProvider,
propsData: {
workItemId: id,
fullPath: 'test-project-path',
@@ -80,7 +86,6 @@ describe('WorkItemCommentForm', () => {
workItemType,
},
stubs: {
- MarkdownField,
WorkItemCommentLocked,
},
});
@@ -101,9 +106,7 @@ describe('WorkItemCommentForm', () => {
signedIn: true,
});
- setText(noteText);
-
- clickSave();
+ findCommentForm().vm.$emit('submitForm', noteText);
await waitForPromises();
@@ -120,9 +123,7 @@ describe('WorkItemCommentForm', () => {
await createComponent();
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- setText('test');
-
- clickSave();
+ findCommentForm().vm.$emit('submitForm', 'test');
await waitForPromises();
@@ -133,6 +134,33 @@ describe('WorkItemCommentForm', () => {
});
});
+ it('emits `replied` event and hides form after successful mutation', async () => {
+ await createComponent({
+ isEditing: true,
+ signedIn: true,
+ queryVariables: {
+ id: mockWorkItemNotesResponse.data.workItem.id,
+ },
+ });
+
+ findCommentForm().vm.$emit('submitForm', 'some text');
+ await waitForPromises();
+
+ expect(wrapper.emitted('replied')).toEqual([[]]);
+ });
+
+ it('clears a draft after successful mutation', async () => {
+ await createComponent({
+ isEditing: true,
+ signedIn: true,
+ });
+
+ findCommentForm().vm.$emit('submitForm', 'some text');
+ await waitForPromises();
+
+ expect(clearDraft).toHaveBeenCalledWith('gid://gitlab/WorkItem/1-comment');
+ });
+
it('emits error when mutation returns error', async () => {
const error = 'eror';
@@ -160,9 +188,7 @@ describe('WorkItemCommentForm', () => {
}),
});
- setText('updated desc');
-
- clickSave();
+ findCommentForm().vm.$emit('submitForm', 'updated desc');
await waitForPromises();
@@ -177,24 +203,12 @@ describe('WorkItemCommentForm', () => {
mutationHandler: jest.fn().mockRejectedValue(new Error(error)),
});
- setText('updated desc');
-
- clickSave();
+ findCommentForm().vm.$emit('submitForm', 'updated desc');
await waitForPromises();
expect(wrapper.emitted('error')).toEqual([[error]]);
});
-
- it('autosaves', async () => {
- await createComponent({
- isEditing: true,
- });
-
- setText('updated');
-
- expect(updateDraft).toHaveBeenCalled();
- });
});
it('calls the global ID work item query when `fetchByIid` prop is false', async () => {
diff --git a/spec/frontend/work_items/components/notes/work_item_comment_form_spec.js b/spec/frontend/work_items/components/notes/work_item_comment_form_spec.js
new file mode 100644
index 00000000000..23a9f285804
--- /dev/null
+++ b/spec/frontend/work_items/components/notes/work_item_comment_form_spec.js
@@ -0,0 +1,164 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import * as autosave from '~/lib/utils/autosave';
+import { ESC_KEY, ENTER_KEY } from '~/lib/utils/keys';
+import * as confirmViaGlModal from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import WorkItemCommentForm from '~/work_items/components/notes/work_item_comment_form.vue';
+import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
+
+const draftComment = 'draft comment';
+
+jest.mock('~/lib/utils/autosave', () => ({
+ updateDraft: jest.fn(),
+ clearDraft: jest.fn(),
+ getDraft: jest.fn().mockReturnValue(draftComment),
+}));
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => ({
+ confirmAction: jest.fn().mockResolvedValue(true),
+}));
+
+describe('Work item comment form component', () => {
+ let wrapper;
+
+ const mockAutosaveKey = 'test-auto-save-key';
+
+ const findMarkdownEditor = () => wrapper.findComponent(MarkdownEditor);
+ const findCancelButton = () => wrapper.find('[data-testid="cancel-button"]');
+ const findConfirmButton = () => wrapper.find('[data-testid="confirm-button"]');
+
+ const createComponent = ({ isSubmitting = false, initialValue = '' } = {}) => {
+ wrapper = shallowMount(WorkItemCommentForm, {
+ propsData: {
+ workItemType: 'Issue',
+ ariaLabel: 'test-aria-label',
+ autosaveKey: mockAutosaveKey,
+ isSubmitting,
+ initialValue,
+ },
+ provide: {
+ fullPath: 'test-project-path',
+ },
+ });
+ };
+
+ it('passes correct markdown preview path to markdown editor', () => {
+ createComponent();
+
+ expect(findMarkdownEditor().props('renderMarkdownPath')).toBe(
+ '/test-project-path/preview_markdown?target_type=Issue',
+ );
+ });
+
+ it('passes correct form field props to markdown editor', () => {
+ createComponent();
+
+ expect(findMarkdownEditor().props('formFieldProps')).toEqual({
+ 'aria-label': 'test-aria-label',
+ id: 'work-item-add-or-edit-comment',
+ name: 'work-item-add-or-edit-comment',
+ placeholder: 'Write a comment or drag your files hereโ€ฆ',
+ });
+ });
+
+ it('passes correct `loading` prop to confirm button', () => {
+ createComponent({ isSubmitting: true });
+
+ expect(findConfirmButton().props('loading')).toBe(true);
+ });
+
+ it('passes a draft from local storage as a value to markdown editor if the draft exists', () => {
+ createComponent({ initialValue: 'parent comment' });
+ expect(findMarkdownEditor().props('value')).toBe(draftComment);
+ });
+
+ it('passes an initialValue prop as a value to markdown editor if storage draft does not exist', () => {
+ jest.spyOn(autosave, 'getDraft').mockImplementation(() => '');
+ createComponent({ initialValue: 'parent comment' });
+
+ expect(findMarkdownEditor().props('value')).toBe('parent comment');
+ });
+
+ it('passes an empty string as a value to markdown editor if storage draft and initialValue are empty', () => {
+ createComponent();
+
+ expect(findMarkdownEditor().props('value')).toBe('');
+ });
+
+ describe('on markdown editor input', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('sets correct comment text value', async () => {
+ expect(findMarkdownEditor().props('value')).toBe('');
+
+ findMarkdownEditor().vm.$emit('input', 'new comment');
+ await nextTick();
+
+ expect(findMarkdownEditor().props('value')).toBe('new comment');
+ });
+
+ it('calls `updateDraft` with correct parameters', async () => {
+ findMarkdownEditor().vm.$emit('input', 'new comment');
+
+ expect(autosave.updateDraft).toHaveBeenCalledWith(mockAutosaveKey, 'new comment');
+ });
+ });
+
+ describe('on cancel editing', () => {
+ beforeEach(() => {
+ jest.spyOn(autosave, 'getDraft').mockImplementation(() => draftComment);
+ createComponent();
+ findMarkdownEditor().vm.$emit('keydown', new KeyboardEvent('keydown', { key: ESC_KEY }));
+
+ return waitForPromises();
+ });
+
+ it('confirms a user action if comment text is not empty', () => {
+ expect(confirmViaGlModal.confirmAction).toHaveBeenCalled();
+ });
+
+ it('emits `cancelEditing` and clears draft from the local storage', () => {
+ expect(wrapper.emitted('cancelEditing')).toHaveLength(1);
+ expect(autosave.clearDraft).toHaveBeenCalledWith(mockAutosaveKey);
+ });
+ });
+
+ it('cancels editing on clicking cancel button', async () => {
+ createComponent();
+ findCancelButton().vm.$emit('click');
+
+ await waitForPromises();
+
+ expect(wrapper.emitted('cancelEditing')).toHaveLength(1);
+ expect(autosave.clearDraft).toHaveBeenCalledWith(mockAutosaveKey);
+ });
+
+ it('emits `submitForm` event on confirm button click', () => {
+ createComponent();
+ findConfirmButton().vm.$emit('click');
+
+ expect(wrapper.emitted('submitForm')).toEqual([[draftComment]]);
+ });
+
+ it('emits `submitForm` event on pressing enter with meta key on markdown editor', () => {
+ createComponent();
+ findMarkdownEditor().vm.$emit(
+ 'keydown',
+ new KeyboardEvent('keydown', { key: ENTER_KEY, metaKey: true }),
+ );
+
+ expect(wrapper.emitted('submitForm')).toEqual([[draftComment]]);
+ });
+
+ it('emits `submitForm` event on pressing ctrl+enter on markdown editor', () => {
+ createComponent();
+ findMarkdownEditor().vm.$emit(
+ 'keydown',
+ new KeyboardEvent('keydown', { key: ENTER_KEY, ctrlKey: true }),
+ );
+
+ expect(wrapper.emitted('submitForm')).toEqual([[draftComment]]);
+ });
+});
diff --git a/spec/frontend/work_items/components/work_item_comment_locked_spec.js b/spec/frontend/work_items/components/notes/work_item_comment_locked_spec.js
index 58491c4b09c..734b474c8fc 100644
--- a/spec/frontend/work_items/components/work_item_comment_locked_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_comment_locked_spec.js
@@ -1,6 +1,6 @@
import { GlLink, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import WorkItemCommentLocked from '~/work_items/components/work_item_comment_locked.vue';
+import WorkItemCommentLocked from '~/work_items/components/notes/work_item_comment_locked.vue';
const createComponent = ({ workItemType = 'Task', isProjectArchived = false } = {}) =>
shallowMount(WorkItemCommentLocked, {
diff --git a/spec/frontend/work_items/components/notes/work_item_discussion_spec.js b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
index 1e2ec7e8dc2..bb65b75c4d8 100644
--- a/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_discussion_spec.js
@@ -6,7 +6,7 @@ import ToggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue';
import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
import WorkItemNote from '~/work_items/components/notes/work_item_note.vue';
import WorkItemNoteReplying from '~/work_items/components/notes/work_item_note_replying.vue';
-import WorkItemCommentForm from '~/work_items/components/work_item_comment_form.vue';
+import WorkItemAddNote from '~/work_items/components/notes/work_item_add_note.vue';
import {
mockWorkItemCommentNote,
mockWorkItemNotesResponseWithComments,
@@ -27,7 +27,7 @@ describe('Work Item Discussion', () => {
const findToggleRepliesWidget = () => wrapper.findComponent(ToggleRepliesWidget);
const findAllThreads = () => wrapper.findAllComponents(WorkItemNote);
const findThreadAtIndex = (index) => findAllThreads().at(index);
- const findWorkItemCommentForm = () => wrapper.findComponent(WorkItemCommentForm);
+ const findWorkItemAddNote = () => wrapper.findComponent(WorkItemAddNote);
const findWorkItemNoteReplying = () => wrapper.findComponent(WorkItemNoteReplying);
const createComponent = ({
@@ -73,7 +73,7 @@ describe('Work Item Discussion', () => {
});
it('should not show the comment form by default', () => {
- expect(findWorkItemCommentForm().exists()).toBe(false);
+ expect(findWorkItemAddNote().exists()).toBe(false);
});
});
@@ -101,8 +101,8 @@ describe('Work Item Discussion', () => {
mainComment.vm.$emit('startReplying');
await nextTick();
- expect(findWorkItemCommentForm().exists()).toBe(true);
- expect(findWorkItemCommentForm().props('autofocus')).toBe(true);
+ expect(findWorkItemAddNote().exists()).toBe(true);
+ expect(findWorkItemAddNote().props('autofocus')).toBe(true);
});
});
@@ -115,7 +115,7 @@ describe('Work Item Discussion', () => {
mainComment.vm.$emit('startReplying');
await nextTick();
- await findWorkItemCommentForm().vm.$emit('replying', 'reply text');
+ await findWorkItemAddNote().vm.$emit('replying', 'reply text');
});
it('should show optimistic behavior when replying', async () => {
@@ -124,7 +124,7 @@ describe('Work Item Discussion', () => {
});
it('should be expanded when the reply is successful', async () => {
- findWorkItemCommentForm().vm.$emit('replied');
+ findWorkItemAddNote().vm.$emit('replied');
await nextTick();
expect(findToggleRepliesWidget().exists()).toBe(true);
expect(findToggleRepliesWidget().props('collapsed')).toBe(false);
@@ -137,4 +137,13 @@ describe('Work Item Discussion', () => {
expect(wrapper.emitted('deleteNote')).toEqual([[mockWorkItemCommentNote]]);
});
+
+ it('emits `error` event when child note emits an `error`', () => {
+ const mockErrorText = 'Houston, we have a problem';
+
+ createComponent();
+ findThreadAtIndex(0).vm.$emit('error', mockErrorText);
+
+ expect(wrapper.emitted('error')).toEqual([[mockErrorText]]);
+ });
});
diff --git a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js
index f3d0e86ee53..d85cd46c1c3 100644
--- a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js
@@ -6,11 +6,13 @@ describe('Work Item Note Actions', () => {
let wrapper;
const findReplyButton = () => wrapper.findComponent(ReplyButton);
+ const findEditButton = () => wrapper.find('[data-testid="edit-work-item-note"]');
- const createComponent = ({ showReply = true } = {}) => {
+ const createComponent = ({ showReply = true, showEdit = true } = {}) => {
wrapper = shallowMount(WorkItemNoteActions, {
propsData: {
showReply,
+ showEdit,
},
});
};
@@ -28,4 +30,23 @@ describe('Work Item Note Actions', () => {
expect(findReplyButton().exists()).toBe(false);
});
});
+
+ it('shows edit button when `showEdit` prop is true', () => {
+ createComponent();
+
+ expect(findEditButton().exists()).toBe(true);
+ });
+
+ it('does not show edit button when `showEdit` prop is false', () => {
+ createComponent({ showEdit: false });
+
+ expect(findEditButton().exists()).toBe(false);
+ });
+
+ it('emits `startEditing` event when edit button is clicked', () => {
+ createComponent();
+ findEditButton().vm.$emit('click');
+
+ expect(wrapper.emitted('startEditing')).toEqual([[]]);
+ });
});
diff --git a/spec/frontend/work_items/components/notes/work_item_note_spec.js b/spec/frontend/work_items/components/notes/work_item_note_spec.js
index 8f7d27def15..9b87419cee7 100644
--- a/spec/frontend/work_items/components/notes/work_item_note_spec.js
+++ b/spec/frontend/work_items/components/notes/work_item_note_spec.js
@@ -1,14 +1,41 @@
import { GlAvatarLink, GlDropdown } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import mockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { updateDraft } from '~/lib/utils/autosave';
+import EditedAt from '~/issues/show/components/edited.vue';
import WorkItemNote from '~/work_items/components/notes/work_item_note.vue';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import NoteBody from '~/work_items/components/notes/work_item_note_body.vue';
import NoteHeader from '~/notes/components/note_header.vue';
import NoteActions from '~/work_items/components/notes/work_item_note_actions.vue';
+import WorkItemCommentForm from '~/work_items/components/notes/work_item_comment_form.vue';
+import updateWorkItemNoteMutation from '~/work_items/graphql/notes/update_work_item_note.mutation.graphql';
import { mockWorkItemCommentNote } from 'jest/work_items/mock_data';
+Vue.use(VueApollo);
+jest.mock('~/lib/utils/autosave');
+
describe('Work Item Note', () => {
let wrapper;
+ const updatedNoteText = '# Some title';
+ const updatedNoteBody = '<h1 data-sourcepos="1:1-1:12" dir="auto">Some title</h1>';
+
+ const successHandler = jest.fn().mockResolvedValue({
+ data: {
+ updateNote: {
+ errors: [],
+ note: {
+ ...mockWorkItemCommentNote,
+ body: updatedNoteText,
+ bodyHtml: updatedNoteBody,
+ },
+ },
+ },
+ });
+ const errorHandler = jest.fn().mockRejectedValue('Oops');
const findAuthorAvatarLink = () => wrapper.findComponent(GlAvatarLink);
const findTimelineEntryItem = () => wrapper.findComponent(TimelineEntryItem);
@@ -16,86 +43,219 @@ describe('Work Item Note', () => {
const findNoteBody = () => wrapper.findComponent(NoteBody);
const findNoteActions = () => wrapper.findComponent(NoteActions);
const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findCommentForm = () => wrapper.findComponent(WorkItemCommentForm);
+ const findEditedAt = () => wrapper.findComponent(EditedAt);
+
const findDeleteNoteButton = () => wrapper.find('[data-testid="delete-note-action"]');
+ const findNoteWrapper = () => wrapper.find('[data-testid="note-wrapper"]');
- const createComponent = ({ note = mockWorkItemCommentNote, isFirstNote = false } = {}) => {
+ const createComponent = ({
+ note = mockWorkItemCommentNote,
+ isFirstNote = false,
+ updateNoteMutationHandler = successHandler,
+ } = {}) => {
wrapper = shallowMount(WorkItemNote, {
propsData: {
note,
isFirstNote,
+ workItemType: 'Task',
},
+ apolloProvider: mockApollo([[updateWorkItemNoteMutation, updateNoteMutationHandler]]),
});
};
- describe('Main comment', () => {
+ describe('when editing', () => {
beforeEach(() => {
- createComponent({ isFirstNote: true });
+ createComponent();
+ findNoteActions().vm.$emit('startEditing');
+ return nextTick();
});
- it('Should have the note header, actions and body', () => {
- expect(findTimelineEntryItem().exists()).toBe(true);
- expect(findNoteHeader().exists()).toBe(true);
- expect(findNoteBody().exists()).toBe(true);
- expect(findNoteActions().exists()).toBe(true);
+ it('should render a comment form', () => {
+ expect(findCommentForm().exists()).toBe(true);
});
- it('Should not have the Avatar link for main thread inside the timeline-entry', () => {
- expect(findAuthorAvatarLink().exists()).toBe(false);
+ it('should not render note wrapper', () => {
+ expect(findNoteWrapper().exists()).toBe(false);
});
- it('Should have the reply button props', () => {
- expect(findNoteActions().props('showReply')).toBe(true);
+ it('updates saved draft with current note text', () => {
+ expect(updateDraft).toHaveBeenCalledWith(
+ `${mockWorkItemCommentNote.id}-comment`,
+ mockWorkItemCommentNote.body,
+ );
+ });
+
+ it('passes correct autosave key prop to comment form component', () => {
+ expect(findCommentForm().props('autosaveKey')).toBe(`${mockWorkItemCommentNote.id}-comment`);
+ });
+
+ it('should hide a form and show wrapper when user cancels editing', async () => {
+ findCommentForm().vm.$emit('cancelEditing');
+ await nextTick();
+
+ expect(findCommentForm().exists()).toBe(false);
+ expect(findNoteWrapper().exists()).toBe(true);
});
});
- describe('Comment threads', () => {
- beforeEach(() => {
+ describe('when submitting a form to edit a note', () => {
+ it('calls update mutation with correct variables', async () => {
createComponent();
- });
+ findNoteActions().vm.$emit('startEditing');
+ await nextTick();
- it('Should have the note header, actions and body', () => {
- expect(findTimelineEntryItem().exists()).toBe(true);
- expect(findNoteHeader().exists()).toBe(true);
- expect(findNoteBody().exists()).toBe(true);
- expect(findNoteActions().exists()).toBe(true);
+ findCommentForm().vm.$emit('submitForm', updatedNoteText);
+
+ expect(successHandler).toHaveBeenCalledWith({
+ input: {
+ id: mockWorkItemCommentNote.id,
+ body: updatedNoteText,
+ },
+ });
});
- it('Should have the Avatar link for comment threads', () => {
- expect(findAuthorAvatarLink().exists()).toBe(true);
+ it('hides the form after succesful mutation', async () => {
+ createComponent();
+ findNoteActions().vm.$emit('startEditing');
+ await nextTick();
+
+ findCommentForm().vm.$emit('submitForm', updatedNoteText);
+ await waitForPromises();
+
+ expect(findCommentForm().exists()).toBe(false);
});
- it('Should not have the reply button props', () => {
- expect(findNoteActions().props('showReply')).toBe(false);
+ describe('when mutation fails', () => {
+ beforeEach(async () => {
+ createComponent({ updateNoteMutationHandler: errorHandler });
+ findNoteActions().vm.$emit('startEditing');
+ await nextTick();
+
+ findCommentForm().vm.$emit('submitForm', updatedNoteText);
+ await waitForPromises();
+ });
+
+ it('opens the form again', () => {
+ expect(findCommentForm().exists()).toBe(true);
+ });
+
+ it('updates the saved draft with the latest comment text', () => {
+ expect(updateDraft).toHaveBeenCalledWith(
+ `${mockWorkItemCommentNote.id}-comment`,
+ updatedNoteText,
+ );
+ });
+
+ it('emits an error', () => {
+ expect(wrapper.emitted('error')).toHaveLength(1);
+ });
});
});
- it('should display a dropdown if user has a permission to delete note', () => {
- createComponent({
- note: {
- ...mockWorkItemCommentNote,
- userPermissions: { ...mockWorkItemCommentNote.userPermissions, adminNote: true },
- },
+ describe('when not editing', () => {
+ it('should not render a comment form', () => {
+ createComponent();
+ expect(findCommentForm().exists()).toBe(false);
});
- expect(findDropdown().exists()).toBe(true);
- });
+ it('should render note wrapper', () => {
+ createComponent();
+ expect(findNoteWrapper().exists()).toBe(true);
+ });
- it('should not display a dropdown if user has no permission to delete note', () => {
- createComponent();
+ it('renders no "edited at" information by default', () => {
+ createComponent();
+ expect(findEditedAt().exists()).toBe(false);
+ });
- expect(findDropdown().exists()).toBe(false);
- });
+ it('renders "edited at" information if the note was edited', () => {
+ createComponent({
+ note: {
+ ...mockWorkItemCommentNote,
+ lastEditedAt: '2023-02-12T07:47:40Z',
+ lastEditedBy: { ...mockWorkItemCommentNote.author, webPath: 'test-path' },
+ },
+ });
- it('should emit `deleteNote` event when delete note action is clicked', () => {
- createComponent({
- note: {
- ...mockWorkItemCommentNote,
- userPermissions: { ...mockWorkItemCommentNote.userPermissions, adminNote: true },
- },
+ expect(findEditedAt().exists()).toBe(true);
+ expect(findEditedAt().props()).toEqual({
+ updatedAt: '2023-02-12T07:47:40Z',
+ updatedByName: 'Administrator',
+ updatedByPath: 'test-path',
+ });
+ });
+
+ describe('main comment', () => {
+ beforeEach(() => {
+ createComponent({ isFirstNote: true });
+ });
+
+ it('should have the note header, actions and body', () => {
+ expect(findTimelineEntryItem().exists()).toBe(true);
+ expect(findNoteHeader().exists()).toBe(true);
+ expect(findNoteBody().exists()).toBe(true);
+ expect(findNoteActions().exists()).toBe(true);
+ });
+
+ it('should not have the Avatar link for main thread inside the timeline-entry', () => {
+ expect(findAuthorAvatarLink().exists()).toBe(false);
+ });
+
+ it('should have the reply button props', () => {
+ expect(findNoteActions().props('showReply')).toBe(true);
+ });
+ });
+
+ describe('comment threads', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should have the note header, actions and body', () => {
+ expect(findTimelineEntryItem().exists()).toBe(true);
+ expect(findNoteHeader().exists()).toBe(true);
+ expect(findNoteBody().exists()).toBe(true);
+ expect(findNoteActions().exists()).toBe(true);
+ });
+
+ it('should have the Avatar link for comment threads', () => {
+ expect(findAuthorAvatarLink().exists()).toBe(true);
+ });
+
+ it('should not have the reply button props', () => {
+ expect(findNoteActions().props('showReply')).toBe(false);
+ });
+ });
+
+ it('should display a dropdown if user has a permission to delete a note', () => {
+ createComponent({
+ note: {
+ ...mockWorkItemCommentNote,
+ userPermissions: { ...mockWorkItemCommentNote.userPermissions, adminNote: true },
+ },
+ });
+
+ expect(findDropdown().exists()).toBe(true);
});
- findDeleteNoteButton().vm.$emit('click');
+ it('should not display a dropdown if user has no permission to delete a note', () => {
+ createComponent();
+
+ expect(findDropdown().exists()).toBe(false);
+ });
- expect(wrapper.emitted('deleteNote')).toEqual([[]]);
+ it('should emit `deleteNote` event when delete note action is clicked', () => {
+ createComponent({
+ note: {
+ ...mockWorkItemCommentNote,
+ userPermissions: { ...mockWorkItemCommentNote.userPermissions, adminNote: true },
+ },
+ });
+
+ findDeleteNoteButton().vm.$emit('click');
+
+ expect(wrapper.emitted('deleteNote')).toEqual([[]]);
+ });
});
});
diff --git a/spec/frontend/work_items/components/work_item_notes_spec.js b/spec/frontend/work_items/components/work_item_notes_spec.js
index e5b4bee68a8..3db848a0ad2 100644
--- a/spec/frontend/work_items/components/work_item_notes_spec.js
+++ b/spec/frontend/work_items/components/work_item_notes_spec.js
@@ -8,7 +8,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import SystemNote from '~/work_items/components/notes/system_note.vue';
import WorkItemNotes from '~/work_items/components/work_item_notes.vue';
import WorkItemDiscussion from '~/work_items/components/notes/work_item_discussion.vue';
-import WorkItemCommentForm from '~/work_items/components/work_item_comment_form.vue';
+import WorkItemAddNote from '~/work_items/components/notes/work_item_add_note.vue';
import ActivityFilter from '~/work_items/components/notes/activity_filter.vue';
import workItemNotesQuery from '~/work_items/graphql/notes/work_item_notes.query.graphql';
import workItemNotesByIidQuery from '~/work_items/graphql/notes/work_item_notes_by_iid.query.graphql';
@@ -54,7 +54,7 @@ describe('WorkItemNotes component', () => {
const findAllSystemNotes = () => wrapper.findAllComponents(SystemNote);
const findAllListItems = () => wrapper.findAll('ul.timeline > *');
const findActivityLabel = () => wrapper.find('label');
- const findWorkItemCommentForm = () => wrapper.findComponent(WorkItemCommentForm);
+ const findWorkItemAddNote = () => wrapper.findComponent(WorkItemAddNote);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
const findSortingFilter = () => wrapper.findComponent(ActivityFilter);
const findSystemNoteAtIndex = (index) => findAllSystemNotes().at(index);
@@ -123,7 +123,7 @@ describe('WorkItemNotes component', () => {
});
await waitForPromises();
- expect(findWorkItemCommentForm().props('fetchByIid')).toEqual(false);
+ expect(findWorkItemAddNote().props('fetchByIid')).toEqual(false);
});
describe('when notes are loading', () => {
@@ -161,7 +161,7 @@ describe('WorkItemNotes component', () => {
});
it('passes correct props to comment form component', () => {
- expect(findWorkItemCommentForm().props('fetchByIid')).toEqual(true);
+ expect(findWorkItemAddNote().props('fetchByIid')).toEqual(true);
});
});
@@ -218,13 +218,13 @@ describe('WorkItemNotes component', () => {
it('puts form at start of list in when sorting by newest first', async () => {
await findSortingFilter().vm.$emit('changeSortOrder', DESC);
- expect(findAllListItems().at(0).is(WorkItemCommentForm)).toEqual(true);
+ expect(findAllListItems().at(0).is(WorkItemAddNote)).toEqual(true);
});
it('puts form at end of list in when sorting by oldest first', async () => {
await findSortingFilter().vm.$emit('changeSortOrder', ASC);
- expect(findAllListItems().at(-1).is(WorkItemCommentForm)).toEqual(true);
+ expect(findAllListItems().at(-1).is(WorkItemAddNote)).toEqual(true);
});
});
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index a74e01db0da..d4832fe376d 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -1631,7 +1631,7 @@ export const projectWorkItemResponse = {
export const mockWorkItemNotesResponse = {
data: {
workItem: {
- id: 'gid://gitlab/WorkItem/600',
+ id: 'gid://gitlab/WorkItem/1',
iid: '60',
widgets: [
{
@@ -1675,10 +1675,13 @@ export const mockWorkItemNotesResponse = {
nodes: [
{
id: 'gid://gitlab/Note/2428',
+ body: 'added #31 as parent issue',
bodyHtml:
'<p data-sourcepos="1:1-1:25" dir="auto">added <a href="/flightjs/Flight/-/issues/31" data-reference-type="issue" data-original="#31" data-link="false" data-link-reference="false" data-project="6" data-issue="224" data-project-path="flightjs/Flight" data-iid="31" data-issue-type="issue" data-container=body data-placement="top" title="Perferendis est quae totam quia laborum tempore ut voluptatem." class="gfm gfm-issue">#31</a> as parent issue</p>',
systemNoteIconName: 'link',
createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -1715,10 +1718,13 @@ export const mockWorkItemNotesResponse = {
nodes: [
{
id: 'gid://gitlab/MilestoneNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
+ body: 'changed milestone to %v4.0',
bodyHtml:
'<p data-sourcepos="1:1-1:23" dir="auto">changed milestone to <a href="/flightjs/Flight/-/milestones/5" data-reference-type="milestone" data-original="%5" data-link="false" data-link-reference="false" data-project="6" data-milestone="30" data-container=body data-placement="top" title="" class="gfm gfm-milestone has-tooltip">%v4.0</a></p>',
systemNoteIconName: 'clock',
createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -1755,9 +1761,12 @@ export const mockWorkItemNotesResponse = {
nodes: [
{
id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a9883864',
+ body: 'changed weight to **89**',
bodyHtml: '<p dir="auto">changed weight to <strong>89</strong></p>',
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -1853,10 +1862,13 @@ export const mockWorkItemNotesByIidResponse = {
nodes: [
{
id: 'gid://gitlab/Note/2428',
+ body: 'added as parent issue',
bodyHtml:
'\u003cp data-sourcepos="1:1-1:25" dir="auto"\u003eadded \u003ca href="/flightjs/Flight/-/issues/31" data-reference-type="issue" data-original="#31" data-link="false" data-link-reference="false" data-project="6" data-issue="224" data-project-path="flightjs/Flight" data-iid="31" data-issue-type="issue" data-container="body" data-placement="top" title="Perferendis est quae totam quia laborum tempore ut voluptatem." class="gfm gfm-issue"\u003e#31\u003c/a\u003e as parent issue\u003c/p\u003e',
systemNoteIconName: 'link',
createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -1895,10 +1907,13 @@ export const mockWorkItemNotesByIidResponse = {
{
id:
'gid://gitlab/MilestoneNote/7b08b89a728a5ceb7de8334246837ba1d07270dc',
+ body: 'changed milestone to %v4.0',
bodyHtml:
'\u003cp data-sourcepos="1:1-1:23" dir="auto"\u003echanged milestone to \u003ca href="/flightjs/Flight/-/milestones/5" data-reference-type="milestone" data-original="%5" data-link="false" data-link-reference="false" data-project="6" data-milestone="30" data-container="body" data-placement="top" title="" class="gfm gfm-milestone has-tooltip"\u003e%v4.0\u003c/a\u003e\u003c/p\u003e',
systemNoteIconName: 'clock',
createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -1937,10 +1952,14 @@ export const mockWorkItemNotesByIidResponse = {
{
id:
'gid://gitlab/IterationNote/addbc177f7664699a135130ab05ffb78c57e4db3',
+ body:
+ 'changed iteration to Et autem debitis nam suscipit eos ut. Jul 13, 2022 - Jul 19, 2022',
bodyHtml:
'\u003cp data-sourcepos="1:1-1:36" dir="auto"\u003echanged iteration to \u003ca href="/groups/flightjs/-/iterations/5352" data-reference-type="iteration" data-original="*iteration:5352" data-link="false" data-link-reference="false" data-project="6" data-iteration="5352" data-container="body" data-placement="top" title="Iteration" class="gfm gfm-iteration has-tooltip"\u003eEt autem debitis nam suscipit eos ut. Jul 13, 2022 - Jul 19, 2022\u003c/a\u003e\u003c/p\u003e',
systemNoteIconName: 'iteration',
createdAt: '2022-11-14T04:19:00Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -2034,10 +2053,13 @@ export const mockMoreWorkItemNotesResponse = {
nodes: [
{
id: 'gid://gitlab/Note/2428',
+ body: 'added #31 as parent issue',
bodyHtml:
'<p data-sourcepos="1:1-1:25" dir="auto">added <a href="/flightjs/Flight/-/issues/31" data-reference-type="issue" data-original="#31" data-link="false" data-link-reference="false" data-project="6" data-issue="224" data-project-path="flightjs/Flight" data-iid="31" data-issue-type="issue" data-container=body data-placement="top" title="Perferendis est quae totam quia laborum tempore ut voluptatem." class="gfm gfm-issue">#31</a> as parent issue</p>',
systemNoteIconName: 'link',
createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -2074,10 +2096,13 @@ export const mockMoreWorkItemNotesResponse = {
nodes: [
{
id: 'gid://gitlab/MilestoneNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83823',
+ body: 'changed milestone to %v4.0',
bodyHtml:
'<p data-sourcepos="1:1-1:23" dir="auto">changed milestone to <a href="/flightjs/Flight/-/milestones/5" data-reference-type="milestone" data-original="%5" data-link="false" data-link-reference="false" data-project="6" data-milestone="30" data-container=body data-placement="top" title="" class="gfm gfm-milestone has-tooltip">%v4.0</a></p>',
systemNoteIconName: 'clock',
createdAt: '2022-11-14T04:18:59Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -2114,9 +2139,12 @@ export const mockMoreWorkItemNotesResponse = {
nodes: [
{
id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a7d83864',
+ body: 'changed weight to **89**',
bodyHtml: '<p dir="auto">changed weight to <strong>89</strong></p>',
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: true,
internal: false,
discussion: {
@@ -2163,17 +2191,21 @@ export const createWorkItemNoteResponse = {
createNote: {
errors: [],
note: {
+ id: 'gid://gitlab/Note/569',
discussion: {
id: 'gid://gitlab/Discussion/c872ba2d7d3eb780d2255138d67ca8b04f65b122',
notes: {
nodes: [
{
id: 'gid://gitlab/Note/569',
+ body: 'Main comment',
bodyHtml: '<p data-sourcepos="1:1-1:9" dir="auto">Main comment</p>',
system: false,
internal: false,
systemNoteIconName: null,
createdAt: '2023-01-25T04:49:46Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
discussion: {
id: 'gid://gitlab/Discussion/c872ba2d7d3eb780d2255138d67ca8b04f65b122',
__typename: 'Discussion',
@@ -2214,10 +2246,13 @@ export const createWorkItemNoteResponse = {
export const mockWorkItemCommentNote = {
id: 'gid://gitlab/Note/158',
+ body: 'How are you ? what do you think about this ?',
bodyHtml:
'<p data-sourcepos="1:1-1:76" dir="auto"><gl-emoji title="waving hand sign" data-name="wave" data-unicode-version="6.0">๐Ÿ‘‹</gl-emoji> Hi <a href="/fredda.brekke" data-reference-type="user" data-user="3" data-container="body" data-placement="top" class="gfm gfm-project_member js-user-link" title="Sherie Nitzsche">@fredda.brekke</a> How are you ? what do you think about this ? <gl-emoji title="person with folded hands" data-name="pray" data-unicode-version="6.0">๐Ÿ™</gl-emoji></p>',
systemNoteIconName: false,
createdAt: '2022-11-25T07:16:20Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: false,
internal: false,
discussion: {
@@ -2289,11 +2324,14 @@ export const mockWorkItemNotesResponseWithComments = {
nodes: [
{
id: 'gid://gitlab/DiscussionNote/174',
+ body: 'Separate thread',
bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Separate thread</p>',
system: false,
internal: false,
systemNoteIconName: null,
createdAt: '2023-01-12T07:47:40Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
discussion: {
id: 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
__typename: 'Discussion',
@@ -2320,11 +2358,14 @@ export const mockWorkItemNotesResponseWithComments = {
},
{
id: 'gid://gitlab/DiscussionNote/235',
+ body: 'Thread comment',
bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Thread comment</p>',
system: false,
internal: false,
systemNoteIconName: null,
createdAt: '2023-01-18T09:09:54Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
discussion: {
id: 'gid://gitlab/Discussion/2bb1162fd0d39297d1a68fdd7d4083d3780af0f3',
__typename: 'Discussion',
@@ -2360,9 +2401,12 @@ export const mockWorkItemNotesResponseWithComments = {
nodes: [
{
id: 'gid://gitlab/WeightNote/0f2f195ec0d1ef95ee9d5b10446b8e96a9883864',
+ body: 'Main thread 2',
bodyHtml: '<p data-sourcepos="1:1-1:15" dir="auto">Main thread 2</p>',
systemNoteIconName: 'weight',
createdAt: '2022-11-25T07:16:20Z',
+ lastEditedAt: null,
+ lastEditedBy: null,
system: false,
internal: false,
discussion: {
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 23de9a50e50..dfb7de34993 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -91,34 +91,6 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching, feature_categ
end
end
- describe 'preloading deployment associations' do
- let!(:environment) { create(:environment, project: project) }
-
- associations = [:last_deployment, :last_visible_deployment, :upcoming_deployment]
- associations.concat Deployment::FINISHED_STATUSES.map { |status| "last_#{status}_deployment".to_sym }
- associations.concat Deployment::UPCOMING_STATUSES.map { |status| "last_#{status}_deployment".to_sym }
-
- context 'raises error for legacy approach' do
- let!(:error_pattern) { /Preloading instance dependent scopes is not supported/ }
-
- subject { described_class.preload(association_name).find_by(id: environment) }
-
- shared_examples 'raises error' do
- it do
- expect { subject }.to raise_error(error_pattern)
- end
- end
-
- associations.each do |association|
- context association.to_s do
- let!(:association_name) { association }
-
- include_examples "raises error"
- end
- end
- end
- end
-
describe 'validate and sanitize external url' do
let_it_be_with_refind(:environment) { create(:environment) }