Testland
Browse all skills & agents

jasmine-tests

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.

Install with skills.sh (any agent)

npx skills add testland/qa --skill jasmine-tests
View source

jasmine-tests

Overview

Per jasmine.github.io/pages/getting_started.html (opens in new window):

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:

  • Legacy AngularJS apps standardized on Jasmine + Karma.
  • Migration cases from Jasmine to Jest (mostly mechanical).
  • Minimal-deps projects that want no external matcher libraries.

For new browser-side projects, prefer vitest-tests or jest-tests. This skill covers the maintenance use case + the migration path.

When to use

  • Existing Karma + Jasmine setup the team isn't ready to migrate.
  • Legacy AngularJS (1.x) project (Karma + Jasmine is the official Angular CLI default until very recent versions).
  • Minimal-dependency requirement (no separate Chai / Sinon).

How to use

  1. Confirm the codebase is legacy Jasmine / Karma or wants zero external assertion libraries (see When to use); for new projects prefer vitest-tests or jest-tests.
  2. Install and scaffold: npm install --save-dev jasmine then npx jasmine init (creates spec/support/jasmine.json).
  3. Write specs under spec/ with describe / it and built-in matchers; wire "test": "jasmine" in package.json.
  4. Replace collaborators with built-in spies (spyOn(...).and.returnValue(...), jasmine.createSpy); always configure the spy so it does not return undefined by accident.
  5. Handle async with async/await or a returned Promise, and use hooks (beforeEach / afterEach) for setup and teardown.
  6. Run npm test; for browser-environment runs (Karma) and moving off Jasmine, see references/karma-and-migration.md.

Step 1 - Install

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
}

Step 2 - First test

// 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"
  }
}

Step 3 - Built-in matchers

Per jasmine.github.io/api/edge/matchers.html:

MatcherUse
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.

Step 4 - Spies (built-in mocking)

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:

MethodEffect
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

Step 5 - Async patterns

// 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();
  });
});

Step 6 - Hooks

describe('User service', () => {
  beforeAll(() => { /* once before all */ });
  afterAll(() => { /* once after all */ });
  beforeEach(() => { /* before each spec */ });
  afterEach(() => { /* after each spec */ });
});

Same pattern as Jest / Vitest.

Step 7 - CI integration

- 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

Browser tests and migrating off Jasmine

Running 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.

Worked example

A legacy service userService.save(user) POSTs to an API; verify it calls the API without hitting the network.

  1. Scaffold once with npx jasmine init.
  2. Spec 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' });
  });
});
  1. Run npm test. spyOn replaces api.post, so no real request fires; the spec passes when save forwards the user to /users.

Anti-patterns

Anti-patternWhy it failsFix
Start new project with Jasmine + Karma in 2026Legacy stack; Karma in maintenanceUse Vitest / Jest for new (see references/karma-and-migration.md)
spyOn without .and configuratorSpy returns undefined; tests pass-by-accidentAlways configure (Step 4)
Use fdescribe / fit (focus) accidentallySuite runs only focused specsLint rule equivalent of mocha/no-exclusive-tests
Mix Jasmine assertions with ChaiTwo assertion APIs in one suite; reader confusionPick one (Step 3 - Jasmine's are sufficient)
Skip migration codemods when moving to JestManual rewrites slow + error-pronejest-codemods (see references/karma-and-migration.md)

Limitations

  • Karma maintenance-only; for browser-environment tests, prefer Vitest browser-mode.
  • Snapshot testing not built-in (use jasmine-snapshot or migrate to Jest).
  • ESM support workable but rough; new Jasmine versions improving.
  • Mock-server / fetch-mock ecosystems weaker than Jest's; more manual setup.

References

  • jas-start (opens in new window) - getting started
  • jasmine.github.io/api/edge - API reference
  • jasmine.github.io/api/edge/matchers.html - matcher list
  • karma-runner.github.io - Karma (legacy)
  • github.com/skovhus/jest-codemods - Jasmine→Jest migration codemods
  • jest-tests, vitest-tests, mocha-tests, ava-tests - sister tools
  • test-code-conventions (qa-test-review) - test code hygiene

Jasmine: Karma browser tests and migrating to Jest

View source (opens in new window)

Jasmine: Karma browser tests and migrating to Jest

Deep reference for jasmine-tests SKILL.md. Consult when running Jasmine specs in a real browser via Karma (the legacy Angular CLI default), or when moving a Jasmine suite to Jest.

Karma integration (browser tests)

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.

Migration to Jest path

Jest's API is mostly compatible with Jasmine - typical migration steps:

  1. Replace spyOn().and.returnValue() with jest.spyOn().mockReturnValue()
  2. Replace jasmine.createSpy() with jest.fn()
  3. Replace jasmine.createSpyObj() with manual jest.fn() per method
  4. Replace expect().toBeNan() with expect(Number.isNaN()).toBe(true) (matcher renamed)
  5. Add jest.config.js with appropriate testMatch
  6. Drop Karma if used (Jest handles its own jsdom env)

For automated migration: jest-codemods package handles ~80% of the syntax transformations.

Related skills

ava-tests

Configures and runs AVA - concurrent-by-default JS/TS test framework with isolated test files (each file runs in its own Node process), no globals (explicit `import test from 'ava'`), async-first API, snapshot support, and TypeScript via `@ava/typescript`. Use when AVA is already the chosen framework and the user wants minimal-API parallel-by-default tests, works with libraries (vs apps) where per-file isolation prevents test interference, or is switching from Mocha for per-file process isolation Mocha cannot provide. For choosing between AVA and Mocha, or for Mocha-specific work, use mocha-tests.

jest-tests

Configures and runs Jest - Meta-built batteries-included JS/TS unit framework with built-in `expect`, snapshot testing, mocking (`jest.mock`, `jest.fn`, `jest.spyOn`, manual `__mocks__/`), test environment selection (`jsdom` / `node`), parallel workers, coverage via Istanbul, watch mode, and CI integration via `--ci` flag. Use when the user works with React (CRA / older Next.js) or Node services and needs the most ecosystem-supported JS test framework.

mocha-tests

Configures and runs Mocha - pluggable JS test runner pairable with Chai assertions, Sinon mocking, and nyc / c8 coverage; supports BDD interface (`describe` / `it`) and TDD interface (`suite` / `test`); async tests via callbacks / promises / async-await; `--parallel` mode (Mocha 8+); `.mocharc.json` config; per-test exclusivity via `.only()` / `.skip()`. Use when the user prefers a minimal pluggable runner (vs Jest's batteries-included) or maintains legacy Mocha codebases.

vitest-tests

Configures and runs Vitest - Vite-native unit framework with Jest-compatible API (`expect`, `vi.fn`, `vi.mock`, `vi.spyOn`); reads `vite.config.*` so existing Vite plugins work; supports in-source testing via `if (import.meta.vitest)`, browser-mode UI for headed tests, type-checking via `vitest --typecheck`, native ESM, and coverage via v8 (default) or istanbul providers. Use when the user works with Vite-based projects (Vue, Svelte, Solid, modern React with Vite) or is migrating from Jest on an existing Vite project (not bundler-free Node - use jest-tests for that).