summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClement Ho <ClemMakesApps@gmail.com>2017-05-05 13:23:31 -0500
committerClement Ho <ClemMakesApps@gmail.com>2017-05-05 13:23:31 -0500
commit48e4991907aa9046c25323af53afc3b7eaa895c4 (patch)
treeda2fc72eeb92f3b4a94d4a64062f32c796f82228
parent933447e0da19f9d0be8574185500cabb5d7ab012 (diff)
downloadgitlab-ce-add-sidebar-specs.tar.gz
Add sidebar specsadd-sidebar-specs
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js20
-rw-r--r--app/assets/javascripts/sidebar/sidebar_bundle.js7
-rw-r--r--app/assets/javascripts/sidebar/sidebar_mediator.js4
-rw-r--r--app/assets/javascripts/sidebar/stores/sidebar_store.js4
-rw-r--r--spec/javascripts/sidebar/assignee_title_spec.js80
-rw-r--r--spec/javascripts/sidebar/assignees_spec.js272
-rw-r--r--spec/javascripts/sidebar/mock_data.js109
-rw-r--r--spec/javascripts/sidebar/sidebar_assignees_spec.js45
-rw-r--r--spec/javascripts/sidebar/sidebar_bundle_spec.js42
-rw-r--r--spec/javascripts/sidebar/sidebar_mediator_spec.js38
-rw-r--r--spec/javascripts/sidebar/sidebar_service_spec.js28
-rw-r--r--spec/javascripts/sidebar/sidebar_store_spec.js80
-rw-r--r--spec/javascripts/sidebar/user_mock_data.js16
13 files changed, 732 insertions, 13 deletions
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
index e2dba1fb0c2..244b67b3ad9 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
+++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.js
@@ -17,15 +17,21 @@ export default {
},
methods: {
listenForSlashCommands() {
- $(document).on('ajax:success', '.gfm-form', (e, data) => {
- const subscribedCommands = ['spend_time', 'time_estimate'];
- const changedCommands = data.commands_changes
+ $(document).on('ajax:success', '.gfm-form', this.slashCommandListened);
+ },
+ slashCommandListened(e, data) {
+ const subscribedCommands = ['spend_time', 'time_estimate'];
+ let changedCommands;
+ if (data !== undefined) {
+ changedCommands = data.commands_changes
? Object.keys(data.commands_changes)
: [];
- if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) {
- this.mediator.fetch();
- }
- });
+ } else {
+ changedCommands = [];
+ }
+ if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) {
+ this.mediator.fetch();
+ }
},
},
mounted() {
diff --git a/app/assets/javascripts/sidebar/sidebar_bundle.js b/app/assets/javascripts/sidebar/sidebar_bundle.js
index 2ce53c2ed30..2b02af87d8a 100644
--- a/app/assets/javascripts/sidebar/sidebar_bundle.js
+++ b/app/assets/javascripts/sidebar/sidebar_bundle.js
@@ -4,7 +4,7 @@ import sidebarAssignees from './components/assignees/sidebar_assignees';
import Mediator from './sidebar_mediator';
-document.addEventListener('DOMContentLoaded', () => {
+function domContentLoaded() {
const mediator = new Mediator(gl.sidebarOptions);
mediator.fetch();
@@ -17,5 +17,8 @@ document.addEventListener('DOMContentLoaded', () => {
}
new Vue(sidebarTimeTracking).$mount('#issuable-time-tracker');
-});
+}
+document.addEventListener('DOMContentLoaded', domContentLoaded);
+
+export default domContentLoaded;
diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js
index c13f3391f0d..5ccfb4ee9c1 100644
--- a/app/assets/javascripts/sidebar/sidebar_mediator.js
+++ b/app/assets/javascripts/sidebar/sidebar_mediator.js
@@ -30,8 +30,8 @@ export default class SidebarMediator {
this.service.get()
.then((response) => {
const data = response.json();
- this.store.processAssigneeData(data);
- this.store.processTimeTrackingData(data);
+ this.store.setAssigneeData(data);
+ this.store.setTimeTrackingData(data);
})
.catch(() => new Flash('Error occured when fetching sidebar data'));
}
diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js
index 94408c4d715..2d44c05bb8d 100644
--- a/app/assets/javascripts/sidebar/stores/sidebar_store.js
+++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js
@@ -17,13 +17,13 @@ export default class SidebarStore {
return SidebarStore.singleton;
}
- processAssigneeData(data) {
+ setAssigneeData(data) {
if (data.assignees) {
this.assignees = data.assignees;
}
}
- processTimeTrackingData(data) {
+ setTimeTrackingData(data) {
this.timeEstimate = data.time_estimate;
this.totalTimeSpent = data.total_time_spent;
this.humanTimeEstimate = data.human_time_estimate;
diff --git a/spec/javascripts/sidebar/assignee_title_spec.js b/spec/javascripts/sidebar/assignee_title_spec.js
new file mode 100644
index 00000000000..5b5b1bf4140
--- /dev/null
+++ b/spec/javascripts/sidebar/assignee_title_spec.js
@@ -0,0 +1,80 @@
+import Vue from 'vue';
+import AssigneeTitle from '~/sidebar/components/assignees/assignee_title';
+
+describe('AssigneeTitle component', () => {
+ let component;
+ let AssigneeTitleComponent;
+
+ beforeEach(() => {
+ AssigneeTitleComponent = Vue.extend(AssigneeTitle);
+ });
+
+ describe('assignee title', () => {
+ it('renders assignee', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ numberOfAssignees: 1,
+ editable: false,
+ },
+ }).$mount();
+
+ expect(component.$el.innerText.trim()).toEqual('Assignee');
+ });
+
+ it('renders 2 assignees', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ numberOfAssignees: 2,
+ editable: false,
+ },
+ }).$mount();
+
+ expect(component.$el.innerText.trim()).toEqual('2 Assignees');
+ });
+ });
+
+ it('does not render spinner by default', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ numberOfAssignees: 0,
+ editable: false,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.fa')).toBeNull();
+ });
+
+ it('renders spinner when loading', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ loading: true,
+ numberOfAssignees: 0,
+ editable: false,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.fa')).not.toBeNull();
+ });
+
+ it('does not render edit link when not editable', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ numberOfAssignees: 0,
+ editable: false,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.edit-link')).toBeNull();
+ });
+
+ it('renders edit link when editable', () => {
+ component = new AssigneeTitleComponent({
+ propsData: {
+ numberOfAssignees: 0,
+ editable: true,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.edit-link')).not.toBeNull();
+ });
+});
diff --git a/spec/javascripts/sidebar/assignees_spec.js b/spec/javascripts/sidebar/assignees_spec.js
new file mode 100644
index 00000000000..cf47940ef1c
--- /dev/null
+++ b/spec/javascripts/sidebar/assignees_spec.js
@@ -0,0 +1,272 @@
+import Vue from 'vue';
+import Assignee from '~/sidebar/components/assignees/assignees';
+import UsersMock from './mock_data';
+import UsersMockHelper from '../test_helpers/user_mock_data';
+
+describe('Assignee component', () => {
+ let component;
+ let AssigneeComponent;
+
+ beforeEach(() => {
+ AssigneeComponent = Vue.extend(Assignee);
+ });
+
+ describe('No assignees/users', () => {
+ it('displays no assignee icon when collapsed', () => {
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users: [],
+ editable: false,
+ },
+ }).$mount();
+
+ const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
+ expect(collapsed.childElementCount).toEqual(1);
+ expect(collapsed.children[0].getAttribute('aria-label')).toEqual('No Assignee');
+ expect(collapsed.children[0].classList.contains('fa')).toEqual(true);
+ expect(collapsed.children[0].classList.contains('fa-user')).toEqual(true);
+ });
+
+ it('displays only "No assignee" when no users are assigned and the issue is read-only', () => {
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users: [],
+ editable: false,
+ },
+ }).$mount();
+ const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();
+
+ expect(componentTextNoUsers).toBe('No assignee');
+ expect(componentTextNoUsers.indexOf('assign yourself')).toEqual(-1);
+ });
+
+ it('displays only "No assignee" when no users are assigned and the issue can be edited', () => {
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users: [],
+ editable: true,
+ },
+ }).$mount();
+ const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();
+
+ expect(componentTextNoUsers.indexOf('No assignee')).toEqual(0);
+ expect(componentTextNoUsers.indexOf('assign yourself')).toBeGreaterThan(0);
+ });
+
+ it('emits the assign-self event when "assign yourself" is clicked', () => {
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users: [],
+ editable: true,
+ },
+ }).$mount();
+
+ spyOn(component, '$emit');
+ component.$el.querySelector('.assign-yourself .btn-link').click();
+ expect(component.$emit).toHaveBeenCalledWith('assign-self');
+ });
+ });
+
+ describe('One assignee/user', () => {
+ it('displays one assignee icon when collapsed', () => {
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users: [
+ UsersMock.user,
+ ],
+ editable: false,
+ },
+ }).$mount();
+
+ const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
+ const assignee = collapsed.children[0];
+ expect(collapsed.childElementCount).toEqual(1);
+ expect(assignee.querySelector('.avatar').getAttribute('src')).toEqual(UsersMock.user.avatarUrl);
+ expect(assignee.querySelector('.avatar').getAttribute('alt')).toEqual(`${UsersMock.user.name}'s avatar`);
+ expect(assignee.querySelector('.author').innerText.trim()).toEqual(UsersMock.user.name);
+ });
+
+ it('Shows one user with avatar, username and author name', () => {
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000/',
+ users: [
+ UsersMock.user,
+ ],
+ editable: true,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelector('.author_link')).not.toBeNull();
+ // The image
+ expect(component.$el.querySelector('.author_link img').getAttribute('src')).toEqual(UsersMock.user.avatarUrl);
+ // Author name
+ expect(component.$el.querySelector('.author_link .author').innerText.trim()).toEqual(UsersMock.user.name);
+ // Username
+ expect(component.$el.querySelector('.author_link .username').innerText.trim()).toEqual(`@${UsersMock.user.username}`);
+ });
+
+ it('has the root url present in the assigneeUrl method', () => {
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000/',
+ users: [
+ UsersMock.user,
+ ],
+ editable: true,
+ },
+ }).$mount();
+
+ expect(component.assigneeUrl(UsersMock.user).indexOf('http://localhost:3000/')).not.toEqual(-1);
+ });
+ });
+
+ describe('Two or more assignees/users', () => {
+ it('displays two assignee icons when collapsed', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(2);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: false,
+ },
+ }).$mount();
+
+ const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
+ expect(collapsed.childElementCount).toEqual(2);
+
+ const first = collapsed.children[0];
+ expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatarUrl);
+ expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(`${users[0].name}'s avatar`);
+ expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);
+
+ const second = collapsed.children[1];
+ expect(second.querySelector('.avatar').getAttribute('src')).toEqual(users[1].avatarUrl);
+ expect(second.querySelector('.avatar').getAttribute('alt')).toEqual(`${users[1].name}'s avatar`);
+ expect(second.querySelector('.author').innerText.trim()).toEqual(users[1].name);
+ });
+
+ it('displays one assignee icon and counter when collapsed', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: false,
+ },
+ }).$mount();
+
+ const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
+ expect(collapsed.childElementCount).toEqual(2);
+
+ const first = collapsed.children[0];
+ expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatarUrl);
+ expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(`${users[0].name}'s avatar`);
+ expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);
+
+ const second = collapsed.children[1];
+ expect(second.querySelector('.avatar-counter').innerText.trim()).toEqual('+2');
+ });
+
+ it('Shows two assignees', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(2);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: true,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelectorAll('.user-item').length).toEqual(users.length);
+ expect(component.$el.querySelector('.user-list-more')).toBe(null);
+ });
+
+ it('Shows the "show-less" assignees label', (done) => {
+ const users = UsersMockHelper.createNumberRandomUsers(6);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: true,
+ },
+ }).$mount();
+
+ expect(component.$el.querySelectorAll('.user-item').length).toEqual(component.defaultRenderCount);
+ expect(component.$el.querySelector('.user-list-more')).not.toBe(null);
+ const usersLabelExpectation = users.length - component.defaultRenderCount;
+ expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim())
+ .not.toBe(`+${usersLabelExpectation} more`);
+ component.toggleShowLess();
+ Vue.nextTick(() => {
+ expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim())
+ .toBe('- show less');
+ done();
+ });
+ });
+
+ it('Shows the "show-less" when "n+ more " label is clicked', (done) => {
+ const users = UsersMockHelper.createNumberRandomUsers(6);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: true,
+ },
+ }).$mount();
+
+ component.$el.querySelector('.user-list-more .btn-link').click();
+ Vue.nextTick(() => {
+ expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim())
+ .toBe('- show less');
+ done();
+ });
+ });
+
+ it('gets the count of avatar via a computed property ', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(6);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: true,
+ },
+ }).$mount();
+
+ expect(component.sidebarAvatarCounter).toEqual(`+${users.length - 1}`);
+ });
+
+ describe('n+ more label', () => {
+ beforeEach(() => {
+ const users = UsersMockHelper.createNumberRandomUsers(6);
+ component = new AssigneeComponent({
+ propsData: {
+ rootPath: 'http://localhost:3000',
+ users,
+ editable: true,
+ },
+ }).$mount();
+ });
+
+ it('shows "+1 more" label', () => {
+ expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim())
+ .toBe('+ 1 more');
+ });
+
+ it('shows "show less" label', (done) => {
+ component.toggleShowLess();
+
+ Vue.nextTick(() => {
+ expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim())
+ .toBe('- show less');
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
new file mode 100644
index 00000000000..0599a63912c
--- /dev/null
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -0,0 +1,109 @@
+/* eslint-disable quote-props*/
+
+const sidebarMockData = {
+ 'GET': {
+ '/gitlab-org/gitlab-shell/issues/5.json': {
+ id: 45,
+ iid: 5,
+ author_id: 23,
+ description: 'Nulla ullam commodi delectus adipisci quis sit.',
+ lock_version: null,
+ milestone_id: 21,
+ position: 0,
+ state: 'closed',
+ title: 'Vel et nulla voluptatibus corporis dolor iste saepe laborum.',
+ updated_by_id: 1,
+ created_at: '2017-02-02T21: 49: 49.664Z',
+ updated_at: '2017-05-03T22: 26: 03.760Z',
+ deleted_at: null,
+ time_estimate: 0,
+ total_time_spent: 0,
+ human_time_estimate: null,
+ human_total_time_spent: null,
+ branch_name: null,
+ confidential: false,
+ assignees: [
+ {
+ name: 'User 0',
+ username: 'user0',
+ id: 22,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/user0',
+ },
+ {
+ name: 'Marguerite Bartell',
+ username: 'tajuana',
+ id: 18,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/tajuana',
+ },
+ {
+ name: 'Laureen Ritchie',
+ username: 'michaele.will',
+ id: 16,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/michaele.will',
+ },
+ ],
+ due_date: null,
+ moved_to_id: null,
+ project_id: 4,
+ weight: null,
+ milestone: {
+ id: 21,
+ iid: 1,
+ project_id: 4,
+ title: 'v0.0',
+ description: 'Molestiae commodi laboriosam odio sunt eaque reprehenderit.',
+ state: 'active',
+ created_at: '2017-02-02T21: 49: 30.530Z',
+ updated_at: '2017-02-02T21: 49: 30.530Z',
+ due_date: null,
+ start_date: null,
+ },
+ labels: [],
+ },
+ },
+ 'PUT': {
+ '/gitlab-org/gitlab-shell/issues/5.json': {
+ data: {},
+ },
+ },
+};
+
+export default {
+ mediator: {
+ endpoint: '/gitlab-org/gitlab-shell/issues/5.json',
+ editable: true,
+ currentUser: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ },
+ rootPath: '/',
+ },
+ time: {
+ time_estimate: 3600,
+ total_time_spent: 0,
+ human_time_estimate: '1h',
+ human_total_time_spent: null,
+ },
+ user: {
+ avatarUrl: 'http://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ },
+
+ sidebarMockInterceptor(request, next) {
+ const body = sidebarMockData[request.method.toUpperCase()][request.url];
+
+ next(request.respondWith(JSON.stringify(body), {
+ status: 200,
+ }));
+ },
+};
diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js
new file mode 100644
index 00000000000..e0df0a3228f
--- /dev/null
+++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js
@@ -0,0 +1,45 @@
+import Vue from 'vue';
+import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees';
+import SidebarMediator from '~/sidebar/sidebar_mediator';
+import SidebarService from '~/sidebar/services/sidebar_service';
+import SidebarStore from '~/sidebar/stores/sidebar_store';
+import Mock from './mock_data';
+
+describe('sidebar assignees', () => {
+ let component;
+ let SidebarAssigneeComponent;
+ preloadFixtures('issues/open-issue.html.raw');
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(Mock.sidebarMockInterceptor);
+ SidebarAssigneeComponent = Vue.extend(SidebarAssignees);
+ spyOn(SidebarMediator.prototype, 'saveAssignees').and.callThrough();
+ spyOn(SidebarMediator.prototype, 'assignYourself').and.callThrough();
+ this.mediator = new SidebarMediator(Mock.mediator);
+ loadFixtures('issues/open-issue.html.raw');
+ this.sidebarAssigneesEl = document.querySelector('#js-vue-sidebar-assignees');
+ });
+
+ afterEach(() => {
+ SidebarService.singleton = null;
+ SidebarStore.singleton = null;
+ SidebarMediator.singleton = null;
+ });
+
+ it('calls the mediator when saves the assignees', () => {
+ component = new SidebarAssigneeComponent()
+ .$mount(this.sidebarAssigneesEl);
+ component.saveAssignees();
+
+ expect(SidebarMediator.prototype.saveAssignees).toHaveBeenCalled();
+ });
+
+ it('calls the mediator when "assignSelf" method is called', () => {
+ component = new SidebarAssigneeComponent()
+ .$mount(this.sidebarAssigneesEl);
+ component.assignSelf();
+
+ expect(SidebarMediator.prototype.assignYourself).toHaveBeenCalled();
+ expect(this.mediator.store.assignees.length).toEqual(1);
+ });
+});
diff --git a/spec/javascripts/sidebar/sidebar_bundle_spec.js b/spec/javascripts/sidebar/sidebar_bundle_spec.js
new file mode 100644
index 00000000000..7760b34e071
--- /dev/null
+++ b/spec/javascripts/sidebar/sidebar_bundle_spec.js
@@ -0,0 +1,42 @@
+import Vue from 'vue';
+import SidebarBundleDomContentLoaded from '~/sidebar/sidebar_bundle';
+import SidebarTimeTracking from '~/sidebar/components/time_tracking/sidebar_time_tracking';
+import SidebarMediator from '~/sidebar/sidebar_mediator';
+import SidebarService from '~/sidebar/services/sidebar_service';
+import SidebarStore from '~/sidebar/stores/sidebar_store';
+import Mock from './mock_data';
+
+describe('sidebar bundle', () => {
+ gl.sidebarOptions = Mock.mediator;
+
+ beforeEach(() => {
+ spyOn(SidebarTimeTracking.methods, 'listenForSlashCommands').and.callFake(() => { });
+ preloadFixtures('issues/open-issue.html.raw');
+ Vue.http.interceptors.push(Mock.sidebarMockInterceptor);
+ loadFixtures('issues/open-issue.html.raw');
+ spyOn(Vue.prototype, '$mount');
+ SidebarBundleDomContentLoaded();
+ this.mediator = new SidebarMediator();
+ });
+
+ afterEach(() => {
+ SidebarService.singleton = null;
+ SidebarStore.singleton = null;
+ SidebarMediator.singleton = null;
+ });
+
+ it('the mediator should be already defined with some data', () => {
+ SidebarBundleDomContentLoaded();
+
+ expect(this.mediator.store).toBeDefined();
+ expect(this.mediator.service).toBeDefined();
+ expect(this.mediator.store.currentUser).toEqual(Mock.mediator.currentUser);
+ expect(this.mediator.store.rootPath).toEqual(Mock.mediator.rootPath);
+ expect(this.mediator.store.endPoint).toEqual(Mock.mediator.endPoint);
+ expect(this.mediator.store.editable).toEqual(Mock.mediator.editable);
+ });
+
+ it('the sidebar time tracking and assignees components to have been mounted', () => {
+ expect(Vue.prototype.$mount).toHaveBeenCalledTimes(2);
+ });
+});
diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js
new file mode 100644
index 00000000000..9bfca0c0991
--- /dev/null
+++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js
@@ -0,0 +1,38 @@
+import Vue from 'vue';
+import SidebarMediator from '~/sidebar/sidebar_mediator';
+import SidebarStore from '~/sidebar/stores/sidebar_store';
+import SidebarService from '~/sidebar/services/sidebar_service';
+import Mock from './mock_data';
+
+describe('Sidebar mediator', () => {
+ beforeEach(() => {
+ Vue.http.interceptors.push(Mock.sidebarMockInterceptor);
+ this.mediator = new SidebarMediator(Mock.mediator);
+ });
+
+ afterEach(() => {
+ SidebarService.singleton = null;
+ SidebarStore.singleton = null;
+ SidebarMediator.singleton = null;
+ });
+
+ it('assigns yourself ', () => {
+ this.mediator.assignYourself();
+
+ expect(this.mediator.store.currentUser).toEqual(Mock.mediator.currentUser);
+ expect(this.mediator.store.assignees[0]).toEqual(Mock.mediator.currentUser);
+ });
+
+ it('saves assignees', (done) => {
+ this.mediator.saveAssignees('issue[assignee_ids]').then((resp) => {
+ expect(resp.status).toEqual(200);
+ done();
+ });
+ });
+
+ it('fetches the data', () => {
+ spyOn(this.mediator.service, 'get').and.callThrough();
+ this.mediator.fetch();
+ expect(this.mediator.service.get).toHaveBeenCalled();
+ });
+});
diff --git a/spec/javascripts/sidebar/sidebar_service_spec.js b/spec/javascripts/sidebar/sidebar_service_spec.js
new file mode 100644
index 00000000000..ed7be76dbcc
--- /dev/null
+++ b/spec/javascripts/sidebar/sidebar_service_spec.js
@@ -0,0 +1,28 @@
+import Vue from 'vue';
+import SidebarService from '~/sidebar/services/sidebar_service';
+import Mock from './mock_data';
+
+describe('Sidebar service', () => {
+ beforeEach(() => {
+ Vue.http.interceptors.push(Mock.sidebarMockInterceptor);
+ this.service = new SidebarService('/gitlab-org/gitlab-shell/issues/5.json');
+ });
+
+ afterEach(() => {
+ SidebarService.singleton = null;
+ });
+
+ it('gets the data', (done) => {
+ this.service.get().then((resp) => {
+ expect(resp).toBeDefined();
+ done();
+ });
+ });
+
+ it('updates the data', (done) => {
+ this.service.update('issue[assignee_ids]', [1]).then((resp) => {
+ expect(resp).toBeDefined();
+ done();
+ });
+ });
+});
diff --git a/spec/javascripts/sidebar/sidebar_store_spec.js b/spec/javascripts/sidebar/sidebar_store_spec.js
new file mode 100644
index 00000000000..6c0f2b6a793
--- /dev/null
+++ b/spec/javascripts/sidebar/sidebar_store_spec.js
@@ -0,0 +1,80 @@
+import SidebarStore from '~/sidebar/stores/sidebar_store';
+import Mock from './mock_data';
+import UsersMockHelper from '../test_helpers/user_mock_data';
+
+describe('Sidebar store', () => {
+ const assignee = {
+ id: 2,
+ name: 'gitlab user 2',
+ username: 'gitlab2',
+ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ };
+
+ const anotherAssignee = {
+ id: 3,
+ name: 'gitlab user 3',
+ username: 'gitlab3',
+ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ };
+
+ beforeEach(() => {
+ this.store = new SidebarStore({
+ currentUser: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ },
+ editable: true,
+ rootPath: '/',
+ endpoint: '/gitlab-org/gitlab-shell/issues/5.json',
+ });
+ });
+
+ afterEach(() => {
+ SidebarStore.singleton = null;
+ });
+
+ it('adds a new assignee', () => {
+ this.store.addAssignee(assignee);
+ expect(this.store.assignees.length).toEqual(1);
+ });
+
+ it('removes an assignee', () => {
+ this.store.removeAssignee(assignee);
+ expect(this.store.assignees.length).toEqual(0);
+ });
+
+ it('finds an existent assignee', () => {
+ let foundAssignee;
+
+ this.store.addAssignee(assignee);
+ foundAssignee = this.store.findAssignee(assignee);
+ expect(foundAssignee).toBeDefined();
+ expect(foundAssignee).toEqual(assignee);
+ foundAssignee = this.store.findAssignee(anotherAssignee);
+ expect(foundAssignee).toBeUndefined();
+ });
+
+ it('removes all assignees', () => {
+ this.store.removeAllAssignees();
+ expect(this.store.assignees.length).toEqual(0);
+ });
+
+ it('set assigned data', () => {
+ const users = {
+ assignees: UsersMockHelper.createNumberRandomUsers(3),
+ };
+
+ this.store.setAssigneeData(users);
+ expect(this.store.assignees.length).toEqual(3);
+ });
+
+ it('set time tracking data', () => {
+ this.store.setTimeTrackingData(Mock.time);
+ expect(this.store.timeEstimate).toEqual(Mock.time.time_estimate);
+ expect(this.store.totalTimeSpent).toEqual(Mock.time.total_time_spent);
+ expect(this.store.humanTimeEstimate).toEqual(Mock.time.human_time_estimate);
+ expect(this.store.humanTotalTimeSpent).toEqual(Mock.time.human_total_time_spent);
+ });
+});
diff --git a/spec/javascripts/sidebar/user_mock_data.js b/spec/javascripts/sidebar/user_mock_data.js
new file mode 100644
index 00000000000..9e7b8346238
--- /dev/null
+++ b/spec/javascripts/sidebar/user_mock_data.js
@@ -0,0 +1,16 @@
+export default {
+ createNumberRandomUsers(numberUsers) {
+ const users = [];
+ for (let i = 0; i < numberUsers; i = i += 1) {
+ users.push(
+ {
+ avatarUrl: 'http://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: (i + 1),
+ name: `GitLab User ${i}`,
+ username: `gitlab${i}`,
+ },
+ );
+ }
+ return users;
+ },
+};