Hone logo
Hone
Problems

Mastering Jest: Crafting Dynamic Test Execution Paths

This challenge focuses on a fundamental aspect of robust testing: creating and controlling execution paths within your Jest test suite. You will learn to conditionally execute tests or parts of tests based on specific criteria, mirroring real-world scenarios where tests might be relevant only under certain conditions or for specific configurations.

Problem Description

Your task is to implement a series of Jest tests for a hypothetical featureFlags module. This module exposes a function isEnabled(featureName: string): boolean that determines if a given feature is active. Your tests should demonstrate how to conditionally run specific test cases based on the status of these feature flags.

You will need to:

  1. Mock the featureFlags module: For the purpose of this challenge, assume the featureFlags module is external and its isEnabled function can be mocked.
  2. Create tests that conditionally execute: Implement test or it blocks that are only run when a specific feature flag is enabled.
  3. Create tests that conditionally skip: Implement test or it blocks that are skipped when a specific feature flag is enabled (or disabled).
  4. Use describe blocks conditionally: Demonstrate how to conditionally group tests using describe blocks.

Expected Behavior:

  • When a feature flag is enabled, the tests designed to run with that flag should execute.
  • When a feature flag is disabled, the tests designed to run with that flag should be skipped.
  • Tests designed to be skipped when a flag is enabled should run when it's disabled.

Edge Cases to Consider:

  • What happens if a feature flag is not defined? (Your mock should handle this gracefully).
  • How do you ensure that other tests not dependent on feature flags still run?

Examples

Example 1: Conditionally Running a Test

Assume featureFlags.isEnabled('newDashboard') returns true.

// featureFlags.ts (hypothetical module)
export const isEnabled = (featureName: string): boolean => {
  // ... actual logic ...
  return false; // Default
};
// my-tests.test.ts
import { isEnabled } from './featureFlags';

// Mocking the featureFlags module
jest.mock('./featureFlags', () => ({
  isEnabled: jest.fn(),
}));

const mockedIsEnabled = isEnabled as jest.Mock;

describe('Dashboard Tests', () => {
  beforeAll(() => {
    mockedIsEnabled.mockImplementation((featureName: string) => {
      if (featureName === 'newDashboard') return true;
      return false;
    });
  });

  // This test should run
  test('should display the new dashboard when newDashboard is enabled', () => {
    expect(mockedIsEnabled('newDashboard')).toBe(true);
    // ... assertions for new dashboard functionality ...
  });

  // This test should NOT run if newDashboard is enabled
  test('should display the old dashboard when newDashboard is disabled', () => {
    expect(mockedIsEnabled('newDashboard')).toBe(false);
    // ... assertions for old dashboard functionality ...
  });
});

Output (when newDashboard is mocked to true):

  • Dashboard Tests
    • should display the new dashboard when newDashboard is enabled (PASSED)
    • should display the old dashboard when newDashboard is disabled (PENDING/SKIPPED)

Example 2: Conditionally Skipping a Test

Assume featureFlags.isEnabled('experimentalSearch') returns false.

// my-tests.test.ts (continuation)
// ... previous mocks and setup ...

describe('Search Tests', () => {
  beforeAll(() => {
    // Ensure newDashboard is still true for other tests if needed
    mockedIsEnabled.mockImplementation((featureName: string) => {
      if (featureName === 'newDashboard') return true;
      if (featureName === 'experimentalSearch') return false; // Experimental search is disabled
      return false;
    });
  });

  // This test should run because experimentalSearch is NOT enabled
  test('should perform standard search operations', () => {
    expect(mockedIsEnabled('experimentalSearch')).toBe(false);
    // ... assertions for standard search ...
  });

  // This test should be skipped because experimentalSearch is disabled
  test.skip('should use the experimental search algorithm when experimentalSearch is enabled', () => {
    // This code block should not be reached in the actual test execution if skipped correctly
    expect(mockedIsEnabled('experimentalSearch')).toBe(true);
    // ... assertions for experimental search ...
  });
});

Output (when experimentalSearch is mocked to false):

  • Search Tests
    • should perform standard search operations (PASSED)
    • should use the experimental search algorithm when experimentalSearch is enabled (SKIPPED)

Example 3: Conditionally Grouping Tests

Consider a scenario where a whole suite of tests for a deprecated feature should only run if a DEPRECATED_FEATURES_ENABLED flag is explicitly turned on.

// my-tests.test.ts (continuation)
// ... previous mocks and setup ...

// Conditionally include a describe block
if (mockedIsEnabled('DEPRECATED_FEATURES_ENABLED')) {
  describe('Deprecated Feature Tests', () => {
    // Tests within this block will only be discovered and run if the condition is met
    test('should still support legacy authentication', () => {
      // ... assertions ...
    });
  });
} else {
  // You might also add a placeholder or a message if the group is skipped
  describe('Deprecated Feature Tests', () => {
    test('should be skipped as deprecated features are disabled', () => {
      // This test will be marked as skipped by Jest if the describe block is not conditionally added.
      // A more common pattern is to not include the describe block at all.
      expect(mockedIsEnabled('DEPRECATED_FEATURES_ENABLED')).toBe(false);
    });
  });
}

Output (when DEPRECATED_FEATURES_ENABLED is mocked to true):

  • Deprecated Feature Tests
    • should still support legacy authentication (PASSED)

Output (when DEPRECATED_FEATURES_ENABLED is mocked to false):

  • Deprecated Feature Tests
    • should be skipped as deprecated features are disabled (SKIPPED)
    • (Or, if the describe block is not included at all, this group simply won't appear in the test runner output)

Constraints

  • Your solution must be written in TypeScript.
  • You must use Jest for testing.
  • You must mock the featureFlags module using jest.mock.
  • The featureFlags module should export a function isEnabled(featureName: string): boolean.
  • You should demonstrate at least one instance of a test running conditionally and one instance of a test being skipped conditionally.
  • Considerations for performance are secondary to correctness and clarity for this challenge.

Notes

  • Think about how Jest discovers and runs tests. describe blocks are evaluated when the test file is imported.
  • You can use jest.fn() to create mock functions and .mockImplementation() to control their return values.
  • Jest provides ways to skip tests directly using .skip (e.g., test.skip(...)) or by returning pending() within a test. However, for this challenge, we are more interested in conditional execution based on external factors (like feature flags), rather than hardcoding skips.
  • Consider using beforeAll or beforeEach to set up your mock implementations for feature flags before tests run.
  • The featureFlags.ts file itself doesn't need to be created; you are only responsible for the test file (.test.ts).
Loading editor...
typescript