diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js
index 6000c56665b..cfab6c40b34 100644
--- a/app/assets/javascripts/autosave.js
+++ b/app/assets/javascripts/autosave.js
@@ -2,11 +2,6 @@
import AccessorUtilities from './lib/utils/accessor';
window.Autosave = (function() {
- /**
- *
- * @param {*} field the textarea
- * @param {Array} key Array with: ['Note', type, id, ]
- */
function Autosave(field, key) {
this.field = field;
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
diff --git a/app/assets/javascripts/notes/components/issue_notes_app.vue b/app/assets/javascripts/notes/components/issue_notes_app.vue
index 4c0351f701b..371addd937e 100644
--- a/app/assets/javascripts/notes/components/issue_notes_app.vue
+++ b/app/assets/javascripts/notes/components/issue_notes_app.vue
@@ -114,10 +114,12 @@
this.fetchNotes();
this.initPolling();
- this.$el.parentElement.addEventListener('toggleAward', (event) => {
- const { awardName, noteId } = event.detail;
- this.actionToggleAward({ awardName, noteId });
- });
+ if (this.$el.parentElement) {
+ this.$el.parentElement.addEventListener('toggleAward', (event) => {
+ const { awardName, noteId } = event.detail;
+ this.actionToggleAward({ awardName, noteId });
+ });
+ }
},
};
@@ -126,7 +128,7 @@
+ class="js-loading loading">
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 0c9eb046298..1ad7648e533 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -134,7 +134,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
};
const pollSuccessCallBack = (resp, commit, state, getters) => {
- if (resp.notes.length) {
+ if (resp.notes && resp.notes.length) {
const { notesById } = getters;
resp.notes.forEach((note) => {
diff --git a/spec/javascripts/notes/components/issue_note_app_spec.js b/spec/javascripts/notes/components/issue_note_app_spec.js
index df8d250ed5e..847cb2a23ff 100644
--- a/spec/javascripts/notes/components/issue_note_app_spec.js
+++ b/spec/javascripts/notes/components/issue_note_app_spec.js
@@ -1,36 +1,197 @@
-describe('issue_note_app', () => {
+import Vue from 'vue';
+import issueNotesApp from '~/notes/components/issue_notes_app.vue';
+import * as mockData from '../mock_data';
- it('should set notes data', () => {
+fdescribe('issue_note_app', () => {
+ let mountComponent;
+ beforeEach(() => {
+ const IssueNotesApp = Vue.extend(issueNotesApp);
+
+ mountComponent = props => new IssueNotesApp({
+ propsData: props,
+ }).$mount();
});
- it('should set issue data', () => {
+ describe('set data', () => {
+ let vm;
+ const responseInterceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify([]), {
+ status: 200,
+ }));
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(responseInterceptor);
+ vm = mountComponent({
+ issueData: mockData.issueDataMock,
+ notesData: mockData.notesDataMock,
+ userData: mockData.userDataMock,
+ });
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, responseInterceptor);
+ });
+
+ it('should set notes data', () => {
+ expect(vm.$store.state.notesData).toEqual(mockData.notesDataMock);
+ });
+
+ it('should set issue data', () => {
+ expect(vm.$store.state.issueData).toEqual(mockData.issueDataMock);
+ });
+
+ it('should set user data', () => {
+ expect(vm.$store.state.userData).toEqual(mockData.userDataMock);
+ });
+
+ it('should fetch notes', () => {
+ expect(vm.$store.state.notes).toEqual([]);
+ });
});
- it('should set user data', () => {
+ fdescribe('render', () => {
+ let vm;
- });
+ const responseInterceptor = (request, next) => {
+ next(request.respondWith(JSON.stringify(mockData.discussionResponse), {
+ status: 200,
+ }));
+ };
- it('should fetch notes', () => {
-
- });
-
- it('should render list of notes', () => {
-
- });
-
- it('should render form', () => {
-
- });
-
- describe('while fetching', () => {
- it('should render loading icon', () => {
+ beforeEach(() => {
+ Vue.http.interceptors.push(responseInterceptor);
+ vm = mountComponent({
+ issueData: mockData.issueDataMock,
+ notesData: mockData.notesDataMock,
+ userData: mockData.userDataMock,
+ });
+ });
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, responseInterceptor);
+ });
+ it('should render list of notes', () => {
+ console.log(vm);
});
it('should render form', () => {
+ expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM');
+ expect(
+ vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
+ ).toEqual('Write a comment or drag your files here...');
+ });
+ });
+
+ describe('while fetching data', () => {
+ let vm;
+ beforeEach(() => {
+ vm = mountComponent({
+ issueData: mockData.issueDataMock,
+ notesData: mockData.notesDataMock,
+ userData: mockData.userDataMock,
+ });
+ });
+
+ it('should render loading icon', () => {
+ expect(vm.$el.querySelector('.js-loading')).toBeDefined();
+ });
+
+ it('should render form', () => {
+ expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM');
+ expect(
+ vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'),
+ ).toEqual('Write a comment or drag your files here...');
+ });
+ });
+
+ describe('update note', () => {
+ describe('individual note', () => {
+ describe('shortup up key', () => {
+ it('shows correct editing form when user clicks up', () => {
+ });
+ });
+
+ describe('dropdown', () => {
+ it('renders edit form', () => {
+ });
+ });
+
+ it('updates the note and resets the edit form', () => {});
+ });
+
+ describe('dicussion note note', () => {
+ describe('shortup up key', () => {
+ it('shows correct editing form when user clicks up', () => {
+ });
+ });
+
+ describe('dropdown', () => {
+ it('renders edit form', () => {
+ });
+ });
+
+ it('updates the note and resets the edit form', () => {});
+ });
+ });
+
+ describe('set target hash', () => {
+ it('updates the URL when the note date is clicked', () => {
+
+ });
+
+ it('stores the correct hash', () => {
+
+ });
+
+ it('updates visually the target note', () => {
});
});
-});
\ No newline at end of file
+
+ 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('quick actions', () => {
+ it('should return executing quick action description when note has single quick action', () => {
+ });
+
+ it('should return generic multiple quick action description when note has multiple quick actions', () => {
+ });
+
+ it('should return generic quick action description when available quick actions list is not populated', () => {
+ });
+ });
+
+ describe('new note form', () => {
+ it('should render markdown docs url', () => {
+
+ });
+
+ it('should render quick action docs url', () => {
+
+ });
+
+ it('should preview markdown', () => {
+
+ });
+
+ describe('discard draft', () => {
+ it('should reset form when reset button is clicked', () => {
+
+ });
+ });
+ });
+
+ describe('edit form', () => {
+ it('should render markdown docs url', () => {});
+ it('should not render quick actions docs url', () => {});
+ });
+});
diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js
index 42d1bf9adc0..ce969f0f460 100644
--- a/spec/javascripts/notes/mock_data.js
+++ b/spec/javascripts/notes/mock_data.js
@@ -1,3 +1,5 @@
+/* eslint disable */
+
export const notesDataMock = {
discussionsPath: '/gitlab-org/gitlab-ce/issues/26/discussions.json',
lastFetchedAt: '1501862675',
@@ -17,7 +19,7 @@ export const userDataMock = {
username: 'root',
};
-export const issueData = {
+export const issueDataMock = {
assignees: [],
author_id: 1,
branch_name: null,
@@ -218,4 +220,98 @@ export const discussionMock = {
path: '/gitlab-org/gitlab-ce/notes/1437',
}],
individual_note: false,
-};
\ No newline at end of file
+};
+
+export const discussionResponse = [{
+ "id": "0fb4e0e3f9276e55ff32eb4195add694aece4edd",
+ "reply_id": "0fb4e0e3f9276e55ff32eb4195add694aece4edd",
+ "expanded": true,
+ "notes": [{
+ "id": 1390,
+ "attachment": {
+ "url": null,
+ "filename": null,
+ "image": false
+ },
+ "author": {
+ "id": 1,
+ "name": "Root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": null,
+ "path": "/root"
+ },
+ "created_at": "2017-08-01T17:09:33.762Z",
+ "updated_at": "2017-08-01T17:09:33.762Z",
+ "system": false,
+ "noteable_id": 98,
+ "noteable_type": "Issue",
+ "type": null,
+ "human_access": "Owner",
+ "note": "sdfdsaf",
+ "note_html": "\u003cp dir=\"auto\"\u003esdfdsaf\u003c/p\u003e",
+ "current_user": {
+ "can_edit": true
+ },
+ "discussion_id": "0fb4e0e3f9276e55ff32eb4195add694aece4edd",
+ "emoji_awardable": true,
+ "award_emoji": [{
+ "name": "baseball",
+ "user": {
+ "id": 1,
+ "name": "Root",
+ "username": "root"
+ }
+ }, {
+ "name": "art",
+ "user": {
+ "id": 1,
+ "name": "Root",
+ "username": "root"
+ }
+ }],
+ "toggle_award_path": "/gitlab-org/gitlab-ce/notes/1390/toggle_award_emoji",
+ "report_abuse_path": "/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F26%23note_1390\u0026user_id=1",
+ "path": "/gitlab-org/gitlab-ce/notes/1390"
+ }],
+ "individual_note": true
+}, {
+ "id": "70d5c92a4039a36c70100c6691c18c27e4b0a790",
+ "reply_id": "70d5c92a4039a36c70100c6691c18c27e4b0a790",
+ "expanded": true,
+ "notes": [{
+ "id": 1391,
+ "attachment": {
+ "url": null,
+ "filename": null,
+ "image": false
+ },
+ "author": {
+ "id": 1,
+ "name": "Root",
+ "username": "root",
+ "state": "active",
+ "avatar_url": null,
+ "path": "/root"
+ },
+ "created_at": "2017-08-02T10:51:38.685Z",
+ "updated_at": "2017-08-02T10:51:38.685Z",
+ "system": false,
+ "noteable_id": 98,
+ "noteable_type": "Issue",
+ "type": null,
+ "human_access": "Owner",
+ "note": "New note!",
+ "note_html": "\u003cp dir=\"auto\"\u003eNew note!\u003c/p\u003e",
+ "current_user": {
+ "can_edit": true
+ },
+ "discussion_id": "70d5c92a4039a36c70100c6691c18c27e4b0a790",
+ "emoji_awardable": true,
+ "award_emoji": [],
+ "toggle_award_path": "/gitlab-org/gitlab-ce/notes/1391/toggle_award_emoji",
+ "report_abuse_path": "/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-ce%2Fissues%2F26%23note_1391\u0026user_id=1",
+ "path": "/gitlab-org/gitlab-ce/notes/1391"
+ }],
+ "individual_note": true
+}];
\ No newline at end of file