TDD Guide Test-driven development skill for generating tests, analyzing coverage, and guiding red-green-refactor workflows across Jest, Pytest, JUnit, and Vitest. --- Workflows Generate Tests from Code 1. Provide source code (TypeScript, JavaScript, Python, Java) 2. Specify target framework (Jest, Pytest, JUnit, Vitest) 3. Run with requirements 4. Review generated test stubs 5. Validation: Tests compile and cover happy path, error cases, edge cases Analyze Coverage Gaps 1. Generate coverage report from test runner ( ) 2. Run on LCOV/JSON/XML report 3. Review prioritized gaps (P0/P1/P2) 4. Gen…

, # Python comments\n r':\\s*

TDD Guide Test-driven development skill for generating tests, analyzing coverage, and guiding red-green-refactor workflows across Jest, Pytest, JUnit, and Vitest. --- Workflows Generate Tests from Code 1. Provide source code (TypeScript, JavaScript, Python, Java) 2. Specify target framework (Jest, Pytest, JUnit, Vitest) 3. Run with requirements 4. Review generated test stubs 5. Validation: Tests compile and cover happy path, error cases, edge cases Analyze Coverage Gaps 1. Generate coverage report from test runner ( ) 2. Run on LCOV/JSON/XML report 3. Review prioritized gaps (P0/P1/P2) 4. Gen…

