Skip to content

Commit

Permalink
Add Unit Tests
Browse files Browse the repository at this point in the history
- **New Features**
- Enhanced testing configurations and setups for improved development
practices.
- Improved module import system for better reliability and maintenance.
- Implemented dependency injection in class functionalities for enhanced
testability and modularity.

- **Bug Fixes**
- Implemented checks to prevent operations on empty tags and ensure
proper logging in specific methods.

- **Tests**
- Introduced comprehensive test suites for key classes to ensure
robustness and functionality integrity.

- **Refactor**
- Modified constructors in several classes to adhere to dependency
injection principles.

- **Documentation**
- Updated project settings and configurations to align with new
development tools and practices.
  • Loading branch information
widoz committed Apr 20, 2024
1 parent f4c02bd commit e75b533
Show file tree
Hide file tree
Showing 14 changed files with 2,348 additions and 37 deletions.
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest.jestCommandLine": "yarn jest",
"jest.rootPath": "src",
"favorites.resources": []
}
26 changes: 17 additions & 9 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31693,13 +31693,13 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
const core = __importStar(__nccwpck_require__(2186));
const artifacts_1 = __nccwpck_require__(1870);
const tags_1 = __nccwpck_require__(7816);
const create_git_1 = __nccwpck_require__(6704);
const temporary_branch_1 = __nccwpck_require__(2786);
const create_git_1 = __nccwpck_require__(6704);
const configuration_1 = __nccwpck_require__(5778);
async function main() {
const configuration = new configuration_1.Configuration(core.getInput.bind(core));
const git = (0, create_git_1.createGit)();
const tags = new tags_1.Tags();
const tags = new tags_1.Tags(git);
const artifacts = new artifacts_1.Artifacts(git, tags, configuration);
const temporaryBranch = new temporary_branch_1.TemporaryBranch(git);
Promise.resolve()
Expand Down Expand Up @@ -31760,7 +31760,9 @@ class Artifacts {
core.startGroup('📦 Creating artifacts');
try {
await this.compile();
await this.tags.collect();
await this.deploy();
await this.tags.move();
}
catch (error) {
core.endGroup();
Expand All @@ -31777,10 +31779,8 @@ class Artifacts {
}
async deploy() {
await this.add();
await this.tags.collect();
await this.commit();
await this.push();
await this.tags.move();
}
async add() {
const result = await exec.exec(`git add -f ${this.configuration.targetDir}/*`);
Expand All @@ -31797,7 +31797,9 @@ class Artifacts {
async push() {
const pushingResult = await this.git.push();
const messages = pushingResult.remoteMessages.all.join('\n');
messages && core.info(`Pushed artifacts with messages: ${messages}`);
if (messages) {
core.info(`Pushed artifacts with messages: ${messages}`);
}
}
}
exports.Artifacts = Artifacts;
Expand Down Expand Up @@ -31835,17 +31837,22 @@ var __importStar = (this && this.__importStar) || function (mod) {
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.Tags = void 0;
const create_git_1 = __nccwpck_require__(6704);
const core = __importStar(__nccwpck_require__(2186));
class Tags {
git;
tags = [];
git = (0, create_git_1.createGit)();
constructor(git) {
this.git = git;
}
async collect() {
this.tags = (await this.git.tags(['--contains'])).all;
core.info(`Collecting tags: ${this.toString()}`);
}
async move() {
core.info(`Moving tags: ${this.toString()}`);
if (!this.tags.length) {
return;
}
await this.remove();
await this.create();
}
Expand All @@ -31868,7 +31875,9 @@ class Tags {
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
pushInfo(result, message) {
const messages = result.remoteMessages.all.join('\n');
messages && core.info(`${message}: ${messages}`);
if (messages) {
core.info(`${message}: ${messages}`);
}
}
}
exports.Tags = Tags;
Expand Down Expand Up @@ -31911,7 +31920,6 @@ class TemporaryBranch {
git;
constructor(git) {
this.git = git;
this.git = git;
}
async create() {
const _isDetached = await this.isDetached();
Expand Down
12 changes: 12 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
clearMocks: true,
preset: 'ts-jest',
moduleDirectories: ['node_modules'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'^@model/(.*)$': '<rootDir>/src/model/$1',
},
setupFilesAfterEnv: ['<rootDir>/tests/setup-tests.ts'],
maxWorkers: 8,
};
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@
"simple-git": "~3.22.0"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
"@total-typescript/shoehorn": "^0.1.0",
"@types/node": "~20.11.25",
"@typescript-eslint/eslint-plugin": "~7.1.1",
"@typescript-eslint/parser": "~7.1.1",
"@vercel/ncc": "~0.38.1",
"eslint": "~8.57.0",
"husky": "~9.0.11",
"jest": "^29.7.0",
"prettier": "~3.2.5",
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "~5.3.0"
},
"scripts": {
Expand Down
8 changes: 4 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import * as core from '@actions/core';
import { Artifacts } from './model/artifacts';
import { Tags } from './model/tags';
import { Artifacts } from '@model/artifacts';
import { Tags } from '@model/tags';
import { TemporaryBranch } from '@model/temporary-branch';
import { createGit } from './create-git';
import { TemporaryBranch } from './model/temporary-branch';
import { Configuration } from './configuration';

async function main(): Promise<void> {
const configuration = new Configuration(core.getInput.bind(core));

const git = createGit();
const tags = new Tags();
const tags = new Tags(git);
const artifacts = new Artifacts(git, tags, configuration);
const temporaryBranch = new TemporaryBranch(git);

Expand Down
12 changes: 7 additions & 5 deletions src/model/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { SimpleGit } from 'simple-git';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import type { Tags } from './tags';
import type { Configuration } from '../configuration';
import type { Configuration } from '@/configuration';

export class Artifacts {
constructor(
Expand All @@ -16,7 +16,9 @@ export class Artifacts {

try {
await this.compile();
await this.tags.collect();
await this.deploy();
await this.tags.move();
} catch (error: Error | unknown) {
core.endGroup();
const message = String(error instanceof Error ? error.message : error);
Expand All @@ -35,11 +37,8 @@ export class Artifacts {

private async deploy(): Promise<void> {
await this.add();

await this.tags.collect();
await this.commit();
await this.push();
await this.tags.move();
}

private async add(): Promise<void> {
Expand All @@ -59,6 +58,9 @@ export class Artifacts {
private async push(): Promise<void> {
const pushingResult = await this.git.push();
const messages = pushingResult.remoteMessages.all.join('\n');
messages && core.info(`Pushed artifacts with messages: ${messages}`);

if (messages) {
core.info(`Pushed artifacts with messages: ${messages}`);
}
}
}
14 changes: 11 additions & 3 deletions src/model/tags.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { PushResult, SimpleGit } from 'simple-git';
import { createGit } from '../create-git';
import * as core from '@actions/core';

export class Tags {
private tags: Array<string> = [];
private readonly git: SimpleGit = createGit();

constructor(private readonly git: Readonly<SimpleGit>) {}

public async collect(): Promise<void> {
this.tags = (await this.git.tags(['--contains'])).all;
Expand All @@ -13,6 +13,11 @@ export class Tags {

public async move(): Promise<void> {
core.info(`Moving tags: ${this.toString()}`);

if (!this.tags.length) {
return;
}

await this.remove();
await this.create();
}
Expand Down Expand Up @@ -40,6 +45,9 @@ export class Tags {
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
private pushInfo(result: Readonly<PushResult>, message: string): void {
const messages = result.remoteMessages.all.join('\n');
messages && core.info(`${message}: ${messages}`);

if (messages) {
core.info(`${message}: ${messages}`);
}
}
}
4 changes: 1 addition & 3 deletions src/model/temporary-branch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import type { PushResult, SimpleGit } from 'simple-git';
import * as core from '@actions/core';

export class TemporaryBranch {
constructor(private readonly git: Readonly<SimpleGit>) {
this.git = git;
}
constructor(private readonly git: Readonly<SimpleGit>) {}

async create(): Promise<void> {
const _isDetached = await this.isDetached();
Expand Down
8 changes: 8 additions & 0 deletions tests/setup-tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { jest } from '@jest/globals';

jest.mock('@actions/core', () => ({
startGroup: jest.fn(),
endGroup: jest.fn(),
info: jest.fn(),
setFailed: jest.fn(),
}));
148 changes: 148 additions & 0 deletions tests/unit/model/artifacts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import type { SimpleGit } from 'simple-git';
import type { Tags } from '@model/tags';
import type { getInput } from '@actions/core';

import { it, jest, describe, expect } from '@jest/globals';
import { exec } from '@actions/exec';
import { fromPartial } from '@total-typescript/shoehorn';
import { Configuration } from '@/configuration';
import { Artifacts } from '@model/artifacts';

jest.mock('@actions/exec', () => ({
__esModule: true,
exec: jest.fn(),
}));

jest.mock('@model/tags', () => ({
__esModule: true,
Tags: {
collect: jest.fn(),
move: jest.fn(),
},
}));

describe('Artifacts', () => {
it('Compile the assets and Deploy when finished', async () => {
const git = fromPartial<SimpleGit>({
commit: jest.fn(() =>
Promise.resolve({ summary: { changes: 0, insertions: 0, deletions: 0 } })
),
push: jest.fn(() =>
Promise.resolve({
remoteMessages: {
all: [''],
},
})
),
});
const tags = fromPartial<Tags>({ collect: jest.fn(), move: jest.fn() });
const artifacts = new Artifacts(git, tags, configuration());

jest.mocked(exec).mockImplementation(async () => Promise.resolve(0));

await artifacts.update();

expect(jest.mocked(exec)).toHaveBeenNthCalledWith(1, 'yarn build');
expect(jest.mocked(exec)).toHaveBeenNthCalledWith(2, 'git add -f ./build/*');
});

it('Throw an error when failing to compile', async () => {
const tags = fromPartial<Tags>({});
const git = fromPartial<SimpleGit>({});
const artifacts = new Artifacts(git, tags, configuration());

jest.mocked(exec).mockImplementation(async () => Promise.resolve(1));

await expect(artifacts.update()).rejects.toThrow(
'Failed creating artifacts: Failing to compile artifacts. Process exited with non-zero code.'
);
});

it('Throw an error when artifacts commit fails', async () => {
const git = fromPartial<SimpleGit>({
commit: jest.fn(() => Promise.reject(new Error('Failed to commit'))),
});
const tags = fromPartial<Tags>({ collect: jest.fn() });
const artifacts = new Artifacts(git, tags, configuration());

jest.mocked(exec).mockImplementation(async () => Promise.resolve(0));

await expect(artifacts.update()).rejects.toThrow('Failed creating artifacts: Failed to commit');
});

it('Throw an error when artifacts push fails', async () => {
const git = fromPartial<SimpleGit>({
commit: jest.fn(() =>
Promise.resolve({ summary: { changes: 0, insertions: 0, deletions: 0 } })
),
push: jest.fn(() => Promise.reject(new Error('Failed to push'))),
});
const tags = fromPartial<Tags>({ collect: jest.fn() });
const artifacts = new Artifacts(git, tags, configuration());

jest.mocked(exec).mockImplementation(async () => Promise.resolve(0));

await expect(artifacts.update()).rejects.toThrow('Failed creating artifacts: Failed to push');
});

it('Throw an error when failing to git-add', async () => {
const git = fromPartial<SimpleGit>({});
const tags = fromPartial<Tags>({ collect: jest.fn() });
const artifacts = new Artifacts(git, tags, configuration());

jest.mocked(exec).mockImplementation(async (command) => (command === 'yarn build' ? 0 : 1));

await expect(artifacts.update()).rejects.toThrow(
'Failed creating artifacts: Failing to git-add the artifacts build. Process exited with non-zero code.'
);
});

it('Throw an error when collecting tags fails', () => {
const git = fromPartial<SimpleGit>({});
const tags = fromPartial<Tags>({
collect: jest.fn(() => Promise.reject(new Error('Failed to collect tags'))),
});
const artifacts = new Artifacts(git, tags, configuration());

jest.mocked(exec).mockImplementation(async () => Promise.resolve(0));

expect(artifacts.update()).rejects.toThrow('Failed creating artifacts: Failed to collect tags');
});

it('Collect tags before moving them', async () => {
const git = fromPartial<SimpleGit>({
commit: jest.fn(() =>
Promise.resolve({ summary: { changes: 0, insertions: 0, deletions: 0 } })
),
push: jest.fn(() =>
Promise.resolve({
remoteMessages: {
all: [''],
},
})
),
});

const collect = jest.fn();
const move = jest.fn();
const tags = fromPartial<Tags>({ collect, move });

const artifacts = new Artifacts(git, tags, configuration());

jest.mocked(exec).mockImplementation(async () => Promise.resolve(0));

await artifacts.update();

expect(collect.mock.invocationCallOrder[0]).toBeLessThan(move.mock.invocationCallOrder[0] ?? 0);
});
});

function configuration(): Configuration {
return new Configuration(stubGetInput());
}

function stubGetInput(): typeof getInput {
return jest.fn((name: string): string => {
return name === 'command' ? 'yarn build' : './build';
});
}
Loading

0 comments on commit e75b533

Please sign in to comment.