Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Commit

Permalink
Added tests for project service
Browse files Browse the repository at this point in the history
  • Loading branch information
tbarlow12 authored and wbreza committed Apr 19, 2019
1 parent cc98d5f commit 94df15d
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 18 deletions.
20 changes: 14 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

102 changes: 97 additions & 5 deletions src/services/projectService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import _ from "lodash";
import ProjectService, { IProjectService } from "./projectService";
import MockFactory from "../common/mockFactory";
import { StorageProviderFactory } from "../providers/storage/storageProviderFactory";
import { IProject, IExportFormat, ISecurityToken, AssetState } from "../models/applicationState";
import { IProject, IExportFormat, ISecurityToken,
AssetState, IAsset, IAssetMetadata } from "../models/applicationState";
import { constants } from "../common/constants";
import { ExportProviderFactory } from "../providers/export/exportProviderFactory";
import { generateKey } from "../common/crypto";
import { encryptProject } from "../common/utils";
import { AssetService } from "./assetService";

describe("Project Service", () => {
let projectSerivce: IProjectService = null;
Expand Down Expand Up @@ -146,15 +148,105 @@ describe("Project Service", () => {
expect(projectSerivce.isDuplicate(testProject, projectList)).toEqual(true);
});

it("deletes all asset metadata files when project is deleted", async () => {
const assets = MockFactory.createTestAssets(10);
function populateProjectAssets(project?: IProject, assetCount = 10) {
if (!project) {
project = MockFactory.createTestProject();
}
const assets = MockFactory.createTestAssets(assetCount);
assets.forEach((asset) => {
asset.state = AssetState.Tagged;
});

testProject.assets = _.keyBy(assets, (asset) => asset.id);
project.assets = _.keyBy(assets, (asset) => asset.id);
return project;
}

it("deletes all asset metadata files when project is deleted", async () => {
const assetCount = 10;
populateProjectAssets(testProject);

await projectSerivce.delete(testProject);
expect(storageProviderMock.deleteFile.mock.calls).toHaveLength(assets.length + 1);
expect(storageProviderMock.deleteFile.mock.calls).toHaveLength(assetCount + 1);
});

it("Deletes tag from all assets within project", async () => {
const tag1 = "tag1";
const tag2 = "tag2";
const region = MockFactory.createTestRegion(undefined, [tag1, tag2]);
const asset: IAsset = {
...MockFactory.createTestAsset("1"),
state: AssetState.Tagged,
};
const assetMetadata = MockFactory.createTestAssetMetadata(asset, [region]);
AssetService.prototype.getAssetMetadata = jest.fn((asset: IAsset) => Promise.resolve(assetMetadata));

const saveMetadata = jest.fn();
AssetService.prototype.save = saveMetadata;

const expectedAssetMetadata: IAssetMetadata = {
...MockFactory.createTestAssetMetadata(
asset,
[
{
...region,
tags: [tag2],
},
],
),

};
const project = populateProjectAssets();
await projectSerivce.deleteTag(project, tag1, assetMetadata);
expect(saveMetadata).toBeCalledWith(expectedAssetMetadata);
});

it("Deletes any empty regions after deleting only tag from region", async () => {
const tag1 = "tag1";
const region = MockFactory.createTestRegion(undefined, [tag1]);
const asset: IAsset = {
...MockFactory.createTestAsset("1"),
state: AssetState.Tagged,
};
const assetMetadata = MockFactory.createTestAssetMetadata(asset, [region]);
AssetService.prototype.getAssetMetadata = jest.fn((asset: IAsset) => Promise.resolve(assetMetadata));

const saveMetadata = jest.fn();
AssetService.prototype.save = saveMetadata;

const expectedAssetMetadata: IAssetMetadata = MockFactory.createTestAssetMetadata(asset, []);
const project = populateProjectAssets();
await projectSerivce.deleteTag(project, tag1, assetMetadata);
expect(saveMetadata).toBeCalledWith(expectedAssetMetadata);
});

it("Updates renamed tag within all assets of project", async () => {
const tag1 = "tag1";
const newTag = "tag2";
const region = MockFactory.createTestRegion(undefined, [tag1]);
const asset: IAsset = {
...MockFactory.createTestAsset("1"),
state: AssetState.Tagged,
};
const assetMetadata = MockFactory.createTestAssetMetadata(asset, [region]);
AssetService.prototype.getAssetMetadata = jest.fn((asset: IAsset) => Promise.resolve(assetMetadata));

const saveMetadata = jest.fn();
AssetService.prototype.save = saveMetadata;

const expectedAssetMetadata: IAssetMetadata = {
...MockFactory.createTestAssetMetadata(
asset,
[
{
...region,
tags: [newTag],
},
],
),

};
const project = populateProjectAssets();
await projectSerivce.renameTag(project, tag1, newTag, assetMetadata);
expect(saveMetadata).toBeCalledWith(expectedAssetMetadata);
});
});
39 changes: 32 additions & 7 deletions src/services/projectService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ export interface IProjectService {
save(project: IProject, securityToken: ISecurityToken): Promise<IProject>;
delete(project: IProject): Promise<void>;
isDuplicate(project: IProject, projectList: IProject[]): boolean;
deleteTag(project: IProject, tagName: string, currentAsset: IAssetMetadata): Promise<IAssetMetadata>;
renameTag(project: IProject, tagName: string, newTagName: string, currentAsset: IAssetMetadata): Promise<IAssetMetadata>;
deleteTag(project: IProject, tagName: string,
currentAsset: IAssetMetadata): Promise<IAssetMetadata>;
renameTag(project: IProject, tagName: string, newTagName: string,
currentAsset: IAssetMetadata): Promise<IAssetMetadata>;
}

/**
Expand Down Expand Up @@ -111,8 +113,9 @@ export default class ProjectService implements IProjectService {
* @param currentAsset Current asset being viewed. Makes changes and returns updated asset to avoid
* needing to reload the asset in the editor page
*/
public async deleteTag(project: IProject, tagName: string, currentAsset: IAssetMetadata): Promise<IAssetMetadata> {
const transformer = (tags) => tags.filter((t) => t!== tagName);
public async deleteTag(project: IProject, tagName: string,
currentAsset: IAssetMetadata): Promise<IAssetMetadata> {
const transformer = (tags) => tags.filter((t) => t !== tagName);
return await this.updateProjectTags(project, tagName, currentAsset, transformer);
}

Expand All @@ -123,7 +126,8 @@ export default class ProjectService implements IProjectService {
* @param currentAsset Current asset being viewed. Makes changes and returns updated asset to avoid
* needing to reload the asset in the editor page
*/
public async renameTag(project: IProject, tagName: string, newTagName: string, currentAsset: IAssetMetadata): Promise<IAssetMetadata> {
public async renameTag(project: IProject, tagName: string, newTagName: string,
currentAsset: IAssetMetadata): Promise<IAssetMetadata> {
const transformer = (tags) => tags.map((t) => (t === tagName) ? newTagName : t);
return await this.updateProjectTags(project, tagName, currentAsset, transformer);
}
Expand All @@ -136,9 +140,27 @@ export default class ProjectService implements IProjectService {
* needing to reload the asset in the editor page
* @param transformer Function that accepts array of tags from a region and returns a modified array of tags
*/
private async updateProjectTags(project: IProject, tagName: string, currentAsset: IAssetMetadata, transformer: (tags: string[]) => string[]) {
private async updateProjectTags(project: IProject, tagName: string, currentAsset: IAssetMetadata,
transformer: (tags: string[]) => string[]): Promise<IAssetMetadata> {
const assetService = new AssetService(project);
const assetKeys = Object.keys(project.assets);
// Loop over assets and update if necessary
for (const assetKey of assetKeys) {
const asset = project.assets[assetKey];
if (asset.state !== AssetState.Tagged) {
return;
}
const assetMetadata = await assetService.getAssetMetadata(asset);
const updatedAssetMetadata = this.updateTagInAssetMetadata(assetMetadata, tagName, transformer);
if (updatedAssetMetadata) {
await assetService.save(updatedAssetMetadata);
}
}
/*
TODO: Replace with async
For some reason in tests, the `forEachAsync` is not recognized as a function
await assetKeys.forEachAsync(async (assetKey) => {
const asset = project.assets[assetKey];
if (asset.state !== AssetState.Tagged) {
Expand All @@ -150,6 +172,8 @@ export default class ProjectService implements IProjectService {
await assetService.save(updatedAssetMetadata);
}
});
*/
return this.updateTagInAssetMetadata(currentAsset, tagName, transformer);
}

Expand All @@ -160,7 +184,8 @@ export default class ProjectService implements IProjectService {
* @param transformer Function that accepts array of tags from a region and returns a modified array of tags
* @returns Modified asset metadata object or null if object does not need to be modified
*/
private updateTagInAssetMetadata(assetMetadata: IAssetMetadata, tagName: string, transformer: (tags: string[]) => string[]) {
private updateTagInAssetMetadata(assetMetadata: IAssetMetadata, tagName: string,
transformer: (tags: string[]) => string[]): IAssetMetadata {
let foundTag = false;
for (const region of assetMetadata.regions) {
if (region.tags.find((t) => t === tagName)) {
Expand Down

0 comments on commit 94df15d

Please sign in to comment.