Getting Started
Introduction
Fauji is a lightweight testing framework for JavaScript applications. Designed with simplicity and developer experience in mind, Fauji provides a Jest-like API with powerful assertion capabilities, comprehensive mocking system, and built-in async testing support.
Installation
npm install fauji --save-dev
Configuration
Fauji requires a simple configuration file fauji.config.json to define test discovery patterns
and source directories. You must create a fauji.config.json
file in your project root
for Fauji to work.
{
"sourceDirectory": "src",
"testMatch": [
"**/*.test.js",
"**/*.spec.js"
]
}
sourceDirectory
- Directory containing your source code (default: current directory)testMatch
- Array of glob patterns to match test files
Allowed Test Patterns
**/*.test.js
- Files ending with .test.js**/*.spec.js
- Files ending with .spec.js**/*.test.ts
- Files ending with .test.ts**/*.spec.ts
- Files ending with .spec.ts
⚠️ Important: Without this configuration file, npx fauji command will exit with an error: "fauji.config.json not found in the project root"
Without Configuration
When you specify all necessary options via command line, the config file becomes optional:
# These work without config file:
npx fauji --dir ./tests --pattern "*.test.js"
npx fauji --dir ./src --pattern "*.spec.js" --name "auth"
npx fauji --dir ./components --pattern "*.test.js" --watch
Flexible to support different project structures
No matter what type of test file structure you follow, Fauji automatically discovers tests in your project based on the testMatch pattern mentioned in the config file.
Co-located Tests
src/
├── components/
│ ├── Button.js
│ ├── Button.test.js
│ ├── Modal.js
│ └── Modal.test.js
├── utils/
│ ├── math.js
│ ├── math.test.js
│ ├── string.js
│ └── string.test.js
└── services/
├── api.js
├── api.test.js
├── auth.js
└── auth.test.js
If you follow the co-located test structure like above, you just need to specify the
sourceDirectory
in the config file as src
and you are good to go.
{
"sourceDirectory": "./src",
"testMatch": ["**/*.test.js", "**/*.spec.js"]
}
Separate Test Directory
src/
├── components/
│ ├── Button.js
│ └── Modal.js
├── utils/
│ ├── math.js
│ └── string.js
└── services/
├── api.js
└── auth.js
tests/
├── components/
│ ├── Button.test.js
│ └── Modal.test.js
├── utils/
│ ├── math.test.js
│ └── string.test.js
└── services/
├── api.test.js
└── auth.test.js
If you prefer to keep your tests in a separate directory like above, you just need to specify the
testDirectory
in the config file as tests
and you are good to go.
{
"sourceDirectory": "./tests",
"testMatch": ["**/*.test.js", "**/*.spec.js"]
}
Writing Your First Test
Create a test file (e.g., math.test.js
) and start writing tests using Fauji's intuitive API:
describe('Math Operations', () => {
test('addition works correctly', () => {
expect(2 + 2).toBe(4);
expect(0.1 + 0.2).toBeCloseTo(0.3);
});
test('handles edge cases', () => {
expect(Infinity + 1).toBe(Infinity);
expect(NaN + 1).toBeNaN();
});
});
// Calculator module test
function add(a, b) {
return a + b;
}
function divide(a, b) {
if (b === 0) throw new Error('Division by zero');
return a / b;
}
describe('Calculator', () => {
test('addition', () => {
expect(add(5, 3)).toBe(8);
expect(add(-1, 1)).toBe(0);
});
test('division', () => {
expect(divide(10, 2)).toBe(5);
expect(() => divide(10, 0)).toThrow('Division by zero');
});
});
Test Structure and Organization
Fauji follows Jest's familiar test structure with describe
blocks for grouping and test
functions for individual test cases:
describe('User Authentication', () => {
// Setup that runs before all tests in this describe block
beforeAll(() => {
console.log('Setting up authentication tests');
});
// Setup that runs before each test
beforeEach(() => {
// Reset any state before each test
});
describe('Login functionality', () => {
test('successful login with valid credentials', () => {
const user = { username: 'john', password: 'secret123' };
const result = authenticate(user);
expect(result).toMatchObject({
success: true,
user: { username: 'john' }
});
});
test('failed login with invalid credentials', () => {
const user = { username: 'john', password: 'wrong' };
const result = authenticate(user);
expect(result.success).toBe(false);
expect(result.error).toContain('Invalid credentials');
});
});
describe('Token validation', () => {
test('validates JWT tokens correctly', () => {
const token = 'valid.jwt.token';
expect(validateToken(token)).toBeTruthy();
});
test('rejects invalid tokens', () => {
expect(validateToken('invalid-token')).toBeFalsy();
expect(validateToken(null)).toBeFalsy();
expect(validateToken('')).toBeFalsy();
});
});
// Cleanup after each test
afterEach(() => {
// Clean up any test data
});
// Cleanup after all tests in this describe block
afterAll(() => {
console.log('Authentication tests completed');
});
});
Essential Matchers Overview
Fauji provides a comprehensive set of matchers for different testing scenarios:
describe('Essential Matchers Demo', () => {
test('equality matchers', () => {
// Strict equality (Object.is)
expect(42).toBe(42);
expect('hello').toBe('hello');
// Deep equality for objects and arrays
expect({ a: 1, b: 2 }).toEqual({ a: 1, b: 2 });
expect([1, 2, 3]).toEqual([1, 2, 3]);
});
test('type checking matchers', () => {
expect([1, 2, 3]).toBeArray();
expect({ key: 'value' }).toBeObject();
expect('hello world').toBeString();
expect(42).toBeNumber();
expect(true).toBeBoolean();
expect(() => {}).toBeFunction();
expect(new Date()).toBeDate();
expect(/pattern/).toBeRegExp();
});
test('truthiness and nullish matchers', () => {
expect(true).toBeTruthy();
expect('non-empty').toBeTruthy();
expect(1).toBeTruthy();
expect(false).toBeFalsy();
expect('').toBeFalsy();
expect(0).toBeFalsy();
expect(null).toBeNull();
expect(undefined).toBeUndefined();
expect('defined').toBeDefined();
});
test('string and pattern matchers', () => {
expect('Hello World').toMatch('World');
expect('user@example.com').toMatch(/\w+@\w+\.\w+/);
expect('Hello World').toContain('Hello');
});
test('array and collection matchers', () => {
expect([1, 2, 3, 4]).toContain(3);
expect([1, 2, 3]).toHaveLength(3);
expect('hello').toHaveLength(5);
expect(new Set([1, 2, 3])).toHaveLength(3);
});
test('object property matchers', () => {
const user = {
name: 'John',
age: 30,
address: { city: 'New York', zip: '10001' }
};
expect(user).toHaveProperty('name');
expect(user).toHaveProperty('name', 'John');
expect(user).toHaveProperty('address.city', 'New York');
expect(user).toMatchObject({ name: 'John', age: 30 });
});
test('numerical comparison matchers', () => {
expect(10).toBeGreaterThan(5);
expect(10).toBeGreaterThanOrEqual(10);
expect(5).toBeLessThan(10);
expect(5).toBeLessThanOrEqual(5);
expect(0.1 + 0.2).toBeCloseTo(0.3, 1);
});
});
Running Tests
Fauji provides a simple and powerful CLI for running your tests. Here are the essential commands to get you started:
Quick Start
# Run all tests in current directory
npx fauji
# Run tests in a specific directory
npx fauji --dir ./tests
# Run tests with a specific pattern
npx fauji --pattern "*.test.js"
Essential Options
# Watch mode - automatically rerun tests when files change
npx fauji --watch
# Run only tests containing "auth" in the filename
npx fauji --name "auth"
# Combine options for targeted testing
npx fauji --dir ./src --name "user" --watch
Common Use Cases
- Development:
npx fauji --watch
- Run tests continuously - Specific Feature:
npx fauji --name "login"
- Test only login-related files - Directory Testing:
npx fauji --dir ./src/components
- Test only components - CI/CD:
npx fauji --parallel
- Run tests in parallel for faster execution
npx fauji --help
to see all available options, or check the complete CLI reference for advanced features like parallel execution, environment options, and performance optimization.
Next Steps
Now that you have Fauji set up and understand the basics, explore these advanced features:
- Using Matchers - Comprehensive guide to all 40+ built-in matchers
- Async Testing - Testing promises, async/await, and asynchronous operations
- Setup & Teardown - Lifecycle hooks and test environment management
- Mock Functions - Spies, stubs, mocks, and module isolation