Initial commit
This commit is contained in:
1
skills/web-frameworks/scripts/tests/coverage-web.json
Normal file
1
skills/web-frameworks/scripts/tests/coverage-web.json
Normal file
File diff suppressed because one or more lines are too long
3
skills/web-frameworks/scripts/tests/requirements.txt
Normal file
3
skills/web-frameworks/scripts/tests/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
pytest>=7.0.0
|
||||
pytest-cov>=4.0.0
|
||||
pytest-mock>=3.10.0
|
||||
319
skills/web-frameworks/scripts/tests/test_nextjs_init.py
Normal file
319
skills/web-frameworks/scripts/tests/test_nextjs_init.py
Normal file
@@ -0,0 +1,319 @@
|
||||
"""Tests for nextjs-init.py script."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
# Add parent directory to path to import the script
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from nextjs_init import NextJSInitializer
|
||||
|
||||
|
||||
class TestNextJSInitializer:
|
||||
"""Test suite for NextJSInitializer."""
|
||||
|
||||
def test_init_with_defaults(self, tmp_path):
|
||||
"""Test initialization with default parameters."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app"
|
||||
)
|
||||
|
||||
assert initializer.name == "test-app"
|
||||
assert initializer.typescript is True
|
||||
assert initializer.app_router is True
|
||||
assert initializer.src_dir is False
|
||||
assert initializer.tailwind is False
|
||||
assert initializer.eslint is True
|
||||
|
||||
def test_validate_name_valid(self, tmp_path):
|
||||
"""Test name validation with valid names."""
|
||||
valid_names = ["my-app", "my_app", "myapp123", "test-app-1"]
|
||||
|
||||
for name in valid_names:
|
||||
initializer = NextJSInitializer(
|
||||
name=name,
|
||||
directory=tmp_path / name
|
||||
)
|
||||
initializer.validate_name() # Should not raise
|
||||
|
||||
def test_validate_name_invalid(self, tmp_path):
|
||||
"""Test name validation with invalid names."""
|
||||
invalid_cases = [
|
||||
("", ValueError, "empty"),
|
||||
("123app", ValueError, "starts with number"),
|
||||
("my app", ValueError, "contains space"),
|
||||
("my@app", ValueError, "contains special char"),
|
||||
]
|
||||
|
||||
for name, expected_error, reason in invalid_cases:
|
||||
initializer = NextJSInitializer(
|
||||
name=name,
|
||||
directory=tmp_path / (name or "empty")
|
||||
)
|
||||
|
||||
with pytest.raises(expected_error):
|
||||
initializer.validate_name()
|
||||
|
||||
def test_check_directory_exists(self, tmp_path):
|
||||
"""Test directory existence check."""
|
||||
existing_dir = tmp_path / "existing"
|
||||
existing_dir.mkdir()
|
||||
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=existing_dir
|
||||
)
|
||||
|
||||
with pytest.raises(FileExistsError):
|
||||
initializer.check_directory()
|
||||
|
||||
def test_create_directory_structure_app_router(self, tmp_path):
|
||||
"""Test directory structure creation with App Router."""
|
||||
project_dir = tmp_path / "test-app"
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=project_dir,
|
||||
app_router=True
|
||||
)
|
||||
|
||||
initializer.create_directory_structure()
|
||||
|
||||
# Check directories
|
||||
assert (project_dir / "app").exists()
|
||||
assert (project_dir / "public").exists()
|
||||
assert (project_dir / "components").exists()
|
||||
assert (project_dir / "lib").exists()
|
||||
|
||||
# Check App Router files
|
||||
assert (project_dir / "app" / "layout.tsx").exists()
|
||||
assert (project_dir / "app" / "page.tsx").exists()
|
||||
assert (project_dir / "app" / "globals.css").exists()
|
||||
|
||||
def test_create_directory_structure_with_src(self, tmp_path):
|
||||
"""Test directory structure with src/ directory."""
|
||||
project_dir = tmp_path / "test-app"
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=project_dir,
|
||||
src_dir=True
|
||||
)
|
||||
|
||||
initializer.create_directory_structure()
|
||||
|
||||
# Check src structure
|
||||
assert (project_dir / "src" / "app").exists()
|
||||
assert (project_dir / "src" / "components").exists()
|
||||
assert (project_dir / "src" / "lib").exists()
|
||||
|
||||
def test_package_json_generation(self, tmp_path):
|
||||
"""Test package.json generation."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app",
|
||||
typescript=True,
|
||||
tailwind=True,
|
||||
eslint=True
|
||||
)
|
||||
|
||||
package_json = initializer._get_package_json()
|
||||
|
||||
assert package_json["name"] == "test-app"
|
||||
assert package_json["version"] == "0.1.0"
|
||||
assert package_json["private"] is True
|
||||
|
||||
# Check scripts
|
||||
assert "dev" in package_json["scripts"]
|
||||
assert "build" in package_json["scripts"]
|
||||
assert "start" in package_json["scripts"]
|
||||
assert "lint" in package_json["scripts"]
|
||||
|
||||
# Check dependencies
|
||||
assert "next" in package_json["dependencies"]
|
||||
assert "react" in package_json["dependencies"]
|
||||
assert "react-dom" in package_json["dependencies"]
|
||||
|
||||
# Check TypeScript dependencies
|
||||
assert "typescript" in package_json["devDependencies"]
|
||||
assert "@types/node" in package_json["devDependencies"]
|
||||
assert "@types/react" in package_json["devDependencies"]
|
||||
|
||||
# Check Tailwind dependencies
|
||||
assert "tailwindcss" in package_json["dependencies"]
|
||||
|
||||
# Check ESLint dependencies
|
||||
assert "eslint" in package_json["devDependencies"]
|
||||
|
||||
def test_tsconfig_generation(self, tmp_path):
|
||||
"""Test tsconfig.json generation."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app",
|
||||
typescript=True,
|
||||
import_alias="@/*"
|
||||
)
|
||||
|
||||
tsconfig = initializer._get_tsconfig()
|
||||
|
||||
assert "compilerOptions" in tsconfig
|
||||
assert tsconfig["compilerOptions"]["strict"] is True
|
||||
assert tsconfig["compilerOptions"]["jsx"] == "preserve"
|
||||
assert "@/*" in tsconfig["compilerOptions"]["paths"]
|
||||
assert "next-env.d.ts" in tsconfig["include"]
|
||||
|
||||
def test_layout_content_typescript(self, tmp_path):
|
||||
"""Test layout.tsx content generation."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app",
|
||||
typescript=True
|
||||
)
|
||||
|
||||
content = initializer._get_layout_content()
|
||||
|
||||
assert "import './globals.css'" in content
|
||||
assert "export const metadata" in content
|
||||
assert "children: React.ReactNode" in content
|
||||
assert "<html lang=\"en\">" in content
|
||||
|
||||
def test_layout_content_javascript(self, tmp_path):
|
||||
"""Test layout.jsx content generation."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app",
|
||||
typescript=False
|
||||
)
|
||||
|
||||
content = initializer._get_layout_content()
|
||||
|
||||
assert "import './globals.css'" in content
|
||||
assert "export const metadata" in content
|
||||
assert "React.ReactNode" not in content # No TypeScript types
|
||||
|
||||
def test_tailwind_config_typescript(self, tmp_path):
|
||||
"""Test Tailwind config generation with TypeScript."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app",
|
||||
typescript=True,
|
||||
tailwind=True
|
||||
)
|
||||
|
||||
config = initializer._get_tailwind_config()
|
||||
|
||||
assert "import type { Config }" in config
|
||||
assert "const config: Config" in config
|
||||
assert "content:" in config
|
||||
|
||||
def test_tailwind_config_javascript(self, tmp_path):
|
||||
"""Test Tailwind config generation with JavaScript."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app",
|
||||
typescript=False,
|
||||
tailwind=True
|
||||
)
|
||||
|
||||
config = initializer._get_tailwind_config()
|
||||
|
||||
assert "module.exports" in config
|
||||
assert "content:" in config
|
||||
|
||||
def test_gitignore_generation(self, tmp_path):
|
||||
"""Test .gitignore generation."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app"
|
||||
)
|
||||
|
||||
gitignore = initializer._get_gitignore()
|
||||
|
||||
assert "/node_modules" in gitignore
|
||||
assert "/.next/" in gitignore
|
||||
assert ".env*.local" in gitignore
|
||||
assert ".DS_Store" in gitignore
|
||||
|
||||
def test_readme_generation(self, tmp_path):
|
||||
"""Test README.md generation."""
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=tmp_path / "test-app"
|
||||
)
|
||||
|
||||
readme = initializer._get_readme()
|
||||
|
||||
assert "# test-app" in readme
|
||||
assert "Next.js" in readme
|
||||
assert "npm run dev" in readme
|
||||
|
||||
def test_create_config_files(self, tmp_path):
|
||||
"""Test configuration files creation."""
|
||||
project_dir = tmp_path / "test-app"
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=project_dir,
|
||||
typescript=True,
|
||||
tailwind=True,
|
||||
eslint=True
|
||||
)
|
||||
|
||||
initializer.create_directory_structure()
|
||||
initializer.create_config_files()
|
||||
|
||||
# Check all config files exist
|
||||
assert (project_dir / "package.json").exists()
|
||||
assert (project_dir / "next.config.js").exists()
|
||||
assert (project_dir / "tsconfig.json").exists()
|
||||
assert (project_dir / ".eslintrc.json").exists()
|
||||
assert (project_dir / "tailwind.config.ts").exists()
|
||||
assert (project_dir / "postcss.config.js").exists()
|
||||
assert (project_dir / ".gitignore").exists()
|
||||
assert (project_dir / "README.md").exists()
|
||||
|
||||
# Verify package.json is valid JSON
|
||||
with open(project_dir / "package.json") as f:
|
||||
package_json = json.load(f)
|
||||
assert package_json["name"] == "test-app"
|
||||
|
||||
def test_full_initialization(self, tmp_path):
|
||||
"""Test full initialization process."""
|
||||
project_dir = tmp_path / "test-app"
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=project_dir,
|
||||
typescript=True,
|
||||
app_router=True,
|
||||
tailwind=True
|
||||
)
|
||||
|
||||
initializer.initialize()
|
||||
|
||||
# Verify directory exists
|
||||
assert project_dir.exists()
|
||||
|
||||
# Verify structure
|
||||
assert (project_dir / "app").exists()
|
||||
assert (project_dir / "public").exists()
|
||||
|
||||
# Verify config files
|
||||
assert (project_dir / "package.json").exists()
|
||||
assert (project_dir / "tsconfig.json").exists()
|
||||
assert (project_dir / "next.config.js").exists()
|
||||
|
||||
def test_pages_router_structure(self, tmp_path):
|
||||
"""Test Pages Router directory structure."""
|
||||
project_dir = tmp_path / "test-app"
|
||||
initializer = NextJSInitializer(
|
||||
name="test-app",
|
||||
directory=project_dir,
|
||||
app_router=False # Use Pages Router
|
||||
)
|
||||
|
||||
initializer.create_directory_structure()
|
||||
|
||||
# Check Pages Router files
|
||||
assert (project_dir / "pages" / "_app.tsx").exists()
|
||||
assert (project_dir / "pages" / "index.tsx").exists()
|
||||
374
skills/web-frameworks/scripts/tests/test_turborepo_migrate.py
Normal file
374
skills/web-frameworks/scripts/tests/test_turborepo_migrate.py
Normal file
@@ -0,0 +1,374 @@
|
||||
"""Tests for turborepo-migrate.py script."""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
# Add parent directory to path to import the script
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from turborepo_migrate import TurborepoMigrator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_monorepo(tmp_path):
|
||||
"""Create a mock monorepo structure."""
|
||||
# Root package.json
|
||||
root_pkg = {
|
||||
"name": "test-monorepo",
|
||||
"private": True,
|
||||
"workspaces": ["apps/*", "packages/*"],
|
||||
"scripts": {
|
||||
"build": "npm run build --workspaces",
|
||||
"test": "npm run test --workspaces"
|
||||
}
|
||||
}
|
||||
|
||||
(tmp_path / "package.json").write_text(json.dumps(root_pkg, indent=2))
|
||||
|
||||
# Create apps
|
||||
apps_dir = tmp_path / "apps"
|
||||
apps_dir.mkdir()
|
||||
|
||||
web_dir = apps_dir / "web"
|
||||
web_dir.mkdir()
|
||||
(web_dir / "package.json").write_text(json.dumps({
|
||||
"name": "web",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"test": "jest",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@repo/ui": "*",
|
||||
"next": "latest"
|
||||
}
|
||||
}, indent=2))
|
||||
|
||||
# Create Next.js output directory
|
||||
(web_dir / ".next").mkdir()
|
||||
|
||||
# Create packages
|
||||
packages_dir = tmp_path / "packages"
|
||||
packages_dir.mkdir()
|
||||
|
||||
ui_dir = packages_dir / "ui"
|
||||
ui_dir.mkdir()
|
||||
(ui_dir / "package.json").write_text(json.dumps({
|
||||
"name": "@repo/ui",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "latest"
|
||||
}
|
||||
}, indent=2))
|
||||
|
||||
# Create dist directory
|
||||
(ui_dir / "dist").mkdir()
|
||||
|
||||
return tmp_path
|
||||
|
||||
|
||||
class TestTurborepoMigrator:
|
||||
"""Test suite for TurborepoMigrator."""
|
||||
|
||||
def test_init(self, tmp_path):
|
||||
"""Test migrator initialization."""
|
||||
migrator = TurborepoMigrator(
|
||||
path=tmp_path,
|
||||
dry_run=True,
|
||||
package_manager="npm"
|
||||
)
|
||||
|
||||
assert migrator.path == tmp_path.resolve()
|
||||
assert migrator.dry_run is True
|
||||
assert migrator.package_manager == "npm"
|
||||
|
||||
def test_validate_path_exists(self, mock_monorepo):
|
||||
"""Test path validation with valid monorepo."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.validate_path() # Should not raise
|
||||
|
||||
def test_validate_path_not_exists(self, tmp_path):
|
||||
"""Test path validation with non-existent path."""
|
||||
migrator = TurborepoMigrator(path=tmp_path / "nonexistent")
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
migrator.validate_path()
|
||||
|
||||
def test_validate_path_not_directory(self, tmp_path):
|
||||
"""Test path validation with file instead of directory."""
|
||||
file_path = tmp_path / "file.txt"
|
||||
file_path.touch()
|
||||
|
||||
migrator = TurborepoMigrator(path=file_path)
|
||||
|
||||
with pytest.raises(NotADirectoryError):
|
||||
migrator.validate_path()
|
||||
|
||||
def test_validate_path_no_package_json(self, tmp_path):
|
||||
"""Test path validation without package.json."""
|
||||
empty_dir = tmp_path / "empty"
|
||||
empty_dir.mkdir()
|
||||
|
||||
migrator = TurborepoMigrator(path=empty_dir)
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
migrator.validate_path()
|
||||
|
||||
def test_analyze_workspace_npm(self, mock_monorepo):
|
||||
"""Test workspace analysis for npm/yarn workspaces."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.analyze_workspace()
|
||||
|
||||
assert migrator.workspace_config["type"] == "npm/yarn"
|
||||
assert "apps/*" in migrator.workspace_config["patterns"]
|
||||
assert "packages/*" in migrator.workspace_config["patterns"]
|
||||
|
||||
def test_analyze_workspace_pnpm(self, tmp_path):
|
||||
"""Test workspace analysis for pnpm workspaces."""
|
||||
# Create root package.json without workspaces
|
||||
(tmp_path / "package.json").write_text(json.dumps({
|
||||
"name": "test-monorepo",
|
||||
"private": True
|
||||
}))
|
||||
|
||||
# Create pnpm-workspace.yaml
|
||||
(tmp_path / "pnpm-workspace.yaml").write_text("""packages:
|
||||
- 'apps/*'
|
||||
- 'packages/*'
|
||||
""")
|
||||
|
||||
migrator = TurborepoMigrator(path=tmp_path)
|
||||
migrator.analyze_workspace()
|
||||
|
||||
assert migrator.workspace_config["type"] == "pnpm"
|
||||
assert migrator.workspace_config["file"] == "pnpm-workspace.yaml"
|
||||
|
||||
def test_discover_packages(self, mock_monorepo):
|
||||
"""Test package discovery."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
assert len(migrator.packages) == 2
|
||||
|
||||
package_names = {pkg["name"] for pkg in migrator.packages}
|
||||
assert "web" in package_names
|
||||
assert "@repo/ui" in package_names
|
||||
|
||||
def test_analyze_scripts(self, mock_monorepo):
|
||||
"""Test script analysis."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
common_scripts = migrator.analyze_scripts()
|
||||
|
||||
# All packages have build, test, lint
|
||||
assert "build" in common_scripts
|
||||
assert "test" in common_scripts
|
||||
assert "lint" in common_scripts
|
||||
|
||||
# Check package counts
|
||||
assert len(common_scripts["build"]) == 2
|
||||
assert len(common_scripts["test"]) == 2
|
||||
|
||||
def test_infer_build_outputs(self, mock_monorepo):
|
||||
"""Test build output inference."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
outputs = migrator._infer_build_outputs()
|
||||
|
||||
# Should detect .next and dist directories
|
||||
assert ".next/**" in outputs
|
||||
assert "!.next/cache/**" in outputs
|
||||
assert "dist/**" in outputs
|
||||
|
||||
def test_generate_turbo_config(self, mock_monorepo):
|
||||
"""Test turbo.json generation."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
common_scripts = migrator.analyze_scripts()
|
||||
turbo_config = migrator.generate_turbo_config(common_scripts)
|
||||
|
||||
assert "$schema" in turbo_config
|
||||
assert "pipeline" in turbo_config
|
||||
|
||||
# Check build task
|
||||
assert "build" in turbo_config["pipeline"]
|
||||
assert turbo_config["pipeline"]["build"]["dependsOn"] == ["^build"]
|
||||
assert "outputs" in turbo_config["pipeline"]["build"]
|
||||
|
||||
# Check test task
|
||||
assert "test" in turbo_config["pipeline"]
|
||||
assert "coverage/**" in turbo_config["pipeline"]["test"]["outputs"]
|
||||
|
||||
# Check lint task
|
||||
assert "lint" in turbo_config["pipeline"]
|
||||
|
||||
# Note: dev task won't be in pipeline because it's only in 1 package
|
||||
# (needs to be in 2+ packages to be considered "common")
|
||||
# This is correct behavior - only truly common scripts are included
|
||||
|
||||
def test_update_root_package_json(self, mock_monorepo):
|
||||
"""Test root package.json update."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
updated_package_json = migrator.update_root_package_json()
|
||||
|
||||
# Check turbo added to devDependencies
|
||||
assert "turbo" in updated_package_json["devDependencies"]
|
||||
assert updated_package_json["devDependencies"]["turbo"] == "latest"
|
||||
|
||||
# Check scripts updated (only common scripts are added)
|
||||
assert updated_package_json["scripts"]["build"] == "turbo run build"
|
||||
assert updated_package_json["scripts"]["test"] == "turbo run test"
|
||||
assert updated_package_json["scripts"]["lint"] == "turbo run lint"
|
||||
# dev is only in one package, so it won't be added
|
||||
|
||||
def test_generate_migration_report(self, mock_monorepo):
|
||||
"""Test migration report generation."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
common_scripts = migrator.analyze_scripts()
|
||||
turbo_config = migrator.generate_turbo_config(common_scripts)
|
||||
updated_package_json = migrator.update_root_package_json()
|
||||
|
||||
report = migrator.generate_migration_report(turbo_config, updated_package_json)
|
||||
|
||||
assert "TURBOREPO MIGRATION REPORT" in report
|
||||
assert "PACKAGES:" in report
|
||||
assert "TURBO.JSON PIPELINE:" in report
|
||||
assert "ROOT PACKAGE.JSON SCRIPTS:" in report
|
||||
assert "RECOMMENDATIONS:" in report
|
||||
|
||||
# Check package names appear
|
||||
assert "web" in report
|
||||
assert "@repo/ui" in report
|
||||
|
||||
def test_write_files_dry_run(self, mock_monorepo, capsys):
|
||||
"""Test file writing in dry-run mode."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo, dry_run=True)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
common_scripts = migrator.analyze_scripts()
|
||||
turbo_config = migrator.generate_turbo_config(common_scripts)
|
||||
updated_package_json = migrator.update_root_package_json()
|
||||
|
||||
migrator.write_files(turbo_config, updated_package_json)
|
||||
|
||||
# Check files not created
|
||||
assert not (mock_monorepo / "turbo.json").exists()
|
||||
|
||||
# Check output
|
||||
captured = capsys.readouterr()
|
||||
assert "DRY RUN" in captured.out
|
||||
|
||||
def test_write_files_actual(self, mock_monorepo):
|
||||
"""Test actual file writing."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo, dry_run=False)
|
||||
migrator.analyze_workspace()
|
||||
migrator.discover_packages()
|
||||
|
||||
common_scripts = migrator.analyze_scripts()
|
||||
turbo_config = migrator.generate_turbo_config(common_scripts)
|
||||
updated_package_json = migrator.update_root_package_json()
|
||||
|
||||
migrator.write_files(turbo_config, updated_package_json)
|
||||
|
||||
# Check turbo.json created
|
||||
assert (mock_monorepo / "turbo.json").exists()
|
||||
|
||||
# Verify content
|
||||
with open(mock_monorepo / "turbo.json") as f:
|
||||
saved_config = json.load(f)
|
||||
assert saved_config["$schema"] == turbo_config["$schema"]
|
||||
assert "pipeline" in saved_config
|
||||
|
||||
# Check package.json updated
|
||||
with open(mock_monorepo / "package.json") as f:
|
||||
saved_package = json.load(f)
|
||||
assert "turbo" in saved_package["devDependencies"]
|
||||
|
||||
def test_full_migration_dry_run(self, mock_monorepo):
|
||||
"""Test full migration process in dry-run mode."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo, dry_run=True)
|
||||
migrator.migrate()
|
||||
|
||||
# Files should not be created in dry-run
|
||||
assert not (mock_monorepo / "turbo.json").exists()
|
||||
|
||||
# Original package.json should be unchanged
|
||||
with open(mock_monorepo / "package.json") as f:
|
||||
package_json = json.load(f)
|
||||
assert "turbo" not in package_json.get("devDependencies", {})
|
||||
|
||||
def test_full_migration_actual(self, mock_monorepo):
|
||||
"""Test full migration process."""
|
||||
migrator = TurborepoMigrator(path=mock_monorepo, dry_run=False)
|
||||
migrator.migrate()
|
||||
|
||||
# Check turbo.json created
|
||||
assert (mock_monorepo / "turbo.json").exists()
|
||||
|
||||
with open(mock_monorepo / "turbo.json") as f:
|
||||
turbo_config = json.load(f)
|
||||
assert "$schema" in turbo_config
|
||||
assert "pipeline" in turbo_config
|
||||
assert "build" in turbo_config["pipeline"]
|
||||
|
||||
# Check package.json updated
|
||||
with open(mock_monorepo / "package.json") as f:
|
||||
package_json = json.load(f)
|
||||
assert "turbo" in package_json["devDependencies"]
|
||||
assert package_json["scripts"]["build"] == "turbo run build"
|
||||
|
||||
def test_parse_pnpm_workspace(self, tmp_path):
|
||||
"""Test pnpm-workspace.yaml parsing."""
|
||||
yaml_content = """packages:
|
||||
- 'apps/*'
|
||||
- 'packages/*'
|
||||
- 'tools/*'
|
||||
"""
|
||||
yaml_file = tmp_path / "pnpm-workspace.yaml"
|
||||
yaml_file.write_text(yaml_content)
|
||||
|
||||
migrator = TurborepoMigrator(path=tmp_path)
|
||||
patterns = migrator._parse_pnpm_workspace(yaml_file)
|
||||
|
||||
assert len(patterns) == 3
|
||||
assert "apps/*" in patterns
|
||||
assert "packages/*" in patterns
|
||||
assert "tools/*" in patterns
|
||||
|
||||
def test_monorepo_without_workspaces(self, tmp_path):
|
||||
"""Test migration fails for non-workspace monorepo."""
|
||||
# Create package.json without workspaces
|
||||
(tmp_path / "package.json").write_text(json.dumps({
|
||||
"name": "not-a-monorepo",
|
||||
"version": "1.0.0"
|
||||
}))
|
||||
|
||||
migrator = TurborepoMigrator(path=tmp_path)
|
||||
|
||||
# migrate() calls sys.exit(1) on error, so we catch SystemExit
|
||||
with pytest.raises(SystemExit):
|
||||
migrator.migrate()
|
||||
Reference in New Issue
Block a user