solokit 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solokit/__init__.py +10 -0
- solokit/__version__.py +3 -0
- solokit/cli.py +374 -0
- solokit/core/__init__.py +1 -0
- solokit/core/cache.py +102 -0
- solokit/core/command_runner.py +278 -0
- solokit/core/config.py +453 -0
- solokit/core/config_validator.py +204 -0
- solokit/core/constants.py +291 -0
- solokit/core/error_formatter.py +279 -0
- solokit/core/error_handlers.py +346 -0
- solokit/core/exceptions.py +1567 -0
- solokit/core/file_ops.py +309 -0
- solokit/core/logging_config.py +166 -0
- solokit/core/output.py +99 -0
- solokit/core/performance.py +57 -0
- solokit/core/protocols.py +141 -0
- solokit/core/types.py +312 -0
- solokit/deployment/__init__.py +1 -0
- solokit/deployment/executor.py +411 -0
- solokit/git/__init__.py +1 -0
- solokit/git/integration.py +619 -0
- solokit/init/__init__.py +41 -0
- solokit/init/claude_commands_installer.py +87 -0
- solokit/init/dependency_installer.py +313 -0
- solokit/init/docs_structure.py +90 -0
- solokit/init/env_generator.py +160 -0
- solokit/init/environment_validator.py +334 -0
- solokit/init/git_hooks_installer.py +71 -0
- solokit/init/git_setup.py +188 -0
- solokit/init/gitignore_updater.py +195 -0
- solokit/init/initial_commit.py +145 -0
- solokit/init/initial_scans.py +109 -0
- solokit/init/orchestrator.py +246 -0
- solokit/init/readme_generator.py +207 -0
- solokit/init/session_structure.py +239 -0
- solokit/init/template_installer.py +424 -0
- solokit/learning/__init__.py +1 -0
- solokit/learning/archiver.py +115 -0
- solokit/learning/categorizer.py +126 -0
- solokit/learning/curator.py +428 -0
- solokit/learning/extractor.py +352 -0
- solokit/learning/reporter.py +351 -0
- solokit/learning/repository.py +254 -0
- solokit/learning/similarity.py +342 -0
- solokit/learning/validator.py +144 -0
- solokit/project/__init__.py +1 -0
- solokit/project/init.py +1162 -0
- solokit/project/stack.py +436 -0
- solokit/project/sync_plugin.py +438 -0
- solokit/project/tree.py +375 -0
- solokit/quality/__init__.py +1 -0
- solokit/quality/api_validator.py +424 -0
- solokit/quality/checkers/__init__.py +25 -0
- solokit/quality/checkers/base.py +114 -0
- solokit/quality/checkers/context7.py +221 -0
- solokit/quality/checkers/custom.py +162 -0
- solokit/quality/checkers/deployment.py +323 -0
- solokit/quality/checkers/documentation.py +179 -0
- solokit/quality/checkers/formatting.py +161 -0
- solokit/quality/checkers/integration.py +394 -0
- solokit/quality/checkers/linting.py +159 -0
- solokit/quality/checkers/security.py +261 -0
- solokit/quality/checkers/spec_completeness.py +127 -0
- solokit/quality/checkers/tests.py +184 -0
- solokit/quality/env_validator.py +306 -0
- solokit/quality/gates.py +655 -0
- solokit/quality/reporters/__init__.py +10 -0
- solokit/quality/reporters/base.py +25 -0
- solokit/quality/reporters/console.py +98 -0
- solokit/quality/reporters/json_reporter.py +34 -0
- solokit/quality/results.py +98 -0
- solokit/session/__init__.py +1 -0
- solokit/session/briefing/__init__.py +245 -0
- solokit/session/briefing/documentation_loader.py +53 -0
- solokit/session/briefing/formatter.py +476 -0
- solokit/session/briefing/git_context.py +282 -0
- solokit/session/briefing/learning_loader.py +212 -0
- solokit/session/briefing/milestone_builder.py +78 -0
- solokit/session/briefing/orchestrator.py +137 -0
- solokit/session/briefing/stack_detector.py +51 -0
- solokit/session/briefing/tree_generator.py +52 -0
- solokit/session/briefing/work_item_loader.py +209 -0
- solokit/session/briefing.py +353 -0
- solokit/session/complete.py +1188 -0
- solokit/session/status.py +246 -0
- solokit/session/validate.py +452 -0
- solokit/templates/.claude/commands/end.md +109 -0
- solokit/templates/.claude/commands/init.md +159 -0
- solokit/templates/.claude/commands/learn-curate.md +88 -0
- solokit/templates/.claude/commands/learn-search.md +62 -0
- solokit/templates/.claude/commands/learn-show.md +69 -0
- solokit/templates/.claude/commands/learn.md +136 -0
- solokit/templates/.claude/commands/start.md +114 -0
- solokit/templates/.claude/commands/status.md +22 -0
- solokit/templates/.claude/commands/validate.md +27 -0
- solokit/templates/.claude/commands/work-delete.md +119 -0
- solokit/templates/.claude/commands/work-graph.md +139 -0
- solokit/templates/.claude/commands/work-list.md +26 -0
- solokit/templates/.claude/commands/work-new.md +114 -0
- solokit/templates/.claude/commands/work-next.md +25 -0
- solokit/templates/.claude/commands/work-show.md +24 -0
- solokit/templates/.claude/commands/work-update.md +141 -0
- solokit/templates/CHANGELOG.md +17 -0
- solokit/templates/WORK_ITEM_TYPES.md +141 -0
- solokit/templates/__init__.py +1 -0
- solokit/templates/bug_spec.md +217 -0
- solokit/templates/config.schema.json +150 -0
- solokit/templates/dashboard_refine/base/.gitignore +36 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/layout.tsx +22 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/page.tsx +68 -0
- solokit/templates/dashboard_refine/base/app/(dashboard)/users/page.tsx +77 -0
- solokit/templates/dashboard_refine/base/app/globals.css +60 -0
- solokit/templates/dashboard_refine/base/app/layout.tsx +23 -0
- solokit/templates/dashboard_refine/base/app/page.tsx +9 -0
- solokit/templates/dashboard_refine/base/components/client-refine-wrapper.tsx +21 -0
- solokit/templates/dashboard_refine/base/components/layout/header.tsx +44 -0
- solokit/templates/dashboard_refine/base/components/layout/sidebar.tsx +82 -0
- solokit/templates/dashboard_refine/base/components/ui/button.tsx +53 -0
- solokit/templates/dashboard_refine/base/components/ui/card.tsx +78 -0
- solokit/templates/dashboard_refine/base/components/ui/table.tsx +116 -0
- solokit/templates/dashboard_refine/base/components.json +16 -0
- solokit/templates/dashboard_refine/base/lib/refine.tsx +65 -0
- solokit/templates/dashboard_refine/base/lib/utils.ts +13 -0
- solokit/templates/dashboard_refine/base/next.config.ts +10 -0
- solokit/templates/dashboard_refine/base/package.json.template +40 -0
- solokit/templates/dashboard_refine/base/postcss.config.mjs +8 -0
- solokit/templates/dashboard_refine/base/providers/refine-provider.tsx +26 -0
- solokit/templates/dashboard_refine/base/tailwind.config.ts +57 -0
- solokit/templates/dashboard_refine/base/tsconfig.json +27 -0
- solokit/templates/dashboard_refine/docker/Dockerfile +57 -0
- solokit/templates/dashboard_refine/docker/docker-compose.prod.yml +31 -0
- solokit/templates/dashboard_refine/docker/docker-compose.yml +21 -0
- solokit/templates/dashboard_refine/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/dashboard_refine/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/dashboard_refine/tier-1-essential/package.json.tier1.template +57 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/setup.ts +26 -0
- solokit/templates/dashboard_refine/tier-1-essential/tests/unit/example.test.tsx +73 -0
- solokit/templates/dashboard_refine/tier-2-standard/package.json.tier2.template +62 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/eslint.config.mjs +22 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/package.json.tier3.template +79 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/stryker.conf.json +38 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/dashboard.spec.ts +88 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/e2e/user-management.spec.ts +102 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/tests/integration/dashboard.test.tsx +90 -0
- solokit/templates/dashboard_refine/tier-3-comprehensive/type-coverage.json +16 -0
- solokit/templates/dashboard_refine/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/dashboard_refine/tier-4-production/k6/dashboard-load-test.js +70 -0
- solokit/templates/dashboard_refine/tier-4-production/next.config.ts +46 -0
- solokit/templates/dashboard_refine/tier-4-production/package.json.tier4.template +89 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/dashboard_refine/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/deployment_spec.md +500 -0
- solokit/templates/feature_spec.md +248 -0
- solokit/templates/fullstack_nextjs/base/.gitignore +36 -0
- solokit/templates/fullstack_nextjs/base/app/api/example/route.ts +65 -0
- solokit/templates/fullstack_nextjs/base/app/globals.css +27 -0
- solokit/templates/fullstack_nextjs/base/app/layout.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/app/page.tsx +32 -0
- solokit/templates/fullstack_nextjs/base/components/example-component.tsx +20 -0
- solokit/templates/fullstack_nextjs/base/lib/prisma.ts +17 -0
- solokit/templates/fullstack_nextjs/base/lib/utils.ts +13 -0
- solokit/templates/fullstack_nextjs/base/lib/validations.ts +20 -0
- solokit/templates/fullstack_nextjs/base/next.config.ts +7 -0
- solokit/templates/fullstack_nextjs/base/package.json.template +32 -0
- solokit/templates/fullstack_nextjs/base/postcss.config.mjs +8 -0
- solokit/templates/fullstack_nextjs/base/prisma/schema.prisma +21 -0
- solokit/templates/fullstack_nextjs/base/tailwind.config.ts +19 -0
- solokit/templates/fullstack_nextjs/base/tsconfig.json +27 -0
- solokit/templates/fullstack_nextjs/docker/Dockerfile +60 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.prod.yml +57 -0
- solokit/templates/fullstack_nextjs/docker/docker-compose.yml +47 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/package.json.tier1.template +48 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/api/example.test.ts +88 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/fullstack_nextjs/tier-1-essential/tests/unit/example.test.tsx +22 -0
- solokit/templates/fullstack_nextjs/tier-2-standard/package.json.tier2.template +52 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/package.json.tier3.template +68 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/stryker.conf.json +33 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/e2e/flow.spec.ts +59 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/tests/integration/api.test.ts +165 -0
- solokit/templates/fullstack_nextjs/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/fullstack_nextjs/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/fullstack_nextjs/tier-4-production/k6/load-test.js +45 -0
- solokit/templates/fullstack_nextjs/tier-4-production/next.config.ts +46 -0
- solokit/templates/fullstack_nextjs/tier-4-production/package.json.tier4.template +77 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/fullstack_nextjs/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/git-hooks/prepare-commit-msg +24 -0
- solokit/templates/integration_test_spec.md +363 -0
- solokit/templates/learnings.json +15 -0
- solokit/templates/ml_ai_fastapi/base/.gitignore +104 -0
- solokit/templates/ml_ai_fastapi/base/alembic/env.py +96 -0
- solokit/templates/ml_ai_fastapi/base/alembic.ini +114 -0
- solokit/templates/ml_ai_fastapi/base/pyproject.toml.template +91 -0
- solokit/templates/ml_ai_fastapi/base/requirements.txt.template +28 -0
- solokit/templates/ml_ai_fastapi/base/src/__init__.py +5 -0
- solokit/templates/ml_ai_fastapi/base/src/api/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/dependencies.py +20 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/example.py +134 -0
- solokit/templates/ml_ai_fastapi/base/src/api/routes/health.py +66 -0
- solokit/templates/ml_ai_fastapi/base/src/core/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/core/config.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/core/database.py +50 -0
- solokit/templates/ml_ai_fastapi/base/src/main.py +64 -0
- solokit/templates/ml_ai_fastapi/base/src/models/__init__.py +7 -0
- solokit/templates/ml_ai_fastapi/base/src/models/example.py +61 -0
- solokit/templates/ml_ai_fastapi/base/src/services/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/base/src/services/example.py +115 -0
- solokit/templates/ml_ai_fastapi/docker/Dockerfile +59 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.prod.yml +112 -0
- solokit/templates/ml_ai_fastapi/docker/docker-compose.yml +77 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyproject.toml.tier1.template +112 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pyrightconfig.json +41 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/pytest.ini +69 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/requirements-dev.txt +17 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/ruff.toml +81 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/conftest.py +72 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/test_main.py +49 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-1-essential/tests/unit/test_example.py +113 -0
- solokit/templates/ml_ai_fastapi/tier-2-standard/pyproject.toml.tier2.template +130 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/locustfile.py +99 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/mutmut_config.py +53 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/pyproject.toml.tier3.template +150 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/conftest.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-3-comprehensive/tests/integration/test_api.py +131 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/pyproject.toml.tier4.template +162 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/requirements-prod.txt +25 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/api/routes/metrics.py +19 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/logging.py +74 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/monitoring.py +68 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/core/sentry.py +66 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/__init__.py +3 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/logging.py +79 -0
- solokit/templates/ml_ai_fastapi/tier-4-production/src/middleware/tracing.py +60 -0
- solokit/templates/refactor_spec.md +287 -0
- solokit/templates/saas_t3/base/.gitignore +36 -0
- solokit/templates/saas_t3/base/app/api/trpc/[trpc]/route.ts +33 -0
- solokit/templates/saas_t3/base/app/globals.css +27 -0
- solokit/templates/saas_t3/base/app/layout.tsx +23 -0
- solokit/templates/saas_t3/base/app/page.tsx +31 -0
- solokit/templates/saas_t3/base/lib/api.tsx +77 -0
- solokit/templates/saas_t3/base/lib/utils.ts +13 -0
- solokit/templates/saas_t3/base/next.config.ts +7 -0
- solokit/templates/saas_t3/base/package.json.template +38 -0
- solokit/templates/saas_t3/base/postcss.config.mjs +8 -0
- solokit/templates/saas_t3/base/prisma/schema.prisma +20 -0
- solokit/templates/saas_t3/base/server/api/root.ts +19 -0
- solokit/templates/saas_t3/base/server/api/routers/example.ts +28 -0
- solokit/templates/saas_t3/base/server/api/trpc.ts +52 -0
- solokit/templates/saas_t3/base/server/db.ts +17 -0
- solokit/templates/saas_t3/base/tailwind.config.ts +19 -0
- solokit/templates/saas_t3/base/tsconfig.json +27 -0
- solokit/templates/saas_t3/docker/Dockerfile +60 -0
- solokit/templates/saas_t3/docker/docker-compose.prod.yml +59 -0
- solokit/templates/saas_t3/docker/docker-compose.yml +49 -0
- solokit/templates/saas_t3/tier-1-essential/.eslintrc.json +7 -0
- solokit/templates/saas_t3/tier-1-essential/jest.config.ts +17 -0
- solokit/templates/saas_t3/tier-1-essential/jest.setup.ts +1 -0
- solokit/templates/saas_t3/tier-1-essential/package.json.tier1.template +54 -0
- solokit/templates/saas_t3/tier-1-essential/tests/setup.ts +22 -0
- solokit/templates/saas_t3/tier-1-essential/tests/unit/example.test.tsx +24 -0
- solokit/templates/saas_t3/tier-2-standard/package.json.tier2.template +58 -0
- solokit/templates/saas_t3/tier-3-comprehensive/eslint.config.mjs +39 -0
- solokit/templates/saas_t3/tier-3-comprehensive/package.json.tier3.template +74 -0
- solokit/templates/saas_t3/tier-3-comprehensive/playwright.config.ts +66 -0
- solokit/templates/saas_t3/tier-3-comprehensive/stryker.conf.json +34 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/e2e/home.spec.ts +41 -0
- solokit/templates/saas_t3/tier-3-comprehensive/tests/integration/api.test.ts +44 -0
- solokit/templates/saas_t3/tier-3-comprehensive/type-coverage.json +12 -0
- solokit/templates/saas_t3/tier-4-production/instrumentation.ts +9 -0
- solokit/templates/saas_t3/tier-4-production/k6/load-test.js +51 -0
- solokit/templates/saas_t3/tier-4-production/next.config.ts +46 -0
- solokit/templates/saas_t3/tier-4-production/package.json.tier4.template +83 -0
- solokit/templates/saas_t3/tier-4-production/sentry.client.config.ts +26 -0
- solokit/templates/saas_t3/tier-4-production/sentry.edge.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/sentry.server.config.ts +11 -0
- solokit/templates/saas_t3/tier-4-production/vercel.json +37 -0
- solokit/templates/security_spec.md +287 -0
- solokit/templates/stack-versions.yaml +617 -0
- solokit/templates/status_update.json +6 -0
- solokit/templates/template-registry.json +257 -0
- solokit/templates/work_items.json +11 -0
- solokit/testing/__init__.py +1 -0
- solokit/testing/integration_runner.py +550 -0
- solokit/testing/performance.py +637 -0
- solokit/visualization/__init__.py +1 -0
- solokit/visualization/dependency_graph.py +788 -0
- solokit/work_items/__init__.py +1 -0
- solokit/work_items/creator.py +217 -0
- solokit/work_items/delete.py +264 -0
- solokit/work_items/get_dependencies.py +185 -0
- solokit/work_items/get_dependents.py +113 -0
- solokit/work_items/get_metadata.py +121 -0
- solokit/work_items/get_next_recommendations.py +133 -0
- solokit/work_items/manager.py +235 -0
- solokit/work_items/milestones.py +137 -0
- solokit/work_items/query.py +376 -0
- solokit/work_items/repository.py +267 -0
- solokit/work_items/scheduler.py +184 -0
- solokit/work_items/spec_parser.py +838 -0
- solokit/work_items/spec_validator.py +493 -0
- solokit/work_items/updater.py +157 -0
- solokit/work_items/validator.py +205 -0
- solokit-0.1.1.dist-info/METADATA +640 -0
- solokit-0.1.1.dist-info/RECORD +323 -0
- solokit-0.1.1.dist-info/WHEEL +5 -0
- solokit-0.1.1.dist-info/entry_points.txt +2 -0
- solokit-0.1.1.dist-info/licenses/LICENSE +21 -0
- solokit-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{project_name}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "{project_description}",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "next dev",
|
|
9
|
+
"build": "next build",
|
|
10
|
+
"start": "next start",
|
|
11
|
+
"lint": "next lint",
|
|
12
|
+
"lint:fix": "next lint --fix",
|
|
13
|
+
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
|
14
|
+
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,css,md}\"",
|
|
15
|
+
"type-check": "tsc --noEmit",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"test:coverage": "jest --coverage",
|
|
18
|
+
"test:watch": "jest --watch",
|
|
19
|
+
"test:e2e": "playwright test",
|
|
20
|
+
"test:e2e:ui": "playwright test --ui",
|
|
21
|
+
"test:e2e:debug": "playwright test --debug",
|
|
22
|
+
"test:a11y": "playwright test --grep @a11y",
|
|
23
|
+
"test:mutation": "stryker run",
|
|
24
|
+
"check:duplication": "jscpd .",
|
|
25
|
+
"check:types": "type-coverage",
|
|
26
|
+
"check:unused": "ts-prune",
|
|
27
|
+
"prepare": "husky install",
|
|
28
|
+
"audit": "npm audit --audit-level=moderate"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"next": "16.0.1",
|
|
32
|
+
"react": "19.2.0",
|
|
33
|
+
"react-dom": "19.2.0",
|
|
34
|
+
"@refinedev/cli": "2.16.50",
|
|
35
|
+
"@refinedev/core": "5.0.5",
|
|
36
|
+
"@refinedev/nextjs-router": "7.0.4",
|
|
37
|
+
"@refinedev/react-table": "6.0.1",
|
|
38
|
+
"@refinedev/react-hook-form": "5.0.2",
|
|
39
|
+
"recharts": "3.3.0",
|
|
40
|
+
"react-hook-form": "7.66.0",
|
|
41
|
+
"zod": "4.1.12",
|
|
42
|
+
"@hookform/resolvers": "5.2.2",
|
|
43
|
+
"lucide-react": "0.553.0",
|
|
44
|
+
"class-variance-authority": "0.7.1",
|
|
45
|
+
"clsx": "2.1.1",
|
|
46
|
+
"tailwind-merge": "3.3.1",
|
|
47
|
+
"tailwindcss": "4.1.17",
|
|
48
|
+
"@tailwindcss/postcss": "4.1.17"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"typescript": "5.9.3",
|
|
52
|
+
"@types/node": "20.19.24",
|
|
53
|
+
"@types/react": "19.2.2",
|
|
54
|
+
"@types/react-dom": "19.2.2",
|
|
55
|
+
"eslint": "9.39.1",
|
|
56
|
+
"eslint-config-next": "16.0.1",
|
|
57
|
+
"@typescript-eslint/parser": "8.46.3",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "8.46.3",
|
|
59
|
+
"prettier": "3.6.2",
|
|
60
|
+
"jest": "30.2.0",
|
|
61
|
+
"@types/jest": "30.0.0",
|
|
62
|
+
"ts-jest": "29.4.5",
|
|
63
|
+
"jest-environment-jsdom": "30.2.0",
|
|
64
|
+
"@testing-library/react": "16.3.0",
|
|
65
|
+
"@testing-library/jest-dom": "6.9.1",
|
|
66
|
+
"husky": "9.1.7",
|
|
67
|
+
"lint-staged": "16.2.6",
|
|
68
|
+
"jscpd": "4.0.5",
|
|
69
|
+
"ts-prune": "0.10.3",
|
|
70
|
+
"type-coverage": "2.29.7",
|
|
71
|
+
"@stryker-mutator/core": "9.3.0",
|
|
72
|
+
"@stryker-mutator/jest-runner": "9.3.0",
|
|
73
|
+
"@playwright/test": "1.56.1",
|
|
74
|
+
"playwright": "1.56.1",
|
|
75
|
+
"@axe-core/playwright": "4.11.0",
|
|
76
|
+
"eslint-plugin-jest-dom": "5.5.0",
|
|
77
|
+
"eslint-plugin-testing-library": "7.13.3"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Read environment variables from file.
|
|
5
|
+
* https://github.com/motdotla/dotenv
|
|
6
|
+
*/
|
|
7
|
+
// require('dotenv').config();
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* See https://playwright.dev/docs/test-configuration.
|
|
11
|
+
*/
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
testDir: './tests/e2e',
|
|
14
|
+
/* Run tests in files in parallel */
|
|
15
|
+
fullyParallel: true,
|
|
16
|
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
17
|
+
forbidOnly: !!process.env.CI,
|
|
18
|
+
/* Retry on CI only */
|
|
19
|
+
retries: process.env.CI ? 2 : 0,
|
|
20
|
+
/* Opt out of parallel tests on CI. */
|
|
21
|
+
workers: process.env.CI ? 1 : undefined,
|
|
22
|
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
23
|
+
reporter: 'html',
|
|
24
|
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
25
|
+
use: {
|
|
26
|
+
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
27
|
+
baseURL: 'http://localhost:3000',
|
|
28
|
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
29
|
+
trace: 'on-first-retry',
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
/* Configure projects for major browsers */
|
|
33
|
+
projects: [
|
|
34
|
+
{
|
|
35
|
+
name: 'chromium',
|
|
36
|
+
use: { ...devices['Desktop Chrome'] },
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
name: 'firefox',
|
|
41
|
+
use: { ...devices['Desktop Firefox'] },
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
name: 'webkit',
|
|
46
|
+
use: { ...devices['Desktop Safari'] },
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/* Test against mobile viewports. */
|
|
50
|
+
{
|
|
51
|
+
name: 'Mobile Chrome',
|
|
52
|
+
use: { ...devices['Pixel 5'] },
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'Mobile Safari',
|
|
56
|
+
use: { ...devices['iPhone 12'] },
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
|
|
60
|
+
/* Run your local dev server before starting the tests */
|
|
61
|
+
webServer: {
|
|
62
|
+
command: 'npm run dev',
|
|
63
|
+
url: 'http://localhost:3000',
|
|
64
|
+
reuseExistingServer: !process.env.CI,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json",
|
|
3
|
+
"packageManager": "npm",
|
|
4
|
+
"reporters": ["html", "clear-text", "progress"],
|
|
5
|
+
"testRunner": "jest",
|
|
6
|
+
"jest": {
|
|
7
|
+
"projectType": "custom",
|
|
8
|
+
"configFile": "jest.config.ts",
|
|
9
|
+
"enableFindRelatedTests": true
|
|
10
|
+
},
|
|
11
|
+
"coverageAnalysis": "perTest",
|
|
12
|
+
"mutate": [
|
|
13
|
+
"app/**/*.ts",
|
|
14
|
+
"app/**/*.tsx",
|
|
15
|
+
"components/**/*.ts",
|
|
16
|
+
"components/**/*.tsx",
|
|
17
|
+
"lib/**/*.ts",
|
|
18
|
+
"lib/**/*.tsx",
|
|
19
|
+
"providers/**/*.ts",
|
|
20
|
+
"providers/**/*.tsx",
|
|
21
|
+
"!**/*.test.ts",
|
|
22
|
+
"!**/*.test.tsx",
|
|
23
|
+
"!**/*.spec.ts",
|
|
24
|
+
"!**/*.spec.tsx"
|
|
25
|
+
],
|
|
26
|
+
"thresholds": {
|
|
27
|
+
"high": 80,
|
|
28
|
+
"low": 60,
|
|
29
|
+
"break": 50
|
|
30
|
+
},
|
|
31
|
+
"ignorePatterns": [
|
|
32
|
+
"node_modules",
|
|
33
|
+
".next",
|
|
34
|
+
"coverage",
|
|
35
|
+
"dist",
|
|
36
|
+
"build"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import AxeBuilder from '@axe-core/playwright';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Dashboard E2E Tests
|
|
6
|
+
* Tests the main dashboard functionality and accessibility
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
test.describe('Dashboard Page', () => {
|
|
10
|
+
test('should display dashboard with stats cards', async ({ page }) => {
|
|
11
|
+
await page.goto('/dashboard');
|
|
12
|
+
|
|
13
|
+
// Check that dashboard title is visible
|
|
14
|
+
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
|
|
15
|
+
|
|
16
|
+
// Check that stat cards are present
|
|
17
|
+
const cards = page.locator('[class*="grid"] > div');
|
|
18
|
+
await expect(cards).toHaveCount(4); // 4 stat cards
|
|
19
|
+
|
|
20
|
+
// Verify stat card content
|
|
21
|
+
await expect(page.getByText('Total Users')).toBeVisible();
|
|
22
|
+
await expect(page.getByText('Total Orders')).toBeVisible();
|
|
23
|
+
await expect(page.getByText('Revenue')).toBeVisible();
|
|
24
|
+
await expect(page.getByText('Products')).toBeVisible();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('should have working navigation in sidebar', async ({ page }) => {
|
|
28
|
+
await page.goto('/dashboard');
|
|
29
|
+
|
|
30
|
+
// Check sidebar navigation links
|
|
31
|
+
const sidebar = page.locator('aside');
|
|
32
|
+
await expect(sidebar).toBeVisible();
|
|
33
|
+
|
|
34
|
+
// Click on Users link
|
|
35
|
+
await page.getByRole('link', { name: 'Users' }).click();
|
|
36
|
+
await expect(page).toHaveURL('/dashboard/users');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should have accessible search functionality', async ({ page }) => {
|
|
40
|
+
await page.goto('/dashboard');
|
|
41
|
+
|
|
42
|
+
// Find search input by aria-label
|
|
43
|
+
const searchInput = page.getByLabel('Search');
|
|
44
|
+
await expect(searchInput).toBeVisible();
|
|
45
|
+
|
|
46
|
+
// Test search input is focusable
|
|
47
|
+
await searchInput.focus();
|
|
48
|
+
await searchInput.fill('test query');
|
|
49
|
+
await expect(searchInput).toHaveValue('test query');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('should pass accessibility checks', async ({ page }) => {
|
|
53
|
+
await page.goto('/dashboard');
|
|
54
|
+
|
|
55
|
+
// Run accessibility scan
|
|
56
|
+
const accessibilityScanResults = await new AxeBuilder({ page })
|
|
57
|
+
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
|
|
58
|
+
.analyze();
|
|
59
|
+
|
|
60
|
+
// Assert no accessibility violations
|
|
61
|
+
expect(accessibilityScanResults.violations).toEqual([]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('should be responsive on mobile', async ({ page }) => {
|
|
65
|
+
// Set mobile viewport
|
|
66
|
+
await page.setViewportSize({ width: 375, height: 667 });
|
|
67
|
+
await page.goto('/dashboard');
|
|
68
|
+
|
|
69
|
+
// Check that content is visible on mobile
|
|
70
|
+
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
|
|
71
|
+
|
|
72
|
+
// Sidebar should be hidden on mobile
|
|
73
|
+
const sidebar = page.locator('aside');
|
|
74
|
+
await expect(sidebar).toBeHidden();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('should have keyboard navigation support', async ({ page }) => {
|
|
78
|
+
await page.goto('/dashboard');
|
|
79
|
+
|
|
80
|
+
// Tab through focusable elements
|
|
81
|
+
await page.keyboard.press('Tab');
|
|
82
|
+
await page.keyboard.press('Tab');
|
|
83
|
+
|
|
84
|
+
// Verify focused element is visible
|
|
85
|
+
const focusedElement = await page.evaluate(() => document.activeElement?.tagName);
|
|
86
|
+
expect(focusedElement).toBeTruthy();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import AxeBuilder from '@axe-core/playwright';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* User Management E2E Tests
|
|
6
|
+
* Tests CRUD operations and accessibility for user resource
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
test.describe('User Management', () => {
|
|
10
|
+
test('should display users list page', async ({ page }) => {
|
|
11
|
+
await page.goto('/dashboard/users');
|
|
12
|
+
|
|
13
|
+
// Check page title
|
|
14
|
+
await expect(page.getByRole('heading', { name: 'Users' })).toBeVisible();
|
|
15
|
+
|
|
16
|
+
// Check "Add User" button exists
|
|
17
|
+
await expect(page.getByRole('button', { name: /Add User/i })).toBeVisible();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('should display user table with data', async ({ page }) => {
|
|
21
|
+
await page.goto('/dashboard/users');
|
|
22
|
+
|
|
23
|
+
// Wait for table to load
|
|
24
|
+
const table = page.locator('table');
|
|
25
|
+
await expect(table).toBeVisible();
|
|
26
|
+
|
|
27
|
+
// Check table headers
|
|
28
|
+
await expect(page.getByRole('columnheader', { name: 'ID' })).toBeVisible();
|
|
29
|
+
await expect(page.getByRole('columnheader', { name: 'Name' })).toBeVisible();
|
|
30
|
+
await expect(page.getByRole('columnheader', { name: 'Email' })).toBeVisible();
|
|
31
|
+
await expect(page.getByRole('columnheader', { name: 'Actions' })).toBeVisible();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should handle loading state', async ({ page }) => {
|
|
35
|
+
await page.goto('/dashboard/users');
|
|
36
|
+
|
|
37
|
+
// Check for loading state (may appear briefly)
|
|
38
|
+
const loadingOrTable = page.locator('table, :text("Loading")');
|
|
39
|
+
await expect(loadingOrTable).toBeVisible();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('should have accessible table structure', async ({ page }) => {
|
|
43
|
+
await page.goto('/dashboard/users');
|
|
44
|
+
|
|
45
|
+
// Wait for table
|
|
46
|
+
await page.waitForSelector('table');
|
|
47
|
+
|
|
48
|
+
// Run accessibility scan on table
|
|
49
|
+
const accessibilityScanResults = await new AxeBuilder({ page })
|
|
50
|
+
.include('table')
|
|
51
|
+
.withTags(['wcag2a', 'wcag2aa'])
|
|
52
|
+
.analyze();
|
|
53
|
+
|
|
54
|
+
expect(accessibilityScanResults.violations).toEqual([]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('should navigate back to dashboard', async ({ page }) => {
|
|
58
|
+
await page.goto('/dashboard/users');
|
|
59
|
+
|
|
60
|
+
// Click dashboard link in sidebar
|
|
61
|
+
await page.getByRole('link', { name: 'Dashboard' }).first().click();
|
|
62
|
+
await expect(page).toHaveURL('/dashboard');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should pass full page accessibility audit', async ({ page }) => {
|
|
66
|
+
await page.goto('/dashboard/users');
|
|
67
|
+
|
|
68
|
+
// Wait for page to fully load
|
|
69
|
+
await page.waitForLoadState('networkidle');
|
|
70
|
+
|
|
71
|
+
// Run comprehensive accessibility scan
|
|
72
|
+
const accessibilityScanResults = await new AxeBuilder({ page })
|
|
73
|
+
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice'])
|
|
74
|
+
.analyze();
|
|
75
|
+
|
|
76
|
+
// Log any violations for debugging
|
|
77
|
+
if (accessibilityScanResults.violations.length > 0) {
|
|
78
|
+
console.log('Accessibility violations:',
|
|
79
|
+
JSON.stringify(accessibilityScanResults.violations, null, 2)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
expect(accessibilityScanResults.violations).toEqual([]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('should support keyboard navigation in table', async ({ page }) => {
|
|
87
|
+
await page.goto('/dashboard/users');
|
|
88
|
+
|
|
89
|
+
// Wait for table
|
|
90
|
+
await page.waitForSelector('table');
|
|
91
|
+
|
|
92
|
+
// Tab into the table
|
|
93
|
+
await page.keyboard.press('Tab');
|
|
94
|
+
|
|
95
|
+
// Verify we can navigate with keyboard
|
|
96
|
+
const focusedElement = await page.evaluate(() => {
|
|
97
|
+
return document.activeElement?.tagName;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(['BUTTON', 'A', 'INPUT', 'TABLE']).toContain(focusedElement);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
2
|
+
import { RefineProvider } from "@/providers/refine-provider";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Dashboard Integration Tests
|
|
6
|
+
* Tests the integration between Refine provider and dashboard components
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Mock Next.js navigation
|
|
10
|
+
jest.mock("next/navigation", () => ({
|
|
11
|
+
useRouter: () => ({
|
|
12
|
+
push: jest.fn(),
|
|
13
|
+
replace: jest.fn(),
|
|
14
|
+
prefetch: jest.fn(),
|
|
15
|
+
}),
|
|
16
|
+
usePathname: () => "/dashboard",
|
|
17
|
+
useSearchParams: () => new URLSearchParams(),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
// Mock Refine hooks
|
|
21
|
+
jest.mock("@refinedev/core", () => ({
|
|
22
|
+
Refine: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
|
23
|
+
useList: () => ({
|
|
24
|
+
data: {
|
|
25
|
+
data: [
|
|
26
|
+
{ id: 1, name: "John Doe", email: "john@example.com" },
|
|
27
|
+
{ id: 2, name: "Jane Smith", email: "jane@example.com" },
|
|
28
|
+
],
|
|
29
|
+
total: 2,
|
|
30
|
+
},
|
|
31
|
+
isLoading: false,
|
|
32
|
+
isError: false,
|
|
33
|
+
}),
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
describe("Dashboard Integration", () => {
|
|
37
|
+
it("should render RefineProvider without errors", () => {
|
|
38
|
+
const { container } = render(
|
|
39
|
+
<RefineProvider>
|
|
40
|
+
<div>Test Content</div>
|
|
41
|
+
</RefineProvider>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(container).toBeInTheDocument();
|
|
45
|
+
expect(screen.getByText("Test Content")).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should provide Refine context to children", () => {
|
|
49
|
+
const TestComponent = () => {
|
|
50
|
+
return <div>Refine is working</div>;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
render(
|
|
54
|
+
<RefineProvider>
|
|
55
|
+
<TestComponent />
|
|
56
|
+
</RefineProvider>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(screen.getByText("Refine is working")).toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("should handle data fetching in components", async () => {
|
|
63
|
+
const { useList } = await import("@refinedev/core");
|
|
64
|
+
|
|
65
|
+
const TestComponent = () => {
|
|
66
|
+
const { data, isLoading } = useList({ resource: "users" });
|
|
67
|
+
|
|
68
|
+
if (isLoading) return <div>Loading...</div>;
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<div>
|
|
72
|
+
{data?.data.map((user: any) => (
|
|
73
|
+
<div key={user.id}>{user.name}</div>
|
|
74
|
+
))}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
render(
|
|
80
|
+
<RefineProvider>
|
|
81
|
+
<TestComponent />
|
|
82
|
+
</RefineProvider>
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
await waitFor(() => {
|
|
86
|
+
expect(screen.getByText("John Doe")).toBeInTheDocument();
|
|
87
|
+
expect(screen.getByText("Jane Smith")).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import http from 'k6/http';
|
|
2
|
+
import { check, sleep } from 'k6';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Dashboard Load Test
|
|
6
|
+
* Tests performance under various load conditions
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const options = {
|
|
10
|
+
stages: [
|
|
11
|
+
{ duration: '30s', target: 20 }, // Ramp up to 20 users
|
|
12
|
+
{ duration: '1m', target: 20 }, // Stay at 20 users
|
|
13
|
+
{ duration: '30s', target: 50 }, // Spike to 50 users
|
|
14
|
+
{ duration: '1m', target: 50 }, // Stay at 50 users
|
|
15
|
+
{ duration: '30s', target: 0 }, // Ramp down to 0 users
|
|
16
|
+
],
|
|
17
|
+
thresholds: {
|
|
18
|
+
http_req_duration: ['p(95)<500'], // 95% of requests should be below 500ms
|
|
19
|
+
http_req_failed: ['rate<0.01'], // Less than 1% of requests should fail
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const BASE_URL = __ENV.BASE_URL || 'http://localhost:3000';
|
|
24
|
+
|
|
25
|
+
export default function () {
|
|
26
|
+
// Test dashboard homepage
|
|
27
|
+
let response = http.get(`${BASE_URL}/dashboard`);
|
|
28
|
+
check(response, {
|
|
29
|
+
'dashboard status is 200': (r) => r.status === 200,
|
|
30
|
+
'dashboard loads quickly': (r) => r.timings.duration < 500,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
sleep(1);
|
|
34
|
+
|
|
35
|
+
// Test users list page
|
|
36
|
+
response = http.get(`${BASE_URL}/dashboard/users`);
|
|
37
|
+
check(response, {
|
|
38
|
+
'users page status is 200': (r) => r.status === 200,
|
|
39
|
+
'users page loads quickly': (r) => r.timings.duration < 500,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
sleep(1);
|
|
43
|
+
|
|
44
|
+
// Test API endpoint (if available)
|
|
45
|
+
response = http.get(`${BASE_URL}/api/health`);
|
|
46
|
+
check(response, {
|
|
47
|
+
'API responds': (r) => r.status === 200 || r.status === 404,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
sleep(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function handleSummary(data) {
|
|
54
|
+
return {
|
|
55
|
+
'summary.json': JSON.stringify(data),
|
|
56
|
+
stdout: textSummary(data, { indent: ' ', enableColors: true }),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function textSummary(data, options) {
|
|
61
|
+
// Simple text summary
|
|
62
|
+
return `
|
|
63
|
+
Dashboard Load Test Results
|
|
64
|
+
===========================
|
|
65
|
+
Total Requests: ${data.metrics.http_reqs.values.count}
|
|
66
|
+
Failed Requests: ${data.metrics.http_req_failed.values.rate * 100}%
|
|
67
|
+
Average Duration: ${data.metrics.http_req_duration.values.avg.toFixed(2)}ms
|
|
68
|
+
95th Percentile: ${data.metrics.http_req_duration.values['p(95)'].toFixed(2)}ms
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
import { withSentryConfig } from "@sentry/nextjs";
|
|
3
|
+
|
|
4
|
+
const nextConfig: NextConfig = {
|
|
5
|
+
reactStrictMode: true,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// Injected content via Sentry wizard below
|
|
9
|
+
export default withSentryConfig(nextConfig, {
|
|
10
|
+
// For all available options, see:
|
|
11
|
+
// https://github.com/getsentry/sentry-webpack-plugin#options
|
|
12
|
+
|
|
13
|
+
org: process.env.SENTRY_ORG,
|
|
14
|
+
project: process.env.SENTRY_PROJECT,
|
|
15
|
+
|
|
16
|
+
// Only print logs for uploading source maps in CI
|
|
17
|
+
silent: !process.env.CI,
|
|
18
|
+
|
|
19
|
+
// For all available options, see:
|
|
20
|
+
// https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
|
|
21
|
+
|
|
22
|
+
// Upload a larger set of source maps for prettier stack traces (increases build time)
|
|
23
|
+
widenClientFileUpload: true,
|
|
24
|
+
|
|
25
|
+
// Automatically annotate React components to show their full name in breadcrumbs and session replay
|
|
26
|
+
reactComponentAnnotation: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
// Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
|
|
31
|
+
// This can increase your server load as well as your hosting bill.
|
|
32
|
+
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
|
|
33
|
+
// side errors will fail.
|
|
34
|
+
tunnelRoute: "/monitoring",
|
|
35
|
+
|
|
36
|
+
// Hides source maps from generated client bundles
|
|
37
|
+
|
|
38
|
+
// Automatically tree-shake Sentry logger statements to reduce bundle size
|
|
39
|
+
disableLogger: true,
|
|
40
|
+
|
|
41
|
+
// Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
|
|
42
|
+
// See the following for more information:
|
|
43
|
+
// https://docs.sentry.io/product/crons/
|
|
44
|
+
// https://vercel.com/docs/cron-jobs
|
|
45
|
+
automaticVercelMonitors: true,
|
|
46
|
+
});
|