feat: Add testing infrastructure and documentation
- Set up Vitest for unit testing with jsdom - Add test setup with Web Audio API and requestAnimationFrame mocks - Create initial test suites for DOM and animations modules - Add test scripts to package.json (test, test:ui, test:run, coverage) - Update CI workflow to include test execution - Create CONTRIBUTING.md with conventional commits guidelines - Create SECURITY.md with security policy - Update ESLint config to support test files - All tests passing (8/8) Co-authored-by: ZaneThePython <102631678+ZaneThePython@users.noreply.github.com>
This commit is contained in:
40
tests/animations.test.js
Normal file
40
tests/animations.test.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { typeWriter } from '../assets/js/modules/animations.js';
|
||||
|
||||
describe('Animations Module', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
});
|
||||
|
||||
describe('typeWriter', () => {
|
||||
it('should type text character by character', async () => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
const text = 'Hello';
|
||||
typeWriter(element, text, 50);
|
||||
|
||||
// Wait for first setTimeout to execute
|
||||
await vi.runAllTimersAsync();
|
||||
|
||||
// Complete text should be shown
|
||||
expect(element.innerHTML).toBe('Hello');
|
||||
});
|
||||
|
||||
it('should handle null element gracefully', () => {
|
||||
expect(() => {
|
||||
typeWriter(null, 'text', 50);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should handle empty text', () => {
|
||||
const element = document.createElement('div');
|
||||
document.body.appendChild(element);
|
||||
|
||||
typeWriter(element, '', 50);
|
||||
vi.advanceTimersByTime(100);
|
||||
|
||||
expect(element.innerHTML).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
69
tests/dom.test.js
Normal file
69
tests/dom.test.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { DOM, getNavElements, getMainElements } from '../assets/js/modules/dom.js';
|
||||
|
||||
describe('DOM Module', () => {
|
||||
beforeEach(() => {
|
||||
// Setup basic HTML structure
|
||||
document.body.innerHTML = `
|
||||
<div class="container">
|
||||
<div class="avatar">Avatar</div>
|
||||
<h1 class="brand-name">ZaneDev</h1>
|
||||
<p class="tagline">Tagline</p>
|
||||
<nav class="navigation">
|
||||
<a href="#" class="nav-button">Button 1</a>
|
||||
<a href="#" class="nav-button">Button 2</a>
|
||||
</nav>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
describe('DOM utility', () => {
|
||||
it('should cache and retrieve elements', () => {
|
||||
const avatar = DOM.get('.avatar');
|
||||
expect(avatar).toBeTruthy();
|
||||
expect(avatar.textContent).toBe('Avatar');
|
||||
|
||||
// Should return cached version on second call
|
||||
const avatarAgain = DOM.get('.avatar');
|
||||
expect(avatarAgain).toBe(avatar);
|
||||
});
|
||||
|
||||
it('should get all elements matching selector', () => {
|
||||
const buttons = DOM.getAll('.nav-button');
|
||||
expect(buttons).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should clear cache', () => {
|
||||
DOM.get('.avatar');
|
||||
expect(Object.keys(DOM.cache).length).toBeGreaterThan(0);
|
||||
|
||||
DOM.clearCache();
|
||||
expect(Object.keys(DOM.cache).length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMainElements', () => {
|
||||
it('should return main UI elements', () => {
|
||||
const elements = getMainElements();
|
||||
|
||||
expect(elements.avatar).toBeTruthy();
|
||||
expect(elements.brandName).toBeTruthy();
|
||||
expect(elements.tagline).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNavElements', () => {
|
||||
it('should return navigation elements', () => {
|
||||
// Add required elements for navigation
|
||||
document.body.innerHTML += `
|
||||
<div class="content-section"></div>
|
||||
<button class="close-button">Close</button>
|
||||
`;
|
||||
|
||||
const elements = getNavElements();
|
||||
|
||||
expect(elements.navButtons).toBeTruthy();
|
||||
expect(elements.navButtons.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
34
tests/setup.js
Normal file
34
tests/setup.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// Test setup file
|
||||
import { beforeEach, vi } from 'vitest';
|
||||
|
||||
// Mock Web Audio API
|
||||
global.AudioContext = vi.fn().mockImplementation(() => ({
|
||||
createOscillator: vi.fn().mockReturnValue({
|
||||
connect: vi.fn(),
|
||||
frequency: {
|
||||
setValueAtTime: vi.fn(),
|
||||
exponentialRampToValueAtTime: vi.fn(),
|
||||
},
|
||||
start: vi.fn(),
|
||||
stop: vi.fn(),
|
||||
}),
|
||||
createGain: vi.fn().mockReturnValue({
|
||||
connect: vi.fn(),
|
||||
gain: {
|
||||
setValueAtTime: vi.fn(),
|
||||
exponentialRampToValueAtTime: vi.fn(),
|
||||
},
|
||||
}),
|
||||
destination: {},
|
||||
currentTime: 0,
|
||||
}));
|
||||
|
||||
// Mock requestAnimationFrame
|
||||
global.requestAnimationFrame = vi.fn((callback) => setTimeout(callback, 16));
|
||||
global.cancelAnimationFrame = vi.fn(clearTimeout);
|
||||
|
||||
// Reset DOM before each test
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
document.head.innerHTML = '';
|
||||
});
|
||||
Reference in New Issue
Block a user