Source profileQuality 92/100

PramodDutta/qaskills/seed-skills/jasmine-testing/SKILL.md

Jasmine Testing

BDD-style JavaScript testing with Jasmine covering spies, async patterns, custom matchers, clock manipulation, and comprehensive test organization for frontend and Node.js applications.

Source repository stars
211
Declared platforms
3
Static risk flags
0
Last source update
2026-08-28
Source checked
2026-08-28

Decision brief

What it does: where it fits

You are an expert software engineer specializing in BDD-style testing with Jasmine. When the user asks you to write, review, or debug Jasmine tests, follow these detailed instructions to produce production-grade test suites that are readable, maintainable, and comprehensive.

Best for

    Not for

    • Testing implementation details -- Spying on private methods or asserting internal state creates brittle tests that break during refactoring without catching real bugs.
    • Multiple unrelated assertions in one spec -- Combining unrelated checks in a single it block makes it impossible to identify which behavior failed.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexDeclaredSource recordInstall path and trigger
    Claude CodeDeclaredSource recordInstall path and trigger
    CursorDeclaredSource recordInstall path and trigger
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/PramodDutta/qaskills --skill "seed-skills/jasmine-testing"
    Safe inspection promptEditorial

    Inspect the Agent Skill "Jasmine Testing" from https://github.com/PramodDutta/qaskills/blob/fb3fbec70591bad971dd97c5d9add6eaa99bae18/seed-skills/jasmine-testing/SKILL.md at commit fb3fbec70591bad971dd97c5d9add6eaa99bae18. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      package.json Setup

      Review the “package.json Setup” section in the pinned source before continuing.

      Review and apply the “package.json Setup” source section.
    2. 02

      Core Principles

      1. Behavior-Driven Development -- Write specs that describe behavior from the user's perspective using describe, it, and expect in natural language. 2. One expectation focus per spec -- Each it block should verify a single logical behavior to make failures easy to diagnose. 3. A…

      Behavior-Driven Development -- Write specs that describe behavior from the user's perspective using describe, it, and expect in natural language.One expectation focus per spec -- Each it block should verify a single logical behavior to make failures easy to diagnose.Arrange-Act-Assert -- Structure every spec into setup, execution, and verification phases even when using beforeEach.
    3. 03

      Project Structure

      Review the “Project Structure” section in the pinned source before continuing.

      Review and apply the “Project Structure” source section.
    4. 04

      Configuration

      Review the “Configuration” section in the pinned source before continuing.

      Review and apply the “Configuration” source section.
    5. 05

      jasmine.json

      Review the “jasmine.json” section in the pinned source before continuing.

      Review and apply the “jasmine.json” source section.

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score92/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars211SourceRepository attention, not individual Skill quality
    Compatibility3 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    PramodDutta/qaskills
    Skill path
    seed-skills/jasmine-testing/SKILL.md
    Commit
    fb3fbec70591bad971dd97c5d9add6eaa99bae18
    License
    MIT
    Collected
    2026-08-28
    Default branch
    main
    View the original SKILL.md

    Jasmine Testing Skill

    You are an expert software engineer specializing in BDD-style testing with Jasmine. When the user asks you to write, review, or debug Jasmine tests, follow these detailed instructions to produce production-grade test suites that are readable, maintainable, and comprehensive.

    Core Principles

    1. Behavior-Driven Development -- Write specs that describe behavior from the user's perspective using describe, it, and expect in natural language.
    2. One expectation focus per spec -- Each it block should verify a single logical behavior to make failures easy to diagnose.
    3. Arrange-Act-Assert -- Structure every spec into setup, execution, and verification phases even when using beforeEach.
    4. Isolate with spies -- Use jasmine.createSpy() and jasmine.createSpyObj() to eliminate external dependencies and side effects.
    5. Descriptive spec names -- Spec names should read as complete sentences: it('should return the sum of two positive numbers').
    6. Clean up after yourself -- Always uninstall clocks, restore spies, and tear down DOM modifications in afterEach blocks.
    7. Prefer async/await -- Use modern async patterns over done() callbacks for cleaner, more readable async specs.

    Project Structure

    src/
      services/
        user.service.js
        user.service.spec.js
        payment.service.js
        payment.service.spec.js
      utils/
        validators.js
        validators.spec.js
        formatters.js
        formatters.spec.js
      models/
        user.model.js
        user.model.spec.js
      helpers/
        jasmine-helpers.js
    spec/
      support/
        jasmine.json
      integration/
        user-payment.spec.js
    

    Configuration

    jasmine.json

    {
      "spec_dir": "spec",
      "spec_files": [
        "**/*[sS]pec.?(m)js"
      ],
      "helpers": [
        "helpers/**/*.?(m)js"
      ],
      "env": {
        "stopSpecOnExpectationFailure": false,
        "random": true,
        "forbidDuplicateNames": true
      }
    }
    

    package.json Setup

    {
      "devDependencies": {
        "jasmine": "^5.1.0",
        "@types/jasmine": "^5.1.0"
      },
      "scripts": {
        "test": "jasmine",
        "test:watch": "nodemon --exec jasmine",
        "test:coverage": "c8 jasmine"
      }
    }
    

    Basic Test Structure

    describe('Calculator', () => {
      let calculator;
    
      beforeEach(() => {
        calculator = new Calculator();
      });
    
      afterEach(() => {
        calculator = null;
      });
    
      describe('add', () => {
        it('should return the sum of two positive numbers', () => {
          const result = calculator.add(2, 3);
    
          expect(result).toBe(5);
        });
    
        it('should handle negative numbers', () => {
          const result = calculator.add(-1, -3);
    
          expect(result).toBe(-4);
        });
    
        it('should handle zero', () => {
          const result = calculator.add(0, 5);
    
          expect(result).toBe(5);
        });
      });
    
      describe('divide', () => {
        it('should return the quotient of two numbers', () => {
          const result = calculator.divide(10, 2);
    
          expect(result).toBe(5);
        });
    
        it('should throw an error when dividing by zero', () => {
          expect(() => calculator.divide(10, 0)).toThrowError('Division by zero');
        });
      });
    });
    

    Spy Patterns

    Creating Spies

    describe('UserService', () => {
      let userService;
      let apiClient;
    
      beforeEach(() => {
        apiClient = jasmine.createSpyObj('ApiClient', ['get', 'post', 'put', 'delete']);
        userService = new UserService(apiClient);
      });
    
      it('should fetch user by ID', async () => {
        const mockUser = { id: 1, name: 'Alice' };
        apiClient.get.and.returnValue(Promise.resolve(mockUser));
    
        const user = await userService.getUser(1);
    
        expect(apiClient.get).toHaveBeenCalledWith('/users/1');
        expect(apiClient.get).toHaveBeenCalledTimes(1);
        expect(user).toEqual(mockUser);
      });
    
      it('should create a new user', async () => {
        const newUser = { name: 'Bob', email: '[email protected]' };
        const savedUser = { id: 2, ...newUser };
        apiClient.post.and.returnValue(Promise.resolve(savedUser));
    
        const result = await userService.createUser(newUser);
    
        expect(apiClient.post).toHaveBeenCalledWith('/users', newUser);
        expect(result.id).toBe(2);
      });
    });
    

    Spying on Existing Methods

    describe('EventLogger', () => {
      let logger;
    
      beforeEach(() => {
        logger = new EventLogger();
        spyOn(logger, 'sendToServer').and.callFake(() => Promise.resolve());
        spyOn(console, 'error');
      });
    
      it('should log events and send to server', async () => {
        await logger.logEvent('click', { button: 'submit' });
    
        expect(logger.sendToServer).toHaveBeenCalledWith(
          jasmine.objectContaining({
            type: 'click',
            data: { button: 'submit' },
            timestamp: jasmine.any(Number)
          })
        );
      });
    
      it('should handle server failure gracefully', async () => {
        logger.sendToServer.and.returnValue(Promise.reject(new Error('Network error')));
    
        await logger.logEvent('click', { button: 'submit' });
    
        expect(console.error).toHaveBeenCalledWith(
          'Failed to send event:',
          jasmine.any(Error)
        );
      });
    });
    

    Async Testing Patterns

    Using async/await

    describe('DataFetcher', () => {
      let fetcher;
    
      beforeEach(() => {
        fetcher = new DataFetcher();
      });
    
      it('should fetch and transform data', async () => {
        spyOn(fetcher, 'fetchRaw').and.returnValue(
          Promise.resolve({ items: [{ id: 1 }, { id: 2 }] })
        );
    
        const result = await fetcher.getTransformedData();
    
        expect(result).toEqual([
          jasmine.objectContaining({ id: 1 }),
          jasmine.objectContaining({ id: 2 })
        ]);
      });
    
      it('should retry on failure', async () => {
        let callCount = 0;
        spyOn(fetcher, 'fetchRaw').and.callFake(() => {
          callCount++;
          if (callCount < 3) {
            return Promise.reject(new Error('Temporary failure'));
          }
          return Promise.resolve({ items: [] });
        });
    
        const result = await fetcher.getTransformedData();
    
        expect(fetcher.fetchRaw).toHaveBeenCalledTimes(3);
        expect(result).toEqual([]);
      });
    });
    

    Clock Manipulation

    describe('SessionManager', () => {
      beforeEach(() => {
        jasmine.clock().install();
      });
    
      afterEach(() => {
        jasmine.clock().uninstall();
      });
    
      it('should expire session after 30 minutes', () => {
        const session = new SessionManager();
        session.start();
    
        expect(session.isActive()).toBe(true);
    
        jasmine.clock().tick(30 * 60 * 1000);
    
        expect(session.isActive()).toBe(false);
      });
    
      it('should refresh session on activity', () => {
        const session = new SessionManager();
        session.start();
    
        jasmine.clock().tick(20 * 60 * 1000);
        session.recordActivity();
    
        jasmine.clock().tick(20 * 60 * 1000);
    
        expect(session.isActive()).toBe(true);
      });
    });
    

    Matcher Reference

    Built-in Matchers

    describe('Matcher examples', () => {
      it('demonstrates equality matchers', () => {
        expect(1 + 1).toBe(2);
        expect({ a: 1 }).toEqual({ a: 1 });
        expect(undefined).toBeUndefined();
        expect(null).toBeNull();
        expect('hello').toBeDefined();
        expect(true).toBeTruthy();
        expect(0).toBeFalsy();
      });
    
      it('demonstrates comparison matchers', () => {
        expect(10).toBeGreaterThan(5);
        expect(5).toBeLessThan(10);
        expect(10).toBeGreaterThanOrEqual(10);
        expect(0.1 + 0.2).toBeCloseTo(0.3, 5);
      });
    
      it('demonstrates string matchers', () => {
        expect('hello world').toContain('world');
        expect('hello world').toMatch(/^hello/);
      });
    
      it('demonstrates array matchers', () => {
        expect([1, 2, 3]).toContain(2);
        expect([1, 2, 3]).toHaveSize(3);
      });
    
      it('demonstrates object matchers', () => {
        const user = { name: 'Alice', age: 30, role: 'admin' };
        expect(user).toEqual(jasmine.objectContaining({ name: 'Alice' }));
        expect(user.name).toEqual(jasmine.stringContaining('Ali'));
      });
    
      it('demonstrates exception matchers', () => {
        const badFn = () => { throw new TypeError('invalid type'); };
        expect(badFn).toThrow();
        expect(badFn).toThrowError(TypeError);
        expect(badFn).toThrowError('invalid type');
      });
    });
    

    Custom Matchers

    beforeEach(() => {
      jasmine.addMatchers({
        toBeValidEmail: () => ({
          compare: (actual) => {
            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            const pass = emailRegex.test(actual);
            return {
              pass,
              message: pass
                ? `Expected ${actual} not to be a valid email`
                : `Expected ${actual} to be a valid email`
            };
          }
        }),
        toBeWithinRange: () => ({
          compare: (actual, floor, ceiling) => {
            const pass = actual >= floor && actual <= ceiling;
            return {
              pass,
              message: `Expected ${actual} to be within range [${floor}, ${ceiling}]`
            };
          }
        })
      });
    });
    
    describe('Custom matcher usage', () => {
      it('should validate email format', () => {
        expect('[email protected]').toBeValidEmail();
        expect('invalid-email').not.toBeValidEmail();
      });
    
      it('should check value ranges', () => {
        expect(5).toBeWithinRange(1, 10);
        expect(15).not.toBeWithinRange(1, 10);
      });
    });
    

    Nested Describe Blocks for Organization

    describe('ShoppingCart', () => {
      let cart;
    
      beforeEach(() => {
        cart = new ShoppingCart();
      });
    
      describe('when empty', () => {
        it('should have zero items', () => {
          expect(cart.itemCount()).toBe(0);
        });
    
        it('should have zero total', () => {
          expect(cart.total()).toBe(0);
        });
      });
    
      describe('when adding items', () => {
        beforeEach(() => {
          cart.addItem({ name: 'Widget', price: 9.99, quantity: 2 });
        });
    
        it('should update item count', () => {
          expect(cart.itemCount()).toBe(2);
        });
    
        it('should calculate total correctly', () => {
          expect(cart.total()).toBeCloseTo(19.98, 2);
        });
    
        describe('and applying a discount', () => {
          it('should reduce total by discount percentage', () => {
            cart.applyDiscount(0.1);
            expect(cart.total()).toBeCloseTo(17.98, 2);
          });
        });
      });
    
      describe('when removing items', () => {
        beforeEach(() => {
          cart.addItem({ name: 'Widget', price: 9.99, quantity: 2 });
          cart.addItem({ name: 'Gadget', price: 14.99, quantity: 1 });
        });
    
        it('should remove the specified item', () => {
          cart.removeItem('Widget');
          expect(cart.itemCount()).toBe(1);
        });
    
        it('should throw if item not found', () => {
          expect(() => cart.removeItem('NonExistent')).toThrowError('Item not found');
        });
      });
    });
    

    Best Practices

    1. Use beforeEach for shared setup -- Avoid duplicating setup code across specs; put common initialization in beforeEach blocks for consistency and DRY code.
    2. Always uninstall Jasmine clock -- If you call jasmine.clock().install(), always pair it with jasmine.clock().uninstall() in afterEach to prevent cross-spec contamination.
    3. Use jasmine.objectContaining for partial matches -- When testing objects with dynamic fields like timestamps or IDs, match only the fields you care about.
    4. Prefer createSpyObj over manual mocks -- It creates a clean mock with typed spy methods and avoids accidentally calling real implementations.
    5. Test error paths explicitly -- Every function that can throw or reject should have specs for each error scenario.
    6. Randomize spec execution order -- Set random: true in jasmine.json to catch specs that accidentally depend on execution order.
    7. Use fdescribe and fit only during debugging -- Never commit focused specs to version control; they skip other tests silently.
    8. Write descriptive failure messages -- Use custom matcher messages or add context to expectations so failures are self-documenting.
    9. Keep specs fast -- Unit specs should complete in under 50ms each. Move slow tests to a separate integration suite.
    10. Group related specs with nested describe blocks -- Create a hierarchy that mirrors the conditions and behaviors being tested.

    Anti-Patterns

    1. Testing implementation details -- Spying on private methods or asserting internal state creates brittle tests that break during refactoring without catching real bugs.
    2. Multiple unrelated assertions in one spec -- Combining unrelated checks in a single it block makes it impossible to identify which behavior failed.
    3. Shared mutable state between specs -- Storing test state in variables outside beforeEach causes order-dependent failures that are difficult to debug.
    4. Using done() callback with async/await -- Mixing callback and promise patterns leads to confusing control flow and potential false positives.
    5. Catching exceptions in specs -- Wrapping code in try/catch inside a spec swallows failures; use toThrow() or toThrowError() matchers instead.
    6. Not restoring spies -- Forgetting to restore spied-on methods pollutes the global state for subsequent specs.
    7. Hardcoding test data inline -- Duplicating magic numbers and strings across specs makes maintenance painful; extract shared fixtures.
    8. Ignoring async rejection handling -- Not testing promise rejections means error paths go uncovered and may fail silently in production.
    9. Over-mocking -- Mocking every dependency including simple utility functions reduces test confidence; only mock I/O and non-deterministic code.
    10. Writing tests after the fact -- Retroactive tests tend to mirror implementation rather than specify behavior; practice TDD where possible.

    Frequently asked questions

    What to verify before installation and use

    What does the Jasmine Testing source document cover?

    You are an expert software engineer specializing in BDD-style testing with Jasmine. When the user asks you to write, review, or debug Jasmine tests, follow these detailed instructions to produce production-grade test suites that are readable, maintainable, and comprehensive.

    How do I install Jasmine Testing?

    The source record exposes this install command: npx skills add https://github.com/PramodDutta/qaskills --skill "seed-skills/jasmine-testing". Inspect the command and pinned source before running it.

    Which Agent platforms does the source record declare?

    The pinned source record declares support for: codex, claude code, cursor.

    Alternatives

    Compare before choosing