Agent skill
cli-e2e-test-authoring
Guide for adding new end-to-end tests for the Packmind CLI. This skill should be used when creating new test specs in the `apps/cli-e2e-tests/` directory that exercise CLI commands against a real binary and API.
Install this agent skill to your Project
npx add-skill https://github.com/PackmindHub/packmind/tree/main/apps/cli-e2e-tests/.claude/skills/cli-e2e-test-authoring
SKILL.md
CLI E2E Test Authoring
Overview
Add end-to-end tests that exercise the Packmind CLI binary (dist/apps/cli/main.cjs) in realistic conditions. Tests run the actual CLI as a child process and, when authentication is needed, interact with a running API via HTTP gateways.
Test File Location
All spec files live in apps/cli-e2e-tests/src/ and follow the naming convention <command>.spec.ts.
Choosing a Test Wrapper
Two wrappers are available depending on whether the command requires authentication.
Unauthenticated commands — describeWithTempSpace
Provides an isolated temporary directory. No API required.
import { describeWithTempSpace, runCli } from './helpers';
describeWithTempSpace('my-command without auth', (getContext) => {
let result: Awaited<ReturnType<typeof runCli>>;
beforeEach(async () => {
const { testDir } = await getContext();
result = await runCli('my-command', { cwd: testDir });
});
it('exits with code 1', () => {
expect(result.returnCode).toBe(1);
});
it('shows an error message', () => {
expect(result.stdout).toContain('No credentials found');
});
});
Authenticated commands — describeWithUserSignedUp
Extends describeWithTempSpace by creating a real user account, signing in, and generating an API key. Requires a running API at http://localhost:4200.
import { describeWithUserSignedUp, runCli } from './helpers';
describeWithUserSignedUp('my-command with auth', (getContext) => {
let result: Awaited<ReturnType<typeof runCli>>;
beforeEach(async () => {
const { apiKey, testDir } = await getContext();
result = await runCli('my-command', { apiKey, cwd: testDir });
});
it('succeeds', () => {
expect(result.returnCode).toBe(0);
});
it('displays expected output', () => {
expect(result.stdout).toContain('Expected text');
});
});
The context object from describeWithUserSignedUp provides:
| Field | Description |
|---|---|
testDir |
Isolated temporary directory |
apiKey |
Valid API key for the created user |
user |
User object (email, etc.) |
organization |
Organization the user belongs to |
spaceId |
Global space ID for the organization |
gateway |
Authenticated gateway to call the API directly |
Setting Up Test Preconditions
Git repository
Commands that interact with git (e.g. diff, install) require a git repo. Call setupGitRepo in beforeEach:
import { setupGitRepo } from './helpers';
beforeEach(async () => {
const { testDir } = await getContext();
await setupGitRepo(testDir);
});
Creating API resources
Use gateway from the context to seed data before running the CLI:
beforeEach(async () => {
const { gateway, spaceId, testDir } = await getContext();
await setupGitRepo(testDir);
await gateway.commands.create({ spaceId, /* ... */ });
await gateway.packages.create({ spaceId, /* ... */ });
});
File manipulation
Use file helpers to create or modify files in the test directory:
import { readFile, updateFile, fileExists } from './helpers';
const content = readFile('path/to/file.md', testDir);
updateFile('path/to/file.md', 'new content', testDir);
const exists = fileExists('path/to/file.md', testDir);
Assertion Patterns
Split assertions into individual it blocks. Store the CLI result in a block-scoped let variable populated by beforeEach:
let result: Awaited<ReturnType<typeof runCli>>;
beforeEach(async () => {
result = await runCli('some-command', { apiKey, cwd: testDir });
});
it('succeeds', () => {
expect(result.returnCode).toBe(0);
});
it('displays the summary', () => {
expect(result.stdout).toContain('1 change submitted');
});
Nesting Describes for Multi-Step Scenarios
For commands that require chained operations (e.g. install then modify then diff), nest describe blocks. Each level adds its own beforeEach that builds on the parent context:
describeWithUserSignedUp('diff command', (getContext) => {
beforeEach(async () => {
// setup: git repo + seed data + install
});
describe('when a change is submitted', () => {
beforeEach(async () => {
// modify file + run diff --submit
});
it('succeeds', () => { /* ... */ });
describe('when running diff again', () => {
beforeEach(async () => {
// run diff without --submit
});
it('excludes the already-submitted change', () => { /* ... */ });
});
});
});
Adding a New Gateway
When the CLI command under test requires seeding a new type of API resource:
- Add the interface method to
helpers/IPackmindGateway.ts. All exposed methods must be typed withGateway<IXxxUseCase>orPublicGateway<IXxxUseCase>(imported from@packmind/types) - Create
helpers/gateways/NewResourceGateway.tsimplementing the interface - Add a lazy getter to
helpers/gateways/PackmindGateway.ts(reset oninitializeWithApiKey) - Re-export from
helpers/index.ts
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
working-with-playground-app
This skill provides guidance for building UI/UX prototypes in the Packmind playground app. It should be used when creating a new prototype, iterating on an existing prototype, or working with files in apps/playground/. Triggers on mentions of "playground", "prototype", or direct work within the apps/playground/ directory.
qa-review
Review a user story implementation against its Example Mapping (EM) specification.
packmind-create-command
Guide for creating reusable commands via the Packmind CLI. This skill should be used when users want to create a new command that captures multi-step workflows, recipes, or task automation for distribution to CoPilot.
doc-audit
Audit Packmind end-user documentation (apps/doc/) for broken links, outdated CLI references, non-existent concepts, misleading information, and missing coverage. Produces a structured markdown report at project root. Use when docs may have drifted from the codebase, before a release, or on a regular cadence.
git-commit-guidelines
Enforce git commit best practices using gitmoji + Conventional Commits format. TRIGGER when creating commits. Ensures quality-gate passes, prevents issue auto-closing (no Close/Fix keywords), includes Co-Authored-By for AI commits, and requires user approval before committing.
internal-comms
A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).
Didn't find tool you were looking for?