, # Python colons\n ]\n\n matches = sum(1 for pattern in py_patterns if re.search(pattern, code, re.MULTILINE))\n return matches >= 3\n\n def _is_java(self, code: str) -> bool:\n \"\"\"Check if code is Java.\"\"\"\n java_patterns = [\n r'\\bpublic\\s+class', # public class\n r'\\bprivate\\s+\\w+', # private members\n r'\\bpublic\\s+\\w+\\s+\\w+\\s*\\(', # public methods\n r'import\\s+java\\.', # Java imports\n r'\\bvoid\\s+\\w+\\s*\\(', # void methods\n ]\n\n matches = sum(1 for pattern in java_patterns if re.search(pattern, code))\n return matches >= 2\n\n def detect_test_framework(self, code: str) -> str:\n \"\"\"\n Detect testing framework from test code.\n\n Args:\n code: Test code\n\n Returns:\n Detected framework (jest, vitest, pytest, junit, mocha, unknown)\n \"\"\"\n # Jest patterns\n if 'from \\'@jest/globals\\'' in code or '@jest/' in code:\n self.detected_framework = \"jest\"\n return \"jest\"\n\n # Vitest patterns\n if 'from \\'vitest\\'' in code or 'import { vi }' in code:\n self.detected_framework = \"vitest\"\n return \"vitest\"\n\n # Pytest patterns\n if 'import pytest' in code or 'def test_' in code:\n self.detected_framework = \"pytest\"\n return \"pytest\"\n\n # Unittest patterns\n if 'import unittest' in code and 'unittest.TestCase' in code:\n self.detected_framework = \"unittest\"\n return \"unittest\"\n\n # JUnit patterns\n if '@Test' in code and 'import org.junit' in code:\n self.detected_framework = \"junit\"\n return \"junit\"\n\n # Mocha patterns\n if 'describe(' in code and 'it(' in code:\n self.detected_framework = \"mocha\"\n return \"mocha\"\n\n self.detected_framework = \"unknown\"\n return \"unknown\"\n\n def detect_coverage_format(self, content: str) -> str:\n \"\"\"\n Detect coverage report format.\n\n Args:\n content: Coverage report content\n\n Returns:\n Format type (lcov, json, xml, unknown)\n \"\"\"\n content_stripped = content.strip()\n\n # LCOV format\n if content_stripped.startswith('TN:') or 'SF:' in content_stripped[:200]:\n return \"lcov\"\n\n # JSON format\n if content_stripped.startswith('{'):\n try:\n import json\n json.loads(content_stripped)\n return \"json\"\n except:\n pass\n\n # XML format\n if content_stripped.startswith('\u003c?xml') or content_stripped.startswith('\u003ccoverage'):\n return \"xml\"\n\n return \"unknown\"\n\n def detect_input_format(self, input_data: str) -> Dict[str, Any]:\n \"\"\"\n Detect input format and extract relevant information.\n\n Args:\n input_data: Input data (could be code, coverage report, etc.)\n\n Returns:\n Detection results with format, language, framework\n \"\"\"\n result = {\n 'format': 'unknown',\n 'language': 'unknown',\n 'framework': 'unknown',\n 'content_type': 'unknown'\n }\n\n # Detect if it's a coverage report\n coverage_format = self.detect_coverage_format(input_data)\n if coverage_format != \"unknown\":\n result['format'] = coverage_format\n result['content_type'] = 'coverage_report'\n return result\n\n # Detect if it's source code\n language = self.detect_language(input_data)\n if language != \"unknown\":\n result['language'] = language\n result['content_type'] = 'source_code'\n\n # Detect if it's test code\n framework = self.detect_test_framework(input_data)\n if framework != \"unknown\":\n result['framework'] = framework\n result['content_type'] = 'test_code'\n\n return result\n\n def extract_file_info(self, file_path: str) -> Dict[str, str]:\n \"\"\"\n Extract information from file path.\n\n Args:\n file_path: Path to file\n\n Returns:\n File information (extension, likely language, likely purpose)\n \"\"\"\n import os\n\n file_name = os.path.basename(file_path)\n file_ext = os.path.splitext(file_name)[1].lower()\n\n # Extension to language mapping\n ext_to_lang = {\n '.ts': 'typescript',\n '.tsx': 'typescript',\n '.js': 'javascript',\n '.jsx': 'javascript',\n '.py': 'python',\n '.java': 'java',\n '.kt': 'kotlin',\n '.go': 'go',\n '.rs': 'rust',\n }\n\n # Test file patterns\n is_test = any(pattern in file_name.lower()\n for pattern in ['test', 'spec', '_test.', '.test.'])\n\n return {\n 'file_name': file_name,\n 'extension': file_ext,\n 'language': ext_to_lang.get(file_ext, 'unknown'),\n 'is_test': is_test,\n 'purpose': 'test' if is_test else 'source'\n }\n\n def suggest_test_file_name(self, source_file: str, framework: str) -> str:\n \"\"\"\n Suggest test file name for source file.\n\n Args:\n source_file: Source file path\n framework: Testing framework\n\n Returns:\n Suggested test file name\n \"\"\"\n import os\n\n base_name = os.path.splitext(os.path.basename(source_file))[0]\n ext = os.path.splitext(source_file)[1]\n\n if framework in ['jest', 'vitest', 'mocha']:\n return f\"{base_name}.test{ext}\"\n elif framework in ['pytest', 'unittest']:\n return f\"test_{base_name}.py\"\n elif framework in ['junit', 'testng']:\n return f\"{base_name.capitalize()}Test.java\"\n else:\n return f\"{base_name}_test{ext}\"\n\n def identify_test_patterns(self, code: str) -> List[str]:\n \"\"\"\n Identify test patterns in code.\n\n Args:\n code: Test code\n\n Returns:\n List of identified patterns (AAA, Given-When-Then, etc.)\n \"\"\"\n patterns = []\n\n # Arrange-Act-Assert pattern\n if any(comment in code.lower() for comment in ['// arrange', '# arrange', '// act', '# act']):\n patterns.append('AAA (Arrange-Act-Assert)')\n\n # Given-When-Then pattern\n if any(comment in code.lower() for comment in ['given', 'when', 'then']):\n patterns.append('Given-When-Then')\n\n # Setup/Teardown pattern\n if any(keyword in code for keyword in ['beforeEach', 'afterEach', 'setUp', 'tearDown']):\n patterns.append('Setup-Teardown')\n\n # Mocking pattern\n if any(keyword in code.lower() for keyword in ['mock', 'stub', 'spy']):\n patterns.append('Mocking/Stubbing')\n\n # Parameterized tests\n if any(keyword in code for keyword in ['@pytest.mark.parametrize', 'test.each', '@ParameterizedTest']):\n patterns.append('Parameterized Tests')\n\n return patterns if patterns else ['No specific pattern detected']\n\n def analyze_project_structure(self, file_paths: List[str]) -> Dict[str, Any]:\n \"\"\"\n Analyze project structure from file paths.\n\n Args:\n file_paths: List of file paths in project\n\n Returns:\n Project structure analysis\n \"\"\"\n languages = {}\n test_frameworks = []\n source_files = []\n test_files = []\n\n for file_path in file_paths:\n file_info = self.extract_file_info(file_path)\n\n # Count languages\n lang = file_info['language']\n if lang != 'unknown':\n languages[lang] = languages.get(lang, 0) + 1\n\n # Categorize files\n if file_info['is_test']:\n test_files.append(file_path)\n else:\n source_files.append(file_path)\n\n # Determine primary language\n primary_language = max(languages.items(), key=lambda x: x[1])[0] if languages else 'unknown'\n\n return {\n 'primary_language': primary_language,\n 'languages': languages,\n 'source_file_count': len(source_files),\n 'test_file_count': len(test_files),\n 'test_ratio': len(test_files) / len(source_files) if source_files else 0,\n 'suggested_framework': self._suggest_framework(primary_language)\n }\n\n def _suggest_framework(self, language: str) -> str:\n \"\"\"Suggest testing framework based on language.\"\"\"\n framework_map = {\n 'typescript': 'jest or vitest',\n 'javascript': 'jest or mocha',\n 'python': 'pytest',\n 'java': 'junit',\n 'kotlin': 'junit',\n 'go': 'testing package',\n 'rust': 'cargo test',\n }\n\n return framework_map.get(language, 'unknown')\n\n def detect_environment(self) -> Dict[str, str]:\n \"\"\"\n Detect execution environment (CLI, Desktop, API).\n\n Returns:\n Environment information\n \"\"\"\n # This is a placeholder - actual detection would use environment variables\n # or other runtime checks\n return {\n 'environment': 'cli', # Could be 'desktop', 'api'\n 'output_preference': 'terminal-friendly' # Could be 'rich-markdown', 'json'\n }\n","content_type":"text/x-python; charset=utf-8","language":"python","size":12207,"content_sha256":"a12f1d016967fc0a8a3b3f68b28a172494c33c9252d72d662c7a37f765a6692d"},{"filename":"scripts/framework_adapter.py","content":"\"\"\"\nFramework adapter module.\n\nProvides multi-framework support with adapters for Jest, Pytest, JUnit, Vitest, and more.\nHandles framework-specific patterns, imports, and test structure.\n\"\"\"\n\nfrom typing import Dict, List, Any, Optional\nfrom enum import Enum\n\n\nclass Framework(Enum):\n \"\"\"Supported testing frameworks.\"\"\"\n JEST = \"jest\"\n VITEST = \"vitest\"\n PYTEST = \"pytest\"\n UNITTEST = \"unittest\"\n JUNIT = \"junit\"\n TESTNG = \"testng\"\n MOCHA = \"mocha\"\n JASMINE = \"jasmine\"\n\n\nclass Language(Enum):\n \"\"\"Supported programming languages.\"\"\"\n TYPESCRIPT = \"typescript\"\n JAVASCRIPT = \"javascript\"\n PYTHON = \"python\"\n JAVA = \"java\"\n\n\nclass FrameworkAdapter:\n \"\"\"Adapter for multiple testing frameworks.\"\"\"\n\n def __init__(self, framework: Framework, language: Language):\n \"\"\"\n Initialize framework adapter.\n\n Args:\n framework: Testing framework\n language: Programming language\n \"\"\"\n self.framework = framework\n self.language = language\n\n def generate_imports(self) -> str:\n \"\"\"Generate framework-specific imports.\"\"\"\n if self.framework == Framework.JEST:\n return self._jest_imports()\n elif self.framework == Framework.VITEST:\n return self._vitest_imports()\n elif self.framework == Framework.PYTEST:\n return self._pytest_imports()\n elif self.framework == Framework.UNITTEST:\n return self._unittest_imports()\n elif self.framework == Framework.JUNIT:\n return self._junit_imports()\n elif self.framework == Framework.TESTNG:\n return self._testng_imports()\n elif self.framework == Framework.MOCHA:\n return self._mocha_imports()\n else:\n return \"\"\n\n def _jest_imports(self) -> str:\n \"\"\"Generate Jest imports.\"\"\"\n return \"\"\"import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';\"\"\"\n\n def _vitest_imports(self) -> str:\n \"\"\"Generate Vitest imports.\"\"\"\n return \"\"\"import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';\"\"\"\n\n def _pytest_imports(self) -> str:\n \"\"\"Generate Pytest imports.\"\"\"\n return \"\"\"import pytest\"\"\"\n\n def _unittest_imports(self) -> str:\n \"\"\"Generate unittest imports.\"\"\"\n return \"\"\"import unittest\"\"\"\n\n def _junit_imports(self) -> str:\n \"\"\"Generate JUnit imports.\"\"\"\n return \"\"\"import org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.AfterEach;\nimport static org.junit.jupiter.api.Assertions.*;\"\"\"\n\n def _testng_imports(self) -> str:\n \"\"\"Generate TestNG imports.\"\"\"\n return \"\"\"import org.testng.annotations.Test;\nimport org.testng.annotations.BeforeMethod;\nimport org.testng.annotations.AfterMethod;\nimport static org.testng.Assert.*;\"\"\"\n\n def _mocha_imports(self) -> str:\n \"\"\"Generate Mocha imports.\"\"\"\n return \"\"\"import { describe, it, beforeEach, afterEach } from 'mocha';\nimport { expect } from 'chai';\"\"\"\n\n def generate_test_suite_wrapper(\n self,\n suite_name: str,\n test_content: str\n ) -> str:\n \"\"\"\n Wrap test content in framework-specific suite structure.\n\n Args:\n suite_name: Name of test suite\n test_content: Test functions/methods\n\n Returns:\n Complete test suite code\n \"\"\"\n if self.framework in [Framework.JEST, Framework.VITEST, Framework.MOCHA]:\n return f\"\"\"describe('{suite_name}', () => {{\n{self._indent(test_content, 2)}\n}});\"\"\"\n\n elif self.framework == Framework.PYTEST:\n return f\"\"\"class Test{self._to_class_name(suite_name)}:\n \\\"\\\"\\\"Test suite for {suite_name}.\\\"\\\"\\\"\n\n{self._indent(test_content, 4)}\"\"\"\n\n elif self.framework == Framework.UNITTEST:\n return f\"\"\"class Test{self._to_class_name(suite_name)}(unittest.TestCase):\n \\\"\\\"\\\"Test suite for {suite_name}.\\\"\\\"\\\"\n\n{self._indent(test_content, 4)}\"\"\"\n\n elif self.framework in [Framework.JUNIT, Framework.TESTNG]:\n return f\"\"\"public class {self._to_class_name(suite_name)}Test {{\n\n{self._indent(test_content, 4)}\n}}\"\"\"\n\n return test_content\n\n def generate_test_function(\n self,\n test_name: str,\n test_body: str,\n description: str = \"\"\n ) -> str:\n \"\"\"\n Generate framework-specific test function.\n\n Args:\n test_name: Name of test\n test_body: Test body code\n description: Test description\n\n Returns:\n Complete test function\n \"\"\"\n if self.framework == Framework.JEST:\n return self._jest_test(test_name, test_body, description)\n elif self.framework == Framework.VITEST:\n return self._vitest_test(test_name, test_body, description)\n elif self.framework == Framework.PYTEST:\n return self._pytest_test(test_name, test_body, description)\n elif self.framework == Framework.UNITTEST:\n return self._unittest_test(test_name, test_body, description)\n elif self.framework == Framework.JUNIT:\n return self._junit_test(test_name, test_body, description)\n elif self.framework == Framework.TESTNG:\n return self._testng_test(test_name, test_body, description)\n elif self.framework == Framework.MOCHA:\n return self._mocha_test(test_name, test_body, description)\n else:\n return \"\"\n\n def _jest_test(self, test_name: str, test_body: str, description: str) -> str:\n \"\"\"Generate Jest test.\"\"\"\n return f\"\"\"it('{test_name}', () => {{\n // {description}\n{self._indent(test_body, 2)}\n}});\"\"\"\n\n def _vitest_test(self, test_name: str, test_body: str, description: str) -> str:\n \"\"\"Generate Vitest test.\"\"\"\n return f\"\"\"it('{test_name}', () => {{\n // {description}\n{self._indent(test_body, 2)}\n}});\"\"\"\n\n def _pytest_test(self, test_name: str, test_body: str, description: str) -> str:\n \"\"\"Generate Pytest test.\"\"\"\n func_name = test_name.replace(' ', '_').replace('-', '_')\n return f\"\"\"def test_{func_name}(self):\n \\\"\\\"\\\"\n {description or test_name}\n \\\"\\\"\\\"\n{self._indent(test_body, 4)}\"\"\"\n\n def _unittest_test(self, test_name: str, test_body: str, description: str) -> str:\n \"\"\"Generate unittest test.\"\"\"\n func_name = self._to_camel_case(test_name)\n return f\"\"\"def test_{func_name}(self):\n \\\"\\\"\\\"\n {description or test_name}\n \\\"\\\"\\\"\n{self._indent(test_body, 4)}\"\"\"\n\n def _junit_test(self, test_name: str, test_body: str, description: str) -> str:\n \"\"\"Generate JUnit test.\"\"\"\n method_name = self._to_camel_case(test_name)\n return f\"\"\"@Test\npublic void test{method_name}() {{\n // {description}\n{self._indent(test_body, 4)}\n}}\"\"\"\n\n def _testng_test(self, test_name: str, test_body: str, description: str) -> str:\n \"\"\"Generate TestNG test.\"\"\"\n method_name = self._to_camel_case(test_name)\n return f\"\"\"@Test\npublic void test{method_name}() {{\n // {description}\n{self._indent(test_body, 4)}\n}}\"\"\"\n\n def _mocha_test(self, test_name: str, test_body: str, description: str) -> str:\n \"\"\"Generate Mocha test.\"\"\"\n return f\"\"\"it('{test_name}', () => {{\n // {description}\n{self._indent(test_body, 2)}\n}});\"\"\"\n\n def generate_assertion(\n self,\n actual: str,\n expected: str,\n assertion_type: str = \"equals\"\n ) -> str:\n \"\"\"\n Generate framework-specific assertion.\n\n Args:\n actual: Actual value expression\n expected: Expected value expression\n assertion_type: Type of assertion (equals, not_equals, true, false, throws)\n\n Returns:\n Assertion statement\n \"\"\"\n if self.framework in [Framework.JEST, Framework.VITEST]:\n return self._jest_assertion(actual, expected, assertion_type)\n elif self.framework in [Framework.PYTEST, Framework.UNITTEST]:\n return self._python_assertion(actual, expected, assertion_type)\n elif self.framework in [Framework.JUNIT, Framework.TESTNG]:\n return self._java_assertion(actual, expected, assertion_type)\n elif self.framework == Framework.MOCHA:\n return self._chai_assertion(actual, expected, assertion_type)\n else:\n return f\"assert {actual} == {expected}\"\n\n def _jest_assertion(self, actual: str, expected: str, assertion_type: str) -> str:\n \"\"\"Generate Jest assertion.\"\"\"\n if assertion_type == \"equals\":\n return f\"expect({actual}).toBe({expected});\"\n elif assertion_type == \"not_equals\":\n return f\"expect({actual}).not.toBe({expected});\"\n elif assertion_type == \"true\":\n return f\"expect({actual}).toBe(true);\"\n elif assertion_type == \"false\":\n return f\"expect({actual}).toBe(false);\"\n elif assertion_type == \"throws\":\n return f\"expect(() => {actual}).toThrow();\"\n else:\n return f\"expect({actual}).toBe({expected});\"\n\n def _python_assertion(self, actual: str, expected: str, assertion_type: str) -> str:\n \"\"\"Generate Python assertion.\"\"\"\n if assertion_type == \"equals\":\n return f\"assert {actual} == {expected}\"\n elif assertion_type == \"not_equals\":\n return f\"assert {actual} != {expected}\"\n elif assertion_type == \"true\":\n return f\"assert {actual} is True\"\n elif assertion_type == \"false\":\n return f\"assert {actual} is False\"\n elif assertion_type == \"throws\":\n return f\"with pytest.raises(Exception):\\n {actual}\"\n else:\n return f\"assert {actual} == {expected}\"\n\n def _java_assertion(self, actual: str, expected: str, assertion_type: str) -> str:\n \"\"\"Generate Java assertion.\"\"\"\n if assertion_type == \"equals\":\n return f\"assertEquals({expected}, {actual});\"\n elif assertion_type == \"not_equals\":\n return f\"assertNotEquals({expected}, {actual});\"\n elif assertion_type == \"true\":\n return f\"assertTrue({actual});\"\n elif assertion_type == \"false\":\n return f\"assertFalse({actual});\"\n elif assertion_type == \"throws\":\n return f\"assertThrows(Exception.class, () -> {actual});\"\n else:\n return f\"assertEquals({expected}, {actual});\"\n\n def _chai_assertion(self, actual: str, expected: str, assertion_type: str) -> str:\n \"\"\"Generate Chai assertion.\"\"\"\n if assertion_type == \"equals\":\n return f\"expect({actual}).to.equal({expected});\"\n elif assertion_type == \"not_equals\":\n return f\"expect({actual}).to.not.equal({expected});\"\n elif assertion_type == \"true\":\n return f\"expect({actual}).to.be.true;\"\n elif assertion_type == \"false\":\n return f\"expect({actual}).to.be.false;\"\n elif assertion_type == \"throws\":\n return f\"expect(() => {actual}).to.throw();\"\n else:\n return f\"expect({actual}).to.equal({expected});\"\n\n def generate_setup_teardown(\n self,\n setup_code: str = \"\",\n teardown_code: str = \"\"\n ) -> str:\n \"\"\"Generate setup and teardown hooks.\"\"\"\n result = []\n\n if self.framework in [Framework.JEST, Framework.VITEST, Framework.MOCHA]:\n if setup_code:\n result.append(f\"\"\"beforeEach(() => {{\n{self._indent(setup_code, 2)}\n}});\"\"\")\n if teardown_code:\n result.append(f\"\"\"afterEach(() => {{\n{self._indent(teardown_code, 2)}\n}});\"\"\")\n\n elif self.framework == Framework.PYTEST:\n if setup_code:\n result.append(f\"\"\"@pytest.fixture(autouse=True)\ndef setup_method(self):\n{self._indent(setup_code, 4)}\n yield\"\"\")\n if teardown_code:\n result.append(f\"\"\"\n{self._indent(teardown_code, 4)}\"\"\")\n\n elif self.framework == Framework.UNITTEST:\n if setup_code:\n result.append(f\"\"\"def setUp(self):\n{self._indent(setup_code, 4)}\"\"\")\n if teardown_code:\n result.append(f\"\"\"def tearDown(self):\n{self._indent(teardown_code, 4)}\"\"\")\n\n elif self.framework in [Framework.JUNIT, Framework.TESTNG]:\n annotation = \"@BeforeEach\" if self.framework == Framework.JUNIT else \"@BeforeMethod\"\n if setup_code:\n result.append(f\"\"\"{annotation}\npublic void setUp() {{\n{self._indent(setup_code, 4)}\n}}\"\"\")\n\n annotation = \"@AfterEach\" if self.framework == Framework.JUNIT else \"@AfterMethod\"\n if teardown_code:\n result.append(f\"\"\"{annotation}\npublic void tearDown() {{\n{self._indent(teardown_code, 4)}\n}}\"\"\")\n\n return \"\\n\\n\".join(result)\n\n def _indent(self, text: str, spaces: int) -> str:\n \"\"\"Indent text by number of spaces.\"\"\"\n indent = \" \" * spaces\n lines = text.split('\\n')\n return '\\n'.join(indent + line if line.strip() else line for line in lines)\n\n def _to_camel_case(self, text: str) -> str:\n \"\"\"Convert text to camelCase.\"\"\"\n words = text.replace('-', ' ').replace('_', ' ').split()\n if not words:\n return text\n return words[0].lower() + ''.join(word.capitalize() for word in words[1:])\n\n def _to_class_name(self, text: str) -> str:\n \"\"\"Convert text to ClassName.\"\"\"\n words = text.replace('-', ' ').replace('_', ' ').split()\n return ''.join(word.capitalize() for word in words)\n\n def detect_framework(self, code: str) -> Optional[Framework]:\n \"\"\"\n Auto-detect testing framework from code.\n\n Args:\n code: Test code\n\n Returns:\n Detected framework or None\n \"\"\"\n # Jest patterns\n if 'from \\'@jest/globals\\'' in code or '@jest/' in code:\n return Framework.JEST\n\n # Vitest patterns\n if 'from \\'vitest\\'' in code or 'import { vi }' in code:\n return Framework.VITEST\n\n # Pytest patterns\n if 'import pytest' in code or 'def test_' in code and 'pytest.fixture' in code:\n return Framework.PYTEST\n\n # Unittest patterns\n if 'import unittest' in code and 'unittest.TestCase' in code:\n return Framework.UNITTEST\n\n # JUnit patterns\n if '@Test' in code and 'import org.junit' in code:\n return Framework.JUNIT\n\n # TestNG patterns\n if '@Test' in code and 'import org.testng' in code:\n return Framework.TESTNG\n\n # Mocha patterns\n if 'from \\'mocha\\'' in code or ('describe(' in code and 'from \\'chai\\'' in code):\n return Framework.MOCHA\n\n return None\n","content_type":"text/x-python; charset=utf-8","language":"python","size":14834,"content_sha256":"03a189d01310f04cb025bb9498ecd6bdc7d16eef119e992ff513774939299c58"},{"filename":"scripts/metrics_calculator.py","content":"\"\"\"\nMetrics calculation module.\n\nCalculate comprehensive test and code quality metrics including complexity,\ntest quality scoring, and test execution analysis.\n\"\"\"\n\nfrom typing import Dict, List, Any, Optional\nimport re\n\n\nclass MetricsCalculator:\n \"\"\"Calculate comprehensive test and code quality metrics.\"\"\"\n\n def __init__(self):\n \"\"\"Initialize metrics calculator.\"\"\"\n self.metrics = {}\n\n def calculate_all_metrics(\n self,\n source_code: str,\n test_code: str,\n coverage_data: Optional[Dict[str, Any]] = None,\n execution_data: Optional[Dict[str, Any]] = None\n ) -> Dict[str, Any]:\n \"\"\"\n Calculate all available metrics.\n\n Args:\n source_code: Source code to analyze\n test_code: Test code to analyze\n coverage_data: Coverage report data\n execution_data: Test execution results\n\n Returns:\n Complete metrics dictionary\n \"\"\"\n metrics = {\n 'complexity': self.calculate_complexity(source_code),\n 'test_quality': self.calculate_test_quality(test_code),\n 'coverage': coverage_data or {},\n 'execution': execution_data or {}\n }\n\n self.metrics = metrics\n return metrics\n\n def calculate_complexity(self, code: str) -> Dict[str, Any]:\n \"\"\"\n Calculate code complexity metrics.\n\n Args:\n code: Source code to analyze\n\n Returns:\n Complexity metrics (cyclomatic, cognitive, testability score)\n \"\"\"\n cyclomatic = self._cyclomatic_complexity(code)\n cognitive = self._cognitive_complexity(code)\n testability = self._testability_score(code, cyclomatic)\n\n return {\n 'cyclomatic_complexity': cyclomatic,\n 'cognitive_complexity': cognitive,\n 'testability_score': testability,\n 'assessment': self._complexity_assessment(cyclomatic, cognitive)\n }\n\n def _cyclomatic_complexity(self, code: str) -> int:\n \"\"\"\n Calculate cyclomatic complexity (simplified).\n\n Counts decision points: if, for, while, case, catch, &&, ||\n \"\"\"\n # Count decision points\n decision_points = 0\n\n # Control flow keywords\n keywords = ['if', 'for', 'while', 'case', 'catch', 'except']\n for keyword in keywords:\n # Use word boundaries to avoid matching substrings\n pattern = r'\\b' + keyword + r'\\b'\n decision_points += len(re.findall(pattern, code))\n\n # Logical operators\n decision_points += len(re.findall(r'\\&\\&|\\|\\|', code))\n\n # Base complexity is 1\n return decision_points + 1\n\n def _cognitive_complexity(self, code: str) -> int:\n \"\"\"\n Calculate cognitive complexity (simplified).\n\n Similar to cyclomatic but penalizes nesting and non-obvious flow.\n \"\"\"\n lines = code.split('\\n')\n cognitive_score = 0\n nesting_level = 0\n\n for line in lines:\n stripped = line.strip()\n\n # Increase nesting level\n if any(keyword in stripped for keyword in ['if ', 'for ', 'while ', 'def ', 'function ', 'class ']):\n cognitive_score += (1 + nesting_level)\n if stripped.endswith(':') or stripped.endswith('{'):\n nesting_level += 1\n\n # Decrease nesting level\n if stripped.startswith('}') or (stripped and not stripped.startswith(' ') and nesting_level > 0):\n nesting_level = max(0, nesting_level - 1)\n\n # Penalize complex conditions\n if '&&' in stripped or '||' in stripped:\n cognitive_score += 1\n\n return cognitive_score\n\n def _testability_score(self, code: str, cyclomatic: int) -> float:\n \"\"\"\n Calculate testability score (0-100).\n\n Based on:\n - Complexity (lower is better)\n - Dependencies (fewer is better)\n - Pure functions (more is better)\n \"\"\"\n score = 100.0\n\n # Penalize high complexity\n if cyclomatic > 10:\n score -= (cyclomatic - 10) * 5\n elif cyclomatic > 5:\n score -= (cyclomatic - 5) * 2\n\n # Penalize many dependencies\n imports = len(re.findall(r'import |require\\(|from .* import', code))\n if imports > 10:\n score -= (imports - 10) * 2\n\n # Reward small functions\n functions = len(re.findall(r'def |function ', code))\n lines = len(code.split('\\n'))\n if functions > 0:\n avg_function_size = lines / functions\n if avg_function_size \u003c 20:\n score += 10\n elif avg_function_size > 50:\n score -= 10\n\n return max(0.0, min(100.0, score))\n\n def _complexity_assessment(self, cyclomatic: int, cognitive: int) -> str:\n \"\"\"Generate complexity assessment.\"\"\"\n if cyclomatic \u003c= 5 and cognitive \u003c= 10:\n return \"Low complexity - easy to test\"\n elif cyclomatic \u003c= 10 and cognitive \u003c= 20:\n return \"Medium complexity - moderately testable\"\n elif cyclomatic \u003c= 15 and cognitive \u003c= 30:\n return \"High complexity - challenging to test\"\n else:\n return \"Very high complexity - consider refactoring\"\n\n def calculate_test_quality(self, test_code: str) -> Dict[str, Any]:\n \"\"\"\n Calculate test quality metrics.\n\n Args:\n test_code: Test code to analyze\n\n Returns:\n Test quality metrics\n \"\"\"\n assertions = self._count_assertions(test_code)\n test_functions = self._count_test_functions(test_code)\n isolation_score = self._isolation_score(test_code)\n naming_quality = self._naming_quality(test_code)\n test_smells = self._detect_test_smells(test_code)\n\n avg_assertions = assertions / test_functions if test_functions > 0 else 0\n\n return {\n 'total_tests': test_functions,\n 'total_assertions': assertions,\n 'avg_assertions_per_test': round(avg_assertions, 2),\n 'isolation_score': isolation_score,\n 'naming_quality': naming_quality,\n 'test_smells': test_smells,\n 'quality_score': self._calculate_quality_score(\n avg_assertions, isolation_score, naming_quality, test_smells\n )\n }\n\n def _count_assertions(self, test_code: str) -> int:\n \"\"\"Count assertion statements.\"\"\"\n # Common assertion patterns\n patterns = [\n r'\\bassert[A-Z]\\w*\\(', # JUnit: assertTrue, assertEquals\n r'\\bexpect\\(', # Jest/Vitest: expect()\n r'\\bassert\\s+', # Python: assert\n r'\\.should\\.', # Chai: should\n r'\\.to\\.', # Chai: expect().to\n ]\n\n count = 0\n for pattern in patterns:\n count += len(re.findall(pattern, test_code))\n\n return count\n\n def _count_test_functions(self, test_code: str) -> int:\n \"\"\"Count test functions.\"\"\"\n patterns = [\n r'\\btest_\\w+', # Python: test_*\n r'\\bit\\(', # Jest/Mocha: it()\n r'\\btest\\(', # Jest: test()\n r'@Test', # JUnit: @Test\n r'\\bdef test_', # Python def test_\n ]\n\n count = 0\n for pattern in patterns:\n count += len(re.findall(pattern, test_code))\n\n return max(1, count) # At least 1 to avoid division by zero\n\n def _isolation_score(self, test_code: str) -> float:\n \"\"\"\n Calculate test isolation score (0-100).\n\n Higher score = better isolation (fewer shared dependencies)\n \"\"\"\n score = 100.0\n\n # Penalize global state\n globals_used = len(re.findall(r'\\bglobal\\s+\\w+', test_code))\n score -= globals_used * 10\n\n # Penalize shared setup without proper cleanup\n setup_count = len(re.findall(r'beforeAll|beforeEach|setUp', test_code))\n cleanup_count = len(re.findall(r'afterAll|afterEach|tearDown', test_code))\n if setup_count > cleanup_count:\n score -= (setup_count - cleanup_count) * 5\n\n # Reward mocking\n mocks = len(re.findall(r'mock|stub|spy', test_code, re.IGNORECASE))\n score += min(mocks * 2, 10)\n\n return max(0.0, min(100.0, score))\n\n def _naming_quality(self, test_code: str) -> float:\n \"\"\"\n Calculate test naming quality score (0-100).\n\n Better names are descriptive and follow conventions.\n \"\"\"\n test_names = re.findall(r'(?:it|test|def test_)\\s*\\(?\\s*[\"\\']?([^\"\\')\\n]+)', test_code)\n\n if not test_names:\n return 50.0\n\n score = 0\n for name in test_names:\n name_score = 0\n\n # Check length (too short or too long is bad)\n if 20 \u003c= len(name) \u003c= 80:\n name_score += 30\n elif 10 \u003c= len(name) \u003c 20 or 80 \u003c len(name) \u003c= 100:\n name_score += 15\n\n # Check for descriptive words\n descriptive_words = ['should', 'when', 'given', 'returns', 'throws', 'handles']\n if any(word in name.lower() for word in descriptive_words):\n name_score += 30\n\n # Check for underscores or camelCase (not just letters)\n if '_' in name or re.search(r'[a-z][A-Z]', name):\n name_score += 20\n\n # Avoid generic names\n generic = ['test1', 'test2', 'testit', 'mytest']\n if name.lower() not in generic:\n name_score += 20\n\n score += name_score\n\n return min(100.0, score / len(test_names))\n\n def _detect_test_smells(self, test_code: str) -> List[Dict[str, str]]:\n \"\"\"Detect common test smells.\"\"\"\n smells = []\n\n # Test smell 1: No assertions\n if 'assert' not in test_code.lower() and 'expect' not in test_code.lower():\n smells.append({\n 'smell': 'missing_assertions',\n 'description': 'Tests without assertions',\n 'severity': 'high'\n })\n\n # Test smell 2: Too many assertions\n test_count = self._count_test_functions(test_code)\n assertion_count = self._count_assertions(test_code)\n avg_assertions = assertion_count / test_count if test_count > 0 else 0\n if avg_assertions > 5:\n smells.append({\n 'smell': 'assertion_roulette',\n 'description': f'Too many assertions per test (avg: {avg_assertions:.1f})',\n 'severity': 'medium'\n })\n\n # Test smell 3: Sleeps in tests\n if 'sleep' in test_code.lower() or 'wait' in test_code.lower():\n smells.append({\n 'smell': 'sleepy_test',\n 'description': 'Tests using sleep/wait (potential flakiness)',\n 'severity': 'high'\n })\n\n # Test smell 4: Conditional logic in tests\n if re.search(r'\\bif\\s*\\(', test_code):\n smells.append({\n 'smell': 'conditional_test_logic',\n 'description': 'Tests contain conditional logic',\n 'severity': 'medium'\n })\n\n return smells\n\n def _calculate_quality_score(\n self,\n avg_assertions: float,\n isolation: float,\n naming: float,\n smells: List[Dict[str, str]]\n ) -> float:\n \"\"\"Calculate overall test quality score.\"\"\"\n score = 0.0\n\n # Assertions (30 points)\n if 1 \u003c= avg_assertions \u003c= 3:\n score += 30\n elif 0 \u003c avg_assertions \u003c 1 or 3 \u003c avg_assertions \u003c= 5:\n score += 20\n else:\n score += 10\n\n # Isolation (30 points)\n score += isolation * 0.3\n\n # Naming (20 points)\n score += naming * 0.2\n\n # Smells (20 points - deduct based on severity)\n smell_penalty = 0\n for smell in smells:\n if smell['severity'] == 'high':\n smell_penalty += 10\n elif smell['severity'] == 'medium':\n smell_penalty += 5\n else:\n smell_penalty += 2\n\n score = max(0, score - smell_penalty)\n\n return round(min(100.0, score), 2)\n\n def analyze_execution_metrics(\n self,\n execution_data: Dict[str, Any]\n ) -> Dict[str, Any]:\n \"\"\"\n Analyze test execution metrics.\n\n Args:\n execution_data: Test execution results with timing\n\n Returns:\n Execution analysis\n \"\"\"\n tests = execution_data.get('tests', [])\n\n if not tests:\n return {}\n\n # Calculate timing statistics\n timings = [test.get('duration', 0) for test in tests]\n total_time = sum(timings)\n avg_time = total_time / len(tests) if tests else 0\n\n # Identify slow tests (>100ms for unit tests)\n slow_tests = [\n test for test in tests\n if test.get('duration', 0) > 100\n ]\n\n # Identify flaky tests (if failure history available)\n flaky_tests = [\n test for test in tests\n if test.get('failure_rate', 0) > 0.1 # Failed >10% of time\n ]\n\n return {\n 'total_tests': len(tests),\n 'total_time_ms': round(total_time, 2),\n 'avg_time_ms': round(avg_time, 2),\n 'slow_tests': len(slow_tests),\n 'slow_test_details': slow_tests[:5], # Top 5\n 'flaky_tests': len(flaky_tests),\n 'flaky_test_details': flaky_tests,\n 'pass_rate': self._calculate_pass_rate(tests)\n }\n\n def _calculate_pass_rate(self, tests: List[Dict[str, Any]]) -> float:\n \"\"\"Calculate test pass rate.\"\"\"\n if not tests:\n return 0.0\n\n passed = sum(1 for test in tests if test.get('status') == 'passed')\n return round((passed / len(tests)) * 100, 2)\n\n def generate_metrics_summary(self) -> str:\n \"\"\"Generate human-readable metrics summary.\"\"\"\n if not self.metrics:\n return \"No metrics calculated yet.\"\n\n lines = [\"# Test Metrics Summary\\n\"]\n\n # Complexity\n if 'complexity' in self.metrics:\n comp = self.metrics['complexity']\n lines.append(f\"## Code Complexity\")\n lines.append(f\"- Cyclomatic Complexity: {comp['cyclomatic_complexity']}\")\n lines.append(f\"- Cognitive Complexity: {comp['cognitive_complexity']}\")\n lines.append(f\"- Testability Score: {comp['testability_score']:.1f}/100\")\n lines.append(f\"- Assessment: {comp['assessment']}\\n\")\n\n # Test Quality\n if 'test_quality' in self.metrics:\n qual = self.metrics['test_quality']\n lines.append(f\"## Test Quality\")\n lines.append(f\"- Total Tests: {qual['total_tests']}\")\n lines.append(f\"- Assertions per Test: {qual['avg_assertions_per_test']}\")\n lines.append(f\"- Isolation Score: {qual['isolation_score']:.1f}/100\")\n lines.append(f\"- Naming Quality: {qual['naming_quality']:.1f}/100\")\n lines.append(f\"- Quality Score: {qual['quality_score']:.1f}/100\\n\")\n\n if qual['test_smells']:\n lines.append(f\"### Test Smells Detected:\")\n for smell in qual['test_smells']:\n lines.append(f\"- {smell['description']} (severity: {smell['severity']})\")\n lines.append(\"\")\n\n return \"\\n\".join(lines)\n","content_type":"text/x-python; charset=utf-8","language":"python","size":15476,"content_sha256":"8080b0daa70cb38114cf7937e3e8f942cef99b81db3fdd786e1ca44350bd57a8"},{"filename":"scripts/output_formatter.py","content":"\"\"\"\nOutput formatting module.\n\nProvides context-aware output formatting for different environments (Desktop, CLI, API).\nImplements progressive disclosure and token-efficient reporting.\n\"\"\"\n\nfrom typing import Dict, List, Any, Optional\n\n\nclass OutputFormatter:\n \"\"\"Format output based on environment and preferences.\"\"\"\n\n def __init__(self, environment: str = \"cli\", verbose: bool = False):\n \"\"\"\n Initialize output formatter.\n\n Args:\n environment: Target environment (desktop, cli, api)\n verbose: Whether to include detailed output\n \"\"\"\n self.environment = environment\n self.verbose = verbose\n\n def format_coverage_summary(\n self,\n summary: Dict[str, Any],\n detailed: bool = False\n ) -> str:\n \"\"\"\n Format coverage summary.\n\n Args:\n summary: Coverage summary data\n detailed: Whether to include detailed breakdown\n\n Returns:\n Formatted coverage summary\n \"\"\"\n if self.environment == \"desktop\":\n return self._format_coverage_markdown(summary, detailed)\n elif self.environment == \"api\":\n return self._format_coverage_json(summary)\n else:\n return self._format_coverage_terminal(summary, detailed)\n\n def _format_coverage_markdown(self, summary: Dict[str, Any], detailed: bool) -> str:\n \"\"\"Format coverage as rich markdown (for Claude Desktop).\"\"\"\n lines = [\"## Test Coverage Summary\\n\"]\n\n # Overall metrics\n lines.append(\"### Overall Metrics\")\n lines.append(f\"- **Line Coverage**: {summary.get('line_coverage', 0):.1f}%\")\n lines.append(f\"- **Branch Coverage**: {summary.get('branch_coverage', 0):.1f}%\")\n lines.append(f\"- **Function Coverage**: {summary.get('function_coverage', 0):.1f}%\\n\")\n\n # Visual indicator\n line_cov = summary.get('line_coverage', 0)\n lines.append(self._coverage_badge(line_cov))\n lines.append(\"\")\n\n # Detailed breakdown if requested\n if detailed:\n lines.append(\"### Detailed Breakdown\")\n lines.append(f\"- Total Lines: {summary.get('total_lines', 0)}\")\n lines.append(f\"- Covered Lines: {summary.get('covered_lines', 0)}\")\n lines.append(f\"- Total Branches: {summary.get('total_branches', 0)}\")\n lines.append(f\"- Covered Branches: {summary.get('covered_branches', 0)}\")\n lines.append(f\"- Total Functions: {summary.get('total_functions', 0)}\")\n lines.append(f\"- Covered Functions: {summary.get('covered_functions', 0)}\\n\")\n\n return \"\\n\".join(lines)\n\n def _format_coverage_terminal(self, summary: Dict[str, Any], detailed: bool) -> str:\n \"\"\"Format coverage for terminal (Claude Code CLI).\"\"\"\n lines = [\"Coverage Summary:\"]\n lines.append(f\" Line: {summary.get('line_coverage', 0):.1f}%\")\n lines.append(f\" Branch: {summary.get('branch_coverage', 0):.1f}%\")\n lines.append(f\" Function: {summary.get('function_coverage', 0):.1f}%\")\n\n if detailed:\n lines.append(f\"\\nDetails:\")\n lines.append(f\" Lines: {summary.get('covered_lines', 0)}/{summary.get('total_lines', 0)}\")\n lines.append(f\" Branches: {summary.get('covered_branches', 0)}/{summary.get('total_branches', 0)}\")\n\n return \"\\n\".join(lines)\n\n def _format_coverage_json(self, summary: Dict[str, Any]) -> str:\n \"\"\"Format coverage as JSON (for API/CI integration).\"\"\"\n import json\n return json.dumps(summary, indent=2)\n\n def _coverage_badge(self, coverage: float) -> str:\n \"\"\"Generate coverage badge markdown.\"\"\"\n if coverage >= 80:\n color = \"green\"\n emoji = \"✅\"\n elif coverage >= 60:\n color = \"yellow\"\n emoji = \"⚠️\"\n else:\n color = \"red\"\n emoji = \"❌\"\n\n return f\"{emoji} **{coverage:.1f}%** coverage ({color})\"\n\n def format_recommendations(\n self,\n recommendations: List[Dict[str, Any]],\n max_items: Optional[int] = None\n ) -> str:\n \"\"\"\n Format recommendations with progressive disclosure.\n\n Args:\n recommendations: List of recommendation dictionaries\n max_items: Maximum number of items to show (None for all)\n\n Returns:\n Formatted recommendations\n \"\"\"\n if not recommendations:\n return \"No recommendations at this time.\"\n\n # Group by priority\n p0 = [r for r in recommendations if r.get('priority') == 'P0']\n p1 = [r for r in recommendations if r.get('priority') == 'P1']\n p2 = [r for r in recommendations if r.get('priority') == 'P2']\n\n if self.environment == \"desktop\":\n return self._format_recommendations_markdown(p0, p1, p2, max_items)\n elif self.environment == \"api\":\n return self._format_recommendations_json(recommendations)\n else:\n return self._format_recommendations_terminal(p0, p1, p2, max_items)\n\n def _format_recommendations_markdown(\n self,\n p0: List[Dict],\n p1: List[Dict],\n p2: List[Dict],\n max_items: Optional[int]\n ) -> str:\n \"\"\"Format recommendations as rich markdown.\"\"\"\n lines = [\"## Recommendations\\n\"]\n\n if p0:\n lines.append(\"### 🔴 Critical (P0)\")\n for i, rec in enumerate(p0[:max_items] if max_items else p0):\n lines.append(f\"{i+1}. **{rec.get('message', 'No message')}**\")\n lines.append(f\" - Action: {rec.get('action', 'No action specified')}\")\n if 'file' in rec:\n lines.append(f\" - File: `{rec['file']}`\")\n lines.append(\"\")\n\n if p1 and (not max_items or len(p0) \u003c max_items):\n remaining = max_items - len(p0) if max_items else None\n lines.append(\"### 🟡 Important (P1)\")\n for i, rec in enumerate(p1[:remaining] if remaining else p1):\n lines.append(f\"{i+1}. {rec.get('message', 'No message')}\")\n lines.append(f\" - Action: {rec.get('action', 'No action specified')}\")\n lines.append(\"\")\n\n if p2 and self.verbose:\n lines.append(\"### 🔵 Nice to Have (P2)\")\n for i, rec in enumerate(p2):\n lines.append(f\"{i+1}. {rec.get('message', 'No message')}\")\n lines.append(\"\")\n\n return \"\\n\".join(lines)\n\n def _format_recommendations_terminal(\n self,\n p0: List[Dict],\n p1: List[Dict],\n p2: List[Dict],\n max_items: Optional[int]\n ) -> str:\n \"\"\"Format recommendations for terminal.\"\"\"\n lines = [\"Recommendations:\"]\n\n if p0:\n lines.append(\"\\nCritical (P0):\")\n for i, rec in enumerate(p0[:max_items] if max_items else p0):\n lines.append(f\" {i+1}. {rec.get('message', 'No message')}\")\n lines.append(f\" Action: {rec.get('action', 'No action')}\")\n\n if p1 and (not max_items or len(p0) \u003c max_items):\n remaining = max_items - len(p0) if max_items else None\n lines.append(\"\\nImportant (P1):\")\n for i, rec in enumerate(p1[:remaining] if remaining else p1):\n lines.append(f\" {i+1}. {rec.get('message', 'No message')}\")\n\n return \"\\n\".join(lines)\n\n def _format_recommendations_json(self, recommendations: List[Dict[str, Any]]) -> str:\n \"\"\"Format recommendations as JSON.\"\"\"\n import json\n return json.dumps(recommendations, indent=2)\n\n def format_test_results(\n self,\n results: Dict[str, Any],\n show_details: bool = False\n ) -> str:\n \"\"\"\n Format test execution results.\n\n Args:\n results: Test results data\n show_details: Whether to show detailed results\n\n Returns:\n Formatted test results\n \"\"\"\n if self.environment == \"desktop\":\n return self._format_results_markdown(results, show_details)\n elif self.environment == \"api\":\n return self._format_results_json(results)\n else:\n return self._format_results_terminal(results, show_details)\n\n def _format_results_markdown(self, results: Dict[str, Any], show_details: bool) -> str:\n \"\"\"Format test results as markdown.\"\"\"\n lines = [\"## Test Results\\n\"]\n\n total = results.get('total_tests', 0)\n passed = results.get('passed', 0)\n failed = results.get('failed', 0)\n skipped = results.get('skipped', 0)\n\n # Summary\n lines.append(f\"- **Total Tests**: {total}\")\n lines.append(f\"- **Passed**: ✅ {passed}\")\n if failed > 0:\n lines.append(f\"- **Failed**: ❌ {failed}\")\n if skipped > 0:\n lines.append(f\"- **Skipped**: ⏭️ {skipped}\")\n\n # Pass rate\n pass_rate = (passed / total * 100) if total > 0 else 0\n lines.append(f\"- **Pass Rate**: {pass_rate:.1f}%\\n\")\n\n # Failed tests details\n if show_details and failed > 0:\n lines.append(\"### Failed Tests\")\n for test in results.get('failed_tests', []):\n lines.append(f\"- `{test.get('name', 'Unknown')}`\")\n if 'error' in test:\n lines.append(f\" ```\\n {test['error']}\\n ```\")\n\n return \"\\n\".join(lines)\n\n def _format_results_terminal(self, results: Dict[str, Any], show_details: bool) -> str:\n \"\"\"Format test results for terminal.\"\"\"\n total = results.get('total_tests', 0)\n passed = results.get('passed', 0)\n failed = results.get('failed', 0)\n\n lines = [f\"Test Results: {passed}/{total} passed\"]\n\n if failed > 0:\n lines.append(f\" Failed: {failed}\")\n\n if show_details and failed > 0:\n lines.append(\"\\nFailed tests:\")\n for test in results.get('failed_tests', [])[:5]:\n lines.append(f\" - {test.get('name', 'Unknown')}\")\n\n return \"\\n\".join(lines)\n\n def _format_results_json(self, results: Dict[str, Any]) -> str:\n \"\"\"Format test results as JSON.\"\"\"\n import json\n return json.dumps(results, indent=2)\n\n def create_summary_report(\n self,\n coverage: Dict[str, Any],\n metrics: Dict[str, Any],\n recommendations: List[Dict[str, Any]]\n ) -> str:\n \"\"\"\n Create comprehensive summary report (token-efficient).\n\n Args:\n coverage: Coverage data\n metrics: Quality metrics\n recommendations: Recommendations list\n\n Returns:\n Summary report (\u003c200 tokens)\n \"\"\"\n lines = []\n\n # Coverage (1-2 lines)\n line_cov = coverage.get('line_coverage', 0)\n branch_cov = coverage.get('branch_coverage', 0)\n lines.append(f\"Coverage: {line_cov:.0f}% lines, {branch_cov:.0f}% branches\")\n\n # Quality (1-2 lines)\n if 'test_quality' in metrics:\n quality_score = metrics['test_quality'].get('quality_score', 0)\n lines.append(f\"Test Quality: {quality_score:.0f}/100\")\n\n # Top recommendations (2-3 lines)\n p0_count = sum(1 for r in recommendations if r.get('priority') == 'P0')\n if p0_count > 0:\n lines.append(f\"Critical issues: {p0_count}\")\n top_rec = next((r for r in recommendations if r.get('priority') == 'P0'), None)\n if top_rec:\n lines.append(f\" - {top_rec.get('message', '')}\")\n\n return \"\\n\".join(lines)\n\n def should_show_detailed(self, data_size: int) -> bool:\n \"\"\"\n Determine if detailed output should be shown based on data size.\n\n Args:\n data_size: Size of data to display\n\n Returns:\n Whether to show detailed output\n \"\"\"\n if self.verbose:\n return True\n\n # Progressive disclosure thresholds\n if self.environment == \"desktop\":\n return data_size \u003c 100 # Show more in Desktop\n else:\n return data_size \u003c 20 # Show less in CLI\n\n def truncate_output(self, text: str, max_lines: int = 50) -> str:\n \"\"\"\n Truncate output to maximum lines.\n\n Args:\n text: Text to truncate\n max_lines: Maximum number of lines\n\n Returns:\n Truncated text with indicator\n \"\"\"\n lines = text.split('\\n')\n\n if len(lines) \u003c= max_lines:\n return text\n\n truncated = '\\n'.join(lines[:max_lines])\n remaining = len(lines) - max_lines\n\n return f\"{truncated}\\n\\n... ({remaining} more lines, use --verbose for full output)\"\n","content_type":"text/x-python; charset=utf-8","language":"python","size":12734,"content_sha256":"e92a7559ae39c9b144a55b2dfaf6f14d9137a7e37aa9ee07adaf7c4c346b21fd"},{"filename":"scripts/tdd_workflow.py","content":"\"\"\"\nTDD workflow guidance module.\n\nProvides step-by-step guidance through red-green-refactor cycles with validation.\n\"\"\"\n\nfrom typing import Dict, List, Any, Optional\nfrom enum import Enum\n\n\nclass TDDPhase(Enum):\n \"\"\"TDD cycle phases.\"\"\"\n RED = \"red\" # Write failing test\n GREEN = \"green\" # Make test pass\n REFACTOR = \"refactor\" # Improve code\n\n\nclass WorkflowState(Enum):\n \"\"\"Current state of TDD workflow.\"\"\"\n INITIAL = \"initial\"\n TEST_WRITTEN = \"test_written\"\n TEST_FAILING = \"test_failing\"\n TEST_PASSING = \"test_passing\"\n CODE_REFACTORED = \"code_refactored\"\n\n\nclass TDDWorkflow:\n \"\"\"Guide users through TDD red-green-refactor workflow.\"\"\"\n\n def __init__(self):\n \"\"\"Initialize TDD workflow guide.\"\"\"\n self.current_phase = TDDPhase.RED\n self.state = WorkflowState.INITIAL\n self.history = []\n\n def start_cycle(self, requirement: str) -> Dict[str, Any]:\n \"\"\"\n Start a new TDD cycle.\n\n Args:\n requirement: User story or requirement to implement\n\n Returns:\n Guidance for RED phase\n \"\"\"\n self.current_phase = TDDPhase.RED\n self.state = WorkflowState.INITIAL\n\n return {\n 'phase': 'RED',\n 'instruction': 'Write a failing test for the requirement',\n 'requirement': requirement,\n 'checklist': [\n 'Write test that describes desired behavior',\n 'Test should fail when run (no implementation yet)',\n 'Test name clearly describes what is being tested',\n 'Test has clear arrange-act-assert structure'\n ],\n 'tips': [\n 'Focus on behavior, not implementation',\n 'Start with simplest test case',\n 'Test should be specific and focused'\n ]\n }\n\n def validate_red_phase(\n self,\n test_code: str,\n test_result: Optional[Dict[str, Any]] = None\n ) -> Dict[str, Any]:\n \"\"\"\n Validate RED phase completion.\n\n Args:\n test_code: The test code written\n test_result: Test execution result (optional)\n\n Returns:\n Validation result and next steps\n \"\"\"\n validations = []\n\n # Check test exists\n if not test_code or len(test_code.strip()) \u003c 10:\n validations.append({\n 'valid': False,\n 'message': 'No test code provided'\n })\n else:\n validations.append({\n 'valid': True,\n 'message': 'Test code provided'\n })\n\n # Check for assertions\n has_assertion = any(keyword in test_code.lower()\n for keyword in ['assert', 'expect', 'should'])\n validations.append({\n 'valid': has_assertion,\n 'message': 'Contains assertions' if has_assertion else 'Missing assertions'\n })\n\n # Check test result if provided\n if test_result:\n test_failed = test_result.get('status') == 'failed'\n validations.append({\n 'valid': test_failed,\n 'message': 'Test fails as expected' if test_failed else 'Test should fail in RED phase'\n })\n\n all_valid = all(v['valid'] for v in validations)\n\n if all_valid:\n self.state = WorkflowState.TEST_FAILING\n self.current_phase = TDDPhase.GREEN\n return {\n 'phase_complete': True,\n 'next_phase': 'GREEN',\n 'validations': validations,\n 'instruction': 'Write minimal code to make the test pass'\n }\n else:\n return {\n 'phase_complete': False,\n 'current_phase': 'RED',\n 'validations': validations,\n 'instruction': 'Address validation issues before proceeding'\n }\n\n def validate_green_phase(\n self,\n implementation_code: str,\n test_result: Dict[str, Any]\n ) -> Dict[str, Any]:\n \"\"\"\n Validate GREEN phase completion.\n\n Args:\n implementation_code: The implementation code\n test_result: Test execution result\n\n Returns:\n Validation result and next steps\n \"\"\"\n validations = []\n\n # Check implementation exists\n if not implementation_code or len(implementation_code.strip()) \u003c 5:\n validations.append({\n 'valid': False,\n 'message': 'No implementation code provided'\n })\n else:\n validations.append({\n 'valid': True,\n 'message': 'Implementation code provided'\n })\n\n # Check test now passes\n test_passed = test_result.get('status') == 'passed'\n validations.append({\n 'valid': test_passed,\n 'message': 'Test passes' if test_passed else 'Test still failing'\n })\n\n # Check for minimal implementation (heuristic)\n is_minimal = self._check_minimal_implementation(implementation_code)\n validations.append({\n 'valid': is_minimal,\n 'message': 'Implementation appears minimal' if is_minimal\n else 'Implementation may be over-engineered'\n })\n\n all_valid = all(v['valid'] for v in validations)\n\n if all_valid:\n self.state = WorkflowState.TEST_PASSING\n self.current_phase = TDDPhase.REFACTOR\n return {\n 'phase_complete': True,\n 'next_phase': 'REFACTOR',\n 'validations': validations,\n 'instruction': 'Refactor code while keeping tests green',\n 'refactoring_suggestions': self._suggest_refactorings(implementation_code)\n }\n else:\n return {\n 'phase_complete': False,\n 'current_phase': 'GREEN',\n 'validations': validations,\n 'instruction': 'Make the test pass before refactoring'\n }\n\n def validate_refactor_phase(\n self,\n original_code: str,\n refactored_code: str,\n test_result: Dict[str, Any]\n ) -> Dict[str, Any]:\n \"\"\"\n Validate REFACTOR phase completion.\n\n Args:\n original_code: Original implementation\n refactored_code: Refactored implementation\n test_result: Test execution result after refactoring\n\n Returns:\n Validation result and cycle completion status\n \"\"\"\n validations = []\n\n # Check tests still pass\n test_passed = test_result.get('status') == 'passed'\n validations.append({\n 'valid': test_passed,\n 'message': 'Tests still pass after refactoring' if test_passed\n else 'Tests broken by refactoring'\n })\n\n # Check code was actually refactored\n code_changed = original_code != refactored_code\n validations.append({\n 'valid': code_changed,\n 'message': 'Code was refactored' if code_changed\n else 'No refactoring applied (optional)'\n })\n\n # Check code quality improved\n quality_improved = self._check_quality_improvement(original_code, refactored_code)\n if code_changed:\n validations.append({\n 'valid': quality_improved,\n 'message': 'Code quality improved' if quality_improved\n else 'Consider further refactoring for better quality'\n })\n\n all_valid = all(v['valid'] for v in validations if v.get('valid') is not None)\n\n if all_valid:\n self.state = WorkflowState.CODE_REFACTORED\n self.history.append({\n 'cycle_complete': True,\n 'final_state': self.state\n })\n return {\n 'phase_complete': True,\n 'cycle_complete': True,\n 'validations': validations,\n 'message': 'TDD cycle complete! Ready for next requirement.',\n 'next_steps': [\n 'Commit your changes',\n 'Start next TDD cycle with new requirement',\n 'Or add more test cases for current feature'\n ]\n }\n else:\n return {\n 'phase_complete': False,\n 'current_phase': 'REFACTOR',\n 'validations': validations,\n 'instruction': 'Ensure tests still pass after refactoring'\n }\n\n def _check_minimal_implementation(self, code: str) -> bool:\n \"\"\"Check if implementation is minimal (heuristic).\"\"\"\n # Simple heuristics:\n # - Not too long (\u003c 50 lines for unit tests)\n # - Not too complex (few nested structures)\n\n lines = code.split('\\n')\n non_empty_lines = [line for line in lines if line.strip() and not line.strip().startswith('#')]\n\n # Check length\n if len(non_empty_lines) > 50:\n return False\n\n # Check nesting depth (simplified)\n max_depth = 0\n current_depth = 0\n for line in lines:\n stripped = line.lstrip()\n if stripped:\n indent = len(line) - len(stripped)\n depth = indent // 4 # Assuming 4-space indent\n max_depth = max(max_depth, depth)\n\n # Max nesting of 3 levels for simple implementation\n return max_depth \u003c= 3\n\n def _check_quality_improvement(self, original: str, refactored: str) -> bool:\n \"\"\"Check if refactoring improved code quality.\"\"\"\n # Simple heuristics:\n # - Reduced duplication\n # - Better naming\n # - Simpler structure\n\n # Check for reduced duplication (basic check)\n original_lines = set(line.strip() for line in original.split('\\n') if line.strip())\n refactored_lines = set(line.strip() for line in refactored.split('\\n') if line.strip())\n\n # If unique lines increased proportionally, likely extracted duplicates\n if len(refactored_lines) > len(original_lines):\n return True\n\n # Check for better naming (longer, more descriptive names)\n original_avg_identifier_length = self._avg_identifier_length(original)\n refactored_avg_identifier_length = self._avg_identifier_length(refactored)\n\n if refactored_avg_identifier_length > original_avg_identifier_length:\n return True\n\n # If no clear improvement detected, assume refactoring was beneficial\n return True\n\n def _avg_identifier_length(self, code: str) -> float:\n \"\"\"Calculate average identifier length (proxy for naming quality).\"\"\"\n import re\n identifiers = re.findall(r'\\b[a-zA-Z_][a-zA-Z0-9_]*\\b', code)\n\n # Filter out keywords\n keywords = {'if', 'else', 'for', 'while', 'def', 'class', 'return', 'import', 'from'}\n identifiers = [i for i in identifiers if i.lower() not in keywords]\n\n if not identifiers:\n return 0.0\n\n return sum(len(i) for i in identifiers) / len(identifiers)\n\n def _suggest_refactorings(self, code: str) -> List[str]:\n \"\"\"Suggest potential refactorings.\"\"\"\n suggestions = []\n\n # Check for long functions\n lines = code.split('\\n')\n if len(lines) > 30:\n suggestions.append('Consider breaking long function into smaller functions')\n\n # Check for duplication (simple check)\n line_counts = {}\n for line in lines:\n stripped = line.strip()\n if len(stripped) > 10: # Ignore very short lines\n line_counts[stripped] = line_counts.get(stripped, 0) + 1\n\n duplicates = [line for line, count in line_counts.items() if count > 2]\n if duplicates:\n suggestions.append(f'Found {len(duplicates)} duplicated code patterns - consider extraction')\n\n # Check for magic numbers\n import re\n magic_numbers = re.findall(r'\\b\\d+\\b', code)\n if len(magic_numbers) > 5:\n suggestions.append('Consider extracting magic numbers to named constants')\n\n # Check for long parameter lists\n if 'def ' in code or 'function' in code:\n param_matches = re.findall(r'\\(([^)]+)\\)', code)\n for params in param_matches:\n if params.count(',') > 3:\n suggestions.append('Consider using parameter object for functions with many parameters')\n break\n\n if not suggestions:\n suggestions.append('Code looks clean - no obvious refactorings needed')\n\n return suggestions\n\n def generate_workflow_summary(self) -> str:\n \"\"\"Generate summary of TDD workflow progress.\"\"\"\n summary = [\n \"# TDD Workflow Summary\\n\",\n f\"Current Phase: {self.current_phase.value.upper()}\",\n f\"Current State: {self.state.value.replace('_', ' ').title()}\",\n f\"Completed Cycles: {len(self.history)}\\n\"\n ]\n\n summary.append(\"## TDD Cycle Steps:\\n\")\n summary.append(\"1. **RED**: Write a failing test\")\n summary.append(\" - Test describes desired behavior\")\n summary.append(\" - Test fails (no implementation)\\n\")\n\n summary.append(\"2. **GREEN**: Make the test pass\")\n summary.append(\" - Write minimal code to pass test\")\n summary.append(\" - All tests should pass\\n\")\n\n summary.append(\"3. **REFACTOR**: Improve the code\")\n summary.append(\" - Clean up implementation\")\n summary.append(\" - Tests still pass\")\n summary.append(\" - Code is more maintainable\\n\")\n\n return \"\\n\".join(summary)\n\n def get_phase_guidance(self, phase: Optional[TDDPhase] = None) -> Dict[str, Any]:\n \"\"\"\n Get detailed guidance for a specific phase.\n\n Args:\n phase: TDD phase (uses current if not specified)\n\n Returns:\n Detailed guidance dictionary\n \"\"\"\n target_phase = phase or self.current_phase\n\n if target_phase == TDDPhase.RED:\n return {\n 'phase': 'RED',\n 'goal': 'Write a failing test',\n 'steps': [\n '1. Read and understand the requirement',\n '2. Think about expected behavior',\n '3. Write test that verifies this behavior',\n '4. Run test and ensure it fails',\n '5. Verify failure reason is correct (not syntax error)'\n ],\n 'common_mistakes': [\n 'Test passes immediately (no real assertion)',\n 'Test fails for wrong reason (syntax error)',\n 'Test is too broad or tests multiple things'\n ],\n 'tips': [\n 'Start with simplest test case',\n 'One assertion per test (focused)',\n 'Test should read like specification'\n ]\n }\n\n elif target_phase == TDDPhase.GREEN:\n return {\n 'phase': 'GREEN',\n 'goal': 'Make the test pass with minimal code',\n 'steps': [\n '1. Write simplest code that makes test pass',\n '2. Run test and verify it passes',\n '3. Run all tests to ensure no regression',\n '4. Resist urge to add extra features'\n ],\n 'common_mistakes': [\n 'Over-engineering solution',\n 'Adding features not covered by tests',\n 'Breaking existing tests'\n ],\n 'tips': [\n 'Fake it till you make it (hardcode if needed)',\n 'Triangulate with more tests if needed',\n 'Keep implementation simple'\n ]\n }\n\n elif target_phase == TDDPhase.REFACTOR:\n return {\n 'phase': 'REFACTOR',\n 'goal': 'Improve code quality while keeping tests green',\n 'steps': [\n '1. Identify code smells or duplication',\n '2. Apply one refactoring at a time',\n '3. Run tests after each change',\n '4. Commit when satisfied with quality'\n ],\n 'common_mistakes': [\n 'Changing behavior (breaking tests)',\n 'Refactoring too much at once',\n 'Skipping this phase'\n ],\n 'tips': [\n 'Extract methods for better naming',\n 'Remove duplication',\n 'Improve variable names',\n 'Tests are safety net - use them!'\n ]\n }\n\n return {}\n","content_type":"text/x-python; charset=utf-8","language":"python","size":16968,"content_sha256":"5048dda42125f9c95cd49dbf67816f5bc635fee0cc5938a74a4d1b59361f9095"},{"filename":"scripts/test_generator.py","content":"\"\"\"\nTest case generation module.\n\nGenerates test cases from requirements, user stories, API specs, and code analysis.\nSupports multiple testing frameworks with intelligent test scaffolding.\n\"\"\"\n\nfrom typing import Dict, List, Any, Optional\nfrom enum import Enum\n\n\nclass TestFramework(Enum):\n \"\"\"Supported testing frameworks.\"\"\"\n JEST = \"jest\"\n VITEST = \"vitest\"\n PYTEST = \"pytest\"\n JUNIT = \"junit\"\n MOCHA = \"mocha\"\n\n\nclass TestType(Enum):\n \"\"\"Types of tests to generate.\"\"\"\n UNIT = \"unit\"\n INTEGRATION = \"integration\"\n E2E = \"e2e\"\n\n\nclass TestGenerator:\n \"\"\"Generate test cases and test stubs from requirements and code.\"\"\"\n\n def __init__(self, framework: TestFramework, language: str):\n \"\"\"\n Initialize test generator.\n\n Args:\n framework: Testing framework to use\n language: Programming language (typescript, javascript, python, java)\n \"\"\"\n self.framework = framework\n self.language = language\n self.test_cases = []\n\n def generate_from_requirements(\n self,\n requirements: Dict[str, Any],\n test_type: TestType = TestType.UNIT\n ) -> List[Dict[str, Any]]:\n \"\"\"\n Generate test cases from requirements.\n\n Args:\n requirements: Dictionary with user_stories, acceptance_criteria, api_specs\n test_type: Type of tests to generate\n\n Returns:\n List of test case specifications\n \"\"\"\n test_cases = []\n\n # Generate from user stories\n if 'user_stories' in requirements:\n for story in requirements['user_stories']:\n test_cases.extend(self._test_cases_from_story(story))\n\n # Generate from acceptance criteria\n if 'acceptance_criteria' in requirements:\n for criterion in requirements['acceptance_criteria']:\n test_cases.extend(self._test_cases_from_criteria(criterion))\n\n # Generate from API specs\n if 'api_specs' in requirements:\n for endpoint in requirements['api_specs']:\n test_cases.extend(self._test_cases_from_api(endpoint))\n\n self.test_cases = test_cases\n return test_cases\n\n def _test_cases_from_story(self, story: Dict[str, Any]) -> List[Dict[str, Any]]:\n \"\"\"Generate test cases from user story.\"\"\"\n test_cases = []\n\n # Happy path test\n test_cases.append({\n 'name': f\"should_{story.get('action', 'work')}_successfully\",\n 'type': 'happy_path',\n 'description': story.get('description', ''),\n 'given': story.get('given', []),\n 'when': story.get('when', ''),\n 'then': story.get('then', ''),\n 'priority': 'P0'\n })\n\n # Error cases\n if 'error_conditions' in story:\n for error in story['error_conditions']:\n test_cases.append({\n 'name': f\"should_handle_{error.get('condition', 'error')}\",\n 'type': 'error_case',\n 'description': error.get('description', ''),\n 'expected_error': error.get('error_type', ''),\n 'priority': 'P0'\n })\n\n # Edge cases\n if 'edge_cases' in story:\n for edge_case in story['edge_cases']:\n test_cases.append({\n 'name': f\"should_handle_{edge_case.get('scenario', 'edge_case')}\",\n 'type': 'edge_case',\n 'description': edge_case.get('description', ''),\n 'priority': 'P1'\n })\n\n return test_cases\n\n def _test_cases_from_criteria(self, criterion: Dict[str, Any]) -> List[Dict[str, Any]]:\n \"\"\"Generate test cases from acceptance criteria.\"\"\"\n return [{\n 'name': f\"should_meet_{criterion.get('id', 'criterion')}\",\n 'type': 'acceptance',\n 'description': criterion.get('description', ''),\n 'verification': criterion.get('verification_steps', []),\n 'priority': 'P0'\n }]\n\n def _test_cases_from_api(self, endpoint: Dict[str, Any]) -> List[Dict[str, Any]]:\n \"\"\"Generate test cases from API specification.\"\"\"\n test_cases = []\n method = endpoint.get('method', 'GET')\n path = endpoint.get('path', '/')\n\n # Success case\n test_cases.append({\n 'name': f\"should_{method.lower()}_{path.replace('/', '_')}_successfully\",\n 'type': 'api_success',\n 'method': method,\n 'path': path,\n 'expected_status': endpoint.get('success_status', 200),\n 'priority': 'P0'\n })\n\n # Validation errors\n if 'required_params' in endpoint:\n test_cases.append({\n 'name': f\"should_return_400_for_missing_params\",\n 'type': 'api_validation',\n 'method': method,\n 'path': path,\n 'expected_status': 400,\n 'priority': 'P0'\n })\n\n # Authorization\n if endpoint.get('requires_auth', False):\n test_cases.append({\n 'name': f\"should_return_401_for_unauthenticated\",\n 'type': 'api_auth',\n 'method': method,\n 'path': path,\n 'expected_status': 401,\n 'priority': 'P0'\n })\n\n return test_cases\n\n def generate_test_stub(self, test_case: Dict[str, Any]) -> str:\n \"\"\"\n Generate test stub code for a test case.\n\n Args:\n test_case: Test case specification\n\n Returns:\n Test stub code as string\n \"\"\"\n if self.framework == TestFramework.JEST:\n return self._generate_jest_stub(test_case)\n elif self.framework == TestFramework.PYTEST:\n return self._generate_pytest_stub(test_case)\n elif self.framework == TestFramework.JUNIT:\n return self._generate_junit_stub(test_case)\n elif self.framework == TestFramework.VITEST:\n return self._generate_vitest_stub(test_case)\n else:\n return self._generate_generic_stub(test_case)\n\n def _generate_jest_stub(self, test_case: Dict[str, Any]) -> str:\n \"\"\"Generate Jest test stub.\"\"\"\n name = test_case.get('name', 'test')\n description = test_case.get('description', '')\n\n stub = f\"\"\"\ndescribe('{{Feature Name}}', () => {{\n it('{name}', () => {{\n // {description}\n\n // Arrange\n // TODO: Set up test data and dependencies\n\n // Act\n // TODO: Execute the code under test\n\n // Assert\n // TODO: Verify expected behavior\n expect(true).toBe(true); // Replace with actual assertion\n }});\n}});\n\"\"\"\n return stub.strip()\n\n def _generate_pytest_stub(self, test_case: Dict[str, Any]) -> str:\n \"\"\"Generate Pytest test stub.\"\"\"\n name = test_case.get('name', 'test')\n description = test_case.get('description', '')\n\n stub = f\"\"\"\ndef test_{name}():\n \\\"\\\"\\\"\n {description}\n \\\"\\\"\\\"\n # Arrange\n # TODO: Set up test data and dependencies\n\n # Act\n # TODO: Execute the code under test\n\n # Assert\n # TODO: Verify expected behavior\n assert True # Replace with actual assertion\n\"\"\"\n return stub.strip()\n\n def _generate_junit_stub(self, test_case: Dict[str, Any]) -> str:\n \"\"\"Generate JUnit test stub.\"\"\"\n name = test_case.get('name', 'test')\n description = test_case.get('description', '')\n\n # Convert snake_case to camelCase for Java\n method_name = ''.join(word.capitalize() if i > 0 else word\n for i, word in enumerate(name.split('_')))\n\n stub = f\"\"\"\n@Test\npublic void {method_name}() {{\n // {description}\n\n // Arrange\n // TODO: Set up test data and dependencies\n\n // Act\n // TODO: Execute the code under test\n\n // Assert\n // TODO: Verify expected behavior\n assertTrue(true); // Replace with actual assertion\n}}\n\"\"\"\n return stub.strip()\n\n def _generate_vitest_stub(self, test_case: Dict[str, Any]) -> str:\n \"\"\"Generate Vitest test stub (similar to Jest).\"\"\"\n name = test_case.get('name', 'test')\n description = test_case.get('description', '')\n\n stub = f\"\"\"\ndescribe('{{Feature Name}}', () => {{\n it('{name}', () => {{\n // {description}\n\n // Arrange\n // TODO: Set up test data and dependencies\n\n // Act\n // TODO: Execute the code under test\n\n // Assert\n // TODO: Verify expected behavior\n expect(true).toBe(true); // Replace with actual assertion\n }});\n}});\n\"\"\"\n return stub.strip()\n\n def _generate_generic_stub(self, test_case: Dict[str, Any]) -> str:\n \"\"\"Generate generic test stub.\"\"\"\n name = test_case.get('name', 'test')\n description = test_case.get('description', '')\n\n return f\"\"\"\n# Test: {name}\n# Description: {description}\n#\n# TODO: Implement test\n# 1. Arrange: Set up test data\n# 2. Act: Execute code under test\n# 3. Assert: Verify expected behavior\n\"\"\"\n\n def generate_test_file(\n self,\n module_name: str,\n test_cases: Optional[List[Dict[str, Any]]] = None\n ) -> str:\n \"\"\"\n Generate complete test file with all test stubs.\n\n Args:\n module_name: Name of module being tested\n test_cases: List of test cases (uses self.test_cases if not provided)\n\n Returns:\n Complete test file content\n \"\"\"\n cases = test_cases or self.test_cases\n\n if self.framework == TestFramework.JEST:\n return self._generate_jest_file(module_name, cases)\n elif self.framework == TestFramework.PYTEST:\n return self._generate_pytest_file(module_name, cases)\n elif self.framework == TestFramework.JUNIT:\n return self._generate_junit_file(module_name, cases)\n elif self.framework == TestFramework.VITEST:\n return self._generate_vitest_file(module_name, cases)\n else:\n return \"\"\n\n def _generate_jest_file(self, module_name: str, test_cases: List[Dict[str, Any]]) -> str:\n \"\"\"Generate complete Jest test file.\"\"\"\n imports = f\"import {{ {module_name} }} from '../{module_name}';\\n\\n\"\n\n stubs = []\n for test_case in test_cases:\n stubs.append(self._generate_jest_stub(test_case))\n\n return imports + \"\\n\\n\".join(stubs)\n\n def _generate_pytest_file(self, module_name: str, test_cases: List[Dict[str, Any]]) -> str:\n \"\"\"Generate complete Pytest test file.\"\"\"\n imports = f\"import pytest\\nfrom {module_name} import *\\n\\n\\n\"\n\n stubs = []\n for test_case in test_cases:\n stubs.append(self._generate_pytest_stub(test_case))\n\n return imports + \"\\n\\n\\n\".join(stubs)\n\n def _generate_junit_file(self, module_name: str, test_cases: List[Dict[str, Any]]) -> str:\n \"\"\"Generate complete JUnit test file.\"\"\"\n class_name = ''.join(word.capitalize() for word in module_name.split('_'))\n\n imports = \"\"\"import org.junit.jupiter.api.Test;\nimport static org.junit.jupiter.api.Assertions.*;\n\n\"\"\"\n\n class_header = f\"public class {class_name}Test {{\\n\\n\"\n\n stubs = []\n for test_case in test_cases:\n stubs.append(self._generate_junit_stub(test_case))\n\n class_footer = \"\\n}\"\n\n return imports + class_header + \"\\n\\n\".join(stubs) + class_footer\n\n def _generate_vitest_file(self, module_name: str, test_cases: List[Dict[str, Any]]) -> str:\n \"\"\"Generate complete Vitest test file.\"\"\"\n imports = f\"import {{ describe, it, expect }} from 'vitest';\\nimport {{ {module_name} }} from '../{module_name}';\\n\\n\"\n\n stubs = []\n for test_case in test_cases:\n stubs.append(self._generate_vitest_stub(test_case))\n\n return imports + \"\\n\\n\".join(stubs)\n\n def suggest_missing_scenarios(\n self,\n existing_tests: List[str],\n code_analysis: Dict[str, Any]\n ) -> List[Dict[str, Any]]:\n \"\"\"\n Suggest missing test scenarios based on code analysis.\n\n Args:\n existing_tests: List of existing test names\n code_analysis: Analysis of code under test (branches, error paths, etc.)\n\n Returns:\n List of suggested test scenarios\n \"\"\"\n suggestions = []\n\n # Check for untested error conditions\n if 'error_handlers' in code_analysis:\n for error_handler in code_analysis['error_handlers']:\n error_name = error_handler.get('type', 'error')\n if not self._has_test_for(existing_tests, error_name):\n suggestions.append({\n 'name': f\"should_handle_{error_name}\",\n 'type': 'error_case',\n 'reason': 'Error handler exists but no corresponding test',\n 'priority': 'P0'\n })\n\n # Check for untested branches\n if 'conditional_branches' in code_analysis:\n for branch in code_analysis['conditional_branches']:\n branch_name = branch.get('condition', 'condition')\n if not self._has_test_for(existing_tests, branch_name):\n suggestions.append({\n 'name': f\"should_test_{branch_name}_branch\",\n 'type': 'branch_coverage',\n 'reason': 'Conditional branch not fully tested',\n 'priority': 'P1'\n })\n\n # Check for boundary conditions\n if 'input_validation' in code_analysis:\n for validation in code_analysis['input_validation']:\n param = validation.get('parameter', 'input')\n if not self._has_test_for(existing_tests, f\"{param}_boundary\"):\n suggestions.append({\n 'name': f\"should_test_{param}_boundary_values\",\n 'type': 'boundary',\n 'reason': 'Input validation exists but boundary tests missing',\n 'priority': 'P1'\n })\n\n return suggestions\n\n def _has_test_for(self, existing_tests: List[str], keyword: str) -> bool:\n \"\"\"Check if existing tests cover a keyword/scenario.\"\"\"\n keyword_lower = keyword.lower().replace('_', '').replace('-', '')\n for test in existing_tests:\n test_lower = test.lower().replace('_', '').replace('-', '')\n if keyword_lower in test_lower:\n return True\n return False\n","content_type":"text/x-python; charset=utf-8","language":"python","size":14617,"content_sha256":"6ec26f0f29339ab23f0ff65fd140eaec143751759c7ddf360ada988059959346"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"TDD Guide","type":"text"}]},{"type":"paragraph","content":[{"text":"Test-driven development skill for generating tests, analyzing coverage, and guiding red-green-refactor workflows across Jest, Pytest, JUnit, and Vitest.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflows","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Generate Tests from Code","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Provide source code (TypeScript, JavaScript, Python, Java)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Specify target framework (Jest, Pytest, JUnit, Vitest)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"test_generator.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" with requirements","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Review generated test stubs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation:","type":"text","marks":[{"type":"strong"}]},{"text":" Tests compile and cover happy path, error cases, edge cases","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Analyze Coverage Gaps","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generate coverage report from test runner (","type":"text"},{"text":"npm test -- --coverage","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"coverage_analyzer.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" on LCOV/JSON/XML report","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Review prioritized gaps (P0/P1/P2)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generate missing tests for uncovered paths","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation:","type":"text","marks":[{"type":"strong"}]},{"text":" Coverage meets target threshold (typically 80%+)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"TDD New Feature","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Write failing test first (RED)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"tdd_workflow.py --phase red","type":"text","marks":[{"type":"code_inline"}]},{"text":" to validate","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement minimal code to pass (GREEN)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"tdd_workflow.py --phase green","type":"text","marks":[{"type":"code_inline"}]},{"text":" to validate","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Refactor while keeping tests green (REFACTOR)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Validation:","type":"text","marks":[{"type":"strong"}]},{"text":" All tests pass after each cycle","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Examples","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Test Generation — Input → Output (Pytest)","type":"text"}]},{"type":"paragraph","content":[{"text":"Input source function (","type":"text","marks":[{"type":"strong"}]},{"text":"math_utils.py","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":"):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"def divide(a: float, b: float) -> float:\n if b == 0:\n raise ValueError(\"Cannot divide by zero\")\n return a / b","type":"text"}]},{"type":"paragraph","content":[{"text":"Command:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python scripts/test_generator.py --input math_utils.py --framework pytest","type":"text"}]},{"type":"paragraph","content":[{"text":"Generated test output (","type":"text","marks":[{"type":"strong"}]},{"text":"test_math_utils.py","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":"):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"import pytest\nfrom math_utils import divide\n\nclass TestDivide:\n def test_divide_positive_numbers(self):\n assert divide(10, 2) == 5.0\n\n def test_divide_negative_numerator(self):\n assert divide(-10, 2) == -5.0\n\n def test_divide_float_result(self):\n assert divide(1, 3) == pytest.approx(0.333, rel=1e-3)\n\n def test_divide_by_zero_raises_value_error(self):\n with pytest.raises(ValueError, match=\"Cannot divide by zero\"):\n divide(10, 0)\n\n def test_divide_zero_numerator(self):\n assert divide(0, 5) == 0.0","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":3},"content":[{"text":"Coverage Analysis — Sample P0/P1/P2 Output","type":"text"}]},{"type":"paragraph","content":[{"text":"Command:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python scripts/coverage_analyzer.py --report lcov.info --threshold 80","type":"text"}]},{"type":"paragraph","content":[{"text":"Sample output:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Coverage Report — Overall: 63% (threshold: 80%)\n\nP0 — Critical gaps (uncovered error paths):\n auth/login.py:42-58 handle_expired_token() 0% covered\n payments/process.py:91-110 handle_payment_failure() 0% covered\n\nP1 — High-value gaps (core logic branches):\n users/service.py:77 update_profile() — else branch 0% covered\n orders/cart.py:134 apply_discount() — zero-qty guard 0% covered\n\nP2 — Low-risk gaps (utility / helper functions):\n utils/formatting.py:12 format_currency() 0% covered\n\nRecommended: Generate tests for P0 items first to reach 80% threshold.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Key Tools","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Purpose","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Usage","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"test_generator.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Generate test cases from code/requirements","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"python scripts/test_generator.py --input source.py --framework pytest","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"coverage_analyzer.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Parse and analyze coverage reports","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"python scripts/coverage_analyzer.py --report lcov.info --threshold 80","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tdd_workflow.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Guide red-green-refactor cycles","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"python scripts/tdd_workflow.py --phase red --test test_auth.py","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fixture_generator.py","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Generate test data and mocks","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"python scripts/fixture_generator.py --entity User --count 5","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Additional scripts: ","type":"text"},{"text":"framework_adapter.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" (convert between frameworks), ","type":"text"},{"text":"metrics_calculator.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" (quality metrics), ","type":"text"},{"text":"format_detector.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" (detect language/framework), ","type":"text"},{"text":"output_formatter.py","type":"text","marks":[{"type":"code_inline"}]},{"text":" (CLI/desktop/CI output).","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Input Requirements","type":"text"}]},{"type":"paragraph","content":[{"text":"For Test Generation:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Source code (file path or pasted content)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Target framework (Jest, Pytest, JUnit, Vitest)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Coverage scope (unit, integration, edge cases)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"For Coverage Analysis:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Coverage report file (LCOV, JSON, or XML format)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Optional: Source code for context","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Optional: Target threshold percentage","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"For TDD Workflow:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Feature requirements or user story","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Current phase (RED, GREEN, REFACTOR)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test code and implementation status","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Spec-First Workflow","type":"text"}]},{"type":"paragraph","content":[{"text":"TDD is most effective when driven by a written spec. The flow:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Write or receive a spec","type":"text","marks":[{"type":"strong"}]},{"text":" — stored in ","type":"text"},{"text":"specs/\u003cfeature>.md","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Extract acceptance criteria","type":"text","marks":[{"type":"strong"}]},{"text":" — each criterion becomes one or more test cases","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Write failing tests (RED)","type":"text","marks":[{"type":"strong"}]},{"text":" — one test per acceptance criterion","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Implement minimal code (GREEN)","type":"text","marks":[{"type":"strong"}]},{"text":" — satisfy each test in order","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Refactor","type":"text","marks":[{"type":"strong"}]},{"text":" — clean up while all tests stay green","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Spec Directory Convention","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"project/\n├── specs/\n│ ├── user-auth.md # Feature spec with acceptance criteria\n│ ├── payment-processing.md\n│ └── notification-system.md\n├── tests/\n│ ├── test_user_auth.py # Tests derived from specs/user-auth.md\n│ ├── test_payments.py\n│ └── test_notifications.py\n└── src/","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Extracting Tests from Specs","type":"text"}]},{"type":"paragraph","content":[{"text":"Each acceptance criterion in a spec maps to at least one test:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Spec Criterion","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Test Case","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"User can log in with valid credentials\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"test_login_valid_credentials_returns_token","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"Invalid password returns 401\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"test_login_invalid_password_returns_401","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"\"Account locks after 5 failed attempts\"","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"test_login_locks_after_five_failures","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Tip:","type":"text","marks":[{"type":"strong"}]},{"text":" Number your acceptance criteria in the spec. Reference the number in the test docstring for traceability (","type":"text"},{"text":"# AC-3: Account locks after 5 failed attempts","type":"text","marks":[{"type":"code_inline"}]},{"text":").","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"Cross-reference:","type":"text","marks":[{"type":"strong"}]},{"text":" See ","type":"text"},{"text":"engineering/spec-driven-workflow","type":"text","marks":[{"type":"code_inline"}]},{"text":" for the full spec methodology, including spec templates and review checklists.","type":"text"}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Red-Green-Refactor Examples Per Language","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"TypeScript / Jest","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"// test/cart.test.ts\ndescribe(\"Cart\", () => {\n describe(\"addItem\", () => {\n it(\"should add a new item to an empty cart\", () => {\n const cart = new Cart();\n cart.addItem({ id: \"sku-1\", name: \"Widget\", price: 9.99, qty: 1 });\n\n expect(cart.items).toHaveLength(1);\n expect(cart.items[0].id).toBe(\"sku-1\");\n });\n\n it(\"should increment quantity when adding an existing item\", () => {\n const cart = new Cart();\n cart.addItem({ id: \"sku-1\", name: \"Widget\", price: 9.99, qty: 1 });\n cart.addItem({ id: \"sku-1\", name: \"Widget\", price: 9.99, qty: 2 });\n\n expect(cart.items).toHaveLength(1);\n expect(cart.items[0].qty).toBe(3);\n });\n\n it(\"should throw when quantity is zero or negative\", () => {\n const cart = new Cart();\n expect(() =>\n cart.addItem({ id: \"sku-1\", name: \"Widget\", price: 9.99, qty: 0 })\n ).toThrow(\"Quantity must be positive\");\n });\n });\n});","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Python / Pytest (Advanced Patterns)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"# tests/conftest.py — shared fixtures\nimport pytest\nfrom app.db import create_engine, Session\n\[email protected](scope=\"session\")\ndef db_engine():\n engine = create_engine(\"sqlite:///:memory:\")\n yield engine\n engine.dispose()\n\[email protected]\ndef db_session(db_engine):\n session = Session(bind=db_engine)\n yield session\n session.rollback()\n session.close()\n\n# tests/test_pricing.py — parametrize for multiple cases\nimport pytest\nfrom app.pricing import calculate_discount\n\[email protected](\"subtotal, expected_discount\", [\n (50.0, 0.0), # Below threshold — no discount\n (100.0, 5.0), # 5% tier\n (250.0, 25.0), # 10% tier\n (500.0, 75.0), # 15% tier\n])\ndef test_calculate_discount(subtotal, expected_discount):\n assert calculate_discount(subtotal) == pytest.approx(expected_discount)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Go — Table-Driven Tests","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"go"},"content":[{"text":"// cart_test.go\npackage cart\n\nimport \"testing\"\n\nfunc TestApplyDiscount(t *testing.T) {\n tests := []struct {\n name string\n subtotal float64\n want float64\n }{\n {\"no discount below threshold\", 50.0, 0.0},\n {\"5 percent tier\", 100.0, 5.0},\n {\"10 percent tier\", 250.0, 25.0},\n {\"15 percent tier\", 500.0, 75.0},\n {\"zero subtotal\", 0.0, 0.0},\n }\n\n for _, tt := range tests {\n t.Run(tt.name, func(t *testing.T) {\n got := ApplyDiscount(tt.subtotal)\n if got != tt.want {\n t.Errorf(\"ApplyDiscount(%v) = %v, want %v\", tt.subtotal, got, tt.want)\n }\n })\n }\n}","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Bounded Autonomy Rules","type":"text"}]},{"type":"paragraph","content":[{"text":"When generating tests autonomously, follow these rules to decide when to stop and ask the user:","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Stop and Ask When","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ambiguous requirements","type":"text","marks":[{"type":"strong"}]},{"text":" — the spec or user story has conflicting or unclear acceptance criteria","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Missing edge cases","type":"text","marks":[{"type":"strong"}]},{"text":" — you cannot determine boundary values without domain knowledge (e.g., max allowed transaction amount)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test count exceeds 50","type":"text","marks":[{"type":"strong"}]},{"text":" — large test suites need human review before committing; present a summary and ask which areas to prioritize","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"External dependencies unclear","type":"text","marks":[{"type":"strong"}]},{"text":" — the feature relies on third-party APIs or services with undocumented behavior","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Security-sensitive logic","type":"text","marks":[{"type":"strong"}]},{"text":" — authentication, authorization, encryption, or payment flows require human sign-off on test scenarios","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Continue Autonomously When","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear spec with numbered acceptance criteria","type":"text","marks":[{"type":"strong"}]},{"text":" — each criterion maps directly to tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Straightforward CRUD operations","type":"text","marks":[{"type":"strong"}]},{"text":" — create, read, update, delete with well-defined models","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Well-defined API contracts","type":"text","marks":[{"type":"strong"}]},{"text":" — OpenAPI spec or typed interfaces available","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pure functions","type":"text","marks":[{"type":"strong"}]},{"text":" — deterministic input/output with no side effects","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Existing test patterns","type":"text","marks":[{"type":"strong"}]},{"text":" — the codebase already has similar tests to follow","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Property-Based Testing","type":"text"}]},{"type":"paragraph","content":[{"text":"Property-based testing generates random inputs to verify invariants instead of relying on hand-picked examples. Use it when the input space is large and the expected behavior can be described as a property.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Python — Hypothesis","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"python"},"content":[{"text":"from hypothesis import given, strategies as st\nfrom app.serializers import serialize, deserialize\n\n@given(st.text())\ndef test_roundtrip_serialization(data):\n \"\"\"Serialization followed by deserialization returns the original.\"\"\"\n assert deserialize(serialize(data)) == data\n\n@given(st.integers(), st.integers())\ndef test_addition_is_commutative(a, b):\n assert a + b == b + a","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"TypeScript — fast-check","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"import fc from \"fast-check\";\nimport { encode, decode } from \"./codec\";\n\ntest(\"encode/decode roundtrip\", () => {\n fc.assert(\n fc.property(fc.string(), (input) => {\n expect(decode(encode(input))).toBe(input);\n })\n );\n});","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"When to Use Property-Based Over Example-Based","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Property-Based","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Example","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Data transformations","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Serialize/deserialize roundtrips","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mathematical properties","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Commutativity, associativity, idempotency","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Encoding/decoding","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Base64, URL encoding, compression","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sorting and filtering","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Output is sorted, length preserved","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Parser correctness","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Valid input always parses without error","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Mutation Testing","type":"text"}]},{"type":"paragraph","content":[{"text":"Mutation testing modifies your production code (creates \"mutants\") and checks whether your tests catch the changes. If a mutant survives (tests still pass), your tests have a gap that coverage alone cannot reveal.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Tools","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Language","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Command","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"TypeScript/JavaScript","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Stryker","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"npx stryker run","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Python","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"mutmut","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"mutmut run --paths-to-mutate=src/","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Java","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"PIT","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"mvn org.pitest:pitest-maven:mutationCoverage","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Why Mutation Testing Matters","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"100% line coverage != good tests","type":"text","marks":[{"type":"strong"}]},{"text":" — coverage tells you code was executed, not that it was verified","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Catches weak assertions","type":"text","marks":[{"type":"strong"}]},{"text":" — tests that run code but assert nothing meaningful","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Finds missing boundary tests","type":"text","marks":[{"type":"strong"}]},{"text":" — mutants that change ","type":"text"},{"text":"\u003c","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"\u003c=","type":"text","marks":[{"type":"code_inline"}]},{"text":" expose off-by-one gaps","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quantifiable quality metric","type":"text","marks":[{"type":"strong"}]},{"text":" — mutation score (% mutants killed) is a stronger signal than coverage %","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Recommendation:","type":"text","marks":[{"type":"strong"}]},{"text":" Run mutation testing on critical paths (auth, payments, data processing) even if overall coverage is high. Target 85%+ mutation score on P0 modules.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Cross-References","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Skill","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Relationship","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"engineering/spec-driven-workflow","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Spec → acceptance criteria → test extraction pipeline","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"engineering-team/focused-fix","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Phase 5 (Verify) uses TDD to confirm the fix with a regression test","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"engineering-team/senior-qa","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Broader QA strategy; TDD is one layer in the test pyramid","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"engineering-team/code-reviewer","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Review generated tests for assertion quality and coverage completeness","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"engineering-team/senior-fullstack","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Project scaffolders include testing infrastructure compatible with TDD workflows","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"Limitations","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Scope","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Details","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Unit test focus","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Integration and E2E tests require different patterns","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Static analysis","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cannot execute tests or measure runtime behavior","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Language support","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best for TypeScript, JavaScript, Python, Java","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Report formats","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"LCOV, JSON, XML only; other formats need conversion","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Generated tests","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Provide scaffolding; require human review for complex logic","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"When to use other tools:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"E2E testing: Playwright, Cypress, Selenium","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Performance testing: k6, JMeter, Locust","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Security testing: OWASP ZAP, Burp Suite","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"More in this skill","type":"text"}]},{"type":"paragraph","content":[{"text":"Load these only when the task needs them.","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/ci-integration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/ci-integration.md","title":null}}]},{"text":" — CI/CD Integration Guide","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/framework-guide.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/framework-guide.md","title":null}}]},{"text":" — Testing Framework Guide","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/tdd-best-practices.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/tdd-best-practices.md","title":null}}]},{"text":" — TDD Best Practices","type":"text"}]}]}]}]},"metadata":{"date":"2026-11-02","name":"tdd-guide","author":"@skillopedia","source":{"stars":29164,"repo_name":"claude-skills","origin_url":"https://github.com/alirezarezvani/claude-skills/blob/HEAD/engineering-team/skills/tdd-guide/SKILL.md","repo_owner":"alirezarezvani","body_sha256":"f702941af49fd8b657b7288c700ecb768cf459f8457fecc468780aaacfa419a0","cluster_key":"b528844ae783f2f56c0c442c1e06e81379675eaf1d5ac3e668efdaa6ff6792d8","clean_bundle":{"format":"clean-skill-bundle-v1","source":"alirezarezvani/claude-skills/engineering-team/skills/tdd-guide/SKILL.md","text_bytes":159518,"source_commit":"9ef0c3c213932e645cc5cbeeb3c35c3a762a2437","skills_sh_rank":12893,"attachment_count":16,"text_attachments":16,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"engineering-team/skills/tdd-guide/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"testing-qa","category_label":"Testing"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"testing-qa","import_tag":"skills-sh-top20k-2026-11","description":"Use when writing tests first, generating tests, fixtures or mocks, or closing coverage gaps in Jest, Pytest, JUnit, Vitest or Mocha. Drives red-green-refactor with tdd_workflow.py, generates tests with test_generator.py and reads coverage with coverage_analyzer.py."}},"renderedAt":1793666256075}

TDD Guide Test-driven development skill for generating tests, analyzing coverage, and guiding red-green-refactor workflows across Jest, Pytest, JUnit, and Vitest. --- Workflows Generate Tests from Code 1. Provide source code (TypeScript, JavaScript, Python, Java) 2. Specify target framework (Jest, Pytest, JUnit, Vitest) 3. Run with requirements 4. Review generated test stubs 5. Validation: Tests compile and cover happy path, error cases, edge cases Analyze Coverage Gaps 1. Generate coverage report from test runner ( ) 2. Run on LCOV/JSON/XML report 3. Review prioritized gaps (P0/P1/P2) 4. Gen…