Hone logo
Hone
Problems

Test Scheduler with Jest

This challenge asks you to build a simple test scheduler using Jest. The scheduler should allow you to define a series of tests, each with a dependency on other tests. The scheduler will execute the tests in the correct order, ensuring that dependencies are met before their dependent tests are run. This is a useful exercise for understanding dependency management and test execution order.

Problem Description

You need to create a TestScheduler class in TypeScript that manages and executes a series of tests with dependencies. Each test is represented by an object with an id (string) and a dependencies array (array of strings representing the IDs of tests it depends on). The TestScheduler should ensure that all dependencies of a test are completed successfully before executing that test.

Key Requirements:

  • Test Definition: Tests are defined as objects with id and dependencies properties.
  • Dependency Resolution: The scheduler must correctly resolve dependencies and execute tests in the appropriate order.
  • Error Handling: If a dependency fails, the scheduler should mark the dependent test as failed and stop further execution of tests that depend on the failed test.
  • Test Execution: Each test should be a function that returns a Promise. The Promise should resolve if the test passes and reject if the test fails.
  • Status Tracking: The scheduler should maintain the status of each test (pending, running, passed, failed).

Expected Behavior:

  1. The scheduler should take an array of test definitions and an object mapping test IDs to test functions as input.
  2. It should execute the tests in an order that satisfies all dependencies.
  3. It should track the status of each test.
  4. If a test fails, all dependent tests should be marked as failed without execution.
  5. The scheduler should return a Promise that resolves when all tests have been executed (either successfully or with failures).

Edge Cases to Consider:

  • Circular Dependencies: The scheduler should detect and handle circular dependencies gracefully (e.g., by throwing an error or preventing execution). For this challenge, you can assume there are no circular dependencies in the input.
  • Missing Dependencies: The scheduler should handle cases where a test depends on a non-existent test ID. For this challenge, you can assume all dependencies exist.
  • Tests with No Dependencies: These tests should be executed as early as possible.
  • Tests with Multiple Dependencies: The scheduler should wait for all dependencies to complete before executing the test.

Examples

Example 1:

Input:
tests = [
  { id: 'test1', dependencies: [] },
  { id: 'test2', dependencies: ['test1'] },
  { id: 'test3', dependencies: ['test2'] }
]
testFunctions = {
  'test1': () => Promise.resolve(),
  'test2': () => Promise.resolve(),
  'test3': () => Promise.resolve()
}
Output:
{
  test1: 'passed',
  test2: 'passed',
  test3: 'passed'
}
Explanation: test1 has no dependencies, so it runs first. Then test2 runs (depending on test1), and finally test3 runs (depending on test2). All tests pass.

Example 2:

Input:
tests = [
  { id: 'test1', dependencies: [] },
  { id: 'test2', dependencies: ['test1'] },
  { id: 'test3', dependencies: ['test2'] }
]
testFunctions = {
  'test1': () => Promise.reject('Test 1 failed'),
  'test2': () => Promise.resolve(),
  'test3': () => Promise.resolve()
}
Output:
{
  test1: 'failed',
  test2: 'failed',
  test3: 'failed'
}
Explanation: test1 fails.  Because test2 depends on test1, test2 is marked as failed without execution.  Similarly, test3 is marked as failed.

Example 3: (Tests with different dependency structures)

Input:
tests = [
  { id: 'test1', dependencies: [] },
  { id: 'test2', dependencies: [] },
  { id: 'test3', dependencies: ['test1', 'test2'] }
]
testFunctions = {
  'test1': () => Promise.resolve(),
  'test2': () => Promise.resolve(),
  'test3': () => Promise.resolve()
}
Output:
{
  test1: 'passed',
  test2: 'passed',
  test3: 'passed'
}
Explanation: test1 and test2 have no dependencies, so they can run concurrently.  test3 runs after both test1 and test2 complete.

Constraints

  • The number of tests will be between 1 and 100.
  • Test IDs will be unique strings.
  • Dependencies will be valid test IDs.
  • Test functions will always return Promises.
  • The scheduler should complete within a reasonable time (e.g., less than 5 seconds).

Notes

  • Consider using a topological sort algorithm to determine the execution order of the tests.
  • You can use an object or map to store the status of each test.
  • Think about how to handle asynchronous operations (Promises) correctly.
  • Focus on clarity and maintainability of your code. Good error handling is important.
  • You are expected to write unit tests using Jest to verify the correctness of your TestScheduler class. Consider testing various scenarios, including successful executions, failures, and edge cases.
Loading editor...
typescript