Files
skill-seekers-reference/tests/test_cli_refactor_e2e.py
yusyus 064405c052 fix: resolve 18 bugs and code quality issues across adaptors, CLI, and chunking pipeline
Bug fixes:
- Fix --var flag silently dropped in create routing (args.workflow_var → args.var)
- Fix double _score_code_quality() call in word scraper
- Add .docx file extension validation in WordToSkillConverter
- Fix weaviate ImportError masked by generic Exception handler
- Fix RAG chunking crash using non-existent converter.output_dir

Chunking pipeline improvements:
- Wire --chunk-overlap-tokens through entire package pipeline
  (package_skill → adaptor.package → format_skill_md → _maybe_chunk_content → RAGChunker)
- Add auto-scaling overlap: max(50, chunk_tokens//10) when chunk size is non-default
- Rename --no-preserve-code to --no-preserve-code-blocks (backward-compat alias kept)
- Replace hardcoded 512/50 chunk defaults with DEFAULT_CHUNK_TOKENS/DEFAULT_CHUNK_OVERLAP_TOKENS
  constants across all 12 concrete adaptors, rag_chunker, base, and package_skill

Code quality:
- Extract shared _generate_openai_embeddings() and _generate_st_embeddings() to SkillAdaptor
  base class, removing ~150 lines of duplication from chroma/weaviate/pinecone
- Add Pinecone adaptor with full upload support (pinecone_adaptor.py)

Tests (14 new):
- chunk_overlap_tokens parameter wiring, auto-scaling overlap, preserve_code_blocks flag
- .docx/.doc/no-extension file validation, --var flag routing E2E
- Embedding method inheritance verification, backward-compatible flag aliases

Docs:
- Update CHANGELOG, CLI_REFERENCE, API_REFERENCE, packaging guide (EN+ZH)
- Update README test count badge (1880+ → 2283+)

All 2283 tests passing, 8 skipped, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:57:59 +03:00

375 lines
14 KiB
Python

#!/usr/bin/env python3
"""
End-to-End Tests for CLI Refactor (Issues #285 and #268)
These tests verify that the unified CLI architecture works correctly:
1. Parser sync: All parsers use shared argument definitions
2. Preset system: Analyze command supports presets
3. Backward compatibility: Old flags still work with deprecation warnings
4. Integration: The complete flow from CLI to execution
"""
import pytest
import subprocess
import argparse
class TestParserSync:
"""E2E tests for parser synchronization (Issue #285)."""
def test_scrape_interactive_flag_works(self):
"""Test that --interactive flag (previously missing) now works."""
result = subprocess.run(
["skill-seekers", "scrape", "--interactive", "--help"], capture_output=True, text=True
)
assert result.returncode == 0, "Command should execute successfully"
assert "--interactive" in result.stdout, "Help should show --interactive flag"
assert "-i" in result.stdout, "Help should show short form -i"
def test_scrape_chunk_for_rag_flag_works(self):
"""Test that --chunk-for-rag flag (previously missing) now works."""
result = subprocess.run(
["skill-seekers", "scrape", "--help"], capture_output=True, text=True
)
assert "--chunk-for-rag" in result.stdout, "Help should show --chunk-for-rag flag"
assert "--chunk-tokens" in result.stdout, "Help should show --chunk-tokens flag"
assert "--chunk-overlap-tokens" in result.stdout, (
"Help should show --chunk-overlap-tokens flag"
)
def test_scrape_verbose_flag_works(self):
"""Test that --verbose flag (previously missing) now works."""
result = subprocess.run(
["skill-seekers", "scrape", "--help"], capture_output=True, text=True
)
assert "--verbose" in result.stdout, "Help should show --verbose flag"
assert "-v" in result.stdout, "Help should show short form -v"
def test_scrape_url_flag_works(self):
"""Test that --url flag (previously missing) now works."""
result = subprocess.run(
["skill-seekers", "scrape", "--help"], capture_output=True, text=True
)
assert "--url URL" in result.stdout, "Help should show --url flag"
def test_github_all_flags_present(self):
"""Test that github command has all expected flags."""
result = subprocess.run(
["skill-seekers", "github", "--help"], capture_output=True, text=True
)
# Key github flags that should be present
expected_flags = [
"--repo",
"--api-key",
"--profile",
"--non-interactive",
]
for flag in expected_flags:
assert flag in result.stdout, f"Help should show {flag} flag"
class TestPresetSystem:
"""E2E tests for preset system (Issue #268)."""
def test_analyze_preset_flag_exists(self):
"""Test that analyze command has --preset flag."""
result = subprocess.run(
["skill-seekers", "analyze", "--help"], capture_output=True, text=True
)
assert "--preset" in result.stdout, "Help should show --preset flag"
assert "quick" in result.stdout, "Help should mention 'quick' preset"
assert "standard" in result.stdout, "Help should mention 'standard' preset"
assert "comprehensive" in result.stdout, "Help should mention 'comprehensive' preset"
def test_analyze_preset_list_flag_exists(self):
"""Test that analyze command has --preset-list flag."""
result = subprocess.run(
["skill-seekers", "analyze", "--help"], capture_output=True, text=True
)
assert "--preset-list" in result.stdout, "Help should show --preset-list flag"
def test_preset_list_shows_presets(self):
"""Test that --preset-list shows all available presets."""
result = subprocess.run(
["skill-seekers", "analyze", "--preset-list"], capture_output=True, text=True
)
assert result.returncode == 0, "Command should execute successfully"
assert "Available presets" in result.stdout, "Should show preset list header"
assert "quick" in result.stdout, "Should show quick preset"
assert "standard" in result.stdout, "Should show standard preset"
assert "comprehensive" in result.stdout, "Should show comprehensive preset"
assert "1-2 minutes" in result.stdout, "Should show time estimates"
def test_deprecated_quick_flag_shows_warning(self, tmp_path):
"""Test that --quick flag shows deprecation warning."""
result = subprocess.run(
["skill-seekers", "analyze", "--directory", str(tmp_path), "--quick"],
capture_output=True,
text=True,
)
# Note: Deprecation warnings go to stderr or stdout
output = result.stdout + result.stderr
assert "DEPRECATED" in output, "Should show deprecation warning"
assert "--preset quick" in output, "Should suggest alternative"
def test_deprecated_comprehensive_flag_shows_warning(self, tmp_path):
"""Test that --comprehensive flag shows deprecation warning."""
result = subprocess.run(
["skill-seekers", "analyze", "--directory", str(tmp_path), "--comprehensive"],
capture_output=True,
text=True,
)
output = result.stdout + result.stderr
assert "DEPRECATED" in output, "Should show deprecation warning"
assert "--preset comprehensive" in output, "Should suggest alternative"
class TestBackwardCompatibility:
"""E2E tests for backward compatibility."""
def test_old_scrape_command_still_works(self):
"""Test that old scrape command invocations still work."""
result = subprocess.run(["skill-seekers-scrape", "--help"], capture_output=True, text=True)
assert result.returncode == 0, "Old command should still work"
assert "documentation" in result.stdout.lower(), "Help should mention documentation"
def test_unified_cli_and_standalone_have_same_args(self):
"""Test that unified CLI and standalone have identical arguments."""
# Get help from unified CLI
unified_result = subprocess.run(
["skill-seekers", "scrape", "--help"], capture_output=True, text=True
)
# Get help from standalone
standalone_result = subprocess.run(
["skill-seekers-scrape", "--help"], capture_output=True, text=True
)
# Both should have the same key flags
key_flags = [
"--interactive",
"--url",
"--verbose",
"--chunk-for-rag",
"--config",
"--max-pages",
]
for flag in key_flags:
assert flag in unified_result.stdout, f"Unified should have {flag}"
assert flag in standalone_result.stdout, f"Standalone should have {flag}"
class TestProgrammaticAPI:
"""Test that the shared argument functions work programmatically."""
def test_import_shared_scrape_arguments(self):
"""Test that shared scrape arguments can be imported."""
from skill_seekers.cli.arguments.scrape import add_scrape_arguments
parser = argparse.ArgumentParser()
add_scrape_arguments(parser)
# Verify key arguments were added
args_dict = vars(parser.parse_args(["https://example.com"]))
assert "url" in args_dict
def test_import_shared_github_arguments(self):
"""Test that shared github arguments can be imported."""
from skill_seekers.cli.arguments.github import add_github_arguments
parser = argparse.ArgumentParser()
add_github_arguments(parser)
# Parse with --repo flag
args = parser.parse_args(["--repo", "owner/repo"])
assert args.repo == "owner/repo"
def test_import_analyze_presets(self):
"""Test that analyze presets can be imported."""
from skill_seekers.cli.presets.analyze_presets import ANALYZE_PRESETS, AnalysisPreset
assert "quick" in ANALYZE_PRESETS
assert "standard" in ANALYZE_PRESETS
assert "comprehensive" in ANALYZE_PRESETS
# Verify preset structure
quick = ANALYZE_PRESETS["quick"]
assert isinstance(quick, AnalysisPreset)
assert quick.name == "Quick"
assert quick.depth == "surface"
# Note: enhance_level is not part of AnalysisPreset anymore.
# It's controlled separately via --enhance-level flag (default 2)
class TestIntegration:
"""Integration tests for the complete flow."""
def test_unified_cli_subcommands_registered(self):
"""Test that all subcommands are properly registered."""
result = subprocess.run(["skill-seekers", "--help"], capture_output=True, text=True)
# All major commands should be listed
expected_commands = [
"scrape",
"github",
"pdf",
"unified",
"analyze",
"enhance",
"package",
"upload",
]
for cmd in expected_commands:
assert cmd in result.stdout, f"Should list {cmd} command"
def test_scrape_help_detailed(self):
"""Test that scrape help shows all argument details."""
result = subprocess.run(
["skill-seekers", "scrape", "--help"], capture_output=True, text=True
)
# Check for argument categories
assert "url" in result.stdout.lower(), "Should show url argument"
assert "scraping options" in result.stdout.lower() or "options" in result.stdout.lower()
assert "enhancement" in result.stdout.lower(), "Should mention enhancement options"
def test_analyze_help_shows_presets(self):
"""Test that analyze help prominently shows preset information."""
result = subprocess.run(
["skill-seekers", "analyze", "--help"], capture_output=True, text=True
)
assert "--preset" in result.stdout, "Should show --preset flag"
assert "DEFAULT" in result.stdout or "default" in result.stdout, (
"Should indicate default preset"
)
class TestE2EWorkflow:
"""End-to-end workflow tests."""
@pytest.mark.slow
def test_dry_run_scrape_with_new_args(self, tmp_path):
"""Test scraping with previously missing arguments (dry run)."""
result = subprocess.run(
[
"skill-seekers",
"scrape",
"--url",
"https://example.com",
"--interactive",
"false", # Would fail if arg didn't exist
"--verbose", # Would fail if arg didn't exist
"--dry-run",
],
capture_output=True,
text=True,
timeout=10,
)
# Dry run should complete without errors
# (it may return non-zero if --interactive false isn't valid,
# but it shouldn't crash with "unrecognized arguments")
assert "unrecognized arguments" not in result.stderr.lower()
@pytest.mark.slow
def test_analyze_with_preset_flag(self, tmp_path):
"""Test analyze with preset flag (no dry-run available)."""
# Create a dummy directory to analyze
test_dir = tmp_path / "test_code"
test_dir.mkdir()
(test_dir / "test.py").write_text("def hello(): pass")
# Just verify the flag is recognized (no execution)
result = subprocess.run(
["skill-seekers", "analyze", "--help"],
capture_output=True,
text=True,
)
# Verify preset flag exists
assert "--preset" in result.stdout, "Should have --preset flag"
assert "unrecognized arguments" not in result.stderr.lower()
class TestVarFlagRouting:
"""Test that --var flag is correctly routed through create command."""
def test_var_flag_accepted_by_create(self):
"""Test that --var flag is accepted (not 'unrecognized') by create command."""
result = subprocess.run(
["skill-seekers", "create", "--help"],
capture_output=True,
text=True,
)
assert "--var" in result.stdout, "create --help should show --var flag"
def test_var_flag_accepted_by_analyze(self):
"""Test that --var flag is accepted by analyze command."""
result = subprocess.run(
["skill-seekers", "analyze", "--help"],
capture_output=True,
text=True,
)
assert "--var" in result.stdout, "analyze --help should show --var flag"
@pytest.mark.slow
def test_var_flag_not_rejected_in_create_local(self, tmp_path):
"""Test --var KEY=VALUE doesn't cause 'unrecognized arguments' in create."""
test_dir = tmp_path / "test_code"
test_dir.mkdir()
(test_dir / "test.py").write_text("def hello(): pass")
result = subprocess.run(
[
"skill-seekers", "create", str(test_dir),
"--var", "foo=bar",
"--dry-run",
],
capture_output=True,
text=True,
timeout=15,
)
assert "unrecognized arguments" not in result.stderr.lower(), (
f"--var should be accepted, got stderr: {result.stderr}"
)
class TestBackwardCompatibleFlags:
"""Test that deprecated flag aliases still work."""
def test_no_preserve_code_alias_accepted_by_package(self):
"""Test --no-preserve-code (old name) is still accepted by package command."""
result = subprocess.run(
["skill-seekers", "package", "--help"],
capture_output=True,
text=True,
)
# The old flag should not appear in --help (it's suppressed)
# but should not cause an error if used
assert result.returncode == 0
def test_no_preserve_code_alias_accepted_by_scrape(self):
"""Test --no-preserve-code (old name) is still accepted by scrape command."""
result = subprocess.run(
["skill-seekers", "scrape", "--help"],
capture_output=True,
text=True,
)
assert result.returncode == 0
def test_no_preserve_code_alias_accepted_by_create(self):
"""Test --no-preserve-code (old name) is still accepted by create command."""
result = subprocess.run(
["skill-seekers", "create", "--help-all"],
capture_output=True,
text=True,
)
assert result.returncode == 0
if __name__ == "__main__":
pytest.main([__file__, "-v", "-s"])