@codecovevienna/gittt-cli
Version:
Tracking time with CLI into a git repository
1,570 lines (1,300 loc) • 60.1 kB
text/typescript
import { assert, expect } from "chai";
import path from "path";
import proxyquire from "proxyquire";
import sinon from "sinon";
import { FileHelper, GitHelper, LogHelper, ProjectHelper } from "../../helper/index";
import { IProject, IRecord, IGitttFile } from "../../interfaces";
import { RECORD_TYPES, GitRemoteError, GitNoOriginError, GitNoRepoError, GitNoUrlError } from "../../types";
import { emptyHelper } from "../helper";
const sandboxDir = "./sandbox";
const configDir: string = path.join(sandboxDir, ".git-time-tracker");
const configFileName = "config.json";
const timerFileName = "timer.json";
const projectsDir = "projects";
LogHelper.DEBUG = false;
LogHelper.silence = true;
describe("ProjectHelper", function () {
let mockedFileHelper: FileHelper;
let mockedGitHelper: GitHelper;
before(function () {
proxyquire.noCallThru();
const fileProxy: any = proxyquire("../../helper/file", {});
const gitProxy: any = proxyquire("../../helper/git", {
"simple-git/promise": (baseDir: string): any => {
expect(baseDir).to.eq(configDir);
return {};
},
});
mockedFileHelper = new fileProxy.FileHelper(configDir, configFileName, timerFileName, projectsDir);
mockedGitHelper = new gitProxy.GitHelper(configDir, mockedFileHelper);
});
describe("General", function () {
it("should create instance", async function () {
const projectHelper: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
expect(projectHelper).to.be.instanceOf(ProjectHelper);
});
it("should return project file name", async function () {
expect(ProjectHelper.projectToProjectFilename({
meta: {
host: "github.com",
port: 443,
},
name: "mocked",
records: [],
})).to.eq("mocked.json");
});
it("should return project meta from domain", async function () {
expect(ProjectHelper.domainToProjectMeta("gitlab_com_10022")).to.deep.eq({
host: "gitlab.com",
port: 10022,
});
});
it("should return project meta from domain [no port]", async function () {
expect(ProjectHelper.domainToProjectMeta("gitlab_com")).to.deep.eq({
host: "gitlab.com",
port: 0,
});
});
it("should return project file path", async function () {
expect(ProjectHelper.getProjectPath({
meta: {
host: "github.com",
port: 443,
},
name: "mocked",
records: [],
})).to.eq("github_com_443/mocked.json");
});
it("should return project file path [no meta data]", async function () {
expect(ProjectHelper.getProjectPath({
name: "mocked",
records: [],
})).to.eq("mocked.json");
});
it("should get gittt project from .gittt.yml", async function () {
const getGitttFileStub = sinon.stub(mockedFileHelper, "getGitttFile").resolves({
name: "mocked_project_1",
} as IGitttFile);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const project: IProject = await instance.getGitttProject();
expect(project).to.deep.eq({
name: "mocked_project_1",
records: []
} as IProject);
getGitttFileStub.restore();
});
it("should get gittt project with requiresRoles from .gittt.yml", async function () {
const getGitttFileStub = sinon.stub(mockedFileHelper, "getGitttFile").resolves({
name: "mocked_project_1",
requiresRoles: true,
} as IGitttFile);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const project: IProject = await instance.getGitttProject();
expect(project).to.deep.eq({
name: "mocked_project_1",
records: [],
requiresRoles: true,
} as IProject);
getGitttFileStub.restore();
});
it("should get gittt project from .git/config", async function () {
const getGitttFileStub = sinon.stub(mockedFileHelper, "getGitttFile").throws(new Error("mocked"))
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getProjectFromGitStub = sinon.stub(instance, "getProjectFromGit").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
} as IProject);
const project: IProject = await instance.getGitttProject();
expect(project?.meta?.host).to.eq("github.com");
expect(project?.meta?.port).to.eq(443);
expect(project?.name).to.eq("test_mocked");
getProjectFromGitStub.restore();
getGitttFileStub.restore();
});
it("should fail to get gittt project", async function () {
const getGitttFileStub = sinon.stub(mockedFileHelper, "getGitttFile").throws(new Error("mocked"))
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getProjectFromGitStub = sinon.stub(instance, "getProjectFromGit").throws(new Error("mocked2"))
try {
await instance.getGitttProject()
} catch (err: any) {
expect(err).to.not.be.undefined
}
getProjectFromGitStub.restore();
getGitttFileStub.restore();
});
it("should initialize project", async function () {
const initProjectStub = sinon.stub(mockedFileHelper, "initProject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getProjectFromGitStub = sinon.stub(instance, "getGitttProject").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
} as IProject);
const project: IProject = await instance.initProject();
expect(project.meta?.host).to.eq("github.com");
expect(project.meta?.port).to.eq(443);
expect(project.name).to.eq("test_mocked");
assert.isTrue(initProjectStub.calledOnce);
assert.isTrue(commitChangesStub.calledOnce);
assert.isTrue(getProjectFromGitStub.calledOnce);
initProjectStub.restore();
commitChangesStub.restore();
getProjectFromGitStub.restore();
});
it("should fail to initialize project", async function () {
const initProjectStub = sinon
.stub(mockedFileHelper, "initProject")
.rejects(new Error("Mocked error"));
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getProjectFromGitStub = sinon.stub(instance, "getGitttProject").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
} as IProject);
try {
await instance.initProject();
} catch (err: any) {
assert.isDefined(err);
}
assert.isTrue(initProjectStub.calledOnce);
assert.isTrue(getProjectFromGitStub.calledOnce);
initProjectStub.restore();
getProjectFromGitStub.restore();
});
it("should get project by name", async function () {
const mockedProject: IProject = {
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
};
const initProjectStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([mockedProject]);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const project: IProject | undefined = await instance.getProjectByName("test_mocked");
expect(project).to.eq(mockedProject);
initProjectStub.restore();
});
it("should get project by name [fallback to git {no name}]", async function () {
const mockedProject: IProject = {
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
};
const findAllProjectsStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([]);
const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves(mockedProject);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getProjectFromGitStub = sinon.stub(instance, "getGitttProject").resolves(mockedProject);
const project: IProject | undefined = await instance.getProjectByName("");
expect(project).to.eq(mockedProject);
assert.isTrue(getProjectFromGitStub.calledOnce);
assert.isTrue(findProjectByNameStub.calledOnce);
findAllProjectsStub.restore();
findProjectByNameStub.restore();
});
it("should fail to get project by name [no git folder]", async function () {
const findAllProjectsStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([]);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getProjectFromGitStub = sinon.stub(instance, "getGitttProject").throws(new Error("Mocked"));
try {
await instance.getProjectByName("test_mocked");
} catch (err: any) {
expect(err.message).to.eq("Mocked")
}
assert.isTrue(getProjectFromGitStub.calledOnce);
findAllProjectsStub.restore();
});
it("should get or ask project from git [git directory]", async function () {
const mockedProject: IProject = {
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
};
const populatedMockedProject: IProject = {
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 1337,
end: 123456789,
type: RECORD_TYPES.Time,
} as IRecord
],
};
const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves(populatedMockedProject);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const initProjectStub = sinon.stub(instance, "getGitttProject").resolves(mockedProject);
const project: IProject | undefined = await instance.getOrAskForProjectFromGit();
expect(project).to.eq(populatedMockedProject);
assert.isTrue(findProjectByNameStub.calledOnce);
initProjectStub.restore();
findProjectByNameStub.restore();
});
it("should get or ask project from git [not a git directory]", async function () {
const mockedHelper: any = Object.assign({}, emptyHelper);
const mockedProject: IProject = {
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
};
mockedHelper.QuestionHelper = class {
public static chooseProjectFile = sinon.stub().resolves("domain/test_mocked");
}
const findAllProjectsStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([mockedProject]);
const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves(mockedProject);
const proxy: any = proxyquire("../../helper/project", {
"./": mockedHelper,
});
const instance: ProjectHelper = new proxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
const getProjectFromGitStub = sinon.stub(instance, "getProjectFromGit").throws(new GitRemoteError("Mocked Error"));
const project: IProject | undefined = await instance.getOrAskForProjectFromGit();
expect(project).to.eq(mockedProject);
getProjectFromGitStub.restore();
findProjectByNameStub.restore();
findAllProjectsStub.restore();
});
it("should fail to get or ask project from git [wrong error type]", async function () {
const mockedHelper: any = Object.assign({}, emptyHelper);
const mockedProject: IProject = {
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
};
mockedHelper.QuestionHelper = class {
public static chooseProjectFile = sinon.stub().resolves("domain/test_mocked");
}
const findAllProjectsStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([mockedProject]);
const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves(mockedProject);
const proxy: any = proxyquire("../../helper/project", {
"./": mockedHelper,
});
const instance: ProjectHelper = new proxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").throws(new Error("Mocked Error"));
let thrownError: Error | undefined;
try {
await instance.getOrAskForProjectFromGit();
} catch (err: any) {
thrownError = err;
}
assert.isDefined(thrownError);
getGitttProjectStub.restore();
findProjectByNameStub.restore();
findAllProjectsStub.restore();
});
it("should fail to get or ask project from git [no project]", async function () {
const mockedHelper: any = Object.assign({}, emptyHelper);
const mockedProject: IProject = {
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
};
mockedHelper.QuestionHelper = class {
public static chooseProjectFile = sinon.stub().resolves("domain/test_mocked");
}
const findAllProjectsStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([mockedProject]);
const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves(undefined);
const proxy: any = proxyquire("../../helper/project", {
"./": mockedHelper,
});
const instance: ProjectHelper = new proxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").throws(new GitRemoteError("Mocked Error"));
let thrownError: Error | undefined;
try {
await instance.getOrAskForProjectFromGit();
} catch (err: any) {
thrownError = err;
}
assert.isDefined(thrownError);
getGitttProjectStub.restore();
findProjectByNameStub.restore();
findAllProjectsStub.restore();
});
});
describe("Adding records", function () {
it("should add record to project", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
} as IProject);
await instance.addRecordToProject({
amount: 1337,
end: 12054,
message: "test",
type: RECORD_TYPES.Time,
});
assert.isTrue(commitChangesStub.calledWith(`Added 1337 hours to test_mocked: "test"`));
assert.isTrue(saveProjectObjectStub.calledOnce);
assert.isTrue(getGitttProjectStub.calledOnce);
commitChangesStub.restore();
saveProjectObjectStub.restore();
getGitttProjectStub.restore();
});
it("should add record to project without message", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
} as IProject);
await instance.addRecordToProject({
amount: 1337,
end: 12054,
type: RECORD_TYPES.Time,
});
assert.isTrue(commitChangesStub.calledWith(`Added 1337 hours to test_mocked`));
assert.isTrue(saveProjectObjectStub.calledOnce);
assert.isTrue(getGitttProjectStub.calledOnce);
commitChangesStub.restore();
saveProjectObjectStub.restore();
getGitttProjectStub.restore();
});
// it("should add record of one hour to project without message", async function () {
// const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves({
// meta: {
// host: "github.com",
// port: 443,
// },
// name: "test_mocked",
// records: [],
// } as IProject);
// const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
// const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
// const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
// const getProjectFromGitStub = sinon.stub(instance, "getProjectFromGit").returns({
// meta: {
// host: "github.com",
// port: 443,
// },
// name: "test_mocked",
// records: [],
// } as IProject);
// assert.isTrue(commitChangesStub.calledWith(`Added 1337 hours to test_mocked`));
// assert.isTrue(findProjectByNameStub.calledOnce);
// assert.isTrue(saveProjectObjectStub.calledOnce);
// assert.isTrue(getProjectFromGitStub.calledOnce);
// findProjectByNameStub.restore();
// commitChangesStub.restore();
// saveProjectObjectStub.restore();
// getProjectFromGitStub.restore();
// });
it("should add record to project without created timestamp", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
} as IProject);
await instance.addRecordToProject({
amount: 1337,
end: 12054,
type: RECORD_TYPES.Time,
});
assert.isTrue(commitChangesStub.calledWith(`Added 1337 hours to test_mocked`));
assert.isTrue(saveProjectObjectStub.calledOnce);
assert.isTrue(getGitttProjectStub.calledOnce);
commitChangesStub.restore();
saveProjectObjectStub.restore();
getGitttProjectStub.restore();
});
it("should add record of one hour to project without message", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [],
} as IProject);
await instance.addRecordToProject({
amount: 1,
end: 12054,
type: RECORD_TYPES.Time,
});
assert.isTrue(commitChangesStub.calledWith(`Added 1 hour to test_mocked`));
assert.isTrue(saveProjectObjectStub.calledOnce);
assert.isTrue(getGitttProjectStub.calledOnce);
commitChangesStub.restore();
saveProjectObjectStub.restore();
getGitttProjectStub.restore();
});
// it("should add record to non existing project", async function () {
// const findProjectByNameStub = sinon
// .stub(mockedFileHelper, "findProjectByName")
// .resolves(undefined);
// const initProjectStub = sinon.stub(mockedFileHelper, "initProject").resolves({
// meta: {
// host: "github.com",
// port: 443,
// },
// name: "test_mocked",
// records: [],
// } as IProject);
// const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
// const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
// const confirmMigrationStub = sinon.stub(QuestionHelper, "confirmMigration").resolves(false);
// const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
// const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves({
// meta: {
// host: "github.com",
// port: 443,
// },
// name: "test_mocked",
// records: [],
// } as IProject);
// await instance.addRecordToProject({
// amount: 1,
// end: 12054,
// type: RECORD_TYPES.Time,
// });
// assert.isTrue(commitChangesStub.calledWith(`Added 1 hour to test_mocked`));
// assert.isTrue(confirmMigrationStub.calledOnce);
// assert.isTrue(findProjectByNameStub.calledOnce);
// assert.isTrue(initProjectStub.calledOnce);
// assert.isTrue(saveProjectObjectStub.calledOnce);
// assert.isTrue(getGitttProjectStub.calledTwice);
// findProjectByNameStub.restore();
// initProjectStub.restore();
// commitChangesStub.restore();
// saveProjectObjectStub.restore();
// getGitttProjectStub.restore();
// confirmMigrationStub.restore();
// });
// it("should fail to add record to non existing project", async function () {
// const exitStub = sinon.stub(process, "exit");
// const findProjectByNameStub = sinon
// .stub(mockedFileHelper, "findProjectByName")
// .resolves(undefined);
// const initProjectStub = sinon
// .stub(mockedFileHelper, "initProject")
// .rejects(new Error("Mocked error"));
// const confirmMigrationStub = sinon.stub(QuestionHelper, "confirmMigration").resolves(false);
// const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
// const getProjectFromGitStub = sinon.stub(instance, "getProjectFromGit").returns({
// meta: {
// host: "github.com",
// port: 443,
// },
// name: "test_mocked",
// records: [],
// } as IProject);
// await instance.addRecordToProject({
// amount: 1337,
// end: 12054,
// message: "test",
// type: RECORD_TYPES.Time,
// });
// assert.isTrue(exitStub.called);
// assert.isTrue(findProjectByNameStub.calledOnce);
// assert.isTrue(initProjectStub.calledOnce);
// assert.isTrue(getProjectFromGitStub.calledTwice);
// findProjectByNameStub.restore();
// getProjectFromGitStub.restore();
// initProjectStub.restore();
// exitStub.restore();
// confirmMigrationStub.restore();
// });
// TODO re-enable
// it("should add record to migrated project", async function () {
// const findProjectByNameStub = sinon
// .stub(mockedFileHelper, "findProjectByName")
// // No project found to add record to
// .onCall(0).resolves(undefined)
// // Return project to migrate from
// .onCall(1).resolves({
// meta: {
// host: "from.com",
// port: 1337,
// },
// name: "migrate_from",
// records: [],
// } as IProject);
// const confirmMigrationStub = sinon.stub(QuestionHelper, "confirmMigration").resolves(true);
// const findAllProjectsStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([]);
// const chooseProjectFileStub = sinon.stub(QuestionHelper, "chooseProjectFile")
// .resolves("from_com/migrate_from.json");
// const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
// const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
// const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
// const getProjectFromGitStub = sinon.stub(instance, "getProjectFromGit").returns({
// meta: {
// host: "to.com",
// port: 2212,
// },
// name: "migrate_to",
// records: [],
// } as IProject);
// // const migrateStub = sinon.stub(instance, "migrate").resolves({
// // meta: {
// // host: "to.com",
// // port: 2212,
// // },
// // name: "migrate_to",
// // records: [],
// // } as IProject);
// await instance.addRecordToProject({
// amount: 1337,
// end: 12054,
// message: "test",
// type: RECORD_TYPES.Time,
// });
// assert.isTrue(confirmMigrationStub.calledOnce);
// assert.isTrue(findAllProjectsStub.calledOnce);
// assert.isTrue(findProjectByNameStub.calledTwice);
// assert.isTrue(getProjectFromGitStub.calledTwice);
// // assert.isTrue(migrateStub.calledOnce);
// assert.isTrue(saveProjectObjectStub.calledOnce);
// assert.isTrue(commitChangesStub.calledWith(`Added 1337 hours to migrate_to: "test"`));
// findProjectByNameStub.restore();
// confirmMigrationStub.restore();
// findAllProjectsStub.restore();
// chooseProjectFileStub.restore();
// getProjectFromGitStub.restore();
// // migrateStub.restore();
// saveProjectObjectStub.restore();
// commitChangesStub.restore();
// });
// TODO re-enable
// it("should fail to add record to migrated project [project not found]", async function () {
// const exitStub = sinon.stub(process, "exit");
// const findProjectByNameStub = sinon
// .stub(mockedFileHelper, "findProjectByName")
// // No project found to add record to
// .onCall(0).resolves(undefined)
// // Unable to find project on disk
// .onCall(1).resolves(undefined);
// const confirmMigrationStub = sinon.stub(QuestionHelper, "confirmMigration").resolves(true);
// const findAllProjectsStub = sinon.stub(mockedFileHelper, "findAllProjects").resolves([]);
// const chooseProjectFileStub = sinon.stub(QuestionHelper, "chooseProjectFile")
// .resolves("from_com/migrate_from.json");
// const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
// const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
// const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
// const getProjectFromGitStub = sinon.stub(instance, "getProjectFromGit").returns({
// meta: {
// host: "to.com",
// port: 2212,
// },
// name: "migrate_to",
// records: [],
// } as IProject);
// // const migrateStub = sinon.stub(instance, "migrate").resolves({
// // meta: {
// // host: "to.com",
// // port: 2212,
// // },
// // name: "migrate_to",
// // records: [],
// // } as IProject);
// try {
// await instance.addRecordToProject({
// amount: 1337,
// end: 69,
// message: "test",
// type: RECORD_TYPES.Time,
// });
// } catch (err: any) {
// assert.isDefined(err);
// }
// assert.isTrue(confirmMigrationStub.calledOnce);
// assert.isTrue(findAllProjectsStub.calledOnce);
// assert.isTrue(findProjectByNameStub.calledTwice);
// assert.isTrue(getProjectFromGitStub.calledOnce);
// // assert.isTrue(migrateStub.notCalled);
// assert.isTrue(saveProjectObjectStub.notCalled);
// assert.isTrue(commitChangesStub.notCalled);
// findProjectByNameStub.restore();
// confirmMigrationStub.restore();
// findAllProjectsStub.restore();
// chooseProjectFileStub.restore();
// getProjectFromGitStub.restore();
// // migrateStub.restore();
// saveProjectObjectStub.restore();
// commitChangesStub.restore();
// exitStub.restore();
// });
describe("Overlapping records", function () {
it("should fail to add overlapping record [start smaller end inside]", async function () {
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 10,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 10,
end: 999,
message: "test1",
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
getGitttProjectStub.restore();
});
it("should fail to add overlapping record [start larger end inside]", async function () {
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 10,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 8,
end: 999,
message: "test1",
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
getGitttProjectStub.restore();
});
it("should fail to add overlapping record [start smaller end outside]", async function () {
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 5,
end: 1001,
message: "test1",
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
getGitttProjectStub.restore();
});
it("should fail to add overlapping record [start inside end outside]", async function () {
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 10,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 10,
end: 1005,
message: "test1",
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
getGitttProjectStub.restore();
});
it("should fail to add overlapping record [start same end same]", async function () {
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 2,
end: 1000,
message: "test1",
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
getGitttProjectStub.restore();
});
it("should fail to add overlapping record, but add non overlapping [with message]", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 5,
end: 1001,
message: "test0",
type: RECORD_TYPES.Time,
},
{
amount: 2,
end: 2001,
message: "test1",
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
assert.isTrue(saveProjectObjectStub.calledOnce);
assert.isTrue(commitChangesStub.calledOnceWith(`Added 2 hours to test_mocked: "test1"`));
getGitttProjectStub.restore();
saveProjectObjectStub.restore();
commitChangesStub.restore();
});
it("should fail to add overlapping record, but add non overlapping [without message]", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 5,
end: 1001,
message: "test0",
type: RECORD_TYPES.Time,
},
{
amount: 2,
end: 2001,
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
assert.isTrue(saveProjectObjectStub.calledOnce);
assert.isTrue(commitChangesStub.calledOnceWith(`Added 2 hours to test_mocked`));
getGitttProjectStub.restore();
saveProjectObjectStub.restore();
commitChangesStub.restore();
});
it("should fail to add overlapping record, but add multiple non overlapping", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const commitChangesStub = sinon.stub(mockedGitHelper, "commitChanges").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject,
);
await instance.addRecordsToProject(
[
{
amount: 5,
end: 1001,
message: "test0",
type: RECORD_TYPES.Time,
},
{
amount: 2,
end: 2001,
type: RECORD_TYPES.Time,
},
{
amount: 3,
end: 3001,
type: RECORD_TYPES.Time,
},
],
undefined,
false,
true,
);
assert.isTrue(getGitttProjectStub.calledOnce);
assert.isTrue(saveProjectObjectStub.calledOnce);
assert.isTrue(commitChangesStub.calledOnceWith(`Added 2 records to test_mocked`));
getGitttProjectStub.restore();
saveProjectObjectStub.restore();
commitChangesStub.restore();
});
});
describe("Unique records", function () {
it("should fail to add not unique record", async function () {
const saveProjectObjectStub = sinon.stub(mockedFileHelper, "saveProjectObject").resolves();
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const getGitttProjectStub = sinon.stub(instance, "getGitttProject").resolves(
{
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
} as IProject
);
await instance.addRecordsToProject(
[
{
amount: 2,
end: 1000,
message: "test",
type: RECORD_TYPES.Time,
},
],
undefined,
true,
false,
);
assert.isTrue(getGitttProjectStub.calledOnce);
assert.isTrue(saveProjectObjectStub.notCalled);
getGitttProjectStub.restore();
saveProjectObjectStub.restore();
});
});
});
describe("Total hours of project", function () {
it("should get total numbers of hours for project", async function () {
const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
created: 1,
type: RECORD_TYPES.Time,
}, {
amount: 3,
created: 2,
type: RECORD_TYPES.Time,
},
],
} as IProject);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const totalHours: number = await instance.getTotalHours("test_mocked");
expect(totalHours).to.eq(5);
assert.isTrue(findProjectByNameStub.calledOnce);
findProjectByNameStub.restore();
});
it("should get total numbers of hours for project [no type]", async function () {
const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves({
meta: {
host: "github.com",
port: 443,
},
name: "test_mocked",
records: [
{
amount: 2,
created: 1,
type: RECORD_TYPES.Time,
}, {
amount: 3,
created: 2,
},
],
} as IProject);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
const totalHours: number = await instance.getTotalHours("test_mocked");
expect(totalHours).to.eq(2);
assert.isTrue(findProjectByNameStub.calledOnce);
findProjectByNameStub.restore();
});
it("should fail to get total numbers of hours for non existing project", async function () {
const findProjectByNameStub = sinon
.stub(mockedFileHelper, "findProjectByName")
.resolves(undefined);
const instance: ProjectHelper = new ProjectHelper(mockedGitHelper, mockedFileHelper);
try {
await instance.getTotalHours("test_mocked");
} catch (err: any) {
assert.isDefined(err);
}
assert.isTrue(findProjectByNameStub.calledOnce);
findProjectByNameStub.restore();
});
});
describe("Parse project from .git", function () {
it("should get project from git", function () {
const shellExecStub = sinon.stub()
.onCall(0).returns({
code: 0,
stderr: "",
stdout: "origin",
})
.onCall(1).returns({
code: 0,
stderr: "",
stdout: "ssh://git@github.com:443/test/mocked.git",
});
const projectProxy: any = proxyquire("../../helper/project", {
shelljs: {
exec: shellExecStub,
},
});
const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
const project: IProject = instance.getProjectFromGit();
assert.isArray(project.records);
expect(project.name).to.eq("test_mocked");
expect(project.meta?.host).to.eq("github.com");
expect(project.meta?.port).to.eq(443);
expect(project.meta?.raw).to.eq("ssh://git@github.com:443/test/mocked.git");
});
it("should get project from git [multiple remotes]", function () {
const shellExecStub = sinon.stub()
.onCall(0).returns({
code: 0,
stderr: "",
stdout: "test\nother\norigin\n",
})
.onCall(1).returns({
code: 0,
stderr: "",
stdout: "ssh://git@github.com:443/test/mocked.git",
});
const projectProxy: any = proxyquire("../../helper/project", {
shelljs: {
exec: shellExecStub,
},
});
const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
const project: IProject = instance.getProjectFromGit();
assert.isArray(project.records);
expect(project.name).to.eq("test_mocked");
expect(project.meta?.host).to.eq("github.com");
expect(project.meta?.port).to.eq(443);
expect(project.meta?.raw).to.eq("ssh://git@github.com:443/test/mocked.git");
});
it("should fail to get project from git [no origin remote]", function () {
const shellExecStub = sinon.stub()
.onCall(0).returns({
code: 0,
stderr: "",
stdout: "test\nother\n",
});
const projectProxy: any = proxyquire("../../helper/project", {
shelljs: {
exec: shellExecStub,
},
});
const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
let thrownError: Error | undefined;
try {
instance.getProjectFromGit();
} catch (err: any) {
thrownError = err;
}
assert.isDefined(thrownError);
expect(thrownError).to.be.instanceOf(GitNoOriginError);
});
it("should fail to get project from git [no git repository]", function () {
const shellExecStub = sinon.stub()
.onCall(0).returns({
code: 128,
stderr: "No git repository",
stdout: "",
});
const projectProxy: any = proxyquire("../../helper/project", {
shelljs: {
exec: shellExecStub,
},
});
const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
let thrownError: Error | undefined;
try {
instance.getProjectFromGit();
} catch (err: any) {
thrownError = err;
}
assert.isDefined(thrownError);
expect(thrownError).to.be.instanceOf(GitNoRepoError);
});
it("should fail to get project from git [shell exec fails]", function () {
const shellExecStub = sinon.stub()
.onCall(0).returns({
code: 1337,
stderr: "",
stdout: "origin",
});
const projectProxy: any = proxyquire("../../helper/project", {
shelljs: {
exec: shellExecStub,
},
});
const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
let thrownError: Error | undefined;
try {
instance.getProjectFromGit();
} catch (err: any) {
thrownError = err;
}
assert.isDefined(thrownError);
expect(thrownError).to.be.instanceOf(GitRemoteError);
});
it("should fail to get project from git [shell exec fails second time]", function () {
const shellExecStub = sinon.stub()
.onCall(0).returns({
code: 0,
stderr: "",
stdout: "origin",
})
.onCall(1).returns({
code: 1337,
stderr: "",
stdout: "ssh://git@github.com:443/test/mocked.git",
});
const projectProxy: any = proxyquire("../../helper/project", {
shelljs: {
exec: shellExecStub,
},
});
const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
let thrownError: Error | undefined;
try {
instance.getProjectFromGit();
} catch (err: any) {
thrownError = err;
}
assert.isDefined(thrownError);
expect(thrownError).to.be.instanceOf(GitNoUrlError);
});
it("should fail to get project from git [invalid stdout]", function () {
const shellExecStub = sinon.stub()
.onCall(0).returns({
code: 0,
stderr: "",
stdout: "origin",
})
.onCall(1).returns({
code: 0,
stderr: "",
stdout: "ssh",
});
const projectProxy: any = proxyquire("../../helper/project", {
shelljs: {
exec: shellExecStub,
},
});
const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
let thrownError: Error | undefined;
try {
instance.getProjectFromGit();
} catch (err: any) {
thrownError = err;
}
assert.isDefined(thrownError);
expect(thrownError).to.be.instanceOf(GitNoUrlError);
});
});
// TODO re-enable
// describe("Migration", function () {
// it("should migrate project [only project in domain]", async function () {
// const fromProject: IProject = {
// meta: {
// host: "github.com",
// port: 443,
// },
// name: "test_mocked",
// records: [
// {
// amount: 1337,
// end: 69,
// type: RECORD_TYPES.Time,
// },
// ],
// };
// const toProject: IProject = {
// meta: {
// host: "gitlab.com",
// port: 443,
// },
// name: "migrated_mocked",
// records: [],
// };
// const projectProxy: any = proxyquire("../../helper/project", {});
// const findProjectsForDomainStub = sinon.stub(mockedFileHelper, "findProjectsForDomain").resolves([
// ]);
// const findProjectByNameStub = sinon.stub(mockedFileHelper, "findProjectByName").resolves(fromProject);
// const initProjectStub = sinon.stub(mockedFileHelper, "initProject").resolves();
// const removeDomainStub = sinon.stub(mockedFileHelper, "removeDomainDirectory").resolves();
// const findLinksByProjectStub = sinon.stub(mockedFileHelper, "findLinksByProject").resolves([]);
// const instance: ProjectHelper = new projectProxy.ProjectHelper(mockedGitHelper, mockedFileHelper);
// await instance.migrate(fromProject, toProject);
// assert.isTrue(findProjectsForDomainStub.calledOnce);
// assert.isTrue(findProjectByNameStub.calledOnce);
// assert.isTrue