スキル一覧に戻る

test-cli-application

pjt222
更新日 Yesterday
5 閲覧
17
2
17
GitHubで表示
テストtestingapidesign

について

このスキルは、Node.js CLIアプリケーションの統合テストを`node:test`モジュールを使用して作成する開発者を支援します。CLIの出力、ファイルシステムの状態、エラーケース、JSONパースのテストを網羅し、適切なクリーンアップを保証します。既存CLIへのテスト追加、新規コマンドのテスト、CLIツールのCI設定時にご利用ください。

クイックインストール

Claude Code

推奨
メイン
npx skills add pjt222/agent-almanac -a claude-code
プラグインコマンド代替
/plugin add https://github.com/pjt222/agent-almanac
Git クローン代替
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/test-cli-application

このコマンドをClaude Codeにコピー&ペーストしてスキルをインストールします

ドキュメント

Test a CLI Application

Escribir pruebas de integración para una CLI Node.js usando el módulo built-in node:test con execSync.

Cuándo Usar

  • Añadir pruebas a una aplicación CLI existente
  • Probar un comando recién creado
  • Verificar el comportamiento del adaptador/plugin a través de frameworks objetivo
  • Configurar CI que valida la corrección de la CLI
  • Captar regresiones después de refactorizar internos de CLI

Entradas

  • Requerido: Ruta al punto de entrada de la CLI (p. ej., cli/index.js)
  • Requerido: Comandos a probar
  • Opcional: Adaptadores de framework a probar (modo dry-run)
  • Opcional: Requisitos de limpieza (archivos/symlinks creados por las pruebas)

Procedimiento

Paso 1: Configurar la Infraestructura de Pruebas

import { describe, it, before, after } from 'node:test';
import assert from 'node:assert/strict';
import { execSync } from 'child_process';
import { existsSync, rmSync } from 'fs';
import { resolve } from 'path';

const CLI = 'node cli/index.js';
const ROOT = process.cwd();

function run(args) {
  return execSync(`${CLI} ${args}`, {
    cwd: ROOT,
    encoding: 'utf8',
    timeout: 10000,
  });
}

Decisiones clave de diseño:

  • node:test está built-in — no se necesita dependencia de test runner
  • execSync ejecuta la CLI como subproceso — prueba el binario real, no funciones internas
  • Timeout de 10 segundos previene cuelgues en prompts interactivos
  • encoding: 'utf8' da salida string para coincidencia con regex
  • Todas las rutas relativas a ROOT para reproducibilidad

Esperado: Un archivo de pruebas que importa de node:test y tiene un helper run() funcional.

En caso de fallo: Si node:test no está disponible, tu versión de Node.js está debajo de 18. Actualizar o usar un polyfill.

Paso 2: Escribir Pruebas Smoke

Las pruebas smoke verifican que la CLI inicia, parsea argumentos y produce las formas de salida esperadas:

describe('meta', () => {
  it('shows version', () => {
    const out = run('--version');
    assert.match(out, /\d+\.\d+\.\d+/);
  });

  it('shows help with all commands', () => {
    const out = run('--help');
    assert.match(out, /install/);
    assert.match(out, /list/);
    assert.match(out, /detect/);
  });
});

describe('registry', () => {
  it('list shows expected counts', () => {
    const out = run('list --domains');
    assert.match(out, /\d+ domains/);
  });

  it('search finds known items', () => {
    const out = run('search "docker"');
    assert.match(out, /result\(s\) for "docker"/);
  });

  it('search returns 0 for nonsense', () => {
    const out = run('search "xyzzy-nonexistent"');
    assert.match(out, /0 result/);
  });
});

Patrones de prueba smoke:

  • --version y --help siempre funcionan
  • La carga del registry valida la integridad de los datos
  • Búsqueda con términos conocidos y desconocidos

Esperado: Las pruebas smoke confirman que la CLI es funcional y los datos están cargados.

En caso de fallo: Si los conteos del registry cambian frecuentemente, usar \d+ en lugar de números hardcoded.

Paso 3: Escribir Pruebas de Lifecycle

Las pruebas de lifecycle verifican secuencias create → verify → delete con limpieza:

describe('install', () => {
  const testPath = resolve(ROOT, '.agents/skills/commit-changes');

  after(() => {
    // Always clean up, even if tests fail
    try { rmSync(testPath); } catch {}
    try { rmSync(resolve(ROOT, '.agents/skills'), { recursive: true }); } catch {}
    try { rmSync(resolve(ROOT, '.agents'), { recursive: true }); } catch {}
  });

  it('dry-run does not create files', () => {
    const out = run('install commit-changes --dry-run');
    assert.match(out, /DRY RUN/);
    assert.ok(!existsSync(testPath));
  });

  it('installs creates the target', () => {
    run('install commit-changes');
    assert.ok(existsSync(testPath));
  });

  it('skips already installed', () => {
    const out = run('install commit-changes');
    assert.match(out, /skipped/);
  });

  it('uninstall removes the target', () => {
    run('uninstall commit-changes');
    assert.ok(!existsSync(testPath));
  });
});

