@bugzy-ai/bugzy 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +248 -0
- package/dist/cli/index.cjs +7547 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +7539 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.cjs +6439 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +54 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +6383 -0
- package/dist/index.js.map +1 -0
- package/dist/subagents/index.cjs +2703 -0
- package/dist/subagents/index.cjs.map +1 -0
- package/dist/subagents/index.d.cts +34 -0
- package/dist/subagents/index.d.ts +34 -0
- package/dist/subagents/index.js +2662 -0
- package/dist/subagents/index.js.map +1 -0
- package/dist/subagents/metadata.cjs +207 -0
- package/dist/subagents/metadata.cjs.map +1 -0
- package/dist/subagents/metadata.d.cts +31 -0
- package/dist/subagents/metadata.d.ts +31 -0
- package/dist/subagents/metadata.js +174 -0
- package/dist/subagents/metadata.js.map +1 -0
- package/dist/tasks/index.cjs +3464 -0
- package/dist/tasks/index.cjs.map +1 -0
- package/dist/tasks/index.d.cts +44 -0
- package/dist/tasks/index.d.ts +44 -0
- package/dist/tasks/index.js +3431 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/templates/init/.bugzy/runtime/project-context.md +35 -0
- package/dist/templates/init/.bugzy/runtime/templates/test-plan-template.md +25 -0
- package/dist/templates/init/.bugzy/runtime/testing-best-practices.md +278 -0
- package/dist/templates/init/.gitignore-template +4 -0
- package/package.json +95 -0
- package/templates/init/.bugzy/runtime/knowledge-base.md +61 -0
- package/templates/init/.bugzy/runtime/knowledge-maintenance-guide.md +97 -0
- package/templates/init/.bugzy/runtime/project-context.md +35 -0
- package/templates/init/.bugzy/runtime/subagent-memory-guide.md +87 -0
- package/templates/init/.bugzy/runtime/templates/test-plan-template.md +25 -0
- package/templates/init/.bugzy/runtime/templates/test-result-schema.md +498 -0
- package/templates/init/.bugzy/runtime/test-execution-strategy.md +535 -0
- package/templates/init/.bugzy/runtime/testing-best-practices.md +632 -0
- package/templates/init/.gitignore-template +25 -0
- package/templates/init/CLAUDE.md +157 -0
- package/templates/init/test-runs/README.md +45 -0
- package/templates/playwright/BasePage.template.ts +190 -0
- package/templates/playwright/auth.setup.template.ts +89 -0
- package/templates/playwright/dataGenerators.helper.template.ts +148 -0
- package/templates/playwright/dateUtils.helper.template.ts +96 -0
- package/templates/playwright/pages.fixture.template.ts +50 -0
- package/templates/playwright/playwright.config.template.ts +97 -0
- package/templates/playwright/reporters/bugzy-reporter.ts +454 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Project Memory
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
**Type**: Test Management System
|
|
5
|
+
**Purpose**: Autonomous QA testing with AI-based test generation and execution
|
|
6
|
+
|
|
7
|
+
## SECURITY NOTICE
|
|
8
|
+
|
|
9
|
+
**CRITICAL: Never Read the .env File**
|
|
10
|
+
|
|
11
|
+
All agents, subagents, and slash commands must follow this security policy:
|
|
12
|
+
|
|
13
|
+
- **NEVER read the `.env` file** - It contains secrets, credentials, and sensitive data
|
|
14
|
+
- **ALWAYS use `.env.testdata`** instead - It contains only variable names, never actual values
|
|
15
|
+
- **Reference variables by name only** - e.g., TEST_BASE_URL, TEST_USER_EMAIL (never read the actual values)
|
|
16
|
+
- **This is enforced** - `.claude/settings.json` has `Read(.env)` in the deny list
|
|
17
|
+
|
|
18
|
+
When you need to know what environment variables are available:
|
|
19
|
+
1. Read `.env.testdata` to see variable names and structure
|
|
20
|
+
2. Reference variables by name in documentation and instructions
|
|
21
|
+
3. Trust that users will configure their own `.env` file from the example
|
|
22
|
+
4. Never attempt to access actual credential values
|
|
23
|
+
|
|
24
|
+
This policy applies to all agents, commands, and any code execution.
|
|
25
|
+
|
|
26
|
+
## Agent System
|
|
27
|
+
|
|
28
|
+
### Active Agents
|
|
29
|
+
<!-- AUTO-GENERATED: This section is populated during project creation -->
|
|
30
|
+
<!-- Configured agents will be listed here based on project setup -->
|
|
31
|
+
|
|
32
|
+
Agents configured for this project are stored in `.claude/agents/`. These are specialized sub-agents that handle specific domains. The active agents and their integrations will be configured during project setup.
|
|
33
|
+
|
|
34
|
+
### Agent Memory Index
|
|
35
|
+
<!-- AUTO-GENERATED: Agent memory files are created during project setup -->
|
|
36
|
+
|
|
37
|
+
Specialized memory files for domain experts will be created in `.bugzy/runtime/memory/` based on configured agents.
|
|
38
|
+
|
|
39
|
+
## Project Structure
|
|
40
|
+
|
|
41
|
+
### Core Components
|
|
42
|
+
- **Test Plan**: `test-plan.md` - Generated via `/generate-test-plan` command using template
|
|
43
|
+
- **Test Cases**: `./test-cases/` - Individual test case files generated via `/generate-test-cases`
|
|
44
|
+
- **Exploration Reports**: `./exploration-reports/` - Structured reports from application exploration sessions
|
|
45
|
+
- **Knowledge Base**: `.bugzy/runtime/knowledge-base.md` - Curated knowledge about the project (maintained using `.bugzy/runtime/knowledge-maintenance-guide.md`)
|
|
46
|
+
- **Issue Tracking**: Managed by issue-tracker agent in your configured project management system
|
|
47
|
+
- **Runtime**: `.bugzy/runtime/` - Project-specific runtime files:
|
|
48
|
+
- `memory/` - Agent memory and knowledge base files
|
|
49
|
+
- `templates/` - Document templates for test plan generation
|
|
50
|
+
- `knowledge-base.md` - Accumulated insights
|
|
51
|
+
- `project-context.md` - **CRITICAL**: Project SDLC, team information, QA workflow, and testing guidelines
|
|
52
|
+
- **MCP Configuration**: `.bugzy/.mcp.json` - Template with all available MCP server configurations
|
|
53
|
+
|
|
54
|
+
### Available Commands
|
|
55
|
+
1. `/generate-test-plan` - Generate comprehensive test plan from product documentation using the documentation-researcher agent
|
|
56
|
+
2. `/explore-application` - Systematically explore the application to discover UI elements, workflows, and behaviors, updating test plan with findings
|
|
57
|
+
3. `/generate-test-cases` - Create E2E browser test cases (exploratory, functional, regression, smoke) based on documentation and test plan
|
|
58
|
+
4. `/run-tests` - Execute test cases using the test-runner agent
|
|
59
|
+
5. `/handle-message` - Process team responses and manage ongoing conversations with the product team using the team-communicator agent
|
|
60
|
+
|
|
61
|
+
### Git Workflow
|
|
62
|
+
|
|
63
|
+
**Git operations are now handled automatically by the execution environment.**
|
|
64
|
+
|
|
65
|
+
Agents and commands should NOT perform git operations (commit, push). Instead:
|
|
66
|
+
|
|
67
|
+
1. **Focus on core work**: Agents generate files and execute tests
|
|
68
|
+
2. **External service handles git**: After task completion, the Cloud Run environment:
|
|
69
|
+
- Commits all changes with standardized messages
|
|
70
|
+
- Pushes to the remote repository
|
|
71
|
+
- Handles authentication and errors
|
|
72
|
+
|
|
73
|
+
**Files Automatically Committed**:
|
|
74
|
+
- `test-plan.md` - Test planning documents
|
|
75
|
+
- `.env.testdata` - Environment variable templates
|
|
76
|
+
- `./test-cases/*.md` - Individual test case files
|
|
77
|
+
- `./exploration-reports/*.md` - Application exploration findings
|
|
78
|
+
- `.bugzy/runtime/knowledge-base.md` - Accumulated testing insights
|
|
79
|
+
- `.bugzy/runtime/memory/*.md` - Agent memory and knowledge base
|
|
80
|
+
- `CLAUDE.md` - Updated project context (when modified)
|
|
81
|
+
- `.bugzy/runtime/project-context.md` - Project-specific runtime context
|
|
82
|
+
|
|
83
|
+
**Git-Ignored Files** (NOT committed):
|
|
84
|
+
- `.env` - Local environment variables with secrets
|
|
85
|
+
- `logs/` - Temporary log files
|
|
86
|
+
- `tmp/` - Temporary files
|
|
87
|
+
- `.playwright-mcp/` - Playwright videos (uploaded to GCS separately)
|
|
88
|
+
- `node_modules/` - Node.js dependencies
|
|
89
|
+
|
|
90
|
+
### Workflow
|
|
91
|
+
|
|
92
|
+
#### Testing Workflow
|
|
93
|
+
1. Generate test plan: `/generate-test-plan` command leverages the documentation-researcher agent to gather requirements
|
|
94
|
+
2. Explore application: `/explore-application --focus [area] --depth [shallow|deep]` discovers actual UI elements and behaviors
|
|
95
|
+
3. Create test cases: `/generate-test-cases --type [type] --focus [feature]` uses discovered documentation and exploration findings
|
|
96
|
+
4. Execute tests: `/run-tests [test-id|type|tag|all]` runs test cases via test-runner agent
|
|
97
|
+
5. Continuous refinement through exploration and test execution
|
|
98
|
+
|
|
99
|
+
### Testing Lifecycle Phases
|
|
100
|
+
1. **Initial Test Plan Creation** - From product documentation
|
|
101
|
+
2. **Application Exploration** - Systematic discovery via `/explore-application`
|
|
102
|
+
3. **Test Case Generation** - Stored as individual files with actual UI elements
|
|
103
|
+
4. **Test Execution** - Automated runs via `/run-tests`
|
|
104
|
+
5. **Continuous Refinement** - Through exploration and test execution
|
|
105
|
+
6. **Regression Testing** - Scheduled or triggered execution
|
|
106
|
+
|
|
107
|
+
## Key Project Insights
|
|
108
|
+
<!-- Critical discoveries and patterns that apply across all domains -->
|
|
109
|
+
|
|
110
|
+
## Cross-Domain Knowledge
|
|
111
|
+
|
|
112
|
+
### Project Context Usage
|
|
113
|
+
The `.bugzy/runtime/project-context.md` file contains critical project information that MUST be referenced by:
|
|
114
|
+
- All agents during initialization to understand project specifics
|
|
115
|
+
- All commands before processing to align with project requirements
|
|
116
|
+
- Any custom implementations to maintain consistency
|
|
117
|
+
|
|
118
|
+
Key information includes: QA workflow, story status management, bug reporting guidelines, testing environment details, and SDLC methodology.
|
|
119
|
+
|
|
120
|
+
### Test Execution Standards
|
|
121
|
+
|
|
122
|
+
**Automated Test Execution** (via `/run-tests` command):
|
|
123
|
+
- Test runs are stored in hierarchical structure: `./test-runs/YYYYMMDD-HHMMSS/TC-XXX/exec-N/`
|
|
124
|
+
- Each test run session creates:
|
|
125
|
+
- `execution-id.txt`: Contains BUGZY_EXECUTION_ID for session tracking
|
|
126
|
+
- `manifest.json`: Overall run metadata with all test cases and executions
|
|
127
|
+
- Per test case folders (`TC-001-login/`, etc.) containing execution attempts
|
|
128
|
+
- Each execution attempt (`exec-1/`, `exec-2/`, `exec-3/`) contains:
|
|
129
|
+
- `result.json`: Playwright test result format with status, duration, errors, attachments
|
|
130
|
+
- `steps.json`: Step-by-step execution with video timestamps (if test uses `test.step()`)
|
|
131
|
+
- `video.webm`: Video recording (copied from Playwright's temp location)
|
|
132
|
+
- `trace.zip`: Trace file (only for failures)
|
|
133
|
+
- `screenshots/`: Screenshots directory (only for failures)
|
|
134
|
+
- Videos are recorded for ALL tests, traces/screenshots only for failures
|
|
135
|
+
- Custom Bugzy reporter handles all artifact organization automatically
|
|
136
|
+
- External service uploads videos from execution folders to GCS
|
|
137
|
+
|
|
138
|
+
**Step-Level Tracking** (Automated Tests):
|
|
139
|
+
- Tests using `test.step()` API generate steps.json files with video timestamps
|
|
140
|
+
- Each step includes timestamp and videoTimeSeconds for easy video navigation
|
|
141
|
+
- High-level steps recommended (3-7 per test) for manageable navigation
|
|
142
|
+
- Steps appear in both result.json (Playwright format) and steps.json (user-friendly format)
|
|
143
|
+
- Tests without `test.step()` still work but won't have steps.json
|
|
144
|
+
|
|
145
|
+
**Manual Test Execution** (via test-runner agent):
|
|
146
|
+
- Manual test cases use separate format: `./test-runs/YYYYMMDD-HHMMSS/TC-XXX/`
|
|
147
|
+
- Each test run generates:
|
|
148
|
+
- `summary.json`: Structured test result with video filename reference
|
|
149
|
+
- `steps.json`: Step-by-step execution with timestamps and video synchronization
|
|
150
|
+
- Video recording via Playwright MCP --save-video flag
|
|
151
|
+
- Videos remain in `.playwright-mcp/` folder - external service uploads to GCS
|
|
152
|
+
|
|
153
|
+
**General Rules**:
|
|
154
|
+
- NO test-related files should be created in project root
|
|
155
|
+
- DO NOT copy, move, or delete video files manually
|
|
156
|
+
- DO NOT CREATE ANY SUMMARY, REPORT, OR ADDITIONAL FILES unless explicitly requested
|
|
157
|
+
<!-- Additional cross-domain information below -->
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Test Runs
|
|
2
|
+
|
|
3
|
+
This directory contains execution results and artifacts from test runs.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
Test runs are organized by timestamp and test case:
|
|
8
|
+
```
|
|
9
|
+
YYYYMMDD-HHMMSS/
|
|
10
|
+
├── TC-XXX/
|
|
11
|
+
│ ├── summary.json
|
|
12
|
+
│ ├── steps.json
|
|
13
|
+
│ └── video.webm
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Contents
|
|
17
|
+
|
|
18
|
+
Each test run includes:
|
|
19
|
+
- **summary.json**: Structured test result with video metadata and status
|
|
20
|
+
- **steps.json**: Detailed execution steps with timestamps and video synchronization
|
|
21
|
+
- **video.webm**: Video recording of the entire test execution
|
|
22
|
+
|
|
23
|
+
**Note**: All test information (status, failures, step details, observations) is captured in the structured JSON files. The video provides visual evidence synchronized with the steps.
|
|
24
|
+
|
|
25
|
+
## Test Result Schema
|
|
26
|
+
|
|
27
|
+
All test results follow the schema defined in `.bugzy/runtime/templates/test-result-schema.md`.
|
|
28
|
+
|
|
29
|
+
Key features:
|
|
30
|
+
- Video recording with synchronized step navigation
|
|
31
|
+
- Timestamped steps for precise playback control
|
|
32
|
+
- Structured metadata for test status, type, and priority
|
|
33
|
+
- User-friendly action descriptions for easy understanding
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
Test runs are automatically generated when:
|
|
38
|
+
- Tests are executed via automation
|
|
39
|
+
- Manual test execution is logged
|
|
40
|
+
- Event processing triggers test validation
|
|
41
|
+
|
|
42
|
+
Results are used for:
|
|
43
|
+
- Issue tracking via the issue-tracker agent
|
|
44
|
+
- Learning extraction for continuous improvement
|
|
45
|
+
- Regression analysis and pattern recognition
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { type Page, type Locator } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base Page Object Model
|
|
5
|
+
* All page objects should extend this class
|
|
6
|
+
*
|
|
7
|
+
* Provides common functionality and patterns for page interactions
|
|
8
|
+
*/
|
|
9
|
+
export class BasePage {
|
|
10
|
+
readonly page: Page;
|
|
11
|
+
|
|
12
|
+
constructor(page: Page) {
|
|
13
|
+
this.page = page;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Navigate to a specific path
|
|
18
|
+
* @param path - The path to navigate to (relative to baseURL)
|
|
19
|
+
*/
|
|
20
|
+
async navigate(path: string): Promise<void> {
|
|
21
|
+
await this.page.goto(path);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Wait for the page to be fully loaded
|
|
26
|
+
*/
|
|
27
|
+
async waitForPageLoad(): Promise<void> {
|
|
28
|
+
await this.page.waitForLoadState('networkidle');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get the current URL
|
|
33
|
+
*/
|
|
34
|
+
getCurrentURL(): string {
|
|
35
|
+
return this.page.url();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the page title
|
|
40
|
+
*/
|
|
41
|
+
async getTitle(): Promise<string> {
|
|
42
|
+
return await this.page.title();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Wait for a locator to be visible
|
|
47
|
+
* @param locator - The locator to wait for
|
|
48
|
+
* @param timeout - Optional custom timeout
|
|
49
|
+
*/
|
|
50
|
+
async waitForVisible(locator: Locator, timeout?: number): Promise<void> {
|
|
51
|
+
await locator.waitFor({ state: 'visible', timeout });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Wait for a locator to be hidden
|
|
56
|
+
* @param locator - The locator to wait for
|
|
57
|
+
* @param timeout - Optional custom timeout
|
|
58
|
+
*/
|
|
59
|
+
async waitForHidden(locator: Locator, timeout?: number): Promise<void> {
|
|
60
|
+
await locator.waitFor({ state: 'hidden', timeout });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Click an element and wait for navigation
|
|
65
|
+
* @param locator - The element to click
|
|
66
|
+
*/
|
|
67
|
+
async clickAndNavigate(locator: Locator): Promise<void> {
|
|
68
|
+
await Promise.all([
|
|
69
|
+
this.page.waitForNavigation(),
|
|
70
|
+
locator.click()
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Fill a form field
|
|
76
|
+
* @param locator - The input field
|
|
77
|
+
* @param value - The value to fill
|
|
78
|
+
*/
|
|
79
|
+
async fillField(locator: Locator, value: string): Promise<void> {
|
|
80
|
+
await locator.clear();
|
|
81
|
+
await locator.fill(value);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Select an option from a dropdown
|
|
86
|
+
* @param locator - The select element
|
|
87
|
+
* @param value - The value to select
|
|
88
|
+
*/
|
|
89
|
+
async selectOption(locator: Locator, value: string): Promise<void> {
|
|
90
|
+
await locator.selectOption(value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Check a checkbox
|
|
95
|
+
* @param locator - The checkbox element
|
|
96
|
+
*/
|
|
97
|
+
async check(locator: Locator): Promise<void> {
|
|
98
|
+
if (!(await locator.isChecked())) {
|
|
99
|
+
await locator.check();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Uncheck a checkbox
|
|
105
|
+
* @param locator - The checkbox element
|
|
106
|
+
*/
|
|
107
|
+
async uncheck(locator: Locator): Promise<void> {
|
|
108
|
+
if (await locator.isChecked()) {
|
|
109
|
+
await locator.uncheck();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Get text content from an element
|
|
115
|
+
* @param locator - The element to get text from
|
|
116
|
+
*/
|
|
117
|
+
async getText(locator: Locator): Promise<string> {
|
|
118
|
+
return (await locator.textContent()) || '';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Check if element is visible
|
|
123
|
+
* @param locator - The element to check
|
|
124
|
+
*/
|
|
125
|
+
async isVisible(locator: Locator): Promise<boolean> {
|
|
126
|
+
return await locator.isVisible();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Check if element is enabled
|
|
131
|
+
* @param locator - The element to check
|
|
132
|
+
*/
|
|
133
|
+
async isEnabled(locator: Locator): Promise<boolean> {
|
|
134
|
+
return await locator.isEnabled();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Scroll element into view
|
|
139
|
+
* @param locator - The element to scroll to
|
|
140
|
+
*/
|
|
141
|
+
async scrollIntoView(locator: Locator): Promise<void> {
|
|
142
|
+
await locator.scrollIntoViewIfNeeded();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Take a screenshot
|
|
147
|
+
* @param name - The screenshot file name
|
|
148
|
+
*/
|
|
149
|
+
async takeScreenshot(name: string): Promise<void> {
|
|
150
|
+
await this.page.screenshot({ path: `screenshots/${name}.png`, fullPage: true });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Execute JavaScript in the browser context
|
|
155
|
+
* @param script - The script to execute
|
|
156
|
+
* @param args - Arguments to pass to the script
|
|
157
|
+
*/
|
|
158
|
+
async executeScript<T>(script: string | Function, ...args: any[]): Promise<T> {
|
|
159
|
+
return await this.page.evaluate(script, ...args);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Wait for API response
|
|
164
|
+
* @param urlPattern - The URL pattern to wait for
|
|
165
|
+
*/
|
|
166
|
+
async waitForResponse(urlPattern: string | RegExp): Promise<void> {
|
|
167
|
+
await this.page.waitForResponse(urlPattern);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Reload the current page
|
|
172
|
+
*/
|
|
173
|
+
async reload(): Promise<void> {
|
|
174
|
+
await this.page.reload();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Go back in browser history
|
|
179
|
+
*/
|
|
180
|
+
async goBack(): Promise<void> {
|
|
181
|
+
await this.page.goBack();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Go forward in browser history
|
|
186
|
+
*/
|
|
187
|
+
async goForward(): Promise<void> {
|
|
188
|
+
await this.page.goForward();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { test as setup, expect } from '@playwright/test';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { mkdir } from 'fs/promises';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Authentication Setup
|
|
7
|
+
* Generated by Bugzy - https://github.com/bugzy-ai/bugzy
|
|
8
|
+
*
|
|
9
|
+
* This file runs before all tests to authenticate and save the state
|
|
10
|
+
* Other tests can reuse this authenticated state for faster execution
|
|
11
|
+
*
|
|
12
|
+
* Benefits:
|
|
13
|
+
* - Login once, reuse for all tests
|
|
14
|
+
* - Faster test execution
|
|
15
|
+
* - More stable tests (no repeated login operations)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const authFile = path.join(__dirname, '../.auth/user.json');
|
|
19
|
+
|
|
20
|
+
setup('authenticate', async ({ page }) => {
|
|
21
|
+
// Skip if no authentication is needed
|
|
22
|
+
// Remove this if you need authentication
|
|
23
|
+
if (!process.env.TEST_USER_EMAIL || !process.env.TEST_USER_PASSWORD) {
|
|
24
|
+
console.log('Skipping authentication setup - no credentials provided');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Navigate to login page
|
|
29
|
+
// Adjust the URL based on your application
|
|
30
|
+
await page.goto('/login');
|
|
31
|
+
|
|
32
|
+
// Perform authentication steps
|
|
33
|
+
// Using role-based selectors for stability
|
|
34
|
+
|
|
35
|
+
// Fill in email
|
|
36
|
+
await page.getByLabel('Email').fill(process.env.TEST_USER_EMAIL);
|
|
37
|
+
|
|
38
|
+
// Fill in password
|
|
39
|
+
await page.getByLabel('Password').fill(process.env.TEST_USER_PASSWORD);
|
|
40
|
+
|
|
41
|
+
// Click the sign in button
|
|
42
|
+
// Adjust the button text based on your app
|
|
43
|
+
await page.getByRole('button', { name: /sign in|login/i }).click();
|
|
44
|
+
|
|
45
|
+
// Wait for redirect after successful login
|
|
46
|
+
// Adjust the URL pattern based on where users land after login
|
|
47
|
+
await page.waitForURL(/.*\/(dashboard|home)/);
|
|
48
|
+
|
|
49
|
+
// Verify authentication was successful
|
|
50
|
+
// Check for a user-specific element (e.g., user menu, profile icon)
|
|
51
|
+
// Adjust based on your application
|
|
52
|
+
// await expect(page.getByRole('button', { name: /profile|account/i })).toBeVisible();
|
|
53
|
+
|
|
54
|
+
// Create .auth directory if it doesn't exist
|
|
55
|
+
await mkdir(path.dirname(authFile), { recursive: true });
|
|
56
|
+
|
|
57
|
+
// Save authentication state to file
|
|
58
|
+
await page.context().storageState({ path: authFile });
|
|
59
|
+
|
|
60
|
+
console.log('✓ Authentication state saved successfully');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Example: Multiple User Roles
|
|
65
|
+
*
|
|
66
|
+
* If you need to test with different user roles (admin, user, etc.),
|
|
67
|
+
* create separate setup files:
|
|
68
|
+
*
|
|
69
|
+
* - auth.setup.admin.ts
|
|
70
|
+
* - auth.setup.user.ts
|
|
71
|
+
* - auth.setup.guest.ts
|
|
72
|
+
*
|
|
73
|
+
* Then configure them in playwright.config.ts:
|
|
74
|
+
*
|
|
75
|
+
* projects: [
|
|
76
|
+
* { name: 'setup-admin', testMatch: /.*\.setup\.admin\.ts/ },
|
|
77
|
+
* { name: 'setup-user', testMatch: /.*\.setup\.user\.ts/ },
|
|
78
|
+
* {
|
|
79
|
+
* name: 'admin-tests',
|
|
80
|
+
* use: { storageState: 'tests/.auth/admin.json' },
|
|
81
|
+
* dependencies: ['setup-admin'],
|
|
82
|
+
* },
|
|
83
|
+
* {
|
|
84
|
+
* name: 'user-tests',
|
|
85
|
+
* use: { storageState: 'tests/.auth/user.json' },
|
|
86
|
+
* dependencies: ['setup-user'],
|
|
87
|
+
* },
|
|
88
|
+
* ]
|
|
89
|
+
*/
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Data Generators
|
|
3
|
+
* Generated by Bugzy - https://github.com/bugzy-ai/bugzy
|
|
4
|
+
*
|
|
5
|
+
* Helper functions for generating realistic test data
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generate a random email address
|
|
10
|
+
* @param prefix - Optional prefix for the email
|
|
11
|
+
*/
|
|
12
|
+
export function generateEmail(prefix = 'test'): string {
|
|
13
|
+
const timestamp = Date.now();
|
|
14
|
+
const random = Math.floor(Math.random() * 10000);
|
|
15
|
+
return `${prefix}-${timestamp}-${random}@example.com`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate a random username
|
|
20
|
+
* @param prefix - Optional prefix for the username
|
|
21
|
+
*/
|
|
22
|
+
export function generateUsername(prefix = 'user'): string {
|
|
23
|
+
const timestamp = Date.now();
|
|
24
|
+
const random = Math.floor(Math.random() * 10000);
|
|
25
|
+
return `${prefix}_${timestamp}_${random}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Generate a random phone number (US format)
|
|
30
|
+
*/
|
|
31
|
+
export function generatePhoneNumber(): string {
|
|
32
|
+
const areaCode = Math.floor(Math.random() * 900) + 100;
|
|
33
|
+
const prefix = Math.floor(Math.random() * 900) + 100;
|
|
34
|
+
const lineNumber = Math.floor(Math.random() * 9000) + 1000;
|
|
35
|
+
return `(${areaCode}) ${prefix}-${lineNumber}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Generate a random string of specified length
|
|
40
|
+
* @param length - Length of the string
|
|
41
|
+
*/
|
|
42
|
+
export function generateRandomString(length: number): string {
|
|
43
|
+
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
44
|
+
let result = '';
|
|
45
|
+
for (let i = 0; i < length; i++) {
|
|
46
|
+
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Generate a random number between min and max (inclusive)
|
|
53
|
+
* @param min - Minimum value
|
|
54
|
+
* @param max - Maximum value
|
|
55
|
+
*/
|
|
56
|
+
export function generateRandomNumber(min: number, max: number): number {
|
|
57
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generate a random boolean value
|
|
62
|
+
*/
|
|
63
|
+
export function generateRandomBoolean(): boolean {
|
|
64
|
+
return Math.random() < 0.5;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Generate a unique ID
|
|
69
|
+
*/
|
|
70
|
+
export function generateUniqueId(): string {
|
|
71
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Generate a random password
|
|
76
|
+
* @param length - Length of the password (default: 12)
|
|
77
|
+
*/
|
|
78
|
+
export function generatePassword(length = 12): string {
|
|
79
|
+
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
80
|
+
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
|
|
81
|
+
const numbers = '0123456789';
|
|
82
|
+
const special = '!@#$%^&*';
|
|
83
|
+
const all = uppercase + lowercase + numbers + special;
|
|
84
|
+
|
|
85
|
+
let password = '';
|
|
86
|
+
// Ensure at least one of each type
|
|
87
|
+
password += uppercase.charAt(Math.floor(Math.random() * uppercase.length));
|
|
88
|
+
password += lowercase.charAt(Math.floor(Math.random() * lowercase.length));
|
|
89
|
+
password += numbers.charAt(Math.floor(Math.random() * numbers.length));
|
|
90
|
+
password += special.charAt(Math.floor(Math.random() * special.length));
|
|
91
|
+
|
|
92
|
+
// Fill the rest
|
|
93
|
+
for (let i = password.length; i < length; i++) {
|
|
94
|
+
password += all.charAt(Math.floor(Math.random() * all.length));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Shuffle the password
|
|
98
|
+
return password
|
|
99
|
+
.split('')
|
|
100
|
+
.sort(() => Math.random() - 0.5)
|
|
101
|
+
.join('');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Generate test user data
|
|
106
|
+
*/
|
|
107
|
+
export interface TestUser {
|
|
108
|
+
email: string;
|
|
109
|
+
username: string;
|
|
110
|
+
password: string;
|
|
111
|
+
firstName: string;
|
|
112
|
+
lastName: string;
|
|
113
|
+
phone: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function generateTestUser(): TestUser {
|
|
117
|
+
const firstNames = ['John', 'Jane', 'Bob', 'Alice', 'Charlie', 'Diana', 'Eve', 'Frank'];
|
|
118
|
+
const lastNames = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis'];
|
|
119
|
+
|
|
120
|
+
const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
|
|
121
|
+
const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
email: generateEmail(firstName.toLowerCase()),
|
|
125
|
+
username: generateUsername(firstName.toLowerCase()),
|
|
126
|
+
password: generatePassword(),
|
|
127
|
+
firstName,
|
|
128
|
+
lastName,
|
|
129
|
+
phone: generatePhoneNumber(),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Pick a random item from an array
|
|
135
|
+
* @param array - Array to pick from
|
|
136
|
+
*/
|
|
137
|
+
export function pickRandom<T>(array: T[]): T {
|
|
138
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Generate a random date between two dates
|
|
143
|
+
* @param start - Start date
|
|
144
|
+
* @param end - End date
|
|
145
|
+
*/
|
|
146
|
+
export function generateRandomDate(start: Date, end: Date): Date {
|
|
147
|
+
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
|
|
148
|
+
}
|