Testing is a crucial aspect of software development that helps ensure your code works as expected and remains maintainable over time. In the world of vanilla JavaScript, testing becomes even more important as we don't have the safety net of frameworks or libraries to catch our mistakes.
Test-Driven Development is a software development approach where you write tests before writing the actual code. The process follows these steps:
This approach helps you focus on the desired behavior of your code and ensures that you have comprehensive test coverage.
To get started with testing in vanilla JavaScript, you'll need a testing framework. Some popular options include:
For this blog, we'll use Jasmine as our testing framework. To set it up, create a new project folder and install Jasmine:
npm init -y npm install --save-dev jasmine
Create a spec
folder for your test files and add a support/jasmine.json
file with the following content:
{ "spec_dir": "spec", "spec_files": [ "**/*[sS]pec.js" ] }
Let's start with a simple example. We'll create a function that adds two numbers and write a test for it.
First, create a file called math.js
in your project root:
function add(a, b) { return a + b; } module.exports = { add };
Now, create a test file called math.spec.js
in the spec
folder:
const { add } = require('../math'); describe('Math operations', () => { it('should add two numbers correctly', () => { expect(add(2, 3)).toBe(5); expect(add(-1, 1)).toBe(0); expect(add(0, 0)).toBe(0); }); });
Run the test using the command:
npx jasmine
You should see that the test passes.
Now, let's implement a new feature using TDD. We'll create a function that checks if a number is prime.
Start by writing a test in math.spec.js
:
const { add, isPrime } = require('../math'); // ... previous test ... describe('Prime number check', () => { it('should correctly identify prime numbers', () => { expect(isPrime(2)).toBe(true); expect(isPrime(3)).toBe(true); expect(isPrime(4)).toBe(false); expect(isPrime(17)).toBe(true); expect(isPrime(20)).toBe(false); }); });
Run the test, and it should fail because we haven't implemented the isPrime
function yet.
Now, let's implement the isPrime
function in math.js
:
function isPrime(num) { if (num <= 1) return false; for (let i = 2; i <= Math.sqrt(num); i++) { if (num % i === 0) return false; } return true; } module.exports = { add, isPrime };
Run the test again, and it should pass.
Mocking is useful when testing functions that depend on external resources or have side effects. Let's create a function that fetches user data and test it using mocks.
Add this function to math.js
:
async function fetchUserData(userId) { const response = await fetch(`https://api.example.com/users/${userId}`); return response.json(); } module.exports = { add, isPrime, fetchUserData };
Now, let's write a test using mocking in math.spec.js
:
const { add, isPrime, fetchUserData } = require('../math'); // ... previous tests ... describe('User data fetching', () => { it('should fetch user data correctly', async () => { const mockFetch = jasmine.createSpy('fetch').and.returnValue(Promise.resolve({ json: () => Promise.resolve({ id: 1, name: 'John Doe' }) })); global.fetch = mockFetch; const userData = await fetchUserData(1); expect(userData).toEqual({ id: 1, name: 'John Doe' }); expect(mockFetch).toHaveBeenCalledWith('https://api.example.com/users/1'); }); });
To ensure you're testing all parts of your code, you can use a coverage tool like Istanbul. Install it with:
npm install --save-dev nyc
Update your package.json
to include a test script:
"scripts": { "test": "nyc jasmine" }
Now, run your tests with coverage:
npm test
This will show you a report of which parts of your code are covered by tests and which are not.
describe
blocks.Test-Driven Development is a powerful technique that can significantly improve the quality and reliability of your vanilla JavaScript code. By writing tests first and following the TDD cycle, you'll create more robust, maintainable, and bug-free applications. Remember to choose the right testing framework for your needs, use mocking when necessary, and aim for high test coverage to get the most out of your testing efforts.
14/09/2024 | VanillaJS
22/10/2024 | VanillaJS
15/10/2024 | VanillaJS
22/10/2024 | VanillaJS
15/10/2024 | VanillaJS
15/10/2024 | VanillaJS
15/10/2024 | VanillaJS
15/10/2024 | VanillaJS
15/10/2024 | VanillaJS
15/10/2024 | VanillaJS