diff --git a/src/app/task/task-list/task-accept.component.spec.ts b/src/app/task/task-list/task-accept.component.spec.ts new file mode 100644 index 0000000..42921cc --- /dev/null +++ b/src/app/task/task-list/task-accept.component.spec.ts @@ -0,0 +1,29 @@ +import { Provider, provide, Component } from 'ng-forward'; +import * as helpers from "../../../spec/helpers"; +import { TaskAcceptComponent } from './task-accept.component'; + +const htmlTemplate: string = ''; + +describe("Components", () => { + describe("Task Accept Component", () => { + + let task = { id: 1, type: "AddMember" }; + + beforeEach(angular.mock.module("templates")); + + function createComponent() { + return helpers.quickCreateComponent({ + template: htmlTemplate, + directives: [TaskAcceptComponent], + properties: { task: task } + }); + } + + it("replace element with the specific task accept component", (done: Function) => { + createComponent().then(fixture => { + expect(fixture.debugElement.queryAll("add-member-task-accept").length).toBe(1); + done(); + }); + }); + }); +}); diff --git a/src/app/task/task-list/task-list.component.spec.ts b/src/app/task/task-list/task-list.component.spec.ts new file mode 100644 index 0000000..cbe27ca --- /dev/null +++ b/src/app/task/task-list/task-list.component.spec.ts @@ -0,0 +1,104 @@ +import { Provider, provide, Component } from 'ng-forward'; +import * as helpers from "../../../spec/helpers"; +import { ComponentTestHelper, createClass } from '../../../spec/component-test-helper'; +import { TaskListComponent } from './task-list.component'; + +const htmlTemplate: string = ''; + +describe("Components", () => { + describe("Task List Component", () => { + + let helper: ComponentTestHelper; + let taskService = jasmine.createSpyObj("taskService", ["getAllPending"]); + let tasks = [{ id: 1 }, { id: 2 }]; + let modal = helpers.mocks.$modal; + taskService.getAllPending = jasmine.createSpy("getAllPending").and.returnValue(Promise.resolve({ headers: () => { }, data: tasks })); + + beforeEach(angular.mock.module("templates")); + + beforeEach((done) => { + let cls = createClass({ + template: htmlTemplate, + directives: [TaskListComponent], + providers: [ + helpers.createProviderToValue("TaskService", taskService), + helpers.createProviderToValue('NotificationService', helpers.mocks.notificationService), + helpers.createProviderToValue('$uibModal', modal), + ].concat(helpers.provideFilters("groupByFilter")), + properties: { tasks: tasks } + }); + helper = new ComponentTestHelper(cls, done); + }); + + it("return specific template for a task", () => { + let task = { type: "AddMember" }; + expect(helper.component.getTaskTemplate(task)).toEqual("app/task/types/add-member/add-member.html"); + }); + + it("return the default template for a task", () => { + let task = { type: "" }; + expect(helper.component.getTaskTemplate(task)).toEqual("app/task/types/default.html"); + }); + + it("open confirmation modal when it has details to accept a task", () => { + let task = { accept_details: true }; + helper.component.accept(task); + expect(modal.open).toHaveBeenCalled(); + }); + + it("open confirmation modal when it has details to reject a task", () => { + let task = { reject_details: true }; + helper.component.reject(task); + expect(modal.open).toHaveBeenCalled(); + }); + + it("call api directly when it has no details to accept a task", () => { + let task = { accept_details: false }; + helper.component.callAccept = jasmine.createSpy("callAccept"); + helper.component.accept(task); + expect(helper.component.callAccept).toHaveBeenCalled(); + }); + + it("call api directly when it has no details to reject a task", () => { + let task = { accept_details: false }; + helper.component.callReject = jasmine.createSpy("callReject"); + helper.component.reject(task); + expect(helper.component.callReject).toHaveBeenCalled(); + }); + + it("call cancel and remove the current task when accept was called successfully", () => { + helper.component.currentTask = { id: 1 }; + let result = helpers.mocks.promiseResultTemplate({ data: { id: 1 } }); + taskService.finishTask = jasmine.createSpy("finishTask").and.returnValue(result); + helper.component.cancel = jasmine.createSpy("cancel"); + helper.component.callAccept(); + expect(helper.component.cancel).toHaveBeenCalled(); + expect(helper.component.tasks).toEqual([{ id: 2 }]); + }); + + it("call cancel and remove the current task when reject was called successfully", () => { + helper.component.currentTask = { id: 1 }; + let result = helpers.mocks.promiseResultTemplate({ data: { id: 1 } }); + taskService.cancelTask = jasmine.createSpy("cancelTask").and.returnValue(result); + helper.component.cancel = jasmine.createSpy("cancel"); + helper.component.callReject(); + expect(helper.component.cancel).toHaveBeenCalled(); + expect(helper.component.tasks).toEqual([{ id: 2 }]); + }); + + it("reset currentTask and close modal when call cancel", () => { + let modalInstance = jasmine.createSpyObj("modalInstance", ["close"]); + helper.component["modalInstance"] = modalInstance; + helper.component.currentTask = { id: 1 }; + helper.component.cancel(); + expect(modalInstance.close).toHaveBeenCalled(); + expect(helper.component.currentTask).toBeNull(); + }); + + it("not fail when call cancel with no modalInstance", () => { + helper.component["modalInstance"] = null; + helper.component.currentTask = null; + helper.component.cancel(); + }); + }); +}); diff --git a/src/app/task/task-list/task-list.component.ts b/src/app/task/task-list/task-list.component.ts index fd23600..4b12114 100644 --- a/src/app/task/task-list/task-list.component.ts +++ b/src/app/task/task-list/task-list.component.ts @@ -89,11 +89,11 @@ export class TaskListComponent { } private getTemplateName(task: noosfero.Task) { - return task.type.replace(/::/, '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()); + return task.type.replace(/::/, '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); } private removeTask(task: noosfero.Task) { - let index = this.tasks.indexOf(task, 0); + let index = this.tasks.map((t: noosfero.Task) => { return t.id; }).indexOf(task.id); if (index > -1) { this.tasks.splice(index, 1); } diff --git a/src/app/task/tasks-menu/tasks-menu.component.spec.ts b/src/app/task/tasks-menu/tasks-menu.component.spec.ts new file mode 100644 index 0000000..a177db3 --- /dev/null +++ b/src/app/task/tasks-menu/tasks-menu.component.spec.ts @@ -0,0 +1,42 @@ +import { Provider, provide, Component } from 'ng-forward'; +import * as helpers from "../../../spec/helpers"; +import { ComponentTestHelper, createClass } from '../../../spec/component-test-helper'; +import { TasksMenuComponent } from './tasks-menu.component'; +import { AuthEvents } from "./../../login"; + +const htmlTemplate: string = ''; + +describe("Components", () => { + describe("Task Menu Component", () => { + + let helper: ComponentTestHelper; + let taskService = jasmine.createSpyObj("taskService", ["getAllPending"]); + let tasks = [{ id: 1 }, { id: 2 }]; + taskService.getAllPending = jasmine.createSpy("getAllPending").and.returnValue(Promise.resolve({ headers: () => { }, data: tasks })); + + beforeEach(angular.mock.module("templates")); + + beforeEach((done) => { + let cls = createClass({ + template: htmlTemplate, + directives: [TasksMenuComponent], + providers: [ + helpers.createProviderToValue("TaskService", taskService), + helpers.createProviderToValue('SessionService', helpers.mocks.sessionWithCurrentUser({})) + ] + }); + helper = new ComponentTestHelper(cls, done); + }); + + it("load person tasks", () => { + expect(taskService.getAllPending).toHaveBeenCalled(); + }); + + it("load person tasks when receive a login event", () => { + helper.component.loadTasks = jasmine.createSpy("loadTasks"); + helper.component.ngOnInit(); + (helper.component['authService'])[AuthEvents[AuthEvents.loginSuccess]].next({}); + expect(helper.component.loadTasks).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/app/task/tasks-menu/tasks-menu.component.ts b/src/app/task/tasks-menu/tasks-menu.component.ts index 919a0b1..ea0ab6f 100644 --- a/src/app/task/tasks-menu/tasks-menu.component.ts +++ b/src/app/task/tasks-menu/tasks-menu.component.ts @@ -1,12 +1,12 @@ import { Component, Inject } from "ng-forward"; import { TaskService } from "../../../lib/ng-noosfero-api/http/task.service"; -import { SessionService } from "./../../login"; +import { AuthService, SessionService, AuthEvents } from "./../../login"; @Component({ selector: "tasks-menu", templateUrl: "app/task/tasks-menu/tasks-menu.html" }) -@Inject(TaskService, SessionService) +@Inject(TaskService, SessionService, AuthService) export class TasksMenuComponent { tasks: noosfero.Task[]; @@ -14,14 +14,21 @@ export class TasksMenuComponent { perPage = 5; person: noosfero.Person; - constructor(private taskService: TaskService, private session: SessionService) { } + constructor(private taskService: TaskService, private session: SessionService, private authService: AuthService) { } ngOnInit() { - this.person = this.session.currentUser() ? this.session.currentUser().person : null; + this.authService.subscribe(AuthEvents[AuthEvents.loginSuccess], () => { + this.loadTasks(); + }); + this.loadTasks(); + } + + loadTasks() { + if (!this.session.currentUser()) return; + this.person = this.session.currentUser().person; this.taskService.getAllPending({ per_page: this.perPage }).then((result: noosfero.RestResult) => { this.total = result.headers('total'); this.tasks = result.data; }); } - } diff --git a/src/app/task/tasks/tasks.component.spec.ts b/src/app/task/tasks/tasks.component.spec.ts new file mode 100644 index 0000000..8843567 --- /dev/null +++ b/src/app/task/tasks/tasks.component.spec.ts @@ -0,0 +1,34 @@ +import { Provider, provide, Component } from 'ng-forward'; +import * as helpers from "../../../spec/helpers"; +import { ComponentTestHelper, createClass } from '../../../spec/component-test-helper'; +import { TasksComponent } from './tasks.component'; +import { AuthEvents } from "./../../login"; + +const htmlTemplate: string = ''; + +describe("Components", () => { + describe("Task Menu Component", () => { + + let helper: ComponentTestHelper; + let taskService = jasmine.createSpyObj("taskService", ["getAllPending"]); + let tasks = [{ id: 1 }, { id: 2 }]; + taskService.getAllPending = jasmine.createSpy("getAllPending").and.returnValue(Promise.resolve({ headers: () => { }, data: tasks })); + + beforeEach(angular.mock.module("templates")); + + beforeEach((done) => { + let cls = createClass({ + template: htmlTemplate, + directives: [TasksComponent], + providers: [ + helpers.createProviderToValue("TaskService", taskService) + ] + }); + helper = new ComponentTestHelper(cls, done); + }); + + it("load person tasks", () => { + expect(taskService.getAllPending).toHaveBeenCalled(); + }); + }); +}); diff --git a/src/app/task/tasks/tasks.component.ts b/src/app/task/tasks/tasks.component.ts index e0b1fc4..d1c0822 100644 --- a/src/app/task/tasks/tasks.component.ts +++ b/src/app/task/tasks/tasks.component.ts @@ -2,7 +2,7 @@ import { Component, Inject, provide } from "ng-forward"; import { TaskService } from "../../../lib/ng-noosfero-api/http/task.service"; @Component({ - selector: "tasks-component", + selector: "tasks", templateUrl: "app/task/tasks/tasks.html", providers: [ provide('taskService', { useClass: TaskService }) diff --git a/src/app/task/types/add-member/add-member-task-accept.component.ts b/src/app/task/types/add-member/add-member-task-accept.component.ts index 112f533..8994fdf 100644 --- a/src/app/task/types/add-member/add-member-task-accept.component.ts +++ b/src/app/task/types/add-member/add-member-task-accept.component.ts @@ -10,7 +10,7 @@ export class AddMemberTaskAcceptComponent { roles: any; constructor() { - //TODO list roles from API + // TODO list roles from API this.roles = ["Profile Administrator", "Member", "Moderator"]; } diff --git a/src/lib/ng-noosfero-api/http/task.service.spec.ts b/src/lib/ng-noosfero-api/http/task.service.spec.ts new file mode 100644 index 0000000..07f21ce --- /dev/null +++ b/src/lib/ng-noosfero-api/http/task.service.spec.ts @@ -0,0 +1,56 @@ +import { TaskService } from "./task.service"; + + +describe("Services", () => { + + describe("Task Service", () => { + + let $httpBackend: ng.IHttpBackendService; + let taskService: TaskService; + + beforeEach(angular.mock.module("main", ($translateProvider: angular.translate.ITranslateProvider) => { + $translateProvider.translations('en', {}); + })); + + beforeEach(inject((_$httpBackend_: ng.IHttpBackendService, _TaskService_: TaskService) => { + $httpBackend = _$httpBackend_; + taskService = _TaskService_; + })); + + + describe("Succesfull requests", () => { + + it("list pending tasks", (done) => { + $httpBackend.expectGET(`/api/v1/tasks?all_pending=true`).respond(200, { tasks: [{ id: 1 }] }); + taskService.getAllPending().then((result: noosfero.RestResult) => { + expect(result.data).toEqual([{ id: 1 }]); + done(); + }); + $httpBackend.flush(); + }); + + it("finish a task", (done) => { + let taskId = 1; + let task: noosfero.Task = { id: taskId }; + $httpBackend.expectPUT(`/api/v1/tasks/${taskId}/finish`).respond(200, { task: { id: taskId } }); + taskService.finishTask(task).then((result: noosfero.RestResult) => { + expect(result.data).toEqual({ id: 1 }); + done(); + }); + $httpBackend.flush(); + }); + + it("cancel a task", (done) => { + let taskId = 1; + let task: noosfero.Task = { id: taskId }; + $httpBackend.expectPUT(`/api/v1/tasks/${taskId}/cancel`).respond(200, { task: { id: taskId } }); + taskService.cancelTask(task).then((result: noosfero.RestResult) => { + expect(result.data).toEqual({ id: 1 }); + done(); + }); + $httpBackend.flush(); + }); + }); + + }); +}); diff --git a/src/lib/ng-noosfero-api/http/task.service.ts b/src/lib/ng-noosfero-api/http/task.service.ts index 7de9136..6f1e939 100644 --- a/src/lib/ng-noosfero-api/http/task.service.ts +++ b/src/lib/ng-noosfero-api/http/task.service.ts @@ -20,18 +20,25 @@ export class TaskService extends RestangularService { }; } - getAllPending(params: any) { + getAllPending(params: any = {}) { params['all_pending'] = true; return this.list(null, params); } finishTask(task: noosfero.Task) { - let element = this.getElement(task.id); - return element.customPUT(null, "finish"); + return this.closeTask(task, "finish"); } cancelTask(task: noosfero.Task) { + return this.closeTask(task, "cancel"); + } + + private closeTask(task: noosfero.Task, action: string) { let element = this.getElement(task.id); - return element.customPUT(null, "cancel"); + let put = element.customPUT(null, action); + let deferred = this.$q.defer>(); + put.then(this.getHandleSuccessFunction>(deferred)); + put.catch(this.getHandleErrorFunction>(deferred)); + return deferred.promise; } } diff --git a/src/spec/mocks.ts b/src/spec/mocks.ts index 6d357bb..0e8b624 100644 --- a/src/spec/mocks.ts +++ b/src/spec/mocks.ts @@ -223,11 +223,16 @@ export var mocks: any = { } }, promiseResultTemplate: (response?: {}) => { - - return { - then: (func?: (response: any) => void) => { - if (func) { return func(response); } + let callback = (func?: (response: any) => any) => { + if (func) { + let ret = func(response); + if (ret && typeof ret.then === "function") return ret; } + return mocks.promiseResultTemplate(response); + }; + return { + then: callback, + finally: callback }; }, $log: { -- libgit2 0.21.2