@sridharkikkeri/playwright-common 1.0.46 → 1.0.48

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.
@@ -76,7 +76,8 @@ const packageJson = {
76
76
  dependencies: {
77
77
  '@playwright/test': '^1.42.0',
78
78
  'allure-playwright': '^3.4.5',
79
- 'playwright': '^1.42.0'
79
+ 'playwright': '^1.42.0',
80
+ '@playwright/mcp-server': 'latest'
80
81
  },
81
82
  devDependencies: {
82
83
  '@typescript-eslint/eslint-plugin': '^8.55.0',
@@ -164,41 +165,47 @@ Object.entries(envConfigs).forEach(([env, config]) => {
164
165
  );
165
166
  });
166
167
 
167
- // Sample Page Object
168
- const samplePage = `import { Page } from '@playwright/test';
169
- import { BasePage } from '../pages/BasePage';
170
-
171
- export class HomePage extends BasePage {
172
- constructor(page: Page) {
173
- super(page, 'HomePage');
174
- }
175
-
176
- private readonly searchInput = this.element('[data-testid="search"]');
177
- private readonly searchBtn = this.element('button[type="submit"]');
178
-
179
- async search(query: string) {
180
- await this.searchInput.fill(query, 'Enter search query');
181
- await this.searchBtn.click('Click search button');
182
- }
168
+ // Copy sample files from templates
169
+ const templatesDir = path.join(__dirname, 'templates');
170
+ if (fs.existsSync(templatesDir)) {
171
+ console.log('\nšŸ“‹ Copying sample files...\n');
172
+
173
+ // Copy fixtures
174
+ const fixturesSrc = path.join(templatesDir, 'fixtures.ts');
175
+ if (fs.existsSync(fixturesSrc)) {
176
+ fs.copyFileSync(fixturesSrc, path.join(projectPath, 'src/main/fixtures/fixtures.ts'));
177
+ console.log(' āœ“ Copied fixtures.ts');
178
+ }
179
+
180
+ // Copy pages
181
+ const loginPageSrc = path.join(templatesDir, 'LoginPage.ts');
182
+ if (fs.existsSync(loginPageSrc)) {
183
+ fs.copyFileSync(loginPageSrc, path.join(projectPath, 'src/main/pages/LoginPage.ts'));
184
+ console.log(' āœ“ Copied LoginPage.ts');
185
+ }
186
+
187
+ const dashboardPageSrc = path.join(templatesDir, 'DashboardPage.ts');
188
+ if (fs.existsSync(dashboardPageSrc)) {
189
+ fs.copyFileSync(dashboardPageSrc, path.join(projectPath, 'src/main/pages/DashboardPage.ts'));
190
+ console.log(' āœ“ Copied DashboardPage.ts');
191
+ }
192
+
193
+ // Copy builder
194
+ const builderSrc = path.join(templatesDir, 'UserBuilder.ts');
195
+ if (fs.existsSync(builderSrc)) {
196
+ fs.copyFileSync(builderSrc, path.join(projectPath, 'src/main/builders/UserBuilder.ts'));
197
+ console.log(' āœ“ Copied UserBuilder.ts');
198
+ }
199
+
200
+ // Copy test
201
+ const testSrc = path.join(templatesDir, 'sample.spec.ts');
202
+ if (fs.existsSync(testSrc)) {
203
+ fs.copyFileSync(testSrc, path.join(projectPath, 'src/tests/specs/sample.spec.ts'));
204
+ console.log(' āœ“ Copied sample.spec.ts');
205
+ }
206
+
207
+ console.log('\nāœ… Sample files copied');
183
208
  }
184
- `;
185
-
186
- fs.writeFileSync(path.join(projectPath, 'src/main/pages/HomePage.ts'), samplePage);
187
-
188
- // Sample Test
189
- const sampleTest = `import { test } from '../../../main/fixtures/fixtures';
190
- import { HomePage } from '../../main/pages/HomePage';
191
-
192
- test.describe('Sample Tests', () => {
193
- test('Search functionality', async ({ page }) => {
194
- const homePage = new HomePage(page);
195
- await page.goto('/');
196
- await homePage.search('playwright');
197
- });
198
- });
199
- `;
200
-
201
- fs.writeFileSync(path.join(projectPath, 'src/tests/specs/sample.spec.ts'), sampleTest);
202
209
 
203
210
  // Test data
204
211
  const testData = {
@@ -295,6 +302,24 @@ npm run screenshot <url> # Take screenshot of URL
295
302
  npm run pdf <url> # Generate PDF of URL
296
303
  \`\`\`
297
304
 
305
+ ## AI Agents & Skills (Experimental)
306
+
307
+ This project includes Playwright MCP Server with AI Agents:
308
+
309
+ **Agents:**
310
+ - šŸ¤– **Planner** - Plans test scenarios
311
+ - šŸ”§ **Generator** - Generates test code
312
+ - 🩹 **Healer** - Auto-fixes failing tests
313
+
314
+ **Skills:**
315
+ - Run tests
316
+ - Inspect DOM
317
+ - Generate selectors
318
+ - Heal failures
319
+ - Seed environment
320
+
321
+ See [Playwright CLI Agents](https://github.com/microsoft/playwright-cli) for setup.
322
+
298
323
  ## Environment-Specific Tests
299
324
 
300
325
  \`\`\`bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sridharkikkeri/playwright-common",
3
- "version": "1.0.46",
3
+ "version": "1.0.48",
4
4
  "description": "Production-grade Playwright framework with AI-powered self-healing, visual regression, and enterprise features",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -13,6 +13,7 @@
13
13
  "files": [
14
14
  "dist",
15
15
  "src",
16
+ "templates",
16
17
  "api-docs",
17
18
  "create-healthedge-tests.js",
18
19
  "README.md",
@@ -0,0 +1,22 @@
1
+ import { Page } from '@playwright/test';
2
+ import { BasePage } from '../main/pages/BasePage';
3
+ import { ElementWrapper } from '../main/wrappers/ElementWrapper';
4
+
5
+ export class DashboardPage extends BasePage {
6
+ readonly welcomeMessage: ElementWrapper;
7
+ readonly logoutButton: ElementWrapper;
8
+
9
+ constructor(page: Page) {
10
+ super(page, { pageName: 'DashboardPage' });
11
+ this.welcomeMessage = this.getByTestId('welcome-message');
12
+ this.logoutButton = this.getByRole('button', { name: 'Logout' });
13
+ }
14
+
15
+ async getWelcomeText(): Promise<string> {
16
+ return await this.welcomeMessage.textContent();
17
+ }
18
+
19
+ async logout(): Promise<void> {
20
+ await this.logoutButton.click('Click logout button');
21
+ }
22
+ }
@@ -0,0 +1,34 @@
1
+ import { Page } from '@playwright/test';
2
+ import { BasePage } from '../main/pages/BasePage';
3
+ import { ElementWrapper } from '../main/wrappers/ElementWrapper';
4
+
5
+ export class LoginPage extends BasePage {
6
+ readonly emailInput: ElementWrapper;
7
+ readonly passwordInput: ElementWrapper;
8
+ readonly loginButton: ElementWrapper;
9
+
10
+ constructor(page: Page) {
11
+ super(page, { pageName: 'LoginPage' });
12
+ this.emailInput = this.getByLabel('Email');
13
+ this.passwordInput = this.getByLabel('Password');
14
+ this.loginButton = this.getByRole('button', { name: 'Login' });
15
+ }
16
+
17
+ async enterEmail(email: string): Promise<void> {
18
+ await this.emailInput.fill(email, 'Enter email address');
19
+ }
20
+
21
+ async enterPassword(password: string): Promise<void> {
22
+ await this.passwordInput.fill(password, 'Enter password');
23
+ }
24
+
25
+ async clickLogin(): Promise<void> {
26
+ await this.loginButton.click('Click login button');
27
+ }
28
+
29
+ async login(email: string, password: string): Promise<void> {
30
+ await this.enterEmail(email);
31
+ await this.enterPassword(password);
32
+ await this.clickLogin();
33
+ }
34
+ }
@@ -0,0 +1,43 @@
1
+ export interface UserData {
2
+ firstName: string;
3
+ lastName: string;
4
+ email?: string;
5
+ phone?: string;
6
+ role?: string;
7
+ }
8
+
9
+ export class UserBuilder {
10
+ private data: UserData = {
11
+ firstName: 'John',
12
+ lastName: 'Doe'
13
+ };
14
+
15
+ setFirstName(name: string): this {
16
+ this.data.firstName = name;
17
+ return this;
18
+ }
19
+
20
+ setLastName(name: string): this {
21
+ this.data.lastName = name;
22
+ return this;
23
+ }
24
+
25
+ setEmail(email: string): this {
26
+ this.data.email = email;
27
+ return this;
28
+ }
29
+
30
+ setPhone(phone: string): this {
31
+ this.data.phone = phone;
32
+ return this;
33
+ }
34
+
35
+ setRole(role: string): this {
36
+ this.data.role = role;
37
+ return this;
38
+ }
39
+
40
+ build(): UserData {
41
+ return { ...this.data };
42
+ }
43
+ }
@@ -0,0 +1,73 @@
1
+ import { test as base } from '@playwright/test';
2
+ import { ActionOrchestrator } from '../main/selfhealing/ActionOrchestrator';
3
+ import { ApiClient } from '../main/api/ApiClient';
4
+ import { AllureUtil } from '../main/reporting/AllureUtil';
5
+ import { LoginPage } from '../main/pages/LoginPage';
6
+ import { DashboardPage } from '../main/pages/DashboardPage';
7
+
8
+ export type FrameworkFixtures = {
9
+ orchestrator: ActionOrchestrator;
10
+ apiClient: ApiClient;
11
+ loginPage: LoginPage;
12
+ dashboardPage: DashboardPage;
13
+ locale: string;
14
+ retryInfo: { current: number; max: number };
15
+ _reportingHook: void;
16
+ };
17
+
18
+ export const test = base.extend<FrameworkFixtures>({
19
+ orchestrator: async ({ page }, use, testInfo) => {
20
+ const orchestrator = new ActionOrchestrator(page, {
21
+ pageName: testInfo.title
22
+ });
23
+ await use(orchestrator);
24
+ },
25
+
26
+ apiClient: async ({ }, use) => {
27
+ const client = new ApiClient(process.env.API_BASE_URL || '');
28
+ await client.init();
29
+ await use(client);
30
+ await client.dispose();
31
+ },
32
+
33
+ loginPage: async ({ page }, use) => {
34
+ await use(new LoginPage(page));
35
+ },
36
+
37
+ dashboardPage: async ({ page }, use) => {
38
+ await use(new DashboardPage(page));
39
+ },
40
+
41
+ locale: async ({ }, use) => {
42
+ const locale = process.env.LOCALE || 'en';
43
+ await use(locale);
44
+ },
45
+
46
+ retryInfo: async ({ }, use, testInfo) => {
47
+ await use({
48
+ current: testInfo.retry,
49
+ max: testInfo.project.retries
50
+ });
51
+ },
52
+
53
+ _reportingHook: [async ({ retryInfo }, use, testInfo) => {
54
+ await use();
55
+
56
+ if (testInfo.status !== testInfo.expectedStatus) {
57
+ AllureUtil.attachText(
58
+ 'Test Failure Details',
59
+ `Error: ${testInfo.error?.message || 'Unknown'}\nStack: ${testInfo.error?.stack || 'N/A'}`
60
+ );
61
+ }
62
+
63
+ if (retryInfo.current > 0) {
64
+ AllureUtil.attachText(
65
+ 'Retry Telemetry',
66
+ `This test is being retried. Attempt: ${retryInfo.current} / ${retryInfo.max}`
67
+ );
68
+ console.warn(`āš ļø Flaky test detected: "${testInfo.title}" (Retry ${retryInfo.current})`);
69
+ }
70
+ }, { auto: true }]
71
+ });
72
+
73
+ export { expect } from '@playwright/test';
@@ -0,0 +1,39 @@
1
+ import { test, expect } from '../main/fixtures/fixtures';
2
+ import { UserBuilder } from '../main/builders/UserBuilder';
3
+ import { ConfigManager } from '../main/config/ConfigManager';
4
+
5
+ test.describe('Sample Test Suite @smoke', () => {
6
+ test('Login with valid credentials', async ({ page, loginPage, dashboardPage }) => {
7
+ const config = ConfigManager.getConfig();
8
+ await page.goto(config.baseUrl!);
9
+ await page.waitForLoadState('networkidle');
10
+
11
+ await loginPage.login('test@example.com', 'password123');
12
+ await page.waitForLoadState('networkidle');
13
+
14
+ const welcomeText = await dashboardPage.getWelcomeText();
15
+ expect(welcomeText).toContain('Welcome');
16
+ });
17
+
18
+ test('Create user with builder pattern', async ({ page, loginPage }) => {
19
+ const timestamp = Date.now();
20
+ const user = new UserBuilder()
21
+ .setFirstName('Test')
22
+ .setLastName(`User-${timestamp}`)
23
+ .setEmail(`test-${timestamp}@example.com`)
24
+ .setRole('admin')
25
+ .build();
26
+
27
+ console.log('Created user:', user);
28
+
29
+ const config = ConfigManager.getConfig();
30
+ await page.goto(config.baseUrl!);
31
+ await loginPage.login(user.email!, 'password123');
32
+ });
33
+
34
+ test('API integration example', async ({ apiClient }) => {
35
+ const response = await apiClient.get('/api/users/1');
36
+ expect(response.status).toBe(200);
37
+ expect(response.data).toHaveProperty('id');
38
+ });
39
+ });