Merge pull request #24 from pullfrog/add-basic-unit-tests
Initial unit tests
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
name: Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "24"
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Run type check
|
||||||
|
run: pnpm typecheck
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: pnpm test
|
||||||
+3
-2
@@ -13,7 +13,7 @@
|
|||||||
"main.d.ts"
|
"main.d.ts"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "vitest",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"build": "node esbuild.config.js",
|
"build": "node esbuild.config.js",
|
||||||
"play": "node play.ts",
|
"play": "node play.ts",
|
||||||
@@ -47,7 +47,8 @@
|
|||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
"esbuild": "^0.25.9",
|
"esbuild": "^0.25.9",
|
||||||
"husky": "^9.0.0",
|
"husky": "^9.0.0",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3",
|
||||||
|
"vitest": "^4.0.17"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
Generated
+874
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@
|
|||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
"lib": ["ESNext"],
|
"lib": ["ESNext"],
|
||||||
|
"types": ["vitest/globals"],
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"rewriteRelativeImportExtensions": true,
|
"rewriteRelativeImportExtensions": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
import { Timer } from './timer.ts';
|
||||||
|
import * as cli from './cli.ts';
|
||||||
|
|
||||||
|
describe('Timer', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.spyOn(cli.log, 'debug');
|
||||||
|
// Mock Date.now to have predictable timestamps
|
||||||
|
vi.useFakeTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
vi.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('constructor', () => {
|
||||||
|
it('should initialize with current timestamp', () => {
|
||||||
|
const mockTime = 1000000;
|
||||||
|
vi.setSystemTime(mockTime);
|
||||||
|
|
||||||
|
const timer = new Timer();
|
||||||
|
timer.checkpoint('test');
|
||||||
|
|
||||||
|
expect(cli.log.debug).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining('test')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('checkpoint', () => {
|
||||||
|
it('should log duration from initial timestamp on first checkpoint', () => {
|
||||||
|
const startTime = 1000000;
|
||||||
|
vi.setSystemTime(startTime);
|
||||||
|
const timer = new Timer();
|
||||||
|
|
||||||
|
const checkpointTime = startTime + 100;
|
||||||
|
vi.setSystemTime(checkpointTime);
|
||||||
|
timer.checkpoint('first');
|
||||||
|
|
||||||
|
expect(cli.log.debug).toHaveBeenCalledWith('» first: 100ms');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log duration from last checkpoint on subsequent checkpoints', () => {
|
||||||
|
const startTime = 1000000;
|
||||||
|
vi.setSystemTime(startTime);
|
||||||
|
const timer = new Timer();
|
||||||
|
|
||||||
|
// First checkpoint
|
||||||
|
const firstCheckpointTime = startTime + 50;
|
||||||
|
vi.setSystemTime(firstCheckpointTime);
|
||||||
|
timer.checkpoint('first');
|
||||||
|
|
||||||
|
// Second checkpoint
|
||||||
|
const secondCheckpointTime = firstCheckpointTime + 75;
|
||||||
|
vi.setSystemTime(secondCheckpointTime);
|
||||||
|
timer.checkpoint('second');
|
||||||
|
|
||||||
|
expect(cli.log.debug).toHaveBeenCalledTimes(2);
|
||||||
|
expect(cli.log.debug).toHaveBeenNthCalledWith(1, '» first: 50ms');
|
||||||
|
expect(cli.log.debug).toHaveBeenNthCalledWith(2, '» second: 75ms');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle multiple checkpoints correctly', () => {
|
||||||
|
const startTime = 1000000;
|
||||||
|
vi.setSystemTime(startTime);
|
||||||
|
const timer = new Timer();
|
||||||
|
|
||||||
|
// First checkpoint
|
||||||
|
vi.setSystemTime(startTime + 10);
|
||||||
|
timer.checkpoint('step1');
|
||||||
|
|
||||||
|
// Second checkpoint
|
||||||
|
vi.setSystemTime(startTime + 25);
|
||||||
|
timer.checkpoint('step2');
|
||||||
|
|
||||||
|
// Third checkpoint
|
||||||
|
vi.setSystemTime(startTime + 45);
|
||||||
|
timer.checkpoint('step3');
|
||||||
|
|
||||||
|
expect(cli.log.debug).toHaveBeenCalledTimes(3);
|
||||||
|
expect(cli.log.debug).toHaveBeenNthCalledWith(1, '» step1: 10ms');
|
||||||
|
expect(cli.log.debug).toHaveBeenNthCalledWith(2, '» step2: 15ms');
|
||||||
|
expect(cli.log.debug).toHaveBeenNthCalledWith(3, '» step3: 20ms');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle zero duration correctly', () => {
|
||||||
|
const startTime = 1000000;
|
||||||
|
vi.setSystemTime(startTime);
|
||||||
|
const timer = new Timer();
|
||||||
|
|
||||||
|
// Checkpoint immediately
|
||||||
|
timer.checkpoint('immediate');
|
||||||
|
|
||||||
|
expect(cli.log.debug).toHaveBeenCalledWith('» immediate: 0ms');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle custom checkpoint names', () => {
|
||||||
|
const startTime = 1000000;
|
||||||
|
vi.setSystemTime(startTime);
|
||||||
|
const timer = new Timer();
|
||||||
|
|
||||||
|
vi.setSystemTime(startTime + 200);
|
||||||
|
timer.checkpoint('Custom Checkpoint Name');
|
||||||
|
|
||||||
|
expect(cli.log.debug).toHaveBeenCalledWith(
|
||||||
|
'» Custom Checkpoint Name: 200ms'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'node',
|
||||||
|
exclude: ['node_modules', '.temp'],
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user