@saulwade/swl-ses 1.0.0
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.
- package/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: php-patrones
|
|
3
|
+
description: >
|
|
4
|
+
Patrones Laravel modernos: Action classes, Service classes, DTOs readonly,
|
|
5
|
+
Pipeline, Repository con interfaces, Enums, Value Objects y Feature Flags.
|
|
6
|
+
Cargar cuando se diseñe arquitectura Laravel o se refactoricen controllers.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
herramientasPermitidas: [Read, Glob, Grep]
|
|
9
|
+
exclusiones:
|
|
10
|
+
- "No cargar para implementar controllers, modelos Eloquent o Jobs concretos — para implementación cargar `php-experto`."
|
|
11
|
+
- "No cargar para escribir tests PHPUnit o Pest — para testing cargar `php-testing`."
|
|
12
|
+
- "No cargar para errores de Composer o extensiones PHP — para build errors cargar `build-errors-php`."
|
|
13
|
+
- "No cargar para patrones de diseño genéricos sin contexto Laravel — este skill cubre Action classes, Service classes y Value Objects en el contexto del ecosistema Laravel."
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
---
|
|
16
|
+
# PHP Patrones — Arquitectura Laravel Moderna
|
|
17
|
+
|
|
18
|
+
Los controladores de Laravel son puntos de entrada HTTP, no contenedores de
|
|
19
|
+
lógica de negocio. Este skill cubre los patrones que mantienen el código
|
|
20
|
+
organizado, testeable y mantenible a medida que la aplicación crece.
|
|
21
|
+
|
|
22
|
+
## Cuándo cargar este skill
|
|
23
|
+
|
|
24
|
+
Invoca `Skill("php-patrones")` cuando:
|
|
25
|
+
|
|
26
|
+
- Se refactorice un controller con más de 50 líneas de lógica
|
|
27
|
+
- Se diseñe la arquitectura de un módulo nuevo
|
|
28
|
+
- Se implemente un flujo con múltiples pasos secuenciales
|
|
29
|
+
- Se requieran DTOs tipados para transferir datos entre capas
|
|
30
|
+
- Se evalúen feature flags con Laravel Pennant
|
|
31
|
+
|
|
32
|
+
## Cuándo NO cargar
|
|
33
|
+
|
|
34
|
+
- La pregunta es sobre implementar controllers, modelos Eloquent o Jobs concretos — para implementación cargar `php-experto`.
|
|
35
|
+
- La tarea es escribir tests PHPUnit o Pest — cargar `php-testing`.
|
|
36
|
+
- Los errores son de Composer o extensiones PHP — cargar `build-errors-php`.
|
|
37
|
+
- La discusión es sobre patrones GoF genéricos sin contexto Laravel — este skill cubre Action classes, Service classes y Value Objects en el ecosistema Laravel.
|
|
38
|
+
|
|
39
|
+
## Conceptos clave
|
|
40
|
+
|
|
41
|
+
### Action Classes — una clase, una operación
|
|
42
|
+
|
|
43
|
+
Una Action encapsula una operación de negocio específica. Es testeable de forma
|
|
44
|
+
aislada, reutilizable desde controllers, jobs y commands, y su nombre documenta
|
|
45
|
+
exactamente lo que hace.
|
|
46
|
+
|
|
47
|
+
### Pipeline Pattern
|
|
48
|
+
|
|
49
|
+
El Pipeline de Laravel permite encadenar operaciones sobre un objeto de forma
|
|
50
|
+
funcional. Cada etapa (pipe) recibe el objeto, lo transforma y lo pasa al siguiente.
|
|
51
|
+
Ideal para flujos con validaciones, transformaciones y efectos secundarios.
|
|
52
|
+
|
|
53
|
+
### DTOs con readonly
|
|
54
|
+
|
|
55
|
+
Los Data Transfer Objects con `readonly` en PHP 8.1+ son inmutables por definición.
|
|
56
|
+
Eliminan setters, garantizan que los datos no cambian después de construirse y
|
|
57
|
+
self-documentan la estructura de datos que fluye entre capas.
|
|
58
|
+
|
|
59
|
+
## Reglas obligatorias
|
|
60
|
+
|
|
61
|
+
### Actions: una responsabilidad, un método público `ejecutar()`
|
|
62
|
+
|
|
63
|
+
```php
|
|
64
|
+
// MAL — Service con multiples responsabilidades mezcladas
|
|
65
|
+
class PedidoService {
|
|
66
|
+
public function crear(array $datos): Pedido { ... }
|
|
67
|
+
public function cancelar(Pedido $pedido): void { ... }
|
|
68
|
+
public function calcularDescuento(Pedido $pedido): float { ... }
|
|
69
|
+
public function enviarNotificacion(Pedido $pedido): void { ... }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// BIEN — Actions separadas y cohesivas
|
|
73
|
+
class CrearPedidoAction {
|
|
74
|
+
public function ejecutar(CrearPedidoDTO $dto): Pedido { ... }
|
|
75
|
+
}
|
|
76
|
+
class CancelarPedidoAction {
|
|
77
|
+
public function ejecutar(Pedido $pedido, string $motivo): void { ... }
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### DTOs readonly para datos de entrada
|
|
82
|
+
|
|
83
|
+
```php
|
|
84
|
+
// MAL — array anonimo sin tipado
|
|
85
|
+
public function ejecutar(array $datos): Pedido
|
|
86
|
+
{
|
|
87
|
+
$nombre = $datos['nombre'] ?? null; // sin autocomplete, sin tipos
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// BIEN — DTO readonly tipado
|
|
91
|
+
readonly class CrearPedidoDTO
|
|
92
|
+
{
|
|
93
|
+
public function __construct(
|
|
94
|
+
public string $nombre,
|
|
95
|
+
public float $total,
|
|
96
|
+
public ?string $cuponDescuento,
|
|
97
|
+
public array $items,
|
|
98
|
+
) {}
|
|
99
|
+
|
|
100
|
+
public static function desdeRequest(StorePedidoRequest $request): self
|
|
101
|
+
{
|
|
102
|
+
return new self(
|
|
103
|
+
nombre: $request->validated('nombre'),
|
|
104
|
+
total: 0.0, // calculado luego
|
|
105
|
+
cuponDescuento: $request->validated('cupon'),
|
|
106
|
+
items: $request->validated('items'),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Repository con interface para abstraer el ORM
|
|
113
|
+
|
|
114
|
+
```php
|
|
115
|
+
interface PedidoRepositoryInterface
|
|
116
|
+
{
|
|
117
|
+
public function encontrarPorId(int $id): ?Pedido;
|
|
118
|
+
public function listarPendientes(): Collection;
|
|
119
|
+
public function guardar(Pedido $pedido): Pedido;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class EloquentPedidoRepository implements PedidoRepositoryInterface
|
|
123
|
+
{
|
|
124
|
+
public function encontrarPorId(int $id): ?Pedido
|
|
125
|
+
{
|
|
126
|
+
return Pedido::with(['items', 'cliente'])->find($id);
|
|
127
|
+
}
|
|
128
|
+
// ...
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Binding en AppServiceProvider
|
|
132
|
+
$this->app->bind(PedidoRepositoryInterface::class, EloquentPedidoRepository::class);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Por qué**: Permite swapear la implementación (ej: agregar cache) sin tocar
|
|
136
|
+
la lógica de negocio. Facilita mocking en tests.
|
|
137
|
+
|
|
138
|
+
## Patrones recomendados
|
|
139
|
+
|
|
140
|
+
### Pipeline para flujos multi-etapa
|
|
141
|
+
|
|
142
|
+
```php
|
|
143
|
+
class ProcesarPedidoAction
|
|
144
|
+
{
|
|
145
|
+
public function ejecutar(Pedido $pedido): Pedido
|
|
146
|
+
{
|
|
147
|
+
return app(Pipeline::class)
|
|
148
|
+
->send($pedido)
|
|
149
|
+
->through([
|
|
150
|
+
ValidarStockPipe::class,
|
|
151
|
+
AplicarDescuentoPipe::class,
|
|
152
|
+
CalcularEnvioPipe::class,
|
|
153
|
+
ReservarInventarioPipe::class,
|
|
154
|
+
])
|
|
155
|
+
->thenReturn();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
class ValidarStockPipe
|
|
160
|
+
{
|
|
161
|
+
public function handle(Pedido $pedido, Closure $next): Pedido
|
|
162
|
+
{
|
|
163
|
+
foreach ($pedido->items as $item) {
|
|
164
|
+
throw_unless($item->producto->tieneStock($item->cantidad),
|
|
165
|
+
new StockInsuficienteException($item->producto));
|
|
166
|
+
}
|
|
167
|
+
return $next($pedido);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Enum casting en modelos
|
|
173
|
+
|
|
174
|
+
```php
|
|
175
|
+
// Definir el enum (PHP 8.1+)
|
|
176
|
+
enum EstatusPedido: string
|
|
177
|
+
{
|
|
178
|
+
case Pendiente = 'pendiente';
|
|
179
|
+
case Pagado = 'pagado';
|
|
180
|
+
case Cancelado = 'cancelado';
|
|
181
|
+
|
|
182
|
+
public function puedeTransicionarA(self $nuevo): bool
|
|
183
|
+
{
|
|
184
|
+
return match($this) {
|
|
185
|
+
self::Pendiente => in_array($nuevo, [self::Pagado, self::Cancelado]),
|
|
186
|
+
default => false,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Castear en el modelo
|
|
192
|
+
class Pedido extends Model
|
|
193
|
+
{
|
|
194
|
+
protected $casts = [
|
|
195
|
+
'estatus' => EstatusPedido::class,
|
|
196
|
+
];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Uso con tipado fuerte
|
|
200
|
+
if ($pedido->estatus->puedeTransicionarA(EstatusPedido::Cancelado)) {
|
|
201
|
+
$pedido->update(['estatus' => EstatusPedido::Cancelado]);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Laravel Pennant para feature flags
|
|
206
|
+
|
|
207
|
+
```php
|
|
208
|
+
// Definir el flag en AppServiceProvider
|
|
209
|
+
Feature::define('nuevo-checkout', fn (User $user) =>
|
|
210
|
+
$user->created_at->isAfter(now()->subDays(30))
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
// Verificar en el codigo
|
|
214
|
+
if (Feature::active('nuevo-checkout')) {
|
|
215
|
+
return new NuevoCheckoutAction();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// En Blade
|
|
219
|
+
@feature('nuevo-checkout')
|
|
220
|
+
<x-nuevo-checkout />
|
|
221
|
+
@endfeature
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Value Objects para conceptos del dominio
|
|
225
|
+
|
|
226
|
+
```php
|
|
227
|
+
readonly class Dinero
|
|
228
|
+
{
|
|
229
|
+
public function __construct(
|
|
230
|
+
public readonly float $monto,
|
|
231
|
+
public readonly string $moneda = 'MXN',
|
|
232
|
+
) {
|
|
233
|
+
if ($monto < 0) {
|
|
234
|
+
throw new \InvalidArgumentException("El monto no puede ser negativo");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public function sumar(self $otro): self
|
|
239
|
+
{
|
|
240
|
+
if ($this->moneda !== $otro->moneda) {
|
|
241
|
+
throw new MonedaIncompatibleException();
|
|
242
|
+
}
|
|
243
|
+
return new self($this->monto + $otro->monto, $this->moneda);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public function __toString(): string
|
|
247
|
+
{
|
|
248
|
+
return number_format($this->monto, 2) . ' ' . $this->moneda;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Anti-patrones conocidos
|
|
254
|
+
|
|
255
|
+
### Fat Controllers — NUNCA más de 10 líneas de lógica por método
|
|
256
|
+
|
|
257
|
+
Un controller que hace queries, calcula totales, envía emails y retorna respuesta
|
|
258
|
+
es imposible de testear y mantener. Delegar a Actions o Services.
|
|
259
|
+
|
|
260
|
+
### Model Callbacks para lógica compleja
|
|
261
|
+
|
|
262
|
+
```php
|
|
263
|
+
// MAL — logica oculta en boot() del modelo
|
|
264
|
+
protected static function boot(): void
|
|
265
|
+
{
|
|
266
|
+
static::created(function (Pedido $pedido) {
|
|
267
|
+
// envia email, actualiza inventario, crea factura...
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// BIEN — logica explicita en un Event Listener o Action
|
|
272
|
+
// El caller sabe que estas cosas suceden porque las ve en el codigo
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Helpers globales para lógica de negocio
|
|
276
|
+
|
|
277
|
+
Los `helpers.php` globales son difíciles de testear y crean acoplamiento implícito.
|
|
278
|
+
Usar classes estaticas o inyectables en su lugar.
|
|
279
|
+
|
|
280
|
+
## Checklist de verificación
|
|
281
|
+
|
|
282
|
+
- [ ] Controllers delegan a Actions o Services (< 15 líneas por método)
|
|
283
|
+
- [ ] DTOs readonly para datos de entrada tipados
|
|
284
|
+
- [ ] Enums en lugar de strings mágicos para estados
|
|
285
|
+
- [ ] Repository interface si la lógica de acceso a datos es compleja
|
|
286
|
+
- [ ] Pipeline para flujos con más de 3 pasos secuenciales
|
|
287
|
+
- [ ] Feature flags para funcionalidades en desarrollo progresivo
|
|
288
|
+
|
|
289
|
+
## Referencias
|
|
290
|
+
|
|
291
|
+
- [Laravel Service Container](https://laravel.com/docs/container)
|
|
292
|
+
- [PHP 8.1 Enums](https://www.php.net/manual/es/language.enumerations.php)
|
|
293
|
+
- [Laravel Pennant](https://laravel.com/docs/pennant)
|
|
294
|
+
|
|
295
|
+
## Gotchas / Errores comunes no obvios
|
|
296
|
+
|
|
297
|
+
**Action class que lanza excepción en lugar de retornar `Result` o DTO rompe el flujo de la pipeline**: si una Action usa `throw new ValidationException(...)` internamente pero la pipeline espera un valor de retorno tipado, el calling code necesita un `try/catch` duplicado en cada lugar. Fix: definir la Action con retorno `Result<T>` o con un DTO de respuesta que incluya el estado de éxito/fallo — reservar las excepciones solo para errores inesperados.
|
|
298
|
+
|
|
299
|
+
**Pipeline de Laravel que modifica `$passable` por referencia en lugar de retornar el nuevo valor no funciona con `Closure::class`**: si un pipe en la pipeline modifica el objeto pasado en lugar de retornar el resultado del `$next($passable)`, los pipes subsecuentes reciben el objeto original sin las modificaciones. Fix: siempre retornar `$next($passable)` desde cada pipe — la pipeline de Laravel es un chain de decorators, no una lista de efectos secundarios.
|
|
300
|
+
|
|
301
|
+
**DTO `readonly` con propiedades de tipo objeto mutable no es realmente inmutable**: `readonly class FacturaDto { public function __construct(public readonly array $items) {} }` — `$dto->items` no puede reasignarse, pero si `$items` contiene objetos mutables, esos objetos pueden modificarse. Fix: usar `array_map` para crear copias de los objetos contenidos, o usar colecciones inmutables con tipos `readonly` anidados.
|
|
302
|
+
|
|
303
|
+
**Feature flag con `Pennant::for($usuario)->active('flag')` no funciona en un Job sin el usuario en contexto**: dentro de un Job, el usuario autenticado no está disponible automáticamente — `Pennant::for(Auth::user())` retorna null si no se pasó el usuario explícitamente al job. Fix: pasar el usuario como propiedad del job en el constructor y usar `Pennant::for($this->usuario)->active('flag')` dentro del job.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: php-testing
|
|
3
|
+
description: >
|
|
4
|
+
Testing PHP con PHPUnit y Pest: factories, feature tests Laravel, Mockery,
|
|
5
|
+
HTTP tests, Job/Event faking y Dusk. Cargar cuando se escriban tests PHP,
|
|
6
|
+
se configuren factories o se establezca cobertura de código.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
herramientasPermitidas: [Read, Grep]
|
|
9
|
+
exclusiones:
|
|
10
|
+
- "No cargar para implementar el código Laravel de producción — primero implementar con `php-experto`, luego escribir tests."
|
|
11
|
+
- "No cargar para diseñar patrones Laravel — para diseño cargar `php-patrones`."
|
|
12
|
+
- "No cargar para errores de Composer o extensiones PHP — para build errors cargar `build-errors-php`."
|
|
13
|
+
- "No cargar para tests de carga o rendimiento en PHP — JMeter, k6 y Gatling no están cubiertos en este skill."
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
---
|
|
16
|
+
# PHP Testing — PHPUnit, Pest y Laravel Testing
|
|
17
|
+
|
|
18
|
+
Laravel incluye una suite de testing completa sobre PHPUnit. Pest es una capa
|
|
19
|
+
expresiva encima de PHPUnit que reduce boilerplate. Este skill cubre la escritura
|
|
20
|
+
de tests idiomáticos para aplicaciones Laravel: feature tests, unit tests,
|
|
21
|
+
factories, fakes y pruebas de browser con Dusk.
|
|
22
|
+
|
|
23
|
+
## Cuándo cargar este skill
|
|
24
|
+
|
|
25
|
+
Invoca `Skill("php-testing")` cuando:
|
|
26
|
+
|
|
27
|
+
- Se escriban tests unitarios o de feature en Laravel
|
|
28
|
+
- Se creen o modifiquen factories de Eloquent
|
|
29
|
+
- Se configuren thresholds de cobertura de código
|
|
30
|
+
- Se prueben Jobs, Events, Mail o Notifications
|
|
31
|
+
- Se implementen browser tests con Laravel Dusk
|
|
32
|
+
|
|
33
|
+
## Cuándo NO cargar
|
|
34
|
+
|
|
35
|
+
- El código Laravel de producción aún no existe — primero implementar con `php-experto`, luego escribir tests.
|
|
36
|
+
- La pregunta es sobre diseñar patrones Laravel (Action classes, DTOs) — cargar `php-patrones`.
|
|
37
|
+
- Los errores son de Composer o extensiones PHP en los tests — cargar `build-errors-php`.
|
|
38
|
+
- La pregunta es sobre tests de carga o rendimiento — JMeter, k6 y Gatling no están cubiertos en este skill.
|
|
39
|
+
|
|
40
|
+
## Conceptos clave
|
|
41
|
+
|
|
42
|
+
### PHPUnit vs Pest
|
|
43
|
+
|
|
44
|
+
PHPUnit usa clases que extienden `TestCase`. Pest usa funciones globales `it()`,
|
|
45
|
+
`test()` y `describe()` con una API fluida. Pest compila a PHPUnit internamente
|
|
46
|
+
— no son incompatibles, pueden coexistir.
|
|
47
|
+
|
|
48
|
+
### RefreshDatabase vs DatabaseTransactions
|
|
49
|
+
|
|
50
|
+
`RefreshDatabase` recrea el schema completo antes de cada test (lento, aislado).
|
|
51
|
+
`DatabaseTransactions` envuelve cada test en una transacción que se revierte
|
|
52
|
+
(rápido, pero no funciona con tests que usan múltiples conexiones o transacciones
|
|
53
|
+
anidadas reales).
|
|
54
|
+
|
|
55
|
+
### Factories con estados
|
|
56
|
+
|
|
57
|
+
Las factories generan modelos con valores por defecto. Los `states` sobreescriben
|
|
58
|
+
atributos para escenarios específicos sin duplicar la factory base.
|
|
59
|
+
|
|
60
|
+
## Reglas obligatorias
|
|
61
|
+
|
|
62
|
+
### SIEMPRE usar factories — nunca crear modelos manualmente en tests
|
|
63
|
+
|
|
64
|
+
```php
|
|
65
|
+
// MAL — fragil, se rompe si el schema cambia
|
|
66
|
+
$usuario = Usuario::create([
|
|
67
|
+
'nombre' => 'Juan',
|
|
68
|
+
'email' => 'juan@test.com',
|
|
69
|
+
'password' => bcrypt('secret'),
|
|
70
|
+
'rol' => 'admin',
|
|
71
|
+
// olvidaste 3 campos NOT NULL con defaults
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
// BIEN — factory maneja defaults, solo sobreescribir lo relevante al test
|
|
75
|
+
$usuario = Usuario::factory()->create(['rol' => 'admin']);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### NUNCA usar sleep() en tests — mockear el tiempo con Carbon::setTestNow()
|
|
79
|
+
|
|
80
|
+
```php
|
|
81
|
+
// MAL
|
|
82
|
+
$token = Token::factory()->create();
|
|
83
|
+
sleep(3601); // esperar que expire
|
|
84
|
+
$this->assertFalse($token->esValido());
|
|
85
|
+
|
|
86
|
+
// BIEN
|
|
87
|
+
$token = Token::factory()->create();
|
|
88
|
+
Carbon::setTestNow(now()->addHour()->addSecond());
|
|
89
|
+
$this->assertFalse($token->esValido());
|
|
90
|
+
Carbon::setTestNow(); // limpiar en tearDown
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Usar fakes ANTES de ejecutar la acción — nunca después
|
|
94
|
+
|
|
95
|
+
```php
|
|
96
|
+
// MAL — el job ya se despacho antes de poner el fake
|
|
97
|
+
$this->post('/pedidos', $datos);
|
|
98
|
+
Queue::fake(); // tarde, no capturo el dispatch
|
|
99
|
+
|
|
100
|
+
// BIEN
|
|
101
|
+
Queue::fake();
|
|
102
|
+
$this->post('/pedidos', $datos);
|
|
103
|
+
Queue::assertPushed(ProcesarPedido::class);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Patrones recomendados
|
|
107
|
+
|
|
108
|
+
### Pest — sintaxis moderna y expresiva
|
|
109
|
+
|
|
110
|
+
```php
|
|
111
|
+
// Pest con datasets (parametrizado)
|
|
112
|
+
it('rechaza emails invalidos', function (string $email) {
|
|
113
|
+
$response = $this->postJson('/api/registro', ['email' => $email]);
|
|
114
|
+
$response->assertUnprocessable();
|
|
115
|
+
})->with([
|
|
116
|
+
'sin arroba' => ['nombre-sin-arroba'],
|
|
117
|
+
'sin dominio' => ['nombre@'],
|
|
118
|
+
'solo espacio' => [' '],
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
// Pest con beforeEach
|
|
122
|
+
beforeEach(function () {
|
|
123
|
+
$this->usuario = Usuario::factory()->create();
|
|
124
|
+
$this->actingAs($this->usuario, 'sanctum');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('puede ver sus pedidos', function () {
|
|
128
|
+
$pedidos = Pedido::factory(3)->create(['usuario_id' => $this->usuario->id]);
|
|
129
|
+
$this->getJson('/api/pedidos')
|
|
130
|
+
->assertOk()
|
|
131
|
+
->assertJsonCount(3, 'data');
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Factory States para escenarios específicos
|
|
136
|
+
|
|
137
|
+
```php
|
|
138
|
+
class PedidoFactory extends Factory
|
|
139
|
+
{
|
|
140
|
+
public function definition(): array
|
|
141
|
+
{
|
|
142
|
+
return [
|
|
143
|
+
'estatus' => 'pendiente',
|
|
144
|
+
'total' => $this->faker->randomFloat(2, 10, 1000),
|
|
145
|
+
'usuario_id' => Usuario::factory(),
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public function pagado(): static
|
|
150
|
+
{
|
|
151
|
+
return $this->state(fn (array $attrs) => [
|
|
152
|
+
'estatus' => 'pagado',
|
|
153
|
+
'pagado_en' => now(),
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public function cancelado(): static
|
|
158
|
+
{
|
|
159
|
+
return $this->state(['estatus' => 'cancelado']);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Uso en tests
|
|
164
|
+
$pedidoPagado = Pedido::factory()->pagado()->create();
|
|
165
|
+
$lote = Pedido::factory(5)->pagado()->create(['usuario_id' => $usuario->id]);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Feature tests con assertJson y assertDatabaseHas
|
|
169
|
+
|
|
170
|
+
```php
|
|
171
|
+
test('crea un producto correctamente', function () {
|
|
172
|
+
$admin = Usuario::factory()->admin()->create();
|
|
173
|
+
|
|
174
|
+
$response = $this->actingAs($admin, 'sanctum')
|
|
175
|
+
->postJson('/api/productos', [
|
|
176
|
+
'nombre' => 'Laptop Pro',
|
|
177
|
+
'precio' => 25000.00,
|
|
178
|
+
'categoria' => 'electronica',
|
|
179
|
+
]);
|
|
180
|
+
|
|
181
|
+
$response
|
|
182
|
+
->assertCreated()
|
|
183
|
+
->assertJsonStructure(['data' => ['id', 'nombre', 'precio']])
|
|
184
|
+
->assertJsonPath('data.nombre', 'Laptop Pro');
|
|
185
|
+
|
|
186
|
+
$this->assertDatabaseHas('productos', [
|
|
187
|
+
'nombre' => 'Laptop Pro',
|
|
188
|
+
'precio' => 25000.00,
|
|
189
|
+
]);
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Mockery para dependencias externas
|
|
194
|
+
|
|
195
|
+
```php
|
|
196
|
+
test('maneja error del servicio de pago', function () {
|
|
197
|
+
$mockPago = Mockery::mock(ServicioPago::class);
|
|
198
|
+
$mockPago->shouldReceive('cobrar')
|
|
199
|
+
->once()
|
|
200
|
+
->andThrow(new PagoRechazadoException('Fondos insuficientes'));
|
|
201
|
+
|
|
202
|
+
$this->app->instance(ServicioPago::class, $mockPago);
|
|
203
|
+
|
|
204
|
+
$response = $this->postJson('/api/checkout', ['pedido_id' => 1]);
|
|
205
|
+
$response->assertUnprocessable()
|
|
206
|
+
->assertJsonPath('errors.0.code', 'PAGO_RECHAZADO');
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Event y Job Faking
|
|
211
|
+
|
|
212
|
+
```php
|
|
213
|
+
test('despacha job al crear pedido', function () {
|
|
214
|
+
Queue::fake();
|
|
215
|
+
Mail::fake();
|
|
216
|
+
|
|
217
|
+
$response = $this->actingAs($this->usuario, 'sanctum')
|
|
218
|
+
->postJson('/api/pedidos', $this->datosPedido);
|
|
219
|
+
|
|
220
|
+
$response->assertCreated();
|
|
221
|
+
Queue::assertPushed(ProcesarPedido::class, fn ($job) =>
|
|
222
|
+
$job->pedido->id === $response->json('data.id')
|
|
223
|
+
);
|
|
224
|
+
Mail::assertQueued(ConfirmacionPedidoMail::class);
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Anti-patrones conocidos
|
|
229
|
+
|
|
230
|
+
### Tests que dependen del orden de ejecución
|
|
231
|
+
|
|
232
|
+
Cada test debe ser completamente independiente. Usar `RefreshDatabase` o
|
|
233
|
+
`DatabaseTransactions`. NUNCA depender de datos creados en otro test.
|
|
234
|
+
|
|
235
|
+
### assertSee con texto que puede cambiar por i18n
|
|
236
|
+
|
|
237
|
+
```php
|
|
238
|
+
// MAL — fragil si cambia la traduccion
|
|
239
|
+
$response->assertSee('El correo electronico ya esta en uso');
|
|
240
|
+
|
|
241
|
+
// BIEN — verificar la estructura y el codigo de error
|
|
242
|
+
$response->assertJsonPath('errors.0.code', 'EMAIL_DUPLICADO');
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Factory::recycle para evitar crear modelos innecesarios
|
|
246
|
+
|
|
247
|
+
```php
|
|
248
|
+
// Cuando multiples modelos deben compartir el mismo usuario
|
|
249
|
+
$usuario = Usuario::factory()->create();
|
|
250
|
+
$pedidos = Pedido::factory(3)->recycle($usuario)->create();
|
|
251
|
+
// Los 3 pedidos apuntan al mismo usuario, no se crean 3 usuarios
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Checklist de verificación
|
|
255
|
+
|
|
256
|
+
- [ ] Factories usadas en lugar de `Model::create()` manual en tests
|
|
257
|
+
- [ ] `RefreshDatabase` o `DatabaseTransactions` en cada clase de test
|
|
258
|
+
- [ ] Fakes configurados ANTES de ejecutar la acción (Queue::fake, Mail::fake)
|
|
259
|
+
- [ ] Sin `sleep()` en tests — usar Carbon::setTestNow()
|
|
260
|
+
- [ ] Tests de feature cubren happy path Y casos de error
|
|
261
|
+
- [ ] Cobertura >= 80% en módulos de lógica de negocio
|
|
262
|
+
|
|
263
|
+
## Referencias
|
|
264
|
+
|
|
265
|
+
- [Laravel Testing](https://laravel.com/docs/testing)
|
|
266
|
+
- [Pest PHP](https://pestphp.com/docs)
|
|
267
|
+
- [Mockery](https://docs.mockery.io)
|
|
268
|
+
|
|
269
|
+
## Gotchas / Errores comunes no obvios
|
|
270
|
+
|
|
271
|
+
**`RefreshDatabase` recrea las migraciones en cada test de la suite completa, haciendo la suite lenta**: usar `RefreshDatabase` en todas las clases de test puede duplicar el tiempo de la suite en proyectos con muchas migraciones. Fix: usar `DatabaseTransactions` para tests que no necesitan un estado limpio absoluto — rollbackea cada test sin recrear el schema. Usar `RefreshDatabase` solo cuando el test modifica el schema o necesita seeds específicos.
|
|
272
|
+
|
|
273
|
+
**Factory `->create()` en un test de unit (no de feature) hace queries reales a la BD**: las factories de Eloquent usan `Model::create()` que ejecuta SQL — en un test unitario sin base de datos, esto lanza `PDOException`. Fix: usar `->make()` en lugar de `->create()` para tests unitarios que solo necesitan el objeto en memoria, o configurar SQLite en memoria en el `phpunit.xml` para tests que requieren BD.
|
|
274
|
+
|
|
275
|
+
**`Event::fake()` en un test de feature que usa `ShouldQueue` no verifica que el listener fue encolado**: `Event::fake()` intercepta el evento pero no verifica que el listener fue despachado a la queue. Causa: `Event::fake()` reemplaza el sistema de eventos completo. Fix: usar `Queue::fake()` junto con `Event::fake()` si se necesita verificar que el listener fue encolado, y usar `Queue::assertPushed(MiListener::class)`.
|
|
276
|
+
|
|
277
|
+
**`assertDatabaseHas` verifica la presencia de una fila pero no que sea exactamente la correcta**: `assertDatabaseHas('facturas', ['monto' => 100])` pasa si hay al menos una factura con monto=100, incluso si el test debería haber creado una específica. Fix: agregar columnas adicionales al assert para identificar la fila específica (ej: `['id' => $factura->id, 'monto' => 100]`), o usar `assertDatabaseCount` para verificar que exactamente N filas coinciden.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
|