src/lib/e2e-export/assertion-generator.ts

Total Symbols
2
Lines of Code
147
Avg Complexity
8.5
Avg Coverage
100.0%

Architecture violations

View all

  • [warning] max-cyclomatic-complexity: 'detectAssertions' has cyclomatic complexity 13 (max 10)

Symbols by Kind

function 2

All Symbols

Name Kind Visibility Status Lines Signature
detectAssertions function exported- 24-100 detectAssertions( actions: CapturedAction[], pageUrl: string, capturedResponses?: CapturedHttpResponse[], ): : E2EAssertion[]
detectNegativeAssertions function exported- 106-146 detectNegativeAssertions( actions: CapturedAction[], ): : E2EAssertion[]

Full Source

/**
 * Assertion Generator
 *
 * Detects potential assertions for E2E tests by analyzing the page DOM:
 *   - Submit buttons → expect URL change or success message
 *   - Required fields → expect validation errors when empty
 *   - Toast/notification containers → expect visible feedback
 *   - Form action attribute → expect redirect
 *
 * Runs in content-script context (DOM access required).
 */

import type {
  E2EAssertion,
  CapturedAction,
  CapturedHttpResponse,
} from "./e2e-export.types";

/**
 * Detects potential success assertions for a form submit.
 * Analyzes the page for common patterns of success feedback and uses
 * captured HTTP responses to generate response assertions.
 */
export function detectAssertions(
  actions: CapturedAction[],
  pageUrl: string,
  capturedResponses?: CapturedHttpResponse[],
): E2EAssertion[] {
  const assertions: E2EAssertion[] = [];

  // 1. If there's a submit action, expect URL might change
  const hasSubmit = actions.some(
    (a) => a.actionType === "click" || a.actionType === "submit",
  );

  if (hasSubmit) {
    assertions.push({
      type: "url-changed",
      expected: pageUrl,
      description: "URL should change after form submit",
    });
  }

  // 2. Look for common success message containers
  const successSelectors = [
    ".alert-success",
    ".toast-success",
    ".notification-success",
    "[role='alert']",
    ".success-message",
    ".flash-success",
    ".Toastify__toast--success",
    ".ant-message-success",
    ".MuiAlert-standardSuccess",
  ];

  for (const sel of successSelectors) {
    if (document.querySelector(sel)) {
      assertions.push({
        type: "element-visible",
        selector: sel,
        description: `Success element "${sel}" should be visible`,
      });
      break; // One success assertion is enough
    }
  }

  // 3. If form has action attribute with different URL, expect redirect
  const forms = document.querySelectorAll("form[action]");
  for (const form of forms) {
    const action = form.getAttribute("action");
    if (
      action &&
      action !== "#" &&
      action !== "" &&
      !action.startsWith("javascript:")
    ) {
      assertions.push({
        type: "redirect",
        expected: action,
        description: `Form should redirect to ${action}`,
      });
      break;
    }
  }

  // 4. HTTP response assertions from captured AJAX/XHR requests
  if (capturedResponses && capturedResponses.length > 0) {
    for (const response of capturedResponses) {
      assertions.push({
        type: "response-ok",
        selector: response.url,
        expected: String(response.status),
        description: `${response.method} ${response.url} should return ${response.status}`,
      });
    }
  }

  return assertions;
}

/**
 * Generates negative-test assertions for required fields.
 * When required fields are left empty, validation errors should appear.
 */
export function detectNegativeAssertions(
  actions: CapturedAction[],
): E2EAssertion[] {
  const assertions: E2EAssertion[] = [];

  const requiredActions = actions.filter((a) => a.required);
  if (requiredActions.length === 0) return assertions;

  // Expect validation error containers
  const errorSelectors = [
    ".field-error",
    ".error-message",
    ".invalid-feedback",
    ".form-error",
    "[role='alert']",
    ".ant-form-item-explain-error",
    ".MuiFormHelperText-root.Mui-error",
    ".text-danger",
    ".text-red-500",
  ];

  for (const sel of errorSelectors) {
    if (document.querySelector(sel)) {
      assertions.push({
        type: "field-error",
        selector: sel,
        description:
          "Validation error should be visible for empty required fields",
      });
      break;
    }
  }

  // Generic: at least one required field should trigger browser validation
  assertions.push({
    type: "visible-text",
    description: "Required field validation should prevent submission",
  });

  return assertions;
}