From qa-unit-tests-js
Configures and runs Jasmine - the original BDD-style JS test framework (predecessor to Jest) with built-in matchers + spies, no external assertion library; ships `jasmine-core` + `jasmine` runner; `spec_dir` + `helpers` convention; `jasmine.json` config; spy patterns (`spyOn`, `createSpy`); pairs with Karma for in-browser testing. Use when the user maintains legacy AngularJS / Karma+Jasmine codebases, or wants minimal BDD-style tests with no third-party assertion library.
How this skill is triggered — by the user, by Claude, or both
Slash command
/qa-unit-tests-js:jasmine-testsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Per [jasmine.github.io/pages/getting_started.html][jas-start]:
Per jasmine.github.io/pages/getting_started.html:
Jasmine (~2010) is the original BDD-style JS test framework. Most
of Jest's API descends from Jasmine - describe, it,
beforeEach, expect(...).toBe(...), spies - were all Jasmine
patterns first.
Modern usage:
For new browser-side projects, prefer vitest-tests
or jest-tests. This skill covers the
maintenance use case + the migration path.
npm install --save-dev jasmine
npx jasmine init
init creates spec/support/jasmine.json:
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.js"
],
"helpers": [
"helpers/**/*.js"
],
"stopSpecOnExpectationFailure": false,
"random": true
}
// spec/sumSpec.js
const { sum } = require('../src/sum');
describe('sum', () => {
it('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
});
Wire package.json:
{
"scripts": {
"test": "jasmine"
}
}
Per jasmine.github.io/api/edge/matchers.html:
| Matcher | Use |
|---|---|
toBe(expected) | Strict equality (===) |
toEqual(expected) | Deep equality |
toBeTruthy() / toBeFalsy() | Boolean coercion |
toBeGreaterThan(n) / toBeLessThan(n) | Numeric comparison |
toBeCloseTo(n, precision) | Float comparison |
toContain(substring) | String / array containment |
toMatch(regex) | Regex match |
toThrow() / toThrowError(...) | Sync throw |
toBeInstanceOf(Class) | Type check |
toBeDefined() / toBeUndefined() / toBeNull() | Existence |
No need for Chai's expect(x).to.equal(y) style - Jasmine's
matchers are first-class.
describe('user service', () => {
it('calls api on save', () => {
spyOn(api, 'post').and.returnValue(Promise.resolve({ id: 1 }));
userService.save(user);
expect(api.post).toHaveBeenCalledWith('/users', user);
});
it('standalone spy', () => {
const spy = jasmine.createSpy('callback');
eventEmitter.on('save', spy);
eventEmitter.emit('save');
expect(spy).toHaveBeenCalled();
});
});
Spy methods:
| Method | Effect |
|---|---|
spyOn(obj, 'method') | Replace method with spy; returns undefined by default |
.and.returnValue(value) | Configure return |
.and.callFake(fn) | Custom implementation |
.and.callThrough() | Spy + delegate to real impl |
jasmine.createSpy(name) | Standalone spy |
jasmine.createSpyObj(name, ['m1', 'm2']) | Object with multiple spies |
// async/await (Jasmine 3.x+)
it('async test', async () => {
const result = await fetchData();
expect(result).toBe('expected');
});
// Promise return (Jasmine 2.x+)
it('promise test', () => {
return fetchData().then(result => {
expect(result).toBe('expected');
});
});
// Done callback (legacy)
it('callback test', (done) => {
fetchData((err, result) => {
expect(result).toBe('expected');
done();
});
});
describe('User service', () => {
beforeAll(() => { /* once before all */ });
afterAll(() => { /* once after all */ });
beforeEach(() => { /* before each spec */ });
afterEach(() => { /* after each spec */ });
});
Same pattern as Jest / Vitest.
For browser-environment tests (legacy Angular CLI default):
npm install --save-dev karma karma-jasmine karma-chrome-launcher
karma.conf.js:
module.exports = function(config) {
config.set({
frameworks: ['jasmine'],
files: ['src/**/*.spec.js'],
browsers: ['ChromeHeadless'],
singleRun: true,
reporters: ['progress', 'junit'],
});
};
npx karma start
Important migration note: Karma is in maintenance-only mode as of 2023; AngularJS reached end-of-life Jan 2022; new Angular projects use Jest or Vitest. Karma + Jasmine setups are explicitly legacy.
Jest's API is mostly compatible with Jasmine - typical migration steps:
spyOn().and.returnValue() with jest.spyOn().mockReturnValue()jasmine.createSpy() with jest.fn()jasmine.createSpyObj() with manual jest.fn() per methodexpect().toBeNan() with expect(Number.isNaN()).toBe(true)
(matcher renamed)jest.config.js with appropriate testMatchFor automated migration: jest-codemods package handles ~80% of
the syntax transformations.
- run: npm ci
- run: npx jasmine --config=spec/support/jasmine.json --reporter=jasmine-spec-reporter
# Or with JUnit XML for CI dashboards:
- run: npx jasmine --reporter=jasmine-junit-xml-reporter
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Start new project with Jasmine + Karma in 2026 | Legacy stack; Karma in maintenance | Use Vitest / Jest for new (Step 7) |
spyOn without .and configurator | Spy returns undefined; tests pass-by-accident | Always configure (Step 4) |
Use fdescribe / fit (focus) accidentally | Suite runs only focused specs | Lint rule equivalent of mocha/no-exclusive-tests |
| Mix Jasmine assertions with Chai | Two assertion APIs in one suite; reader confusion | Pick one (Step 3 - Jasmine's are sufficient) |
| Skip migration codemods when moving to Jest | Manual rewrites slow + error-prone | jest-codemods (Step 8) |
jasmine-snapshot or migrate to Jest).jest-tests,
vitest-tests,
mocha-tests,
ava-tests - sister toolstest-code-conventions - cross-plugin: test code hygienenpx claudepluginhub testland/qa --plugin qa-unit-tests-jsProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.