# Azure DevOps CI/CD Pipeline for Test Execution # Generated by BMad TEA Agent - Test Architect Module # Optimized for: Parallel Sharding, Burn-In Loop # Stack: {test_stack_type} | Framework: {test_framework} # # Variables to customize per project: # INSTALL_CMD - dependency install command (e.g., npm ci, pnpm install --frozen-lockfile) # TEST_CMD - main test command (e.g., npm run test:e2e, npm test, npx vitest) # LINT_CMD - lint command (e.g., npm run lint) # BROWSER_INSTALL - browser install command (frontend/fullstack only; omit for backend) # DEFAULT_NODE_VERSION - Node.js version (read from .nvmrc or default to 24) trigger: branches: include: - main - develop pr: branches: include: - main - develop variables: DEFAULT_NODE_VERSION: "24" npm_config_cache: $(Pipeline.Workspace)/.npm # Set TEST_STACK_TYPE to 'backend' to skip Playwright browser installs TEST_STACK_TYPE: "" # Values: frontend, backend, fullstack (leave empty for auto) stages: # Lint stage - Code quality checks - stage: Lint displayName: "Lint" jobs: - job: LintJob displayName: "Code Quality" pool: vmImage: "ubuntu-latest" timeoutInMinutes: 5 steps: - task: NodeTool@0 inputs: versionSpec: $(DEFAULT_NODE_VERSION) displayName: "Setup Node.js" - task: Cache@2 inputs: key: 'npm | "$(Agent.OS)" | package-lock.json' restoreKeys: 'npm | "$(Agent.OS)"' path: $(npm_config_cache) displayName: "Cache npm" - script: npm ci displayName: "Install dependencies" # Replace with INSTALL_CMD - script: npm run lint displayName: "Run linter" # Replace with LINT_CMD # Test stage - Parallel execution with sharding - stage: Test displayName: "Test" dependsOn: Lint jobs: - job: TestShard displayName: "Test Shard" pool: vmImage: "ubuntu-latest" timeoutInMinutes: 30 strategy: matrix: Shard1: SHARD_INDEX: 1 Shard2: SHARD_INDEX: 2 Shard3: SHARD_INDEX: 3 Shard4: SHARD_INDEX: 4 steps: - task: NodeTool@0 inputs: versionSpec: $(DEFAULT_NODE_VERSION) displayName: "Setup Node.js" - task: Cache@2 inputs: key: 'npm | "$(Agent.OS)" | package-lock.json' restoreKeys: 'npm | "$(Agent.OS)"' path: $(npm_config_cache) displayName: "Cache npm" - script: npm ci displayName: "Install dependencies" # Replace with INSTALL_CMD # Frontend/Fullstack only — skipped for backend-only stacks - script: npx playwright install --with-deps chromium condition: ne(variables['TEST_STACK_TYPE'], 'backend') displayName: "Install Playwright browsers" # Replace with BROWSER_INSTALL - script: npm run test:e2e -- --shard=$(SHARD_INDEX)/4 displayName: "Run tests (shard $(SHARD_INDEX)/4)" # Replace with TEST_CMD + shard args - task: PublishTestResults@2 condition: always() inputs: testResultsFormat: "JUnit" testResultsFiles: "test-results/**/*.xml" mergeTestResults: true displayName: "Publish test results" - publish: test-results/ artifact: test-results-$(SHARD_INDEX) condition: failed() displayName: "Upload failure artifacts" # Burn-in stage - Flaky test detection # Note: Burn-in targets UI flakiness. For backend-only stacks, remove this stage entirely. - stage: BurnIn displayName: "Burn-In (Flaky Detection)" dependsOn: Test condition: and(succeeded(), or(eq(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.CronSchedule.DisplayName'], 'Weekly burn-in'))) jobs: - job: BurnInJob displayName: "Burn-In Loop" pool: vmImage: "ubuntu-latest" timeoutInMinutes: 60 steps: - task: NodeTool@0 inputs: versionSpec: $(DEFAULT_NODE_VERSION) displayName: "Setup Node.js" - script: npm ci displayName: "Install dependencies" # Replace with INSTALL_CMD # Frontend/Fullstack only — skipped for backend-only stacks - script: npx playwright install --with-deps chromium condition: ne(variables['TEST_STACK_TYPE'], 'backend') displayName: "Install Playwright browsers" # Replace with BROWSER_INSTALL - script: | echo "Starting burn-in loop - detecting flaky tests" for i in $(seq 1 10); do echo "Burn-in iteration $i/10" npm run test:e2e || exit 1 done echo "Burn-in complete - no flaky tests detected" displayName: "Run burn-in loop (10 iterations)" # Replace npm run test:e2e with TEST_CMD - publish: test-results/ artifact: burn-in-failures condition: failed() displayName: "Upload burn-in failure artifacts"