@sridharkikkeri/playwright-common 1.0.47 → 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.
@@ -165,41 +165,47 @@ Object.entries(envConfigs).forEach(([env, config]) => {
165
165
  );
166
166
  });
167
167
 
168
- // Sample Page Object
169
- const samplePage = `import { Page } from '@playwright/test';
170
- import { BasePage } from '../pages/BasePage';
171
-
172
- export class HomePage extends BasePage {
173
- constructor(page: Page) {
174
- super(page, 'HomePage');
175
- }
176
-
177
- private readonly searchInput = this.element('[data-testid="search"]');
178
- private readonly searchBtn = this.element('button[type="submit"]');
179
-
180
- async search(query: string) {
181
- await this.searchInput.fill(query, 'Enter search query');
182
- await this.searchBtn.click('Click search button');
183
- }
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');
184
208
  }
185
- `;
186
-
187
- fs.writeFileSync(path.join(projectPath, 'src/main/pages/HomePage.ts'), samplePage);
188
-
189
- // Sample Test
190
- const sampleTest = `import { test } from '../../../main/fixtures/fixtures';
191
- import { HomePage } from '../../main/pages/HomePage';
192
-
193
- test.describe('Sample Tests', () => {
194
- test('Search functionality', async ({ page }) => {
195
- const homePage = new HomePage(page);
196
- await page.goto('/');
197
- await homePage.search('playwright');
198
- });
199
- });
200
- `;
201
-
202
- fs.writeFileSync(path.join(projectPath, 'src/tests/specs/sample.spec.ts'), sampleTest);
203
209
 
204
210
  // Test data
205
211
  const testData = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sridharkikkeri/playwright-common",
3
- "version": "1.0.47",
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
+ });