Hone logo
Hone
Problems

Jest Condition Evaluator

This challenge involves implementing a system to evaluate complex conditions within your Jest tests. This is crucial for creating highly specific and dynamic test assertions, allowing you to verify that certain states or behaviors are met under precise circumstances, making your tests more robust and expressive.

Problem Description

You need to create a function, evaluateConditions, that takes an object representing the current state and an array of conditions to evaluate against that state. Each condition is an object with a field (the key in the state object), an operator (a string representing a comparison), and a value (the value to compare against).

The function should return true if all conditions are met, and false otherwise.

Key Requirements:

  1. Support for multiple operators: Implement support for at least the following operators:

    • == (loose equality)
    • === (strict equality)
    • != (loose inequality)
    • !== (strict inequality)
    • > (greater than)
    • < (less than)
    • >= (greater than or equal to)
    • <= (less than or equal to)
    • includes (checks if a string or array contains a value)
    • startsWith (checks if a string starts with a given prefix)
    • endsWith (checks if a string ends with a given suffix)
  2. Handling missing fields: If a field specified in a condition does not exist in the state object, the condition should be considered unmet, returning false for that specific condition.

  3. All conditions must pass: The function should return true only if all provided conditions evaluate to true. If even one condition fails, the function should return false.

  4. Type Safety: The solution should be implemented in TypeScript, ensuring type safety for state and conditions.

Expected Behavior:

  • If the state object is empty and conditions is empty, return true.
  • If conditions is empty, return true regardless of the state.
  • If any condition fails due to a missing field or an unmet comparison, the function returns false.
  • If all conditions are met, the function returns true.

Edge Cases to Consider:

  • Comparing different data types (e.g., number with string).
  • null and undefined values in the state.
  • Empty strings, arrays, or objects in the state.
  • Conditions involving null or undefined as the value.

Examples

Example 1:

const state = {
  user: {
    name: "Alice",
    age: 30,
    roles: ["admin", "editor"]
  },
  isActive: true
};

const conditions = [
  { field: "user.name", operator: "===", value: "Alice" },
  { field: "user.age", operator: ">", value: 25 },
  { field: "isActive", operator: "===", value: true }
];

// Expected Output: true
// Explanation: All conditions match the state. "Alice" === "Alice", 30 > 25, and true === true.

Example 2:

const state = {
  product: {
    name: "Gadget",
    price: 99.99
  },
  stock: 5
};

const conditions = [
  { field: "product.name", operator: "startsWith", value: "Gad" },
  { field: "product.price", operator: "<", value: 100 },
  { field: "stock", operator: "===", value: 10 }
];

// Expected Output: false
// Explanation: The condition `stock === 10` fails because the stock is 5.

Example 3:

const state = {
  orderId: "ORD12345",
  items: ["book", "pen"]
};

const conditions = [
  { field: "orderId", operator: "includes", value: "123" },
  { field: "items", operator: "includes", value: "pencil" }
];

// Expected Output: false
// Explanation: The condition `items includes "pencil"` fails because the items array does not contain "pencil".

Example 4 (Missing Field):

const state = {
  userData: {
    email: "test@example.com"
  }
};

const conditions = [
  { field: "userData.email", operator: "===", value: "test@example.com" },
  { field: "userData.phone", operator: "!==", value: null } // 'phone' field is missing
];

// Expected Output: false
// Explanation: The condition `userData.phone !== null` fails because the 'phone' field does not exist in the state.

Constraints

  • The state object can be arbitrarily nested.
  • The conditions array can contain up to 100 conditions.
  • The field path in conditions will use dot notation for nesting (e.g., user.address.city).
  • The value in conditions can be of any primitive type or an array.
  • The operator string will always be one of the supported operators.

Notes

  • For nested fields like user.age, you'll need a way to safely access them. Consider using a helper function for deep property access.
  • The includes operator should work for both strings and arrays.
  • Pay close attention to type coercion when implementing loose equality (==) and inequality (!=).
  • The startsWith and endsWith operators should only be applied to string values. If the field is not a string, these conditions should fail.
Loading editor...
typescript