specwright/templates/skills/dev-team/qa/regression-testing/SKILL.md
# Regression Testing Skill > Role: QA Engineer - Regression Testing & Continuous Testing > Created: 2026-01-09 > Purpose: Maintain comprehensive regression test suites and ensure continuous testing throughout development lifecycle ## Skill Activation Activate this skill when: - Setting up regression test suites for new projects - Maintaining and updating existing regression tests - Planning regression testing for releases - Optimizing regression test execution - Addressing test failures and f
npx skillsauth add michsindlinger/specwright specwright/templates/skills/dev-team/qa/regression-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Role: QA Engineer - Regression Testing & Continuous Testing Created: 2026-01-09 Purpose: Maintain comprehensive regression test suites and ensure continuous testing throughout development lifecycle
Activate this skill when:
# spec/spec_helper.rb
RSpec.configure do |config|
# Tag-based test organization
config.define_derived_metadata(file_path: %r{/spec/models/}) do |metadata|
metadata[:type] = :model
metadata[:suite] = :unit
end
config.define_derived_metadata(file_path: %r{/spec/requests/}) do |metadata|
metadata[:type] = :request
metadata[:suite] = :integration
end
config.define_derived_metadata(file_path: %r{/spec/system/}) do |metadata|
metadata[:type] = :system
metadata[:suite] = :e2e
end
# Smoke test tagging
config.define_derived_metadata(smoke: true) do |metadata|
metadata[:suite] = :smoke
end
# Critical path tagging
config.define_derived_metadata(critical: true) do |metadata|
metadata[:priority] = :high
end
end
# spec/smoke/critical_paths_spec.rb
require 'rails_helper'
RSpec.describe 'Critical Paths', type: :system, smoke: true do
it 'allows user signup and login', :critical do
# Signup
visit signup_path
fill_in 'Email', with: '[email protected]'
fill_in 'Password', with: 'SecureP@ss123'
fill_in 'Password confirmation', with: 'SecureP@ss123'
click_button 'Sign Up'
expect(page).to have_content('Welcome')
# Logout
click_button 'Account'
click_link 'Log Out'
# Login
visit login_path
fill_in 'Email', with: '[email protected]'
fill_in 'Password', with: 'SecureP@ss123'
click_button 'Log In'
expect(page).to have_content('Welcome back')
end
it 'allows authenticated user to create and view content', :critical do
user = create(:user)
sign_in(user)
visit new_post_path
fill_in 'Title', with: 'Test Post'
fill_in 'Content', with: 'This is test content'
click_button 'Publish'
expect(page).to have_content('Post published successfully')
expect(page).to have_content('Test Post')
expect(page).to have_content('This is test content')
end
it 'processes payments successfully', :critical do
user = create(:user)
product = create(:product, price: 99.99)
sign_in(user)
visit product_path(product)
click_button 'Buy Now'
# Mock payment processing
fill_in 'Card number', with: '4242424242424242'
fill_in 'Expiry', with: '12/25'
fill_in 'CVC', with: '123'
click_button 'Pay $99.99'
expect(page).to have_content('Payment successful')
expect(user.purchases.last.product).to eq(product)
end
end
# Run smoke tests only
# bundle exec rspec --tag smoke
# .rspec_parallel
--require rails_helper
--color
--format progress
--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
# Run tests in parallel
# bundle exec parallel_rspec spec/ -n 4
# Gemfile
group :test do
gem 'parallel_tests'
end
# spec/spec_helper.rb
require 'rspec/retry'
RSpec.configure do |config|
# Show retry status in spec process
config.verbose_retry = true
# Show exception that triggers a retry if verbose_retry is set to true
config.display_try_failure_messages = true
# Run retry only on system tests (which may have timing issues)
config.around :each, :system do |example|
example.run_with_retry retry: 3, retry_wait: 1
end
# Callback to run before each retry
config.retry_callback = proc do |example|
# Clean up state before retry
Capybara.reset_sessions!
DatabaseCleaner.clean_with(:truncation)
end
end
// jest.config.js
module.exports = {
projects: [
{
displayName: 'unit',
testMatch: ['**/__tests__/**/*.test.[jt]s?(x)'],
testPathIgnorePatterns: ['/integration/', '/e2e/']
},
{
displayName: 'integration',
testMatch: ['**/__tests__/integration/**/*.test.[jt]s?(x)']
}
],
// Smoke tests runner
testNamePattern: process.env.SMOKE_ONLY ? '^.*(smoke|critical).*$' : undefined
};
// Run specific suites
// npm test -- --selectProjects=unit
// npm test -- --selectProjects=integration
// SMOKE_ONLY=true npm test
// src/__tests__/smoke/critical-paths.test.jsx
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { App } from '../../App';
describe('Critical Paths (smoke)', () => {
it('completes user signup flow', async () => {
render(<App />);
// Navigate to signup
await userEvent.click(screen.getByRole('link', { name: /sign up/i }));
// Fill signup form
await userEvent.type(screen.getByLabelText(/email/i), '[email protected]');
await userEvent.type(screen.getByLabelText(/^password$/i), 'SecureP@ss123');
await userEvent.type(screen.getByLabelText(/confirm password/i), 'SecureP@ss123');
await userEvent.click(screen.getByRole('button', { name: /create account/i }));
// Verify success
await waitFor(() => {
expect(screen.getByText(/welcome/i)).toBeInTheDocument();
});
});
it('allows authenticated user to create content', async () => {
const user = userEvent.setup();
render(<App initialRoute="/dashboard" isAuthenticated />);
// Create new post
await user.click(screen.getByRole('button', { name: /new post/i }));
await user.type(screen.getByLabelText(/title/i), 'Test Post');
await user.type(screen.getByLabelText(/content/i), 'Test content');
await user.click(screen.getByRole('button', { name: /publish/i }));
// Verify post created
await waitFor(() => {
expect(screen.getByText('Test Post')).toBeInTheDocument();
});
});
});
// tests/e2e/regression/critical-flows.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Critical User Flows', () => {
test.describe.configure({ mode: 'serial' });
test('user can sign up, create content, and logout', async ({ page }) => {
// Sign up
await page.goto('/signup');
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password', { exact: true }).fill('SecureP@ss123');
await page.getByLabel('Confirm Password').fill('SecureP@ss123');
await page.getByRole('button', { name: 'Sign Up' }).click();
await expect(page).toHaveURL(/.*dashboard/);
await expect(page.getByText(/welcome/i)).toBeVisible();
// Create content
await page.getByRole('button', { name: 'New Post' }).click();
await page.getByLabel('Title').fill('My First Post');
await page.getByLabel('Content').fill('This is my first post content');
await page.getByRole('button', { name: 'Publish' }).click();
await expect(page.getByText('My First Post')).toBeVisible();
// Logout
await page.getByRole('button', { name: 'Account' }).click();
await page.getByRole('menuitem', { name: 'Logout' }).click();
await expect(page).toHaveURL('/');
});
test('handles errors gracefully', async ({ page }) => {
// Test network error handling
await page.route('**/api/**', route => route.abort());
await page.goto('/dashboard');
await expect(page.getByText(/unable to load/i)).toBeVisible();
await expect(page.getByRole('button', { name: /retry/i })).toBeVisible();
});
});
// Playwright parallel execution
// npx playwright test --workers=4
// Run only smoke tests
// npx playwright test --grep @smoke
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Retry failed tests
retries: process.env.CI ? 2 : 0,
// Test timeout
timeout: 30000,
// Expect timeout
expect: {
timeout: 5000
},
// Parallel execution
workers: process.env.CI ? 1 : undefined,
fullyParallel: true,
// Fail fast in CI
maxFailures: process.env.CI ? 5 : undefined,
// Reporter configuration
reporter: [
['html'],
['junit', { outputFile: 'test-results/junit.xml' }],
['list']
],
use: {
// Base URL
baseURL: process.env.BASE_URL || 'http://localhost:3000',
// Screenshot on failure
screenshot: 'only-on-failure',
// Video on retry
video: 'retain-on-failure',
// Trace on first retry
trace: 'on-first-retry'
}
});
# .github/workflows/regression-tests.yml
name: Regression Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
# Run full regression daily at 2 AM
- cron: '0 2 * * *'
jobs:
smoke-tests:
name: Smoke Tests
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- name: Set up database
run: |
bundle exec rails db:create db:schema:load
bundle exec rails db:seed
- name: Run smoke tests
run: bundle exec rspec --tag smoke
timeout-minutes: 5
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: smoke-test-results
path: tmp/rspec-results.xml
unit-tests:
name: Unit Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- name: Run unit tests
run: bundle exec rspec spec/models spec/services spec/helpers
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage.json
flags: unit
integration-tests:
name: Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 20
services:
postgres:
image: postgres:17
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.2
bundler-cache: true
- name: Set up database
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
run: |
bundle exec rails db:create db:schema:load
- name: Run integration tests
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test
run: bundle exec rspec spec/requests spec/controllers
e2e-tests:
name: E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Start application
run: |
npm run build
npm start &
npx wait-on http://localhost:3000
- name: Run E2E tests
run: npx playwright test
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: playwright-report/
full-regression:
name: Full Regression Suite
runs-on: ubuntu-latest
# Only run on schedule or manual trigger
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
timeout-minutes: 60
strategy:
matrix:
browser: [chromium, firefox, webkit]
steps:
- uses: actions/checkout@v3
- name: Set up environment
# ... setup steps ...
- name: Run full test suite
run: |
bundle exec rspec
npx playwright test --project=${{ matrix.browser }}
- name: Generate combined report
if: always()
run: |
# Combine all test results
node scripts/combine-test-results.js
regression-summary:
name: Regression Summary
runs-on: ubuntu-latest
needs: [smoke-tests, unit-tests, integration-tests, e2e-tests]
if: always()
steps:
- name: Download all artifacts
uses: actions/download-artifact@v3
- name: Generate summary report
run: |
echo "## Regression Test Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Suite | Status | Duration |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|----------|" >> $GITHUB_STEP_SUMMARY
# Parse results and add to summary
# (Implementation depends on your test result format)
[MCP_TOOLS]
<!-- Populated during skill creation based on: 1. User's installed MCP servers 2. User's selection for this skill Recommended for this skill (examples): - github - Monitor CI/CD pipelines and test runs - filesystem - Access test suites and artifacts - slack - Send test failure notifications Note: Skills work without MCP servers, but functionality may be limited -->**Test Priority Levels:**
**P0 - Smoke Tests (5-10 minutes)**
- User authentication flow
- Critical business transactions
- Data integrity checks
- System health checks
**P1 - Core Regression (15-20 minutes)**
- All P0 tests
- Main user workflows
- API endpoints
- Database operations
**P2 - Full Regression (30-60 minutes)**
- All P1 tests
- Edge cases and error scenarios
- Cross-browser testing
- Performance tests
**P3 - Extended Regression (1-2 hours)**
- All P2 tests
- Compatibility testing
- Localization testing
- Accessibility testing
spec/
├── smoke/ # P0 - Critical paths only
│ └── critical_paths_spec.rb
├── models/ # P1 - Business logic
│ ├── user_spec.rb
│ └── payment_spec.rb
├── requests/ # P1 - API endpoints
│ ├── api/
│ └── web/
├── system/ # P2 - Full user flows
│ ├── authentication/
│ ├── checkout/
│ └── admin/
└── compatibility/ # P3 - Extended tests
├── browsers/
└── devices/
1. **Identify** - Detect failure in CI/CD
2. **Classify** - Product bug vs. test issue
3. **Isolate** - Can failure be reproduced locally?
4. **Document** - Log failure details and context
5. **Fix** - Fix product or test issue
6. **Verify** - Confirm fix resolves failure
7. **Monitor** - Watch for recurrence
**Prevention:**
- Use explicit waits, not sleeps
- Ensure test data isolation
- Clean up state between tests
- Avoid time-dependent assertions
**Detection:**
- Run tests multiple times
- Track test pass/fail history
- Monitor test stability metrics
**Resolution:**
- Quarantine flaky tests immediately
- Investigate root cause
- Fix or rewrite test
- Re-enable after verification
Track these metrics for regression testing:
tools
Session Handoff: Erstellt eine vollständige Zusammenfassung der aktuellen Session für einen sauberen Kontextwechsel. NUR bei explizitem Aufruf (/session-handoff). NICHT automatisch auslösen. Geeignet wenn der User die Session resetten will, den Kontext aufräumen will, oder bei ~120k Tokens angelangt ist.
development
Pre-Mortem Risk Analysis: Strukturierte Prospective-Hindsight-Übung um launch-blocking Risiken vor Commitment aufzudecken. Team stellt sich vor, das Produkt sei 14 Tage nach Launch gefloppt, und arbeitet rückwärts. Klassifiziert Risiken in Tigers (echt), Paper Tigers (hypothetisch), Elephants (unausgesprochen). Nutze diesen Skill vor Build-Commitment, bei zu hoher Stakeholder-Confidence, vor Major-Releases, oder wenn das Team vage Sorgen nicht artikulieren kann. Trigger: /pre-mortem, 'pre-mortem', 'risk analysis', 'was könnte schiefgehen', 'risiken vor launch'.
testing
Six-Sigma Atomicity Validator for create-spec stories
tools
UX pattern definition guidance for navigation, user flows, interactions, and accessibility