summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorKushal Pandya <kushalspandya@gmail.com>2017-05-05 10:57:29 +0000
committerFilipa Lacerda <filipa@gitlab.com>2017-05-05 10:57:29 +0000
commit645593e5af1fe9e7fa345788aeaa90d2313d6486 (patch)
tree514b8e8acbc10e915c50971c31b7fab6fdbcb18f /spec
parenta5347fe58f6ace1ced67fa32a8469ba4e2819606 (diff)
downloadgitlab-ce-645593e5af1fe9e7fa345788aeaa90d2313d6486.tar.gz
Add instant comments support
Diffstat (limited to 'spec')
-rw-r--r--spec/features/merge_requests/user_posts_notes_spec.rb1
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb1
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js11
-rw-r--r--spec/javascripts/notes_spec.js229
-rw-r--r--spec/support/features/issuable_slash_commands_shared_examples.rb1
-rw-r--r--spec/support/time_tracking_shared_examples.rb5
6 files changed, 243 insertions, 5 deletions
diff --git a/spec/features/merge_requests/user_posts_notes_spec.rb b/spec/features/merge_requests/user_posts_notes_spec.rb
index c7cc4d6bc72..7fc0e2ce6ec 100644
--- a/spec/features/merge_requests/user_posts_notes_spec.rb
+++ b/spec/features/merge_requests/user_posts_notes_spec.rb
@@ -98,6 +98,7 @@ describe 'Merge requests > User posts notes', :js do
find('.btn-save').click
end
+ wait_for_ajax
find('.note').hover
find('.js-note-edit').click
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index 1c0f21e5616..f0ad57eb92f 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -160,6 +160,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do
it 'changes target branch from a note' do
write_note("message start \n/target_branch merge-test\n message end.")
+ wait_for_ajax
expect(page).not_to have_content('/target_branch')
expect(page).to have_content('message start')
expect(page).to have_content('message end.')
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index a00efa10119..5eb147ed888 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -362,5 +362,16 @@ require('~/lib/utils/common_utils');
gl.utils.setCiStatusFavicon(BUILD_URL);
});
});
+
+ describe('gl.utils.ajaxPost', () => {
+ it('should perform `$.ajax` call and do `POST` request', () => {
+ const requestURL = '/some/random/api';
+ const data = { keyname: 'value' };
+ const ajaxSpy = spyOn($, 'ajax').and.callFake(() => {});
+
+ gl.utils.ajaxPost(requestURL, data);
+ expect(ajaxSpy.calls.allArgs()[0][0].type).toEqual('POST');
+ });
+ });
});
})();
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index cdc5c4510ff..7bffa90ab14 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -26,7 +26,7 @@ import '~/notes';
describe('task lists', function() {
beforeEach(function() {
- $('form').on('submit', function(e) {
+ $('.js-comment-button').on('click', function(e) {
e.preventDefault();
});
this.notes = new Notes();
@@ -60,9 +60,12 @@ import '~/notes';
reset: function() {}
});
- $('form').on('submit', function(e) {
+ $('.js-comment-button').on('click', (e) => {
+ const $form = $(this);
e.preventDefault();
- $('.js-main-target-form').trigger('ajax:success');
+ this.notes.addNote($form);
+ this.notes.reenableTargetFormSubmitButton(e);
+ this.notes.resetMainTargetForm(e);
});
});
@@ -238,8 +241,8 @@ import '~/notes';
$resultantNote = Notes.animateAppendNote(noteHTML, $notesList);
});
- it('should have `fade-in` class', () => {
- expect($resultantNote.hasClass('fade-in')).toEqual(true);
+ it('should have `fade-in-full` class', () => {
+ expect($resultantNote.hasClass('fade-in-full')).toEqual(true);
});
it('should append note to the notes list', () => {
@@ -269,5 +272,221 @@ import '~/notes';
expect($note.replaceWith).toHaveBeenCalledWith($updatedNote);
});
});
+
+ describe('getFormData', () => {
+ it('should return form metadata object from form reference', () => {
+ this.notes = new Notes();
+
+ const $form = $('form');
+ const sampleComment = 'foobar';
+ $form.find('textarea.js-note-text').val(sampleComment);
+ const { formData, formContent, formAction } = this.notes.getFormData($form);
+
+ expect(formData.indexOf(sampleComment) > -1).toBe(true);
+ expect(formContent).toEqual(sampleComment);
+ expect(formAction).toEqual($form.attr('action'));
+ });
+ });
+
+ describe('hasSlashCommands', () => {
+ beforeEach(() => {
+ this.notes = new Notes();
+ });
+
+ it('should return true when comment has slash commands', () => {
+ const sampleComment = '/wip /milestone %1.0 /merge /unassign Merging this';
+ const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
+
+ expect(hasSlashCommands).toBeTruthy();
+ });
+
+ it('should return false when comment does NOT have any slash commands', () => {
+ const sampleComment = 'Looking good, Awesome!';
+ const hasSlashCommands = this.notes.hasSlashCommands(sampleComment);
+
+ expect(hasSlashCommands).toBeFalsy();
+ });
+ });
+
+ describe('stripSlashCommands', () => {
+ const REGEX_SLASH_COMMANDS = /\/\w+/g;
+
+ it('should strip slash commands from the comment', () => {
+ this.notes = new Notes();
+ const sampleComment = '/wip /milestone %1.0 /merge /unassign Merging this';
+ const stripedComment = this.notes.stripSlashCommands(sampleComment);
+
+ expect(REGEX_SLASH_COMMANDS.test(stripedComment)).toBeFalsy();
+ });
+ });
+
+ describe('createPlaceholderNote', () => {
+ const sampleComment = 'foobar';
+ const uniqueId = 'b1234-a4567';
+ const currentUsername = 'root';
+ const currentUserFullname = 'Administrator';
+
+ beforeEach(() => {
+ this.notes = new Notes();
+ });
+
+ it('should return constructed placeholder element for regular note based on form contents', () => {
+ const $tempNote = this.notes.createPlaceholderNote({
+ formContent: sampleComment,
+ uniqueId,
+ isDiscussionNote: false,
+ currentUsername,
+ currentUserFullname
+ });
+ const $tempNoteHeader = $tempNote.find('.note-header');
+
+ expect($tempNote.prop('nodeName')).toEqual('LI');
+ expect($tempNote.attr('id')).toEqual(uniqueId);
+ $tempNote.find('.timeline-icon > a, .note-header-info > a').each(function() {
+ expect($(this).attr('href')).toEqual(`/${currentUsername}`);
+ });
+ expect($tempNote.find('.timeline-content').hasClass('discussion')).toBeFalsy();
+ expect($tempNoteHeader.find('.hidden-xs').text().trim()).toEqual(currentUserFullname);
+ expect($tempNoteHeader.find('.note-headline-light').text().trim()).toEqual(`@${currentUsername}`);
+ expect($tempNote.find('.note-body .note-text').text().trim()).toEqual(sampleComment);
+ });
+
+ it('should return constructed placeholder element for discussion note based on form contents', () => {
+ const $tempNote = this.notes.createPlaceholderNote({
+ formContent: sampleComment,
+ uniqueId,
+ isDiscussionNote: true,
+ currentUsername,
+ currentUserFullname
+ });
+
+ expect($tempNote.prop('nodeName')).toEqual('LI');
+ expect($tempNote.find('.timeline-content').hasClass('discussion')).toBeTruthy();
+ });
+ });
+
+ describe('postComment & updateComment', () => {
+ const sampleComment = 'foo';
+ const updatedComment = 'bar';
+ const note = {
+ id: 1234,
+ html: `<li class="note note-row-1234 timeline-entry" id="note_1234">
+ <div class="note-text">${sampleComment}</div>
+ </li>`,
+ note: sampleComment,
+ valid: true
+ };
+ let $form;
+ let $notesContainer;
+
+ beforeEach(() => {
+ this.notes = new Notes();
+ window.gon.current_username = 'root';
+ window.gon.current_user_fullname = 'Administrator';
+ $form = $('form');
+ $notesContainer = $('ul.main-notes-list');
+ $form.find('textarea.js-note-text').val(sampleComment);
+ $('.js-comment-button').click();
+ });
+
+ it('should show placeholder note while new comment is being posted', () => {
+ expect($notesContainer.find('.note.being-posted').length > 0).toEqual(true);
+ });
+
+ it('should remove placeholder note when new comment is done posting', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.success(note);
+ expect($notesContainer.find('.note.being-posted').length).toEqual(0);
+ });
+ });
+
+ it('should show actual note element when new comment is done posting', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.success(note);
+ expect($notesContainer.find(`#${note.id}`).length > 0).toEqual(true);
+ });
+ });
+
+ it('should reset Form when new comment is done posting', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.success(note);
+ expect($form.find('textarea.js-note-text')).toEqual('');
+ });
+ });
+
+ it('should trigger ajax:success event on Form when new comment is done posting', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.success(note);
+ spyOn($form, 'trigger');
+ expect($form.trigger).toHaveBeenCalledWith('ajax:success', [note]);
+ });
+ });
+
+ it('should show flash error message when new comment failed to be posted', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.error();
+ expect($notesContainer.parent().find('.flash-container .flash-text').is(':visible')).toEqual(true);
+ });
+ });
+
+ it('should refill form textarea with original comment content when new comment failed to be posted', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.error();
+ expect($form.find('textarea.js-note-text')).toEqual(sampleComment);
+ });
+ });
+
+ it('should show updated comment as _actively being posted_ while comment being updated', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.success(note);
+ const $noteEl = $notesContainer.find(`#note_${note.id}`);
+ $noteEl.find('.js-note-edit').click();
+ $noteEl.find('textarea.js-note-text').val(updatedComment);
+ $noteEl.find('.js-comment-save-button').click();
+ expect($noteEl.hasClass('.being-posted')).toEqual(true);
+ expect($noteEl.find('.note-text').text()).toEqual(updatedComment);
+ });
+ });
+
+ it('should show updated comment when comment update is done posting', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.success(note);
+ const $noteEl = $notesContainer.find(`#note_${note.id}`);
+ $noteEl.find('.js-note-edit').click();
+ $noteEl.find('textarea.js-note-text').val(updatedComment);
+ $noteEl.find('.js-comment-save-button').click();
+
+ spyOn($, 'ajax').and.callFake((updateOptions) => {
+ const updatedNote = Object.assign({}, note);
+ updatedNote.note = updatedComment;
+ updatedNote.html = `<li class="note note-row-1234 timeline-entry" id="note_1234">
+ <div class="note-text">${updatedComment}</div>
+ </li>`;
+ updateOptions.success(updatedNote);
+ const $updatedNoteEl = $notesContainer.find(`#note_${updatedNote.id}`);
+ expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals
+ expect($updatedNoteEl.find('note-text').text().trim()).toEqual(updatedComment); // Verify if comment text updated
+ });
+ });
+ });
+
+ it('should show flash error message when comment failed to be updated', () => {
+ spyOn($, 'ajax').and.callFake((options) => {
+ options.success(note);
+ const $noteEl = $notesContainer.find(`#note_${note.id}`);
+ $noteEl.find('.js-note-edit').click();
+ $noteEl.find('textarea.js-note-text').val(updatedComment);
+ $noteEl.find('.js-comment-save-button').click();
+
+ spyOn($, 'ajax').and.callFake((updateOptions) => {
+ updateOptions.error();
+ const $updatedNoteEl = $notesContainer.find(`#note_${note.id}`);
+ expect($updatedNoteEl.hasClass('.being-posted')).toEqual(false); // Remove being-posted visuals
+ expect($updatedNoteEl.find('note-text').text().trim()).toEqual(sampleComment); // See if comment reverted back to original
+ expect($notesContainer.parent().find('.flash-container .flash-text').is(':visible')).toEqual(true); // Flash error message shown
+ });
+ });
+ });
+ });
});
}).call(window);
diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb
index 6efcdd7a1de..610decdcddb 100644
--- a/spec/support/features/issuable_slash_commands_shared_examples.rb
+++ b/spec/support/features/issuable_slash_commands_shared_examples.rb
@@ -58,6 +58,7 @@ shared_examples 'issuable record that supports slash commands in its description
expect(page).not_to have_content '/label ~bug'
expect(page).not_to have_content '/milestone %"ASAP"'
+ wait_for_ajax
issuable.reload
note = issuable.notes.user.first
diff --git a/spec/support/time_tracking_shared_examples.rb b/spec/support/time_tracking_shared_examples.rb
index 01bc80f957e..e94e17da7e5 100644
--- a/spec/support/time_tracking_shared_examples.rb
+++ b/spec/support/time_tracking_shared_examples.rb
@@ -8,6 +8,7 @@ shared_examples 'issuable time tracker' do
it 'updates the sidebar component when estimate is added' do
submit_time('/estimate 3w 1d 1h')
+ wait_for_ajax
page.within '.time-tracking-estimate-only-pane' do
expect(page).to have_content '3w 1d 1h'
end
@@ -16,6 +17,7 @@ shared_examples 'issuable time tracker' do
it 'updates the sidebar component when spent is added' do
submit_time('/spend 3w 1d 1h')
+ wait_for_ajax
page.within '.time-tracking-spend-only-pane' do
expect(page).to have_content '3w 1d 1h'
end
@@ -25,6 +27,7 @@ shared_examples 'issuable time tracker' do
submit_time('/estimate 3w 1d 1h')
submit_time('/spend 3w 1d 1h')
+ wait_for_ajax
page.within '.time-tracking-comparison-pane' do
expect(page).to have_content '3w 1d 1h'
end
@@ -34,6 +37,7 @@ shared_examples 'issuable time tracker' do
submit_time('/estimate 3w 1d 1h')
submit_time('/remove_estimate')
+ wait_for_ajax
page.within '#issuable-time-tracker' do
expect(page).to have_content 'No estimate or time spent'
end
@@ -43,6 +47,7 @@ shared_examples 'issuable time tracker' do
submit_time('/spend 3w 1d 1h')
submit_time('/remove_time_spent')
+ wait_for_ajax
page.within '#issuable-time-tracker' do
expect(page).to have_content 'No estimate or time spent'
end