blob: ab634c8aa2245e91a599a85cec991835b1539a02 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
********************************************************************************/
import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
import {TestBed} from "@angular/core/testing";
import {provideMockActions} from "@ngrx/effects/testing";
import {Action} from "@ngrx/store";
import {EMPTY, Observable, of, Subscription} from "rxjs";
import {IAPIAttachmentModel, SPA_BACKEND_ROUTE} from "../../../../core";
import {createFileMock} from "../../../../test";
import {
addAttachmentEntityAction,
deleteAttachmentsAction,
setAttachmentCacheAction,
submitAttachmentFormAction,
updateAttachmentTagsAction
} from "../../actions";
import {IAttachmentControlValue, IAttachmentError} from "../../model";
import {SubmitAttachmentsEffect} from "./submit-attachments.effect";
describe("SubmitAttachmentsEffect", () => {
const statementId = 19;
const taskId = "1919";
let actions$: Observable<Action>;
let httpTestingController: HttpTestingController;
let effect: SubmitAttachmentsEffect;
let subscription: Subscription;
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
SubmitAttachmentsEffect,
provideMockActions(() => actions$),
{
provide: SPA_BACKEND_ROUTE,
useValue: "/"
}
]
});
effect = TestBed.inject(SubmitAttachmentsEffect);
httpTestingController = TestBed.inject(HttpTestingController);
});
afterEach(() => {
if (subscription != null) {
subscription.unsubscribe();
}
});
it("should call submit method on submit action", async () => {
const submitSpy = spyOn(effect, "submit").and.returnValue(EMPTY);
actions$ = of(submitAttachmentFormAction({statementId, taskId, value: {add: [], edit: []}}));
subscription = effect.submit$.subscribe();
expect(submitSpy).toHaveBeenCalledWith(statementId, taskId, {add: [], edit: []});
});
it("should call add and remove method on submit", async () => {
const addSpy = spyOn(effect, "addAttachments").and.returnValue(EMPTY);
const editSpy = spyOn(effect, "editAttachments").and.returnValue(EMPTY);
const fetchSpy = spyOn(effect.fetchAttachmentsEffect, "fetchAttachments").and.returnValue(EMPTY);
subscription = effect.submit(statementId, taskId, {add: [], edit: []}).subscribe();
expect(addSpy).toHaveBeenCalledWith(statementId, taskId, [], []);
expect(editSpy).toHaveBeenCalledWith(statementId, taskId, [], []);
expect(fetchSpy).toHaveBeenCalledWith(statementId);
});
it("should throw an error if a single request fails on submit", async () => {
const attachmentError: IAttachmentError = {statementId, attachment: null, error: new Error("Test")};
effect.addAttachments = (
_: number,
__: string,
___: IAttachmentControlValue[],
errors: IAttachmentError[] = []
) => {
errors.push(attachmentError);
return EMPTY;
};
spyOn(effect, "editAttachments").and.returnValue(EMPTY);
spyOn(effect.fetchAttachmentsEffect, "fetchAttachments").and.returnValue(EMPTY);
await expectAsync(effect.submit(statementId, taskId, {add: [], edit: []}).toPromise())
.toBeRejectedWith([attachmentError]);
});
it("should add attachments", async () => {
const errors: IAttachmentError[] = [];
const values: IAttachmentControlValue[] = [
{
name: "18.pdf",
file: createFileMock("18.pdf"),
tagIds: ["tag18", "tag1818"]
},
{
name: "19.pdf",
file: createFileMock("19.pdf"),
tagIds: ["tag19", "tag1919"]
},
{
tagIds: []
},
null
];
const add$ = effect.addAttachments(statementId, taskId, values, errors);
const results: Action[] = [];
subscription = add$.subscribe((_) => results.push(_));
expectAddRequest({id: 18} as any, values[0].tagIds, true);
expectAddRequest({id: 19} as any, values[1].tagIds);
expect(results).toEqual([
setAttachmentCacheAction({statementId, items: values}),
addAttachmentEntityAction({statementId, entity: {id: 19} as any}),
setAttachmentCacheAction({statementId, items: [values[0]]})
]);
expect(errors.length).toBe(1);
expect(errors[0].statementId).toBe(statementId);
expect(errors[0].attachment).toBe(values[0]);
expect(errors[0].error).toBeDefined();
httpTestingController.verify();
});
it("should remove attachments", async () => {
const errors: IAttachmentError[] = [];
const values: IAttachmentControlValue[] = [
{
id: 18,
name: "18.pdf",
tagIds: ["tag18", "tag1818"],
isSelected: false
},
{
id: 19,
name: "19.pdf",
tagIds: ["tag19", "tag1919"],
isSelected: false
},
{
name: "",
tagIds: []
},
null
];
const add$ = effect.editAttachments(statementId, taskId, values, errors);
const results: Action[] = [];
subscription = add$.subscribe((_) => results.push(_));
expectDeleteRequest(18, true);
expectDeleteRequest(19, false);
expect(results).toEqual([
updateAttachmentTagsAction({items: values}),
deleteAttachmentsAction({statementId, entityIds: [19]})
]);
expect(errors.length).toBe(1);
expect(errors[0].statementId).toBe(statementId);
expect(errors[0].attachment).toBe(values[0]);
expect(errors[0].error).toBeDefined();
httpTestingController.verify();
});
it("should edit attachment tags", async () => {
const errors: IAttachmentError[] = [];
const values: IAttachmentControlValue[] = [
{
id: 18,
name: "18.pdf",
tagIds: ["tag18", "tag1818"],
isSelected: true
},
{
id: 19,
name: "19.pdf",
tagIds: ["tag19", "tag1919"],
isSelected: true
},
{
tagIds: []
}
];
const add$ = effect.editAttachments(statementId, taskId, values, errors);
const results: Action[] = [];
subscription = add$.subscribe((_) => results.push(_));
expectPostAttachmentTags(values[0].id, values[0].tagIds, true);
expectPostAttachmentTags(values[1].id, values[1].tagIds, false);
expect(results).toEqual([updateAttachmentTagsAction({items: values})]);
expect(errors.length).toBe(1);
expect(errors[0].statementId).toBe(statementId);
expect(errors[0].attachment).toBe(values[0]);
expect(errors[0].error).toBeDefined();
httpTestingController.verify();
});
function expectAddRequest(returnValue: IAPIAttachmentModel, tagIds: string[], error = false) {
const url = `/process/statements/${statementId}/task/${taskId}/attachments`;
const params = tagIds.reduce((_, tagId, i) => _ + (i > 0 ? "&" : "") + "tagId=" + tagId, "");
const request = httpTestingController.expectOne(url + (params.length > 0 ? "?" : "") + params);
expect(request.request.method).toBe("POST");
if (error) {
request.error(new ErrorEvent("test error"));
} else {
request.flush(returnValue);
}
}
function expectPostAttachmentTags(attachmentId: number, tagIds: string[], error = false) {
const url = `/process/statements/${statementId}/task/${taskId}/attachments/${attachmentId}/tags`;
const request = httpTestingController.expectOne(url);
expect(request.request.method).toBe("POST");
expect(request.request.body).toEqual(tagIds);
if (error) {
request.error(new ErrorEvent("test error"));
} else {
request.flush("204");
}
}
function expectDeleteRequest(attachmentId: number, error = false) {
const url = `/process/statements/${statementId}/task/${taskId}/attachments/${attachmentId}`;
const request = httpTestingController.expectOne(url);
expect(request.request.method).toBe("DELETE");
if (error) {
request.error(new ErrorEvent("test error"));
} else {
request.flush("204");
}
}
});