Version: 0.4.3 Last Updated: 2025-12-27
This document explains the testing setup for the Wyreframe library.
Wyreframe uses Vitest for testing, with rescript-vitest for ReScript integration.
- Fast execution with native ESM support
- Jest-compatible API
- Built-in TypeScript support
- Excellent HMR for watch mode
- V8 coverage provider
src/
├── parser/
│ ├── Core/
│ │ └── __tests__/ # Core module tests
│ ├── Detector/
│ │ └── __tests__/ # Shape detector tests
│ ├── Semantic/
│ │ └── __tests__/ # Semantic parser tests
│ │ └── Elements/
│ │ └── __tests__/ # Element parser tests
│ ├── Interactions/
│ │ └── __tests__/ # Interaction parser tests
│ ├── Fixer/
│ │ └── __tests__/ # Auto-fix tests
│ └── __tests__/ # Integration tests
├── renderer/
│ └── __tests__/ # Renderer tests
├── index.ts # TypeScript API
└── index.test.ts # TypeScript API tests
npm testnpm run test:watchnpm run test:coveragenpm test -- path/to/test.mjsnpm test -- --grep "Button"Use rescript-vitest for writing tests in ReScript:
// src/parser/Core/__tests__/Position_test.res
open RescriptVitest
describe("Position", () => {
test("creates position", () => {
let pos = Position.make(5, 10)
expect(pos.row)->toEqual(5)
expect(pos.col)->toEqual(10)
})
test("moves right", () => {
let pos = Position.make(0, 0)
let moved = Position.right(pos, 3)
expect(moved.col)->toEqual(3)
})
})For TypeScript API tests:
// src/index.test.ts
import { describe, test, expect } from 'vitest';
import { parse, createUI } from './index';
describe('Wyreframe API', () => {
test('parse returns success for valid wireframe', () => {
const wireframe = `
+--------+
| Hello |
+--------+
`;
const result = parse(wireframe);
expect(result.success).toBe(true);
if (result.success) {
expect(result.ast.scenes.length).toBe(1);
}
});
test('createUI renders successfully', () => {
const wireframe = `
@scene: test
+--------+
| Hello |
+--------+
`;
const result = createUI(wireframe);
expect(result.success).toBe(true);
if (result.success) {
expect(result.root).toBeInstanceOf(HTMLElement);
expect(result.sceneManager).toBeDefined();
}
});
});Configuration is in vitest.config.js:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
include: [
'src/**/*_test.mjs',
'src/**/*.test.mjs',
'src/**/*.test.ts'
],
environment: 'jsdom',
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
},
},
});After running npm run test:coverage, view the HTML report:
open coverage/index.htmlCoverage reports are also uploaded to Codecov in CI.
import { parse } from 'wyreframe';
test('handles button elements', () => {
const wireframe = `
+------------------+
| [ Click Me ] |
+------------------+
`;
const result = parse(wireframe);
expect(result.success).toBe(true);
if (result.success) {
const box = result.ast.scenes[0].elements[0];
expect(box.TAG).toBe('Box');
if (box.TAG === 'Box') {
const button = box.children[0];
expect(button.TAG).toBe('Button');
if (button.TAG === 'Button') {
expect(button.text).toBe('Click Me');
}
}
}
});test('returns error for unclosed box', () => {
const wireframe = `
+--------+
| Hello |
+-------
`;
const result = parse(wireframe);
expect(result.success).toBe(false);
if (!result.success) {
expect(result.errors.length).toBeGreaterThan(0);
}
});test('sceneManager navigates between scenes', () => {
const wireframe = `
@scene: page1
+--------+
| Page 1 |
+--------+
---
@scene: page2
+--------+
| Page 2 |
+--------+
`;
const result = createUI(wireframe);
if (result.success) {
const { sceneManager } = result;
sceneManager.goto('page1');
expect(sceneManager.getCurrentScene()).toBe('page1');
sceneManager.goto('page2');
expect(sceneManager.getCurrentScene()).toBe('page2');
sceneManager.back();
expect(sceneManager.getCurrentScene()).toBe('page1');
}
});import { fix, fixOnly } from 'wyreframe';
test('fix corrects misaligned pipes', () => {
const messy = `
+----------+
| Button |
+---------+
`;
const result = fix(messy);
expect(result.success).toBe(true);
if (result.success) {
expect(result.fixed.length).toBeGreaterThan(0);
}
});- One test file per module:
Module.res→Module_test.res - Use descriptive test names: Explain what's being tested
- Test edge cases: Empty inputs, boundary values, error conditions
- Group related tests: Use
describeblocks for organization - Keep tests focused: One logical assertion per test
- Build before testing: Run
npm run res:buildbefore tests
Tests run automatically on every push and pull request:
# .github/workflows/ci.yml
- name: Run tests
run: npm test
- name: Upload coverage
uses: codecov/codecov-action@v4- Ensure test files match patterns in
vitest.config.js - Check file extensions (
.test.ts,.test.mjs,_test.mjs)
- Run
npm run res:buildbefore testing - Verify .mjs files exist next to .res files
- Ensure
environment: 'jsdom'in vitest config - Import JSDOM globals if needed
- Add more test cases
- Test error paths and edge cases
- Remove dead code
Version: 0.4.3 Last Updated: 2025-12-27 License: GPL-3.0