
Hey, Javascript enthusiast! Let’s do something fun today, building a Javascript test framework from scratch. Building your own JavaScript test framework is a great way to understand the inner workings of testing frameworks/libraries like Jest or Mocha. In this tutorial, we’ll create a simple yet powerful test framework from scratch, without relying on any external libraries, complete with helper functions like expect
, describe
, and test
. By the end, you’ll have a fully functional testing environment that runs directly in your browser, with clear pass/fail visuals for each test case. All with plain vanilla Javascript, CSS and HTML.
What’s in this Minimalistic Javascript Test Framework
- Simple test helpers (
expect
,describe
,test
) - Matchers like
toBe
,toContain
,toMatch
- Easy execution within an HTML page and visual representation of test results
- No dependencies or complex setups are required.
Step 1: Define the Core Helper Functions
1.1 The expect
Function
The expect
function is the backbone of our test framework. It allows us to make assertions about values and provides methods like toBe
, toContain
, and toMatch
.
function expect(actual) {
return {
toBe(expected) {
if (actual !== expected) {
throw new Error(`Expected ${expected}, but received ${actual}`);
}
},
toContain(item) {
if (!actual.includes(item)) {
throw new Error(`Expected array to contain ${item}, but it did not.`);
}
},
toMatch(regex) {
if (!regex.test(actual)) {
throw new Error(`Expected string to match ${regex}, but it did not.`);
}
}
};
}
Code language: JavaScript (javascript)
1.2 The test
Function
The test
function defines individual test cases. Each test will execute a callback function, and we’ll track whether it passes or fails.
const tests = [];
function test(description, callback) {
tests.push({ description, callback });
}
Code language: JavaScript (javascript)
1.3 The describe
Function
The describe
function groups related tests together. While optional, it improves readability and organization.
function describe(suiteName, callback) {
console.group(suiteName);
callback();
console.groupEnd();
}
Code language: JavaScript (javascript)
Let’s add all the above scripts in a file named `testFramework.js`.
Step 2: Running Tests on an HTML Page
To run our tests, we’ll create a simple HTML page that displays the results visually.
2.1 HTML Structure
Create an index.html
file with the following structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minimalistic Test Framework</title>
<style>
.test-result { margin: 10px; padding: 10px; border-radius: 5px; }
.pass { background-color: #d4edda; color: #155724; }
.fail { background-color: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<h1>Test Results</h1>
<div id="results"></div>
<script src="testFramework.js"></script>
<script src="tests.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
Note: make sure the charset is defined properly; otherwise results might not render correctly (due to emoji etc.)
2.2 Running Tests Dynamically
Let’s add the following script to our testFramework.js
to execute the tests and display their results:
document.addEventListener('DOMContentLoaded', () => {
const resultsDiv = document.getElementById('results');
let passed = 0;
let failed = 0;
tests.forEach(({ description, callback }) => {
try {
callback();
const resultDiv = document.createElement('div');
resultDiv.className = 'test-result pass';
resultDiv.textContent = `✅ PASS: ${description}`;
resultsDiv.appendChild(resultDiv);
passed++;
} catch (error) {
const resultDiv = document.createElement('div');
resultDiv.className = 'test-result fail';
resultDiv.textContent = `❌ FAIL: ${description} - ${error.message}`;
resultsDiv.appendChild(resultDiv);
failed++;
}
});
// Display summary
const summaryDiv = document.createElement('div');
summaryDiv.textContent = `Summary: Passed: ${passed}, Failed: ${failed}`;
resultsDiv.appendChild(summaryDiv);
});
Code language: JavaScript (javascript)
Step 3: Writing Test Cases
Now that our framework is ready, it is time to write some test cases!
Example Test Cases:
describe('String Operations', () => {
test('should concatenate strings', () => {
const result = 'Hello, ' + 'World!';
expect(result).toBe('Hello, World!');
});
test('should include substring', () => {
const str = 'Hello, World!';
expect(str).toContain('World');
});
});
describe('Array Operations', () => {
test('should find item in array', () => {
const arr = [1, 2, 3, 4];
expect(arr).toContain(3);
});
test('should match regex', () => {
const email = 'test@example.com';
expect(email).toMatch(/^[^@]+@[^@]+\.[^@]+$/);
});
});
Code language: PHP (php)
Put these test cases in a separate file named tests.js
Step 4: Visualizing Test Results
When you open the index.html
file in your browser, you’ll see a clear visual representation of your test results. Passed tests are highlighted in green, while failed tests are marked in red with error messages.

And it’s done. All test results are running and showing the results in a nice visual without depending on any explicit libraries/dependencies! 🎉
Conclusion: A Lightweight Testing Solution
By building this minimalistic JavaScript test framework, hopefully, you’ve gained some insight into how testing tools operate under the hood and had some fun along the way. This framework is easy to set up, doesn’t rely on any external libraries, and provides clear pass/fail visuals for your test cases. However, I wouldn’t recommend this in production settings. Maybe in a special scenario where you are really trying to avoid third-party dependency/build pipeline but still want to ensure high-quality code with test coverage.
Discover more from CODESAMPLEZ.COM
Subscribe to get the latest posts sent to your email.
Leave a Reply