Simple configuration hacks to improve unit test case performance using Jasmine and Karma in Angular
Senior Frontend Dev. Mostly Angular and Svelte. I will be sharing my day-to-day learning experiences here with the community.
Search for a command to run...
Senior Frontend Dev. Mostly Angular and Svelte. I will be sharing my day-to-day learning experiences here with the community.
No comments yet. Be the first to comment.
Chapter 15 of Comprehensive Guide to SvelteKitAuth: Secure Authentication for SvelteKit Apps
Chapter 14 of Comprehensive Guide to SvelteKitAuth: Secure Authentication for SvelteKit Apps
Chapter 13 of Comprehensive Guide to SvelteKitAuth: Secure Authentication for SvelteKit Apps
Chapter 12 of Comprehensive Guide to SvelteKitAuth: Secure Authentication for SvelteKit Apps
Chapter 11 of Comprehensive Guide to SvelteKitAuth: Secure Authentication for SvelteKit Apps
Headless Chrome is a way to run the Chrome browser in a headless environment without the full browser UI. One of the benefits of using Headless Chrome (as opposed to testing directly in Node) is that your JavaScript tests will be executed in the same environment as users of your site. Headless Chrome gives you a real browser context without the memory overhead of running a full version of Chrome.
Configuration in karma.conf.js
browsers: ['Chrome', 'ChromeHeadlessNoSandbox']
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: [
'--no-sandbox',
'--disable-gpu',
'--remote-debugging-port=9222',
'--disable-site-isolation-trials',
]
}
}
More reading on this configuration from developers.google.com
Configurations in package.json file:
{
"test-fast": "node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng test --browsers=ChromeHeadlessNoSandbox --watch=true --codeCoverage=true --source-map=false"
}
npm run test-fast
We can utilize karma-parallel plugin to execute test cases parallely. This npm package splits your unit tests into multiple suites that run in parallel with each other, on different threads of your processor. It's highly customizable straight from your karma config file with how many threads you want to use, and how it splits your tests up.
Configuration details:
npm i karma-parallel --save-devframeworks: ['parallel', 'jasmine', ...others] // <- 'parallel' should be first one here
plugin: [
... others,
require: ('karma-parallel')
],
parallelOptions: {
executors: require('os') ? Math.ceil(require('os').cpus().length / 2) : 1
shardStrategy: 'round-robin'
}
NOTE:
If you adjust your karma config to run without a headless browser, and using the inspector, inspect your <head> tag, you will notice hundreds if not thousands of <style> tags appended to your body. One more point, after running every test case angular recompiles our test bed configuration, meaning we spent 70% of total time in compilation rather than actual execution of test case. To overcome that we need to override default test bed rest module.
NOTE:
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule(),
{ teardown: { destroyAfterEach: true } } // <- this is the new entry
);
Create new file override-reset-test-module-jasmine.ts:
import { getTestBed, TestBed, ComponentFixture } from '@angular/core/testing';
export function overrideResetTestModule() {
const testBedApi: any = getTestBed();
const originReset TestBed.resetTestingModule;
beforeAll(() => {
TestBed.resetTestingModule();
TestBed.resetTestingModule = () => TestBed;
});
afterEach(() => {
testBedApi._activeFixtures.forEach((fixture: ComponentFixture<any>) => fixture.destroy());
testBedApi._instantiated = false;
cleanStylesFromDOM();
});
afterAll(() => {
TestBed.resetTestingModule = originReset;
TestBed.resetTestingModule();
});
function cleanStylesfromDOM(): void {
const head: HTMLHeadElement = document.getElementsByTagName('head')[0];
const styles: HTMLCollectionOf<HTMLStyleElement> I [] = document.getElementsByTagName('style');
for (let i = 0; i < styles.length; i++) {
head.removeChild(styles[i]);
}
}
In you spec file, import this helper file:
describe('', => {
overrideResetTestModule();
// rest of code
});
I follow all these practices on my medium sized project in Angular v13 having around 1500 test cases and execution time is less than a minute (~50 seconds)! Yes less than a minute!!