Reglas de limpieza:

  • Usar hooks after(), no afterEach() — las pruebas de lifecycle se construyen unas sobre otras
  • Envolver la limpieza en try/catch — la limpieza no debe fallar la suite de pruebas
  • Limpiar de hoja a raíz (archivo → directorio padre → directorio abuelo)
  • Si la prueba modifica estado compartido (symlinks, archivos de config), restaurarlo

Esperado: Las pruebas corren en secuencia dentro del bloque describe, la limpieza corre incluso en caso de fallo.

En caso de fallo: Si las pruebas corren en paralelo (no-predeterminado en node:test), forzar secuencial con { concurrency: 1 }.

Paso 4: Escribir Pruebas Dry-Run para Cada Adaptador

Probar la ruta objetivo de cada adaptador sin hacer cambios:

describe('adapter: cursor (dry-run)', () => {
  it('targets .cursor/skills/ path', () => {
    const out = run('install commit-changes --framework cursor --dry-run');
    assert.match(out, /\.cursor\/skills/i);
  });
});

describe('adapter: copilot (dry-run)', () => {
  it('targets .github/ path', () => {
    const out = run('install commit-changes --framework copilot --dry-run');
    assert.match(out, /\.github/i);
  });
});

Este patrón escala a cualquier número de adaptadores. Cada prueba:

  • Usa --framework para sortear la auto-detección
  • Usa --dry-run para que no se creen archivos
  • Asserta que la ruta objetivo aparece en la salida

Esperado: Un bloque describe por adaptador, cada uno con al menos una assertion de ruta.

En caso de fallo: Si el adaptador no existe en el proyecto, la prueba fallará con "Unknown framework." Esto es correcto — las pruebas de adaptador solo deben existir para adaptadores implementados.

Paso 5: Escribir Pruebas de Casos de Error

describe('errors', () => {
  it('rejects unknown items', () => {
    assert.throws(
      () => run('install nonexistent-skill-xyz'),
      /No matching items|Unknown/,
    );
  });

  it('rejects unknown framework', () => {
    assert.throws(
      () => run('install commit-changes --framework nonexistent'),
      /Unknown framework/,
    );
  });

  it('handles missing state gracefully', () => {
    assert.throws(
      () => run('scatter nonexistent-team'),
      /not burning|Unknown/,
    );
  });
});

Patrones de prueba de errores:

  • assert.throws captura códigos de salida no-cero de execSync
  • Coincidencia regex en el mensaje de error (capturado de stderr)
  • Probar errores tanto de "item no encontrado" como de "opción inválida"
  • Verificar que los mensajes de error sugieren acciones correctivas

Esperado: Todos los caminos de error producen códigos de salida no-cero y mensajes útiles.

En caso de fallo: execSync lanza en caso de salida no-cero. El stderr o stdout del error contiene el mensaje. Verificar error.stdout si la regex de assert.throws no coincide.

Paso 6: Escribir Pruebas de Salida JSON

describe('json output', () => {
  it('campfire --json outputs valid JSON', () => {
    const out = run('campfire --json');
    const data = JSON.parse(out);
    assert.ok(typeof data.totalTeams === 'number');
    assert.ok(Array.isArray(data.fires));
  });

  it('gather --dry-run --json outputs structured data', () => {
    const out = run('gather tending --dry-run --json');
    // JSON may follow a DRY RUN header — extract from first '{'
    const jsonStart = out.indexOf('{');
    assert.ok(jsonStart >= 0, 'Should contain JSON');
    const data = JSON.parse(out.slice(jsonStart));
    assert.equal(data.team, 'tending');
  });
});

