{
  "ruleId": "C065",
  "name": "One Behavior per Test (AAA Pattern)",
  "description": "Each test case should focus on testing a single behavior to improve clarity and maintainability",
  "category": "common",
  "severity": "warn",
  "languages": [
    "typescript",
    "javascript",
    "java",
    "csharp",
    "swift",
    "kotlin",
    "dart"
  ],
  "options": {
    "assertApis": {
      "javascript": [
        "expect\\(",
        "assert\\.",
        "should\\.",
        "chai\\.expect"
      ],
      "typescript": [
        "expect\\(",
        "assert\\.",
        "should\\.",
        "chai\\.expect"
      ],
      "java": [
        "assertThat\\(",
        "assertEquals\\(",
        "assertTrue\\(",
        "assertFalse\\(",
        "assertNull\\(",
        "assertNotNull\\("
      ],
      "csharp": [
        "Assert\\.",
        "Xunit\\.Assert",
        "NUnit\\.Framework\\.Assert"
      ],
      "swift": [
        "XCTAssert",
        "XCTAssertEqual",
        "XCTAssertTrue",
        "XCTAssertFalse"
      ],
      "kotlin": [
        "assertThat\\(",
        "assertEquals\\(",
        "assertTrue\\(",
        "assertFalse\\("
      ]
    },
    "actHeuristics": {
      "common": [
        "sut\\.",
        "\\.create\\(",
        "\\.update\\(",
        "\\.delete\\(",
        "\\.save\\(",
        "\\.execute\\(",
        "\\.handle\\(",
        "\\.run\\(",
        "\\.call\\(",
        "\\.process\\(",
        "service\\.",
        "repository\\.",
        "await\\s+\\w+\\."
      ],
      "javascript": [
        "\\.mockReturnValue\\(",
        "\\.mockResolvedValue\\(",
        "render\\(",
        "fireEvent\\.(click|submit|keyPress|keyDown|keyUp)",
        "userService\\.",
        "api\\.",
        "fetch\\(",
        "user\\.click\\(",
        "user\\.type\\(",
        "user\\.clear\\("
      ],
      "typescript": [
        "\\.mockReturnValue\\(",
        "\\.mockResolvedValue\\(",
        "render\\(",
        "fireEvent\\.(click|submit|keyPress|keyDown|keyUp)",
        "userService\\.",
        "api\\.",
        "fetch\\(",
        "user\\.click\\(",
        "user\\.type\\(",
        "user\\.clear\\("
      ],
      "java": [
        "\\.when\\(",
        "\\.thenReturn\\(",
        "\\.doReturn\\(",
        "\\.verify\\("
      ],
      "csharp": [
        "\\.Setup\\(",
        "\\.Returns\\(",
        "\\.Verify\\("
      ],
      "swift": [
        "given\\(",
        "when\\(",
        "then\\("
      ],
      "kotlin": [
        "every\\s*\\{",
        "verify\\s*\\{"
      ]
    },
    "controlFlow": [
      "\\bif\\s*\\(",
      "\\bswitch\\s*\\(",
      "\\bfor\\s*\\(",
      "\\bwhile\\s*\\(",
      "\\btry\\s*\\{"
    ],
    "testPatterns": {
      "javascript": [
        "\\bit\\s*\\(",
        "\\btest\\s*\\(",
        "\\bdescribe\\s*\\("
      ],
      "typescript": [
        "\\bit\\s*\\(",
        "\\btest\\s*\\(",
        "\\bdescribe\\s*\\("
      ],
      "java": [
        "@Test",
        "@ParameterizedTest"
      ],
      "csharp": [
        "\\[Test\\]",
        "\\[Fact\\]",
        "\\[Theory\\]"
      ],
      "swift": [
        "func\\s+test",
        "XCTestCase"
      ],
      "kotlin": [
        "@Test",
        "fun\\s+test"
      ]
    },
    "parameterizedHints": [
      "test\\.each",
      "describe\\.each",
      "@ParameterizedTest",
      "where\\s*:",
      "\\[TestCase"
    ],
    "thresholds": {
      "maxActsPerTest": 3,
      "maxUnrelatedExpects": 2,
      "maxControlFlowStatements": 0,
      "maxTestMethodsPerFunction": 1
    },
    "flags": {
      "flagControlFlowInTest": true,
      "treatSnapshotAsSingleAssert": true,
      "allowMultipleAssertsForSameObject": true,
      "allowSetupAssertions": true,
      "allowMultipleUIActions": true
    },
    "whitelist": {
      "setupMethods": [
        "beforeEach",
        "setUp",
        "before",
        "Given"
      ],
      "teardownMethods": [
        "afterEach",
        "tearDown",
        "after"
      ],
      "helperMethods": [
        "helper",
        "util",
        "mock",
        "stub",
        "spy"
      ]
    },
    "allowlist": {
      "paths": [
        "test/",
        "tests/",
        "__tests__/",
        "spec/",
        "specs/",
        "*.test.*",
        "*.spec.*"
      ],
      "filePatterns": [
        "\\.test\\.",
        "\\.spec\\.",
        "Test\\.java$",
        "Tests\\.cs$",
        "Test\\.swift$",
        "Test\\.kt$"
      ],
      "formInteractionSequences": [
        "fireEvent\\.change.*fireEvent\\.blur",
        "fireEvent\\.change.*fireEvent\\.focus",
        "user\\.type.*user\\.tab",
        "user\\.type.*user\\.clear",
        "render.*fireEvent\\.change.*fireEvent\\.blur"
      ],
      "uiInteractionWorkflows": [
        "fireEvent\\.click.*expect\\(",
        "fireEvent\\.click.*fireEvent\\.click",
        "render.*fireEvent\\.click.*expect\\(",
        "getByRole.*fireEvent\\.click.*expect\\(",
        "queryByText.*fireEvent\\.click",
        "user\\.click.*expect\\(",
        "user\\.click.*user\\.click"
      ],
      "setupActionPatterns": [
        "render\\(",
        "fireEvent\\.(change|blur|focus|mouseEnter|mouseLeave)",
        "user\\.(hover|focus|tab|clear)",
        "\\.mockReturnValue\\(",
        "\\.mockResolvedValue\\("
      ],
      "uiSetupPatterns": [
        "getByRole\\(",
        "queryByText\\(",
        "queryAllByText\\(",
        "getByText\\(",
        "findByRole\\(",
        "act\\(.*render"
      ]
    },
    "overrideExclude": {
      "enabled": true,
      "reason": "C065 needs to analyze test files that are typically excluded by project configs",
      "removePatterns": [
        "**/*.test.*",
        "**/*.spec.*",
        "src/**/*.test.{ts,tsx}",
        "src/**/*.spec.{ts,tsx}"
      ]
    }
  }
}