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.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
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.
vitest-tests or jest-tests.npm install --save-dev jasmine then
npx jasmine init (creates spec/support/jasmine.json).spec/ with describe / it and built-in matchers;
wire "test": "jasmine" in package.json.spyOn(...).and.returnValue(...),
jasmine.createSpy); always configure the spy so it does not return
undefined by accident.async/await or a returned Promise, and use hooks
(beforeEach / afterEach) for setup and teardown.npm test; for browser-environment runs (Karma) and moving off
Jasmine, see references/karma-and-migration.md.npm install --save-dev jasmine
npx jasmine initinit 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.
- 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-reporterRunning specs in a real browser (Karma, the legacy Angular CLI default) and
moving a suite to Jest (jest-codemods handles ~80% of the syntax
transformations) are covered in
references/karma-and-migration.md.
A legacy service userService.save(user) POSTs to an API; verify it calls
the API without hitting the network.
npx jasmine init.spec/userServiceSpec.js:const { userService } = require('../src/userService');
const api = require('../src/api');
describe('userService.save', () => {
it('posts the user to /users', () => {
spyOn(api, 'post').and.returnValue(Promise.resolve({ id: 1 }));
userService.save({ name: 'Alice' });
expect(api.post).toHaveBeenCalledWith('/users', { name: 'Alice' });
});
});npm test. spyOn replaces api.post, so no real request fires; the
spec passes when save forwards the user to /users.| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Start new project with Jasmine + Karma in 2026 | Legacy stack; Karma in maintenance | Use Vitest / Jest for new (see references/karma-and-migration.md) |
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 (see references/karma-and-migration.md) |
jasmine-snapshot or migrate to Jest).jest-tests,
vitest-tests,
mocha-tests,
ava-tests - sister toolstest-code-conventions (qa-test-review) - test code hygiene