Trampas de prueba JSON:

  • Algunos comandos prefijan JSON con texto legible para humanos (p. ej., header DRY RUN)
  • Extraer JSON encontrando el primer carácter {
  • Validar la estructura (presencia de claves, tipos), no los valores exactos
  • Valores como conteos pueden cambiar conforme se añade contenido

Esperado: La salida JSON es parseable y contiene las claves esperadas.

En caso de fallo: Si JSON.parse falla, el comando puede estar mezclando texto humano con JSON. O arreglar el comando para emitir JSON puro en modo --json, o extraer el substring JSON.

Paso 7: Manejar Limpieza y Restauración de Estado

describe('stateful commands', () => {
  const stateDir = resolve(ROOT, '.agent-almanac');

  after(() => {
    // Remove state file created by tests
    try { rmSync(stateDir, { recursive: true }); } catch {}
  });

  // Tests that create/modify state...
});

// Restore symlinks that destructive tests may remove
describe('destructive tests', () => {
  after(() => {
    // Restore symlinks that scatter/uninstall removed
    const skills = ['heal', 'meditate', 'remote-viewing'];
    for (const skill of skills) {
      const link = resolve(ROOT, `.claude/skills/${skill}`);
      if (!existsSync(link)) {
        try {
          execSync(`ln -s ../../skills/${skill} ${link}`, { cwd: ROOT });
        } catch {}
      }
    }
  });
});

Reglas de restauración de estado:

  • Los archivos de estado (.agent-almanac/state.json) deben limpiarse después de las pruebas
  • Symlinks eliminados por scatter/uninstall deben ser restaurados
  • Los archivos de manifiesto (agent-almanac.yml) creados por init deben eliminarse
  • Orden: los hooks after() corren en orden inverso de declaración — declarar hooks de restauración al final

Esperado: La suite de pruebas deja el proyecto en el mismo estado en que lo encontró.

En caso de fallo: Si CI reporta archivos sobrantes después de las ejecuciones de prueba, añadir la limpieza al after(). Usar git status después de las ejecuciones de prueba para detectar estado filtrado.

Validación

  • El archivo de prueba corre con node --test cli/test/cli.test.js
  • Todas las pruebas pasan (0 fallos)
  • Las pruebas smoke cubren --version, --help y carga del registry
  • Las pruebas de lifecycle verifican create → verify → delete con limpieza
  • Existe al menos una prueba dry-run de adaptador por adaptador implementado
  • Los casos de error prueban códigos de salida no-cero con coincidencia de mensaje
  • Las pruebas de salida JSON parsean salida real (no mockeada)
  • Los hooks after restauran todo el estado modificado por las pruebas

Errores Comunes

  • Conteos hardcoded que se rompen: Los totales del registry cambian conforme se añade contenido. Usar regex \d+ o leer el conteo dinámicamente en lugar de assertear 329 skills.
  • Pruebas que dependen del orden de ejecución: node:test corre suites en orden de declaración por defecto, pero las pruebas dentro de una suite pueden no. Usar suites de lifecycle (create → verify → delete) dentro de un solo describe para garantizar el orden.
  • Limpieza faltante en fallo de prueba: Si una prueba falla a media-lifecycle, after() aún corre. Pero si lanzas en before(), las pruebas subsiguientes y after() pueden no correr. Mantener before() mínimo.
  • Prompts interactivos colgando pruebas: Los comandos con prompts de confirmación colgarán execSync. O hacer pipe de echo y | o asegurar que --yes siempre se pase en pruebas.
  • Probar con instalaciones reales en CI: Las pruebas que crean archivos en .claude/skills/ o .agents/skills/ modifican el árbol de trabajo. CI puede fallar en verificaciones de "directorio de trabajo sucio". Siempre limpiar.

Habilidades Relacionadas

  • scaffold-cli-command — construir los comandos que estas pruebas verifican
  • build-cli-plugin — construir los adaptadores probados en el Paso 4
  • design-cli-output — patrones de salida contra los que las pruebas assertan

GitHub リポジトリ

pjt222/agent-almanac
パス: i18n/es/skills/test-cli-application
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

関連スキル

evaluating-llms-harness

テスト

このClaudeスキルは、lm-evaluation-harnessを実行し、MMLUやGSM8Kなど60以上の標準化学術タスクでLLMをベンチマークします。開発者がモデルの品質を比較し、トレーニングの進捗を追跡し、学術的な結果を報告するために設計されています。このツールはHuggingFaceやvLLMモデルを含む様々なバックエンドをサポートしています。

スキルを見る

cloudflare-cron-triggers

テスト

このスキルは、cron式を使用してWorkersをスケジュールするためのCloudflare Cron Triggersの実装に関する包括的な知識を提供します。定期的なタスクの設定、メンテナンスジョブ、自動化されたワークフローの構築を網羅し、無効なcron式やタイムゾーン問題といった一般的な課題への対処法も含みます。開発者はこれを使用して、スケジュールされたハンドラーの設定、cronトリガーのテスト、WorkflowsやGreen Computeとの連携を構成できます。

スキルを見る

webapp-testing

テスト

このClaude Skillは、Playwrightベースのツールキットを提供し、Pythonスクリプトを通じてローカルWebアプリケーションのテストを可能にします。フロントエンドの検証、UIデバッグ、スクリーンショット撮影、ログ表示を実現し、サーバーライフサイクルを管理します。ブラウザ自動化タスクにご利用いただけますが、コンテキストの汚染を避けるため、スクリプトのソースコードを読むのではなく直接実行してください。

スキルを見る

finishing-a-development-branch

テスト

このスキルは、開発者がテストの合格を確認し、構造化された統合オプションを提示することで、完成した作業を仕上げることを支援します。実装が完了した後のマージ、PR作成、ブランチの整理といったワークフローを案内します。コードが準備できてテスト済みの際に使用し、開発プロセスを体系的に完了させましょう。

スキルを見る