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.
expect
, describe
, test
)toBe
, toContain
, toMatch
expect
FunctionThe 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)
test
FunctionThe 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)
describe
FunctionThe 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`.
To run our tests, we’ll create a simple HTML page that displays the results visually.
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.)
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)
Now that our framework is ready, it is time to write some 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
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! 🎉
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.
You've conquered the service worker lifecycle, mastered caching strategies, and explored advanced features. Now it's time to lock down your implementation with battle-tested service worker…
Unlock the full potential of service workers with advanced features like push notifications, background sync, and performance optimization techniques that transform your web app into…
Learn how to integrate service workers in React, Next.js, Vue, and Angular with practical code examples and production-ready implementations for modern web applications.
This website uses cookies.