@majkapp/journey
v1.2.2
Published
Contract-first journey testing with auto-generated user guides, coverage tracking, and living documentation
Maintainers
Readme
@majkapp/journey
Document and test user journeys with living documentation and screenshots.
Features
- Unified Testing & Documentation - Write tests that generate docs
- Implementation-Independent - Tests survive UI refactors
- Screenshot Contracts - Document what each screenshot should show
- Living Documentation - Docs auto-generate from passing tests
- High-Level API - Describe user journeys, not DOM selectors
- Journey Artifacts - Save complete execution snapshots with git tracking
- Reproducible Documentation - Generate docs from saved artifacts without re-running tests
Installation
npm install --save-dev @majkapp/journeyQuick Start
import { UserJourney } from '@majkapp/journey';
import { runBot } from '@majkapp/bot-plugin-server';
test('User can create a task', async () => {
await runBot({ /* config */ }, async (bot) => {
const page = bot.getPage();
const journey = new UserJourney(bot, page, {
pageName: 'task-creation'
});
journey
.defineUseCase({
title: 'Create Task',
description: 'User creates a new task',
implementationIndependence: {
dontCareAbout: [
'Button text',
'Form layout',
'Color schemes'
],
careAbout: [
'Actions work correctly',
'States transition properly',
'Data appears accurately'
]
}
})
.addStep({
title: 'Open form',
description: 'User clicks to open task creation form',
action: async (page, bot) => {
await bot.click('start-task');
},
visual: {
description: 'Form opens with empty fields',
expectedElements: [
'[data-majk-role="task-form"]'
]
}
})
.addStep({
title: 'Submit task',
description: 'User fills and submits form',
action: async (page, bot) => {
await page.locator('[data-majk-role="title-input"]').fill('Test');
await bot.click('submit-task');
},
verify: async (page) => {
const list = await page.locator('[data-majk-role="task-list"]');
const state = await list.getAttribute('data-majk-state');
if (state !== 'populated') throw new Error('Task not created');
},
visual: {
description: 'New task appears in list',
expectedElements: [
'[data-majk-role="task-list-item"]'
],
expectedStates: [
'task-list: state="populated"'
]
}
});
await journey.execute();
});
});Generated Documentation
Running the test generates docs/UserFlows/create-task.md:
# Create Task
> **Status**: ✅ All steps passing
> **Last Updated**: 2025-11-15T...
## Use Case
User creates a new task
## Workflow
1. Open form
2. Submit task
## Implementation Independence
**We don't care about:**
- Button text
- Form layout
- Color schemes
**We only care about:**
- Actions work correctly
- States transition properly
- Data appears accurately
## Step-by-Step Flow
### Step 1: Open form

**What you should see:**
Form opens with empty fields
**Expected Elements:**
- [data-majk-role="task-form"]API
UserJourney
Constructor:
new UserJourney(bot: BotHelper, page: Page, options: JourneyOptions)Methods:
defineUseCase(useCase: UseCase): this- Define the use caseaddStep(step: JourneyStep): this- Add a stepexecute(): Promise<JourneyResult>- Run journey
Types
See src/types.ts for full type definitions.
Journey Artifacts
Every journey execution creates a complete artifact that captures:
- Use case and implementation independence
- Git commit, branch, and clean/dirty status
- Execution timestamp and total duration
- Every step with timing, status, and visual contracts
- All screenshots in a self-contained directory
Artifact Structure
.journey-artifacts/
task-creation/
2025-11-15T14-10-30_6a4ecd3/ # timestamp_gitCommit
manifest.json # Complete execution data
screenshots/
01-open-form.png
02-submit-task.pngmanifest.json
{
"journey": {
"name": "task-creation",
"useCase": { "title": "...", "description": "..." }
},
"execution": {
"timestamp": "2025-11-15T14:10:30.778Z",
"duration": 10070,
"status": "passed",
"gitCommit": "6a4ecd3",
"gitBranch": "feature_task_manager",
"gitClean": false
},
"steps": [
{
"index": 1,
"title": "Open form",
"status": "passed",
"duration": 4422,
"timestamp": "2025-11-15T14:10:30.779Z",
"screenshot": "screenshots/01-open-form.png",
"visual": { "description": "...", "expectedElements": [...] }
}
]
}Generate Docs from Artifacts
Once you have artifacts, you can regenerate documentation without re-running tests:
import { UserJourney } from '@majkapp/journey';
// Generate docs from latest artifact run
await UserJourney.generateDocsFromArtifact(
'.journey-artifacts/task-creation/2025-11-15T14-10-30_6a4ecd3',
'docs/UserFlows'
);Generated documentation includes:
- Git commit info and timestamp
- Individual step durations
- Status indicators (✅/❌)
- Absolute paths to artifact screenshots
Benefits of Artifacts
- Historical Record - Track how journeys evolved across commits
- No Re-runs Required - Generate docs anytime without browser tests
- Review Process - Share artifacts with stakeholders for review
- CI/CD Integration - Archive artifacts, compare across builds
- Regression Detection - Compare screenshots between commits
- Performance Tracking - Monitor journey duration over time
Configuration
const journey = new UserJourney(bot, page, {
pageName: 'task-creation',
docsDir: './docs/UserFlows',
screenshotsDir: './screenshots',
artifactsDir: './.journey-artifacts', // default
saveArtifacts: true, // default
generateDocs: true // default
});Best Practices
- Use semantic data-majk- attributes* in your UI
- Document what users see, not implementation details
- Test behavior, not markup
- Generate docs from tests to keep them in sync
- Commit artifacts to git for historical tracking (optional)
- Use artifacts for documentation in CI/CD pipelines
License
MIT
