Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4362d376f3
commit
cef84e8da0
|
|
@ -5,6 +5,7 @@ import MockAdapter from 'axios-mock-adapter';
|
|||
import Vue, { nextTick } from 'vue';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import Vuex from 'vuex';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
|
||||
import batchComments from '~/batch_comments/stores/modules/batch_comments';
|
||||
|
|
@ -34,7 +35,6 @@ describe('issue_comment_form component', () => {
|
|||
useLocalStorageSpy();
|
||||
|
||||
let trackingSpy;
|
||||
let store;
|
||||
let wrapper;
|
||||
let axiosMock;
|
||||
|
||||
|
|
@ -48,21 +48,7 @@ describe('issue_comment_form component', () => {
|
|||
const findCommentButton = () => findCommentTypeDropdown().find('button');
|
||||
const findErrorAlerts = () => wrapper.findAllComponents(GlAlert).wrappers;
|
||||
|
||||
async function clickCommentButton({ waitForComponent = true, waitForNetwork = true } = {}) {
|
||||
findCommentButton().trigger('click');
|
||||
|
||||
if (waitForComponent || waitForNetwork) {
|
||||
// Wait for the click to bubble out and trigger the handler
|
||||
await nextTick();
|
||||
|
||||
if (waitForNetwork) {
|
||||
// Wait for the network request promise to resolve
|
||||
await nextTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createStore({ actions = {} } = {}) {
|
||||
const createStore = ({ actions = {}, state = {} } = {}) => {
|
||||
const baseModule = notesModule();
|
||||
|
||||
return new Vuex.Store({
|
||||
|
|
@ -71,8 +57,12 @@ describe('issue_comment_form component', () => {
|
|||
...baseModule.actions,
|
||||
...actions,
|
||||
},
|
||||
state: {
|
||||
...baseModule.state,
|
||||
...state,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const createNotableDataMock = (data = {}) => {
|
||||
return {
|
||||
|
|
@ -105,6 +95,7 @@ describe('issue_comment_form component', () => {
|
|||
userData = userDataMock,
|
||||
features = {},
|
||||
mountFunction = shallowMount,
|
||||
store = createStore(),
|
||||
} = {}) => {
|
||||
store.dispatch('setNoteableData', noteableData);
|
||||
store.dispatch('setNotesData', notesData);
|
||||
|
|
@ -139,7 +130,6 @@ describe('issue_comment_form component', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
axiosMock = new MockAdapter(axios);
|
||||
store = createStore();
|
||||
trackingSpy = mockTracking(undefined, null, jest.spyOn);
|
||||
});
|
||||
|
||||
|
|
@ -149,25 +139,32 @@ describe('issue_comment_form component', () => {
|
|||
|
||||
describe('user is logged in', () => {
|
||||
describe('handleSave', () => {
|
||||
it('should request to save note when note is entered', () => {
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'hello world' } });
|
||||
const note = 'hello world';
|
||||
|
||||
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
|
||||
|
||||
findCloseReopenButton().trigger('click');
|
||||
|
||||
expect(wrapper.vm.isSubmitting).toBe(true);
|
||||
expect(wrapper.vm.note).toBe('');
|
||||
expect(wrapper.vm.saveNote).toHaveBeenCalled();
|
||||
it('should request to save note when note is entered', async () => {
|
||||
const saveNoteSpy = jest.fn();
|
||||
const store = createStore({
|
||||
actions: {
|
||||
saveNote: saveNoteSpy,
|
||||
},
|
||||
});
|
||||
mountComponent({ mountFunction: mount, initialData: { note }, store });
|
||||
expect(findCloseReopenButton().props('disabled')).toBe(false);
|
||||
expect(findMarkdownEditor().props('value')).toBe(note);
|
||||
await findCloseReopenButton().trigger('click');
|
||||
expect(findCloseReopenButton().props('disabled')).toBe(true);
|
||||
expect(findMarkdownEditor().props('value')).toBe('');
|
||||
expect(saveNoteSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('tracks event', () => {
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'hello world' } });
|
||||
|
||||
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
|
||||
|
||||
findCloseReopenButton().trigger('click');
|
||||
|
||||
it('tracks event', async () => {
|
||||
const store = createStore({
|
||||
actions: {
|
||||
saveNote: jest.fn().mockResolvedValue(),
|
||||
},
|
||||
});
|
||||
mountComponent({ mountFunction: mount, initialData: { note }, store });
|
||||
await findCloseReopenButton().trigger('click');
|
||||
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'save_markdown', {
|
||||
label: 'markdown_editor',
|
||||
property: 'Issue_comment',
|
||||
|
|
@ -175,12 +172,13 @@ describe('issue_comment_form component', () => {
|
|||
});
|
||||
|
||||
it('does not report errors in the UI when the save succeeds', async () => {
|
||||
mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' } });
|
||||
|
||||
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
|
||||
|
||||
await clickCommentButton();
|
||||
|
||||
const store = createStore({
|
||||
actions: {
|
||||
saveNote: jest.fn().mockResolvedValue(),
|
||||
},
|
||||
});
|
||||
mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' }, store });
|
||||
await findCommentButton().trigger('click');
|
||||
// findErrorAlerts().exists returns false if *any* wrapper is empty,
|
||||
// not necessarily that there aren't any at all.
|
||||
// We want to check here that there are none found, so we use the
|
||||
|
|
@ -197,20 +195,17 @@ describe('issue_comment_form component', () => {
|
|||
`(
|
||||
'displays the correct errors ($errors) for a $httpStatus network response',
|
||||
async ({ errors, httpStatus }) => {
|
||||
store = createStore({
|
||||
const store = createStore({
|
||||
actions: {
|
||||
saveNote: jest.fn().mockRejectedValue({
|
||||
response: { status: httpStatus, data: { errors: { commands_only: errors } } },
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' } });
|
||||
|
||||
await clickCommentButton();
|
||||
|
||||
mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' }, store });
|
||||
await findCommentButton().trigger('click');
|
||||
await waitForPromises();
|
||||
const errorAlerts = findErrorAlerts();
|
||||
|
||||
expect(errorAlerts.length).toBe(errors.length);
|
||||
errors.forEach((msg, index) => {
|
||||
const alert = errorAlerts[index];
|
||||
|
|
@ -222,7 +217,7 @@ describe('issue_comment_form component', () => {
|
|||
|
||||
describe('if response contains validation errors', () => {
|
||||
beforeEach(() => {
|
||||
store = createStore({
|
||||
const store = createStore({
|
||||
actions: {
|
||||
saveNote: jest.fn().mockRejectedValue({
|
||||
response: {
|
||||
|
|
@ -233,9 +228,9 @@ describe('issue_comment_form component', () => {
|
|||
},
|
||||
});
|
||||
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'invalid note' } });
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'invalid note' }, store });
|
||||
|
||||
clickCommentButton();
|
||||
findCommentButton().trigger('click');
|
||||
});
|
||||
|
||||
it('renders an error message', () => {
|
||||
|
|
@ -251,7 +246,7 @@ describe('issue_comment_form component', () => {
|
|||
|
||||
it('should remove the correct error from the list when it is dismissed', async () => {
|
||||
const commandErrors = ['1', '2', '3'];
|
||||
store = createStore({
|
||||
const store = createStore({
|
||||
actions: {
|
||||
saveNote: jest.fn().mockRejectedValue({
|
||||
response: {
|
||||
|
|
@ -261,10 +256,9 @@ describe('issue_comment_form component', () => {
|
|||
}),
|
||||
},
|
||||
});
|
||||
|
||||
mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' } });
|
||||
|
||||
await clickCommentButton();
|
||||
mountComponent({ mountFunction: mount, initialData: { note: '/label ~sdfghj' }, store });
|
||||
await findCommentButton().trigger('click');
|
||||
await waitForPromises();
|
||||
|
||||
let errorAlerts = findErrorAlerts();
|
||||
|
||||
|
|
@ -335,11 +329,8 @@ describe('issue_comment_form component', () => {
|
|||
`(
|
||||
'should render textarea with placeholder for $noteType',
|
||||
async ({ noteIsInternal, placeholder }) => {
|
||||
mountComponent();
|
||||
|
||||
wrapper.vm.noteIsInternal = noteIsInternal;
|
||||
await nextTick();
|
||||
|
||||
await mountComponent();
|
||||
await findConfidentialNoteCheckbox().vm.$emit('input', noteIsInternal);
|
||||
expect(findMarkdownEditor().props('formFieldProps').placeholder).toBe(placeholder);
|
||||
},
|
||||
);
|
||||
|
|
@ -371,25 +362,20 @@ describe('issue_comment_form component', () => {
|
|||
expect(wrapper.find(`[href="${markdownDocsPath}"]`).exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('should resize textarea after note discarded', async () => {
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'foo' } });
|
||||
|
||||
jest.spyOn(wrapper.vm, 'discard');
|
||||
|
||||
wrapper.vm.discard();
|
||||
|
||||
await nextTick();
|
||||
|
||||
it('should resize textarea after note is saved', async () => {
|
||||
const store = createStore();
|
||||
store.registerModule('batchComments', batchComments());
|
||||
store.state.batchComments.drafts = [{ note: 'A' }];
|
||||
await mountComponent({ mountFunction: mount, initialData: { note: 'foo' }, store });
|
||||
await findAddCommentNowButton().trigger('click');
|
||||
await waitForPromises();
|
||||
expect(Autosize.update).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit mode', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ mountFunction: mount });
|
||||
});
|
||||
|
||||
it('should enter edit mode when arrow up is pressed', () => {
|
||||
mountComponent({ mountFunction: mount });
|
||||
jest.spyOn(wrapper.vm, 'editCurrentUserLastNote');
|
||||
|
||||
findMarkdownEditorTextarea().trigger('keydown.up');
|
||||
|
|
@ -400,6 +386,7 @@ describe('issue_comment_form component', () => {
|
|||
describe('event enter', () => {
|
||||
describe('when no draft exists', () => {
|
||||
it('should save note when cmd+enter is pressed', () => {
|
||||
mountComponent({ mountFunction: mount });
|
||||
jest.spyOn(wrapper.vm, 'handleSave');
|
||||
|
||||
findMarkdownEditorTextarea().trigger('keydown.enter', { metaKey: true });
|
||||
|
|
@ -408,6 +395,7 @@ describe('issue_comment_form component', () => {
|
|||
});
|
||||
|
||||
it('should save note when ctrl+enter is pressed', () => {
|
||||
mountComponent({ mountFunction: mount });
|
||||
jest.spyOn(wrapper.vm, 'handleSave');
|
||||
|
||||
findMarkdownEditorTextarea().trigger('keydown.enter', { ctrlKey: true });
|
||||
|
|
@ -417,24 +405,25 @@ describe('issue_comment_form component', () => {
|
|||
});
|
||||
|
||||
describe('when a draft exists', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore();
|
||||
store.registerModule('batchComments', batchComments());
|
||||
store.state.batchComments.drafts = [{ note: 'A' }];
|
||||
});
|
||||
|
||||
it('should save note draft when cmd+enter is pressed', () => {
|
||||
it('should save note draft when cmd+enter is pressed', async () => {
|
||||
mountComponent({ mountFunction: mount, store });
|
||||
jest.spyOn(wrapper.vm, 'handleSaveDraft');
|
||||
|
||||
findMarkdownEditorTextarea().trigger('keydown.enter', { metaKey: true });
|
||||
|
||||
await findMarkdownEditorTextarea().trigger('keydown.enter', { metaKey: true });
|
||||
expect(wrapper.vm.handleSaveDraft).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it('should save note draft when ctrl+enter is pressed', () => {
|
||||
it('should save note draft when ctrl+enter is pressed', async () => {
|
||||
mountComponent({ mountFunction: mount, store });
|
||||
jest.spyOn(wrapper.vm, 'handleSaveDraft');
|
||||
|
||||
findMarkdownEditorTextarea().trigger('keydown.enter', { ctrlKey: true });
|
||||
|
||||
await findMarkdownEditorTextarea().trigger('keydown.enter', { ctrlKey: true });
|
||||
expect(wrapper.vm.handleSaveDraft).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
|
@ -706,7 +695,7 @@ describe('issue_comment_form component', () => {
|
|||
|
||||
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
|
||||
|
||||
clickCommentButton();
|
||||
findCommentButton().trigger('click');
|
||||
|
||||
expect(wrapper.vm.saveNote).not.toHaveBeenCalled();
|
||||
});
|
||||
|
|
@ -719,7 +708,7 @@ describe('issue_comment_form component', () => {
|
|||
|
||||
jest.spyOn(wrapper.vm, 'saveNote').mockResolvedValue();
|
||||
|
||||
clickCommentButton();
|
||||
findCommentButton().trigger('click');
|
||||
|
||||
expect(wrapper.vm.saveNote).toHaveBeenCalled();
|
||||
});
|
||||
|
|
@ -740,14 +729,16 @@ describe('issue_comment_form component', () => {
|
|||
});
|
||||
|
||||
describe('with batchComments in store', () => {
|
||||
beforeEach(() => {
|
||||
store.registerModule('batchComments', batchComments());
|
||||
});
|
||||
|
||||
describe('add to review and comment now buttons', () => {
|
||||
it('when no drafts exist, should not render', () => {
|
||||
mountComponent();
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore();
|
||||
store.registerModule('batchComments', batchComments());
|
||||
});
|
||||
|
||||
it('when no drafts exist, should not render', () => {
|
||||
mountComponent({ store });
|
||||
expect(findCommentTypeDropdown().exists()).toBe(true);
|
||||
expect(findAddToReviewButton().exists()).toBe(false);
|
||||
expect(findAddCommentNowButton().exists()).toBe(false);
|
||||
|
|
@ -758,20 +749,17 @@ describe('issue_comment_form component', () => {
|
|||
store.state.batchComments.drafts = [{ note: 'A' }];
|
||||
});
|
||||
|
||||
it('should render', () => {
|
||||
mountComponent();
|
||||
|
||||
it('should render', async () => {
|
||||
await mountComponent({ store });
|
||||
expect(findCommentTypeDropdown().exists()).toBe(false);
|
||||
expect(findAddToReviewButton().exists()).toBe(true);
|
||||
expect(findAddCommentNowButton().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('clicking `add to review`, should call draft endpoint, set `isDraft` true', () => {
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'a draft note' } });
|
||||
|
||||
it('clicking `add to review`, should call draft endpoint, set `isDraft` true', async () => {
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'a draft note' }, store });
|
||||
jest.spyOn(store, 'dispatch').mockResolvedValue();
|
||||
findAddToReviewButton().trigger('click');
|
||||
|
||||
await findAddToReviewButton().trigger('click');
|
||||
expect(store.dispatch).toHaveBeenCalledWith(
|
||||
'saveNote',
|
||||
expect.objectContaining({
|
||||
|
|
@ -781,12 +769,10 @@ describe('issue_comment_form component', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('clicking `add comment now`, should call note endpoint, set `isDraft` false', () => {
|
||||
mountComponent({ mountFunction: mount, initialData: { note: 'a comment' } });
|
||||
|
||||
it('clicking `add comment now`, should call note endpoint, set `isDraft` false', async () => {
|
||||
await mountComponent({ mountFunction: mount, initialData: { note: 'a comment' }, store });
|
||||
jest.spyOn(store, 'dispatch').mockResolvedValue();
|
||||
findAddCommentNowButton().trigger('click');
|
||||
|
||||
await findAddCommentNowButton().trigger('click');
|
||||
expect(store.dispatch).toHaveBeenCalledWith(
|
||||
'saveNote',
|
||||
expect.objectContaining({
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ RSpec.describe MergeRequests::DeleteNonLatestDiffsService, :clean_gitlab_redis_s
|
|||
merge_request.reset
|
||||
end
|
||||
|
||||
it 'schedules non-latest merge request diffs removal' do
|
||||
it 'schedules non-latest merge request diffs removal',
|
||||
quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/426807' do
|
||||
diffs = merge_request.merge_request_diffs
|
||||
|
||||
expect(diffs.count).to eq(4)
|
||||
|
|
|
|||
Loading…
Reference in New Issue