@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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +248 -0
  3. package/dist/cli/index.cjs +7547 -0
  4. package/dist/cli/index.cjs.map +1 -0
  5. package/dist/cli/index.d.cts +1 -0
  6. package/dist/cli/index.d.ts +1 -0
  7. package/dist/cli/index.js +7539 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/index.cjs +6439 -0
  10. package/dist/index.cjs.map +1 -0
  11. package/dist/index.d.cts +54 -0
  12. package/dist/index.d.ts +54 -0
  13. package/dist/index.js +6383 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/subagents/index.cjs +2703 -0
  16. package/dist/subagents/index.cjs.map +1 -0
  17. package/dist/subagents/index.d.cts +34 -0
  18. package/dist/subagents/index.d.ts +34 -0
  19. package/dist/subagents/index.js +2662 -0
  20. package/dist/subagents/index.js.map +1 -0
  21. package/dist/subagents/metadata.cjs +207 -0
  22. package/dist/subagents/metadata.cjs.map +1 -0
  23. package/dist/subagents/metadata.d.cts +31 -0
  24. package/dist/subagents/metadata.d.ts +31 -0
  25. package/dist/subagents/metadata.js +174 -0
  26. package/dist/subagents/metadata.js.map +1 -0
  27. package/dist/tasks/index.cjs +3464 -0
  28. package/dist/tasks/index.cjs.map +1 -0
  29. package/dist/tasks/index.d.cts +44 -0
  30. package/dist/tasks/index.d.ts +44 -0
  31. package/dist/tasks/index.js +3431 -0
  32. package/dist/tasks/index.js.map +1 -0
  33. package/dist/templates/init/.bugzy/runtime/project-context.md +35 -0
  34. package/dist/templates/init/.bugzy/runtime/templates/test-plan-template.md +25 -0
  35. package/dist/templates/init/.bugzy/runtime/testing-best-practices.md +278 -0
  36. package/dist/templates/init/.gitignore-template +4 -0
  37. package/package.json +95 -0
  38. package/templates/init/.bugzy/runtime/knowledge-base.md +61 -0
  39. package/templates/init/.bugzy/runtime/knowledge-maintenance-guide.md +97 -0
  40. package/templates/init/.bugzy/runtime/project-context.md +35 -0
  41. package/templates/init/.bugzy/runtime/subagent-memory-guide.md +87 -0
  42. package/templates/init/.bugzy/runtime/templates/test-plan-template.md +25 -0
  43. package/templates/init/.bugzy/runtime/templates/test-result-schema.md +498 -0
  44. package/templates/init/.bugzy/runtime/test-execution-strategy.md +535 -0
  45. package/templates/init/.bugzy/runtime/testing-best-practices.md +632 -0
  46. package/templates/init/.gitignore-template +25 -0
  47. package/templates/init/CLAUDE.md +157 -0
  48. package/templates/init/test-runs/README.md +45 -0
  49. package/templates/playwright/BasePage.template.ts +190 -0
  50. package/templates/playwright/auth.setup.template.ts +89 -0
  51. package/templates/playwright/dataGenerators.helper.template.ts +148 -0
  52. package/templates/playwright/dateUtils.helper.template.ts +96 -0
  53. package/templates/playwright/pages.fixture.template.ts +50 -0
  54. package/templates/playwright/playwright.config.template.ts +97 -0
  55. 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
+ }