Skip to content

Commit 27cfb85

Browse files
added unit tests
1 parent f56c0d6 commit 27cfb85

File tree

7 files changed

+269
-0
lines changed

7 files changed

+269
-0
lines changed

src/ui/display/__tests__/help.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { displayHelp } from '../help';
3+
import * as madeWithLove from '../madeWithLove';
4+
5+
describe('displayHelp', () => {
6+
let logSpy: ReturnType<typeof vi.spyOn>;
7+
let madeWithLoveSpy: ReturnType<typeof vi.spyOn>;
8+
9+
beforeEach(() => {
10+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
11+
madeWithLoveSpy = vi
12+
.spyOn(madeWithLove, 'displayMadeWithLove')
13+
.mockImplementation(() => {});
14+
});
15+
16+
afterEach(() => {
17+
logSpy.mockRestore();
18+
madeWithLoveSpy.mockRestore();
19+
});
20+
21+
it('prints the help message and calls displayMadeWithLove', () => {
22+
displayHelp();
23+
expect(logSpy).toHaveBeenCalled();
24+
const output = logSpy.mock.calls.map(call => call[0]).join('\n');
25+
expect(output).toContain('Patch Pulse CLI');
26+
expect(output).toContain('Usage:');
27+
expect(output).toContain('Options:');
28+
expect(output).toContain('Configuration File:');
29+
expect(madeWithLoveSpy).toHaveBeenCalled();
30+
});
31+
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { displayLicense } from '../license';
3+
4+
vi.mock('fs', () => ({
5+
readFileSync: vi.fn(),
6+
}));
7+
8+
describe('displayLicense', () => {
9+
let logSpy: ReturnType<typeof vi.spyOn>;
10+
let errorSpy: ReturnType<typeof vi.spyOn>;
11+
12+
beforeEach(() => {
13+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
14+
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
15+
});
16+
17+
afterEach(() => {
18+
logSpy.mockRestore();
19+
errorSpy.mockRestore();
20+
vi.clearAllMocks();
21+
});
22+
23+
it('prints the license content when LICENSE file is present', async () => {
24+
const fs = await import('fs');
25+
vi.mocked(fs.readFileSync).mockReturnValue('MIT License\nCopyright 2024');
26+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
27+
throw new Error('exit');
28+
});
29+
try {
30+
displayLicense();
31+
} catch {
32+
// expected if process.exit is called
33+
}
34+
expect(fs.readFileSync).toHaveBeenCalled();
35+
expect(logSpy).toHaveBeenCalled();
36+
const output = logSpy.mock.calls.map(call => call[0]).join('\n');
37+
expect(output).toContain('License');
38+
expect(output).toContain('MIT License');
39+
expect(output).toContain('Copyright 2024');
40+
expect(errorSpy).not.toHaveBeenCalled();
41+
exitSpy.mockRestore();
42+
});
43+
44+
it('prints an error and fallback license if LICENSE file is missing', async () => {
45+
const fs = await import('fs');
46+
vi.mocked(fs.readFileSync).mockImplementation(() => {
47+
throw new Error('File not found');
48+
});
49+
const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {
50+
throw new Error('exit');
51+
});
52+
try {
53+
displayLicense();
54+
} catch {
55+
// expected due to process.exit mock
56+
}
57+
expect(errorSpy).toHaveBeenCalled();
58+
expect(logSpy).toHaveBeenCalledWith(
59+
expect.stringContaining('License: MIT')
60+
);
61+
exitSpy.mockRestore();
62+
});
63+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { displayMadeWithLove } from '../madeWithLove';
3+
4+
describe('displayMadeWithLove', () => {
5+
let logSpy: ReturnType<typeof vi.spyOn>;
6+
7+
beforeEach(() => {
8+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
9+
});
10+
11+
afterEach(() => {
12+
logSpy.mockRestore();
13+
});
14+
15+
it('prints the made with love message', () => {
16+
displayMadeWithLove();
17+
expect(logSpy).toHaveBeenCalledTimes(2);
18+
const calls = logSpy.mock.calls.map(call => call[0]);
19+
expect(calls[0]).toContain('─'.repeat(40));
20+
expect(calls[1]).toContain('Made with ❤️ by');
21+
expect(calls[1]).toContain('Barry Michael Doyle');
22+
});
23+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { displayThankYouMessage } from '../thankYouMessage';
3+
4+
describe('displayThankYouMessage', () => {
5+
let logSpy: ReturnType<typeof vi.spyOn>;
6+
7+
beforeEach(() => {
8+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
9+
});
10+
11+
afterEach(() => {
12+
logSpy.mockRestore();
13+
});
14+
15+
it('prints the thank you message and help info', () => {
16+
displayThankYouMessage();
17+
expect(logSpy).toHaveBeenCalledTimes(3);
18+
const calls = logSpy.mock.calls.map(call => call[0]);
19+
expect(calls[0]).toBeUndefined(); // Empty line (console.log() with no arguments)
20+
expect(calls[1]).toContain('🎉 Thank you for using Patch Pulse CLI!');
21+
expect(calls[2]).toContain('💡 For more info:');
22+
expect(calls[2]).toContain('npx patch-pulse --help');
23+
});
24+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { displayUnknownArguments } from '../unknownArguments';
3+
4+
describe('displayUnknownArguments', () => {
5+
let errorSpy: ReturnType<typeof vi.spyOn>;
6+
let logSpy: ReturnType<typeof vi.spyOn>;
7+
8+
beforeEach(() => {
9+
errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
10+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
11+
});
12+
13+
afterEach(() => {
14+
errorSpy.mockRestore();
15+
logSpy.mockRestore();
16+
});
17+
18+
it('displays unknown command error and help suggestions', () => {
19+
displayUnknownArguments(['--unknown', '--flag']);
20+
expect(errorSpy).toHaveBeenCalledWith(
21+
expect.stringContaining('❌ Unknown command:')
22+
);
23+
expect(errorSpy).toHaveBeenCalledWith(
24+
expect.stringContaining('--unknown --flag')
25+
);
26+
expect(logSpy).toHaveBeenCalled();
27+
const output = logSpy.mock.calls.map(call => call[0]).join('\n');
28+
expect(output).toContain('Available commands:');
29+
expect(output).toContain('npx patch-pulse');
30+
expect(output).toContain('npx patch-pulse --help');
31+
expect(output).toContain('Configuration options:');
32+
expect(output).toContain('For more information:');
33+
});
34+
35+
it('handles single unknown argument', () => {
36+
displayUnknownArguments(['--invalid']);
37+
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('--invalid'));
38+
});
39+
40+
it('handles empty array of unknown arguments', () => {
41+
displayUnknownArguments([]);
42+
expect(errorSpy).toHaveBeenCalledWith(
43+
expect.stringContaining('❌ Unknown command:')
44+
);
45+
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining(''));
46+
});
47+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { displayUpdateAvailable } from '../updateAvailable';
3+
4+
describe('displayUpdateAvailable', () => {
5+
let logSpy: ReturnType<typeof vi.spyOn>;
6+
7+
beforeEach(() => {
8+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
9+
});
10+
11+
afterEach(() => {
12+
logSpy.mockRestore();
13+
});
14+
15+
it('displays update available message with version information', () => {
16+
displayUpdateAvailable('1.0.0', '2.0.0');
17+
expect(logSpy).toHaveBeenCalled();
18+
const output = logSpy.mock.calls.map(call => call[0]).join('\n');
19+
expect(output).toContain('═'.repeat(50));
20+
expect(output).toContain('🚀 UPDATE AVAILABLE!');
21+
expect(output).toContain('Current Version:');
22+
expect(output).toContain('1.0.0');
23+
expect(output).toContain('Latest Version:');
24+
expect(output).toContain('2.0.0');
25+
expect(output).toContain('To update, run:');
26+
expect(output).toContain('npx patch-pulse@latest');
27+
});
28+
29+
it('handles different version formats', () => {
30+
displayUpdateAvailable('1.2.3-beta.1', '1.2.3');
31+
const output = logSpy.mock.calls.map(call => call[0]).join('\n');
32+
expect(output).toContain('1.2.3-beta.1');
33+
expect(output).toContain('1.2.3');
34+
});
35+
36+
it('displays the correct number of lines', () => {
37+
displayUpdateAvailable('1.0.0', '2.0.0');
38+
// Should have 8 console.log calls: separator, title, separator, current version, latest version, update instruction, command, separator
39+
expect(logSpy).toHaveBeenCalledTimes(8);
40+
});
41+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2+
import * as madeWithLove from '../madeWithLove';
3+
import { displayVersion } from '../version';
4+
5+
describe('displayVersion', () => {
6+
let logSpy: ReturnType<typeof vi.spyOn>;
7+
let madeWithLoveSpy: ReturnType<typeof vi.spyOn>;
8+
9+
beforeEach(() => {
10+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
11+
madeWithLoveSpy = vi
12+
.spyOn(madeWithLove, 'displayMadeWithLove')
13+
.mockImplementation(() => {});
14+
});
15+
16+
afterEach(() => {
17+
logSpy.mockRestore();
18+
madeWithLoveSpy.mockRestore();
19+
});
20+
21+
it('prints version information and calls displayMadeWithLove', () => {
22+
displayVersion();
23+
expect(logSpy).toHaveBeenCalled();
24+
const output = logSpy.mock.calls.map(call => call[0]).join('\n');
25+
expect(output).toContain('Patch Pulse CLI');
26+
expect(output).toContain('Version:');
27+
expect(output).toContain('Author:');
28+
expect(output).toContain('Repo:');
29+
expect(output).toContain('License:');
30+
expect(output).toContain('MIT');
31+
expect(output).toContain('https://github.com/PatchPulse/cli');
32+
expect(madeWithLoveSpy).toHaveBeenCalled();
33+
});
34+
35+
it('displays the correct number of lines', () => {
36+
displayVersion();
37+
// Should have 1 console.log call for the version info, plus displayMadeWithLove will add more
38+
expect(logSpy).toHaveBeenCalledTimes(1);
39+
});
40+
});

0 commit comments

Comments
 (0)