diff --git a/app/assets/javascripts/notes/components/issue_note_actions.vue b/app/assets/javascripts/notes/components/issue_note_actions.vue index 23b511778cb..c7b1106ee9d 100644 --- a/app/assets/javascripts/notes/components/issue_note_actions.vue +++ b/app/assets/javascripts/notes/components/issue_note_actions.vue @@ -74,7 +74,7 @@ this.emojiSmiling = emojiSmiling; this.emojiSmile = emojiSmile; this.emojiSmiley = emojiSmiley; - } + }, }; diff --git a/app/assets/javascripts/notes/components/issue_note_awards_list.vue b/app/assets/javascripts/notes/components/issue_note_awards_list.vue index f6d27e0a0ae..518042e39af 100644 --- a/app/assets/javascripts/notes/components/issue_note_awards_list.vue +++ b/app/assets/javascripts/notes/components/issue_note_awards_list.vue @@ -143,7 +143,7 @@ let parsedName; // 100 and 1234 emoji are a number. Callback for v-for click sends it as a string - switch(awardName) { + switch (awardName) { case '100': parsedName = 100; break; diff --git a/app/assets/javascripts/notes/components/issue_note_form.vue b/app/assets/javascripts/notes/components/issue_note_form.vue index fb6e16c5590..61a9d0e391c 100644 --- a/app/assets/javascripts/notes/components/issue_note_form.vue +++ b/app/assets/javascripts/notes/components/issue_note_form.vue @@ -152,7 +152,7 @@ diff --git a/app/assets/javascripts/notes/components/issue_notes_app.vue b/app/assets/javascripts/notes/components/issue_notes_app.vue index 0e5ae78e45c..b6fc5e5036f 100644 --- a/app/assets/javascripts/notes/components/issue_notes_app.vue +++ b/app/assets/javascripts/notes/components/issue_notes_app.vue @@ -46,7 +46,6 @@ computed: { ...mapGetters([ 'notes', - 'notesById', 'getNotesDataByProp', ]), }, diff --git a/spec/javascripts/notes/components/issue_note_app_spec.js b/spec/javascripts/notes/components/issue_note_app_spec.js index bff0ae96ceb..1a782a32c43 100644 --- a/spec/javascripts/notes/components/issue_note_app_spec.js +++ b/spec/javascripts/notes/components/issue_note_app_spec.js @@ -252,17 +252,4 @@ describe('issue_note_app', () => { }, 0); }); }); - - // TODO: FILIPA - describe('create new note', () => { - it('should show placeholder note while new comment is being posted', () => {}); - it('should remove placeholder note when new comment is done posting', () => {}); - it('should show actual note element when new comment is done posting', () => {}); - it('should show flash error message when new comment failed to be posted', () => {}); - it('should show flash error message when comment failed to be updated', () => {}); - }); - - describe('shortcuts issuable spec', () => { - - }); }); diff --git a/spec/javascripts/notes/components/issue_note_form_spec.js b/spec/javascripts/notes/components/issue_note_form_spec.js index 78f8ed87d50..702e22bb6dc 100644 --- a/spec/javascripts/notes/components/issue_note_form_spec.js +++ b/spec/javascripts/notes/components/issue_note_form_spec.js @@ -1,23 +1,23 @@ import Vue from 'vue'; import store from '~/notes/stores'; -import issueNote from '~/notes/components/issue_note.vue'; +import issueNoteForm from '~/notes/components/issue_note_form.vue'; import { issueDataMock, notesDataMock } from '../mock_data'; +import { keyboardDownEvent } from '../../issue_show/helpers'; -fdescribe('issue_note_form component', () => { +describe('issue_note_form component', () => { let vm; let props; beforeEach(() => { - const Component = Vue.extend(issueNote); + const Component = Vue.extend(issueNoteForm); store.dispatch('setIssueData', issueDataMock); store.dispatch('setNotesData', notesDataMock); props = { - isEditing: true, + isEditing: false, noteBody: 'Magni suscipit eius consectetur enim et ex et commodi.', noteId: 545, - saveButtonTitle: 'Save comment', }; vm = new Component({ @@ -30,13 +30,16 @@ fdescribe('issue_note_form component', () => { vm.$destroy(); }); - describe('conflicts editing', (done) => { - it('should show conflict message if note changes outside the component', () => { + describe('conflicts editing', () => { + it('should show conflict message if note changes outside the component', (done) => { + vm.isEditing = true; vm.noteBody = 'Foo'; + const message = 'This comment has changed since you started editing, please review the updated comment to ensure information is not lost.'; Vue.nextTick(() => { - console.log('', vm.$el); - + expect( + vm.$el.querySelector('.js-conflict-edit-warning').textContent.replace(/\s+/g, ' ').trim(), + ).toEqual(message); done(); }); }); @@ -44,56 +47,65 @@ fdescribe('issue_note_form component', () => { describe('form', () => { it('should render text area with placeholder', () => { - + expect( + vm.$el.querySelector('textarea').getAttribute('placeholder'), + ).toEqual('Write a comment or drag your files here...'); }); it('should link to markdown docs', () => { - - }); - - it('should link to quick actions docs', () => { - - }); - - it('should preview the content', () => { - - }); - - it('should allow quick actions', () => { - + const { markdownDocs } = notesDataMock; + expect(vm.$el.querySelector(`a[href="${markdownDocs}"]`).textContent.trim()).toEqual('Markdown'); }); describe('keyboard events', () => { describe('up', () => { it('should ender edit mode', () => { + spyOn(vm, 'editMyLastNote').and.callThrough(); + vm.$el.querySelector('textarea').value = 'Foo'; + vm.$el.querySelector('textarea').dispatchEvent(keyboardDownEvent(38, true)); + expect(vm.editMyLastNote).toHaveBeenCalled(); }); }); describe('enter', () => { it('should submit note', () => { + spyOn(vm, 'handleUpdate').and.callThrough(); + vm.$el.querySelector('textarea').value = 'Foo'; + vm.$el.querySelector('textarea').dispatchEvent(keyboardDownEvent(13, true)); - }); - }); - - describe('esc', () => { - it('should show exit', () => { - + expect(vm.handleUpdate).toHaveBeenCalled(); }); }); }); describe('actions', () => { - it('should be possible to cancel', () => { + it('should be possible to cancel', (done) => { + spyOn(vm, 'cancelHandler').and.callThrough(); + vm.isEditing = true; + Vue.nextTick(() => { + vm.$el.querySelector('.note-edit-cancel').click(); + + Vue.nextTick(() => { + expect(vm.cancelHandler).toHaveBeenCalled(); + done(); + }); + }); }); - it('should be possible to update the note', () => { + it('should be possible to update the note', (done) => { + vm.isEditing = true; - }); - - it('should not be possible to save an empty note', () => { + Vue.nextTick(() => { + vm.$el.querySelector('textarea').value = 'Foo'; + vm.$el.querySelector('.js-vue-issue-save').click(); + Vue.nextTick(() => { + expect(vm.isSubmitting).toEqual(true); + done(); + }); + }); }); }); }); diff --git a/spec/javascripts/notes/stores/getters_spec.js b/spec/javascripts/notes/stores/getters_spec.js index ad8fc97362a..48ee1bf9a52 100644 --- a/spec/javascripts/notes/stores/getters_spec.js +++ b/spec/javascripts/notes/stores/getters_spec.js @@ -1,70 +1,58 @@ -import { getters } from '~/notes/stores/getters'; +import * as getters from '~/notes/stores/getters'; +import { notesDataMock, userDataMock, issueDataMock, individualNote } from '../mock_data'; describe('Getters Notes Store', () => { + let state; + beforeEach(() => { + state = { + notes: [individualNote], + targetNoteHash: 'hash', + lastFetchedAt: 'timestamp', + notesData: notesDataMock, + userData: userDataMock, + issueData: issueDataMock, + }; + }); describe('notes', () => { it('should return all notes in the store', () => { - + expect(getters.notes(state)).toEqual([individualNote]); }); }); describe('targetNoteHash', () => { it('should return `targetNoteHash`', () => { - + expect(getters.targetNoteHash(state)).toEqual('hash'); }); }); describe('getNotesData', () => { it('should return all data in `notesData`', () => { - - }); - }); - - describe('getNotesDataByProp', () => { - it('should return the given prop', () => { - + expect(getters.getNotesData(state)).toEqual(notesDataMock); }); }); describe('getIssueData', () => { it('should return all data in `issueData`', () => { - - }); - }); - - describe('getIssueDataByProp', () => { - it('should return the given prop', () => { - + expect(getters.getIssueData(state)).toEqual(issueDataMock); }); }); describe('getUserData', () => { it('should return all data in `userData`', () => { - - }); - }); - - describe('getUserDataByProp', () => { - it('should return the given prop', () => { - + expect(getters.getUserData(state)).toEqual(userDataMock); }); }); describe('notesById', () => { it('should return the note for the given id', () => { - + expect(getters.notesById(state)).toEqual({ 1390: individualNote.notes[0] }); }); }); describe('getCurrentUserLastNote', () => { it('should return the last note of the current user', () => { - - }); - }); - - describe('getDiscussionLastNote', () => { - it('should return the last discussion note of the current user', () => { - + expect(getters.getCurrentUserLastNote(state)).toEqual(individualNote.notes[0]); }); }); }); diff --git a/spec/javascripts/notes/stores/mutation_spec.js b/spec/javascripts/notes/stores/mutation_spec.js index 0fdba840f2e..a38f29c1e39 100644 --- a/spec/javascripts/notes/stores/mutation_spec.js +++ b/spec/javascripts/notes/stores/mutation_spec.js @@ -1,99 +1,207 @@ -import { mutations } from '~/notes/stores/mutations'; +import mutations from '~/notes/stores/mutations'; +import { note, discussionMock, notesDataMock, userDataMock, issueDataMock, individualNote } from '../mock_data'; describe('Mutation Notes Store', () => { describe('ADD_NEW_NOTE', () => { it('should add a new note to an array of notes', () => { + const state = { notes: [] }; + mutations.ADD_NEW_NOTE(state, note); + expect(state).toEqual({ + notes: [{ + expanded: true, + id: note.discussion_id, + individual_note: true, + notes: [note], + reply_id: note.discussion_id, + }], + }); }); }); describe('ADD_NEW_REPLY_TO_DISCUSSION', () => { it('should add a reply to a specific discussion', () => { + const state = { notes: [discussionMock] }; + const newReply = Object.assign({}, note, { discussion_id: discussionMock.id }); + mutations.ADD_NEW_REPLY_TO_DISCUSSION(state, newReply); + expect(state.notes[0].notes.length).toEqual(4); }); }); describe('DELETE_NOTE', () => { - it('should delete an indivudal note', () => { + it('should delete a note ', () => { + const state = { notes: [discussionMock] }; + const toDelete = discussionMock.notes[0]; + const lengthBefore = discussionMock.notes.length; - }); - - it('should delete a note from a discussion', () => { + mutations.DELETE_NOTE(state, toDelete); + expect(state.notes[0].notes.length).toEqual(lengthBefore - 1); }); }); describe('REMOVE_PLACEHOLDER_NOTES', () => { it('should remove all placeholder notes in indivudal notes and discussion', () => { + const placeholderNote = Object.assign({}, individualNote, { isPlaceholderNote: true }); + const state = { notes: [placeholderNote] }; + mutations.REMOVE_PLACEHOLDER_NOTES(state); + expect(state.notes).toEqual([]); }); }); describe('SET_NOTES_DATA', () => { it('should set an object with notesData', () => { + const state = { + notesData: {}, + }; + mutations.SET_NOTES_DATA(state, notesDataMock); + expect(state.notesData).toEqual(notesDataMock); }); }); describe('SET_ISSUE_DATA', () => { it('should set the issue data', () => { + const state = { + issueData: {}, + }; + mutations.SET_ISSUE_DATA(state, issueDataMock); + expect(state.issueData).toEqual(issueDataMock); }); }); describe('SET_USER_DATA', () => { it('should set the user data', () => { + const state = { + userData: {}, + }; + mutations.SET_USER_DATA(state, userDataMock); + expect(state.userData).toEqual(userDataMock); }); }); - describe('SET_INITAL_NOTES', () => { + describe('SET_INITIAL_NOTES', () => { it('should set the initial notes received', () => { + const state = { + notes: [], + }; + mutations.SET_INITIAL_NOTES(state, [note]); + expect(state.notes).toEqual([note]); }); }); describe('SET_LAST_FETCHED_AT', () => { - it('should set timestamp', () => {}); + it('should set timestamp', () => { + const state = { + lastFetchedAt: [], + }; + + mutations.SET_LAST_FETCHED_AT(state, 'timestamp'); + expect(state.lastFetchedAt).toEqual('timestamp'); + }); }); describe('SET_TARGET_NOTE_HASH', () => { - it('should set the note hash', () => {}); + it('should set the note hash', () => { + const state = { + targetNoteHash: [], + }; + + mutations.SET_TARGET_NOTE_HASH(state, 'hash'); + expect(state.targetNoteHash).toEqual('hash'); + }); }); describe('SHOW_PLACEHOLDER_NOTE', () => { it('should set a placeholder note', () => { - + const state = { + notes: [], + }; + mutations.SHOW_PLACEHOLDER_NOTE(state, note); + expect(state.notes[0].isPlaceholderNote).toEqual(true); }); }); describe('TOGGLE_AWARD', () => { it('should add award if user has not reacted yet', () => { + const state = { + notes: [note], + userData: userDataMock, + }; + const data = { + note, + awardName: 'cartwheel', + }; + + mutations.TOGGLE_AWARD(state, data); + const lastIndex = state.notes[0].award_emoji.length - 1; + + expect(state.notes[0].award_emoji[lastIndex]).toEqual({ + name: 'cartwheel', + user: { id: userDataMock.id, name: userDataMock.name, username: userDataMock.username }, + }); }); it('should remove award if user already reacted', () => { + const state = { + notes: [note], + userData: { + id: 1, + name: 'Administrator', + username: 'root', + }, + }; + const data = { + note, + awardName: 'bath_tone3', + }; + mutations.TOGGLE_AWARD(state, data); + expect(state.notes[0].award_emoji.length).toEqual(2); }); }); describe('TOGGLE_DISCUSSION', () => { it('should open a closed discussion', () => { + const discussion = Object.assign({}, discussionMock, { expanded: false }); + const state = { + notes: [discussion], + }; + + mutations.TOGGLE_DISCUSSION(state, { discussionId: discussion.id }); + + expect(state.notes[0].expanded).toEqual(true); }); it('should close a opened discussion', () => { + const state = { + notes: [discussionMock], + }; + mutations.TOGGLE_DISCUSSION(state, { discussionId: discussionMock.id }); + + expect(state.notes[0].expanded).toEqual(false); }); }); describe('UPDATE_NOTE', () => { - it('should update an individual note', () => { + it('should update a note', () => { + const state = { + notes: [individualNote], + }; - }); + const updated = Object.assign({}, individualNote.notes[0], { note: 'Foo' }); - it('should update a note in a discussion', () => { + mutations.UPDATE_NOTE(state, updated); + expect(state.notes[0].notes[0].note).toEqual('Foo'); }); }); });