I apologize beforehand for this post, but I am struggling to figure out how to mock data from fetch request without making request itself and then test functions which have this data as dependency in Jasmine.
Here is my JavaScript code:
let products = []; //Array where transformed data from fetch request is stored for further use
function getProduct(productId) {//function to get product with certain id
let matchProduct = products.find(product => product.id === productId)
return matchProduct;
}
class Product { /*Example of classes used in function below, I can test them fine and they pass tests*/
id;
image;
name;
rating;
priceCents;
keywords;
constructor(productDetails) {
this.id = productDetails.id;
this.image = productDetails.image;
this.name = productDetails.name;
this.rating = productDetails.rating;
this.priceCents = productDetails.priceCents;
this.keywords = productDetails.keywords;
}
getStars() {
return `images/ratings/rating-${this.rating.stars * 10}.png`;
}
getPrice() {
return `$${formatCurrency(this.priceCents)}`;
}
extraInfoHTML() {
return ''
}
}
function loadProducts() {
const promise = fetch('link to host').then(response => {
return response.json(); //host responds with array of objects if translated in json
}).then(productData => { /*manipulating received array of objects to transform objects into classes and saving in new array*/
products = productData.map(productDetails => {
if (productDetails.keywords.includes('appliances')) {
productDetails.type = 'appliance';
productDetails.instructionLink = 'images/appliance-instructions.png';
productDetails.warrantyLink = 'images/appliance-warranty.png';
return new Appliance(productDetails);
}
if (productDetails.type === 'clothing') {
return new Clothing(productDetails);
}
return new Product(productDetails);
});
}).catch(error => {
console.error(error.message);
});
return promise;
}
All code works well and does what it does outside of test environment, but I got interested in how to test function getProduct() without making actual fetch request to remote host and how to test if remote host responded with correct data on request itself and/or request used correct link using Jasmine.
You should mock the fetch request and test your function in isolation. Here is my full check list of properly testing a function in isolation using Jasmine:
Mock the global fetch: Replace global.fetch with a Jasmine spy that returns a Promise
Test without real requests: Use jasmine.createSpy() to create a fake fetch function
Verify test calls: Check that fetch was called with the correct URL
Mock response data: Return sample test data instead of the real API response data
Test error handling: Mock rejected promises to test error scenarios
Here are sample tests to illustrate the above:
// Import your module that contains products, getProduct, loadProducts
// const { products, getProduct, loadProducts, Product, Appliance } = require('./your-products-file');
describe('Product Functions', () => {
let originalFetch;
beforeEach(() => {
// Reset products array
products = [];
// Store original fetch
originalFetch = global.fetch;
});
afterEach(() => {
// Restore original fetch
global.fetch = originalFetch;
});
describe('getProduct', () => {
it('should return product with matching id', () => {
// Mock products data
products = [
new Product({ id: '1', name: 'Test Product', rating: { stars: 4 }, priceCents: 1000 }),
new Product({ id: '2', name: 'Another Product', rating: { stars: 5 }, priceCents: 2000 })
];
const result = getProduct('1');
expect(result.id).toBe('1');
expect(result.name).toBe('Test Product');
});
it('should return undefined for non-existent product', () => {
products = [new Product({ id: '1', name: 'Test', rating: { stars: 4 }, priceCents: 1000 })];
const result = getProduct('999');
expect(result).toBeUndefined();
});
});
describe('loadProducts', () => {
it('should fetch and transform products correctly', async () => {
const mockData = [
{ id: '1', name: 'Regular Product', rating: { stars: 4 }, priceCents: 1000, keywords: [] },
{ id: '2', name: 'Appliance', rating: { stars: 5 }, priceCents: 2000, keywords: ['appliances'] }
];
// Mock fetch
global.fetch = jasmine.createSpy('fetch').and.returnValue(
Promise.resolve({
json: () => Promise.resolve(mockData)
})
);
await loadProducts();
expect(fetch).toHaveBeenCalledWith('link to host');
expect(products.length).toBe(2);
expect(products[0]).toBeInstanceOf(Product);
expect(products[1]).toBeInstanceOf(Appliance);
});
it('should handle fetch errors', async () => {
spyOn(console, 'error');
global.fetch = jasmine.createSpy('fetch').and.returnValue(
Promise.reject(new Error('Network error'))
);
await loadProducts();
expect(console.error).toHaveBeenCalledWith('Network error');
});
});
});