npm package: @scrymore/scry-sbcov
Description: Storybook story coverage analyzer for React component libraries
Author: Scrymore
Latest version: 0.3.0

# scry-sbcov

[![CI](https://github.com/epinnock/scry-sbcov/actions/workflows/ci.yml/badge.svg)](https://github.com/epinnock/scry-sbcov/actions/workflows/ci.yml)

A CLI tool that analyzes React component libraries to identify gaps in Storybook story coverage. Generates comprehensive JSON reports suitable for CI integration, quality gates, and coverage tracking.

## Features

- **Detect components without stories** - Find React components that have no corresponding Storybook stories
- **Analyze scenario coverage** - For components with stories, identify missing prop variants and states (loading, error, disabled, etc.)
- **Track new vs existing code** - SonarQube-style analysis showing coverage metrics separately for new/modified code in PRs
- **Execute and validate stories** - Run stories to detect broken/failing stories (render errors, play function failures)
- **Generate actionable reports** - JSON output with suggested story names and args for missing scenarios

## Installation

```bash
npm install @scrymore/scry-sbcov --save-dev
```

Or run directly with npx:

```bash
npx @scrymore/scry-sbcov
```

## Quick Start

```bash
# Basic analysis with output to file
scry-sbcov --output coverage.json

# CI mode with quality gates
scry-sbcov --ci --base origin/main --threshold-new-code 90

# With story execution (requires playwright)
scry-sbcov --execute --storybook-static ./storybook-static --output report.json

# Verbose output
scry-sbcov -v
```

## CLI Options

```
scry-sbcov [options]

Options:
  -c, --config <path>       Path to config file (default: scry-sbcov.config.js)
  -o, --output <path>       Output JSON report path (default: stdout)
  --include <glob>          Component file patterns (comma-separated)
  --exclude <glob>          Patterns to exclude (comma-separated)
  --stories <glob>          Story file patterns (comma-separated)
  --base <branch>           Base branch for new code analysis (default: main)
  --no-git                  Disable git-based new code analysis
  --execute                 Run stories and capture failures
  --storybook-url <url>     Storybook URL for execution (default: http://localhost:6006)
  --storybook-static <dir>  Path to static Storybook build
  --ci                      CI mode: exit code 1 if quality gate fails
  --threshold-component <n> Component coverage threshold % (default: 80)
  --threshold-new-code <n>  New code coverage threshold % (default: 90)
  -v, --verbose             Verbose output
  --version                 Show version
  --help                    Show help
```

## Configuration

Create a `scry-sbcov.config.js` file in your project root:

```javascript
// scry-sbcov.config.js
module.exports = {
  // Component detection
  include: ['src/components/**/*.tsx'],
  exclude: ['**/*.test.tsx', '**/*.spec.tsx', '**/index.tsx', '**/__mocks__/**'],

  // Story detection
  storyPatterns: ['**/*.stories.tsx', '**/*.stories.ts'],

  // Git analysis
  baseBranch: 'main',
  enableGitAnalysis: true,

  // Story execution
  execute: false,
  storybookUrl: 'http://localhost:6006',
  storybookStaticDir: null,
  executionTimeout: 15000,

  // Quality gates
  thresholds: {
    componentCoverage: 80,
    propCoverage: 70,
    variantCoverage: 60,
    newCodeCoverage: 90,
  },

  // Output
  outputPath: './scry-sbcov-report.json',

  // Scenario detection customization
  scenarioPatterns: {
    loading: ['isLoading', 'loading', 'isProcessing'],
    error: ['isError', 'hasError', 'error', 'errorMessage'],
    empty: ['isEmpty', 'empty', 'noData'],
    disabled: ['disabled', 'isDisabled'],
  },

  // Component matching overrides
  componentStoryMapping: {
    // Manual overrides for complex cases
    'src/components/Button/BaseButton.tsx': 'src/components/Button/Button.stories.tsx',
  },
};
```

You can also add configuration to `package.json`:

```json
{
  "scry-sbcov": {
    "include": ["src/components/**/*.tsx"],
    "thresholds": {
      "componentCoverage": 85
    }
  }
}
```

## Report Output

The tool generates a comprehensive JSON report with the following structure:

```typescript
interface StoryCoverageReport {
  version: '1.0.0';
  generatedAt: string;

  // Git context
  git: {
    commitSha: string;
    branch: string;
    baseBranch: string | null;
    baseCommitSha: string | null;
  };

  // Summary metrics
  summary: {
    totalComponents: number;
    componentsWithStories: number;
    componentsWithoutStories: number;
    totalStoryFiles: number;
    totalStories: number;
    metrics: {
      componentCoverage: number;
      propCoverage: number;
      variantCoverage: number;
      scenarioCoverage: number;
    };
    health: {
      status: 'healthy' | 'degraded' | 'broken' | 'not_executed';
      passingStories: number;
      failingStories: number;
      passRate: number;
    };
  };

  // New code analysis
  newCode: {
    enabled: boolean;
    since: string;
    newComponents: { total: number; withStories: number; coverage: number };
    modifiedComponents: { total: number; newPropsAdded: number; coverage: number };
  };

  // Per-component coverage
  components: ComponentCoverage[];

  // Actionable recommendations
  missingScenarios: MissingScenario[];
  uncoveredComponents: UncoveredComponent[];

  // Quality gate results
  qualityGate: {
    passed: boolean;
    checks: QualityCheck[];
  };
}
```

## CI Integration

### GitHub Actions

```yaml
name: Story Coverage
on: [pull_request]

jobs:
  coverage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Required for git analysis

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - name: Build Storybook
        run: npm run build-storybook

      - name: Run scry-sbcov
        run: |
          npx scry-sbcov \
            --base origin/main \
            --execute \
            --storybook-static ./storybook-static \
            --output coverage-report.json \
            --ci

      - name: Upload Report
        uses: actions/upload-artifact@v4
        with:
          name: story-coverage-report
          path: coverage-report.json
```

### GitLab CI

```yaml
stages:
  - build
  - test

build-storybook:
  stage: build
  image: node:20
  script:
    - npm ci
    - npm run build-storybook
  artifacts:
    paths:
      - storybook-static
    expire_in: 1 hour

story-coverage:
  stage: test
  image: node:20
  needs:
    - job: build-storybook
      artifacts: true
  variables:
    GIT_DEPTH: 0  # Required for git analysis
  script:
    - npm ci
    - npx scry-sbcov --base origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME --output coverage-report.json --ci
  artifacts:
    paths:
      - coverage-report.json
```

## Programmatic Usage

```typescript
import { analyze, loadConfig } from '@scrymore/scry-sbcov';

const config = await loadConfig({
  base: 'main',
  thresholdComponent: 80,
});

const report = await analyze(process.cwd(), config, true);

console.log(`Coverage: ${report.summary.metrics.componentCoverage}%`);
console.log(`Quality Gate: ${report.qualityGate.passed ? 'PASSED' : 'FAILED'}`);
```

## Detected Patterns

### Component Types
- Function components
- Arrow function components
- `forwardRef` wrapped components
- `memo` wrapped components
- Class components (extending React.Component/PureComponent)
- HOC-wrapped components

### Scenario Detection
The tool automatically detects common UI scenarios based on prop naming patterns:

| Pattern | Scenario |
|---------|----------|
| `isLoading`, `loading`, `isProcessing` | Loading State |
| `isError`, `hasError`, `error` | Error State |
| `isEmpty`, `empty`, `noData` | Empty State |
| `disabled`, `isDisabled` | Disabled State |
| `isOpen`, `open`, `expanded` | Open State |
| `isVisible`, `visible`, `hidden` | Visibility State |
| `isSelected`, `selected`, `checked` | Selection State |

### Variant Coverage
For props with union literal types (e.g., `variant: 'primary' | 'secondary'`), the tool tracks which specific values are covered by stories.

## Story Execution

To detect broken stories at runtime, install Playwright:

```bash
npm install playwright --save-dev
```

Then run with the `--execute` flag:

```bash
scry-sbcov --execute --storybook-url http://localhost:6006
# or with a static build
scry-sbcov --execute --storybook-static ./storybook-static
```

Story execution detects:
- Render errors
- Play function failures
- Console errors
- Timeouts

## Requirements

- Node.js >= 18.0.0
- TypeScript project (for full prop extraction)
- Storybook (CSF 3 format recommended)

## Optional Dependencies

- `playwright` - Required for story execution

## Development

### Setup

```bash
git clone https://github.com/epinnock/scry-sbcov.git
cd scry-sbcov
npm install
```

### Available Scripts

```bash
npm run build        # Build TypeScript to dist/
npm run dev          # Build in watch mode
npm run test         # Run tests in watch mode
npm run test:run     # Run tests once
npm run test:coverage # Run tests with coverage report
npm run lint         # Run ESLint
npm run typecheck    # Run TypeScript type checking
```

### CI Checks

Pull requests automatically run the following checks:

| Check | Command | Description |
|-------|---------|-------------|
| Type Check | `npm run typecheck` | Validates TypeScript types |
| Lint | `npm run lint` | Checks code style with ESLint |
| Tests | `npm run test:run` | Runs unit and integration tests |
| Build | `npm run build` | Ensures project compiles |
| Dogfood | CLI on fixtures | Runs scry-sbcov on test fixtures |

Tests run on Node.js 18, 20, and 22 to ensure compatibility.

### Project Structure

```
scry-sbcov/
├── src/
│   ├── cli/           # CLI entry point and config loading
│   ├── core/          # Main analyzer, coverage calc, report gen
│   ├── detectors/     # Component detection (ts-morph)
│   ├── parsers/       # Story file parsing
│   ├── analyzers/     # Git analysis
│   └── types/         # TypeScript interfaces
├── tests/
│   ├── fixtures/      # Sample React components for testing
│   └── *.test.ts      # Test files
└── bin/               # CLI executable
```

## Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Ensure all CI checks pass locally:
   ```bash
   npm run typecheck && npm run lint && npm run test:run && npm run build
   ```
5. Commit your changes (`git commit -m 'Add amazing feature'`)
6. Push to the branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request

## License

MIT