@sridharkikkeri/playwright-common 1.0.21 ā 1.0.22
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/create-healthedge-tests.js +64 -343
- package/package.json +2 -1
- package/src/core/api/ApiClient.ts +289 -0
- package/src/core/api/auth/AuthStrategy.ts +11 -0
- package/src/core/api/auth/CookieAuth.ts +36 -0
- package/src/core/api/auth/OAuth2Auth.ts +46 -0
- package/src/core/config/ConfigManager.ts +72 -0
- package/src/core/i18n/Localization.ts +34 -0
- package/src/core/i18n/en.json +5 -0
- package/src/core/pages/BasePage.ts +47 -0
- package/src/core/reporting/AllureUtil.ts +35 -0
- package/src/core/selfhealing/ActionOrchestrator.ts +117 -0
- package/src/core/selfhealing/ElementProfileStore.ts +76 -0
- package/src/core/selfhealing/LocatorHealing.ts +84 -0
- package/src/core/utils/ErrorUtils.ts +21 -0
- package/src/core/utils/Logger.ts +14 -0
- package/src/core/visual/VisualTesting.ts +95 -0
- package/src/core/wrappers/ElementWrapper.ts +211 -0
- package/src/fixtures/fixtures.ts +90 -0
- package/src/index.ts +17 -0
- package/src/quality/pages/LoginPage.ts +36 -0
- package/src/tests/visual.spec.ts +38 -0
- package/src/tests/visual.spec.ts-snapshots/header-element-darwin.png +0 -0
- package/src/tests/visual.spec.ts-snapshots/playwright-homepage-darwin.png +0 -0
- package/src/tests/visual.spec.ts-snapshots/viewport-masked-darwin.png +0 -0
|
@@ -9,17 +9,26 @@ const projectPath = path.join(process.cwd(), projectName);
|
|
|
9
9
|
|
|
10
10
|
console.log(`\nš Creating HealthEdge Playwright project: ${projectName}\n`);
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
// Recursive Copy Helper
|
|
13
|
+
function copyRecursiveSync(src, dest) {
|
|
14
|
+
const exists = fs.existsSync(src);
|
|
15
|
+
const stats = exists && fs.statSync(src);
|
|
16
|
+
const isDirectory = exists && stats.isDirectory();
|
|
17
|
+
if (isDirectory) {
|
|
18
|
+
if (!fs.existsSync(dest)) {
|
|
19
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
20
|
+
}
|
|
21
|
+
fs.readdirSync(src).forEach((childItemName) => {
|
|
22
|
+
copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
|
|
23
|
+
});
|
|
24
|
+
} else {
|
|
25
|
+
fs.copyFileSync(src, dest);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 1. Create Directories
|
|
30
|
+
const baseDirs = [
|
|
31
|
+
'src/core',
|
|
23
32
|
'src/pages',
|
|
24
33
|
'src/tests',
|
|
25
34
|
'src/fixtures',
|
|
@@ -27,36 +36,55 @@ const dirs = [
|
|
|
27
36
|
'src/utils',
|
|
28
37
|
'allure-results',
|
|
29
38
|
'allure-report',
|
|
30
|
-
'api-docs
|
|
31
|
-
'api-docs/classes',
|
|
32
|
-
'api-docs/interfaces',
|
|
33
|
-
'api-docs/types',
|
|
34
|
-
'api-docs/variables'
|
|
39
|
+
'api-docs'
|
|
35
40
|
];
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
baseDirs.forEach(d => fs.mkdirSync(path.join(projectPath, d), { recursive: true }));
|
|
43
|
+
|
|
44
|
+
// 2. Copy Framework Source (The "As It Is" Magic)
|
|
45
|
+
const frameworkSrc = path.join(__dirname, 'src');
|
|
46
|
+
|
|
47
|
+
if (fs.existsSync(frameworkSrc)) {
|
|
48
|
+
console.log('š Copying framework source files...');
|
|
49
|
+
|
|
50
|
+
// Copy Core files
|
|
51
|
+
if (fs.existsSync(path.join(frameworkSrc, 'core'))) {
|
|
52
|
+
copyRecursiveSync(path.join(frameworkSrc, 'core'), path.join(projectPath, 'src/core'));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Copy Fixture templates
|
|
56
|
+
if (fs.existsSync(path.join(frameworkSrc, 'fixtures'))) {
|
|
57
|
+
copyRecursiveSync(path.join(frameworkSrc, 'fixtures'), path.join(projectPath, 'src/fixtures'));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Copy Quality Pages to user Pages
|
|
61
|
+
if (fs.existsSync(path.join(frameworkSrc, 'quality/pages'))) {
|
|
62
|
+
copyRecursiveSync(path.join(frameworkSrc, 'quality/pages'), path.join(projectPath, 'src/pages'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Copy Sample Tests
|
|
66
|
+
if (fs.existsSync(path.join(frameworkSrc, 'tests'))) {
|
|
67
|
+
copyRecursiveSync(path.join(frameworkSrc, 'tests'), path.join(projectPath, 'src/tests'));
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
console.log('ā ļø Framework source not found in package. Using fallback templates.');
|
|
71
|
+
// Fallback (minimal)
|
|
72
|
+
fs.writeFileSync(path.join(projectPath, 'src/core/placeholder.ts'), '// Framework source missing in package');
|
|
73
|
+
}
|
|
40
74
|
|
|
41
|
-
// package.json for the
|
|
75
|
+
// 3. package.json for the target project
|
|
42
76
|
const packageJson = {
|
|
43
77
|
name: projectName,
|
|
44
78
|
version: '1.0.0',
|
|
45
|
-
description: 'HealthEdge Enterprise
|
|
79
|
+
description: 'HealthEdge Enterprise Test Project',
|
|
46
80
|
scripts: {
|
|
47
81
|
'test': 'playwright test',
|
|
48
82
|
'test:dev': 'TEST_ENV=dev playwright test',
|
|
49
|
-
'test:qa': 'TEST_ENV=qa playwright test',
|
|
50
|
-
'test:auto': 'TEST_ENV=auto playwright test',
|
|
51
|
-
'test:staging': 'TEST_ENV=staging playwright test',
|
|
52
|
-
'test:prod': 'TEST_ENV=prod playwright test',
|
|
53
|
-
'test:visual': 'playwright test src/tests/visual.spec.ts',
|
|
54
83
|
'report': 'allure generate allure-results --clean -o allure-report && allure open allure-report',
|
|
55
|
-
'lint': 'eslint .'
|
|
56
|
-
'lint:fix': 'eslint . --fix'
|
|
84
|
+
'lint': 'eslint . --ext .ts'
|
|
57
85
|
},
|
|
58
86
|
dependencies: {
|
|
59
|
-
'@sridharkikkeri/playwright-common': '^1.0.
|
|
87
|
+
'@sridharkikkeri/playwright-common': '^1.0.22',
|
|
60
88
|
'@playwright/test': '^1.42.0',
|
|
61
89
|
'allure-playwright': '^3.4.5'
|
|
62
90
|
},
|
|
@@ -67,223 +95,10 @@ const packageJson = {
|
|
|
67
95
|
'typescript': '^5.3.0'
|
|
68
96
|
}
|
|
69
97
|
};
|
|
70
|
-
|
|
71
98
|
fs.writeFileSync(path.join(projectPath, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
72
99
|
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
const apiClientTs = `import { ApiClient as CommonApiClient } from '@sridharkikkeri/playwright-common';
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Enterprise API Client Extension.
|
|
79
|
-
* Use this to wrap framework API calls with project-specific logic.
|
|
80
|
-
*/
|
|
81
|
-
export class ApiClient extends CommonApiClient {
|
|
82
|
-
constructor(baseUrl: string) {
|
|
83
|
-
super(baseUrl);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async getWithAuth(endpoint: string, token: string) {
|
|
87
|
-
return this.get(endpoint, {
|
|
88
|
-
headers: { 'Authorization': \`Bearer \${token}\` }
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async postResource(endpoint: string, body: any) {
|
|
93
|
-
return this.post(endpoint, body);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async putResource(endpoint: string, body: any) {
|
|
97
|
-
return this.put(endpoint, body);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async deleteResource(endpoint: string) {
|
|
101
|
-
return this.delete(endpoint);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
`;
|
|
105
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/api/ApiClient.ts'), apiClientTs);
|
|
106
|
-
|
|
107
|
-
const authStrategyTs = `import { AuthStrategy as CommonAuthStrategy } from '@sridharkikkeri/playwright-common';
|
|
108
|
-
|
|
109
|
-
export class AuthStrategy extends CommonAuthStrategy {
|
|
110
|
-
async login(credentials: { user: string; pass: string }): Promise<void> {
|
|
111
|
-
await this.page.goto('/login');
|
|
112
|
-
await this.page.fill('#username', credentials.user);
|
|
113
|
-
await this.page.fill('#password', credentials.pass);
|
|
114
|
-
await this.page.click('#login-btn');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async logout(): Promise<void> {
|
|
118
|
-
await this.page.click('#logout-btn');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
`;
|
|
122
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/api/auth/AuthStrategy.ts'), authStrategyTs);
|
|
123
|
-
|
|
124
|
-
const configManagerTs = `import { ConfigManager as CommonConfigManager } from '@sridharkikkeri/playwright-common';
|
|
125
|
-
|
|
126
|
-
export class ConfigManager extends CommonConfigManager {
|
|
127
|
-
static getEnvironment() { return this.getConfig().environment; }
|
|
128
|
-
static getBaseUrl() { return this.getConfig().baseUrl; }
|
|
129
|
-
static getApiUrl() { return this.getConfig().apiUrl; }
|
|
130
|
-
}
|
|
131
|
-
`;
|
|
132
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/config/ConfigManager.ts'), configManagerTs);
|
|
133
|
-
|
|
134
|
-
const localizationTs = `import { Localization as CommonLocalization } from '@sridharkikkeri/playwright-common';
|
|
135
|
-
|
|
136
|
-
export class Localization extends CommonLocalization {
|
|
137
|
-
static translate(key: string, params?: Record<string, string>) {
|
|
138
|
-
return this.t(key, params);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
`;
|
|
142
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/i18n/Localization.ts'), localizationTs);
|
|
143
|
-
|
|
144
|
-
const basePageTs = `import { Page } from '@playwright/test';
|
|
145
|
-
import { BasePage as CommonBasePage, ActionOrchestrator } from '@sridharkikkeri/playwright-common';
|
|
146
|
-
|
|
147
|
-
export abstract class BasePage extends CommonBasePage {
|
|
148
|
-
constructor(page: Page, options?: { pageName: string; orchestrator?: ActionOrchestrator }) {
|
|
149
|
-
super(page, options);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async navigateTo(path: string) {
|
|
153
|
-
await this.page.goto(path);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async reload() {
|
|
157
|
-
await this.page.reload();
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
`;
|
|
161
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/pages/BasePage.ts'), basePageTs);
|
|
162
|
-
|
|
163
|
-
const allureUtilTs = `import { AllureUtil as CommonAllureUtil } from '@sridharkikkeri/playwright-common';
|
|
164
|
-
|
|
165
|
-
export class AllureUtil extends CommonAllureUtil {
|
|
166
|
-
static async logEnterpriseStep(name: string, action: () => Promise<void>) {
|
|
167
|
-
await this.step(name, action);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
`;
|
|
171
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/reporting/AllureUtil.ts'), allureUtilTs);
|
|
172
|
-
|
|
173
|
-
const locatorHealingTs = `import { LocatorHealing as CommonLocatorHealing } from '@sridharkikkeri/playwright-common';
|
|
174
|
-
|
|
175
|
-
export class LocatorHealing extends CommonLocatorHealing {
|
|
176
|
-
// Implement project-specific recovery heuristics here
|
|
177
|
-
}
|
|
178
|
-
`;
|
|
179
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/selfhealing/LocatorHealing.ts'), locatorHealingTs);
|
|
180
|
-
|
|
181
|
-
const actionOrchestratorTs = `import { ActionOrchestrator as CommonActionOrchestrator } from '@sridharkikkeri/playwright-common';
|
|
182
|
-
|
|
183
|
-
export class ActionOrchestrator extends CommonActionOrchestrator {
|
|
184
|
-
// Hook into orchestration events for custom logging or metrics
|
|
185
|
-
}
|
|
186
|
-
`;
|
|
187
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/selfhealing/ActionOrchestrator.ts'), actionOrchestratorTs);
|
|
188
|
-
|
|
189
|
-
const visualTestingTs = `import { VisualTesting as CommonVisualTesting } from '@sridharkikkeri/playwright-common';
|
|
190
|
-
|
|
191
|
-
export class VisualTesting extends CommonVisualTesting {
|
|
192
|
-
// Custom thresholds or global masking logic
|
|
193
|
-
}
|
|
194
|
-
`;
|
|
195
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/visual/VisualTesting.ts'), visualTestingTs);
|
|
196
|
-
|
|
197
|
-
const elementWrapperTs = `import { ElementWrapper as CommonElementWrapper } from '@sridharkikkeri/playwright-common';
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Enterprise Element Wrapper Extension.
|
|
201
|
-
* Provides a full interaction set with AI-healing proxies.
|
|
202
|
-
*/
|
|
203
|
-
export class ElementWrapper extends CommonElementWrapper {
|
|
204
|
-
/* --- Interaction Proxies --- */
|
|
205
|
-
async clickAndLog(intent?: string) { await this.click(intent); }
|
|
206
|
-
async dblClick(intent?: string) { await this.locator.dblclick(); }
|
|
207
|
-
async hover(intent?: string) { await this.locator.hover(); }
|
|
208
|
-
async fillAndLog(val: string, intent?: string) { await this.fill(val, intent); }
|
|
209
|
-
async press(key: string, intent?: string) { await this.locator.press(key); }
|
|
210
|
-
|
|
211
|
-
/* --- State Proxies --- */
|
|
212
|
-
async isVisible(): Promise<boolean> { return await this.locator.isVisible(); }
|
|
213
|
-
async isEnabled(): Promise<boolean> { return await this.locator.isEnabled(); }
|
|
214
|
-
|
|
215
|
-
/* --- Wait Proxies --- */
|
|
216
|
-
async waitForVisible(timeout = 5000) { await this.locator.waitFor({ state: 'visible', timeout }); }
|
|
217
|
-
async waitForHidden(timeout = 5000) { await this.locator.waitFor({ state: 'hidden', timeout }); }
|
|
218
|
-
}
|
|
219
|
-
`;
|
|
220
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/wrappers/ElementWrapper.ts'), elementWrapperTs);
|
|
221
|
-
|
|
222
|
-
const loggerTs = `import { Logger as CommonLogger } from '@sridharkikkeri/playwright-common';
|
|
223
|
-
|
|
224
|
-
export class Logger extends CommonLogger {
|
|
225
|
-
static debug(msg: string) { console.debug(\`[DEBUG] \${msg}\`); }
|
|
226
|
-
static info(msg: string) { console.log(\`[INFO] \${msg}\`); }
|
|
227
|
-
static warn(msg: string) { console.warn(\`[WARN] \${msg}\`); }
|
|
228
|
-
static error(msg: string, err?: Error) { console.error(\`[ERROR] \${msg}\`, err); }
|
|
229
|
-
}
|
|
230
|
-
`;
|
|
231
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/utils/Logger.ts'), loggerTs);
|
|
232
|
-
|
|
233
|
-
const errorUtilsTs = `import { ErrorUtils as CommonErrorUtils } from '@sridharkikkeri/playwright-common';
|
|
234
|
-
|
|
235
|
-
export class ErrorUtils extends CommonErrorUtils {
|
|
236
|
-
}
|
|
237
|
-
`;
|
|
238
|
-
fs.writeFileSync(path.join(projectPath, 'src/core/utils/ErrorUtils.ts'), errorUtilsTs);
|
|
239
|
-
|
|
240
|
-
// --- UTILS & I18N POPULATION ---
|
|
241
|
-
const stringUtilsTs = `export class StringUtils {
|
|
242
|
-
static capitalize(str: string) { return str.charAt(0).toUpperCase() + str.slice(1); }
|
|
243
|
-
}`;
|
|
244
|
-
fs.writeFileSync(path.join(projectPath, 'src/utils/StringUtils.ts'), stringUtilsTs);
|
|
245
|
-
|
|
246
|
-
const dateUtilsTs = `export class DateUtils {
|
|
247
|
-
static now() { return new Date().toISOString(); }
|
|
248
|
-
}`;
|
|
249
|
-
fs.writeFileSync(path.join(projectPath, 'src/utils/DateUtils.ts'), dateUtilsTs);
|
|
250
|
-
|
|
251
|
-
fs.writeFileSync(path.join(projectPath, 'src/i18n/en.json'), JSON.stringify({ "welcome": "Welcome to HealthEdge" }, null, 2));
|
|
252
|
-
fs.writeFileSync(path.join(projectPath, 'src/i18n/fr.json'), JSON.stringify({ "welcome": "Bienvenue chez HealthEdge" }, null, 2));
|
|
253
|
-
|
|
254
|
-
// --- DOCUMENTATION ---
|
|
255
|
-
fs.writeFileSync(path.join(projectPath, 'api-docs/assets/style.css'), 'body { font-family: -apple-system, sans-serif; padding: 40px; line-height: 1.6; color: #333; } h1 { color: #007bff; }');
|
|
256
|
-
fs.writeFileSync(path.join(projectPath, 'api-docs/index.html'), `
|
|
257
|
-
<!DOCTYPE html>
|
|
258
|
-
<html>
|
|
259
|
-
<head>
|
|
260
|
-
<title>${projectName} Service Documentation</title>
|
|
261
|
-
<link rel="stylesheet" href="assets/style.css">
|
|
262
|
-
</head>
|
|
263
|
-
<body>
|
|
264
|
-
<h1>š¢ ${projectName} Enterprise Automation</h1>
|
|
265
|
-
<p>This project leverages the <strong>HealthEdge Playwright Framework</strong> for resilient, AI-powered automation.</p>
|
|
266
|
-
<hr>
|
|
267
|
-
<h3>Documentation Modules</h3>
|
|
268
|
-
<ul>
|
|
269
|
-
<li><a href="classes/README.md">Class Extensions & Proxies</a></li>
|
|
270
|
-
<li><a href="interfaces/README.md">Data Interfaces</a></li>
|
|
271
|
-
<li><a href="variables/README.md">Environment Variables</a></li>
|
|
272
|
-
</ul>
|
|
273
|
-
</body>
|
|
274
|
-
</html>`);
|
|
275
|
-
|
|
276
|
-
['classes', 'interfaces', 'types', 'variables'].forEach(fold => {
|
|
277
|
-
fs.writeFileSync(path.join(projectPath, `api-docs/${fold}/README.md`), `# ${fold.toUpperCase()}\nStructured documentation for ${fold} in project ${projectName}.`);
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
// --- STANDARD CONFIG & EXAMPLES ---
|
|
281
|
-
const baseConfig = { healingEnabled: true, environment: 'dev', baseUrl: 'https://example.com', apiUrl: 'https://api.example.com', timeout: 30000, retries: 2 };
|
|
282
|
-
const environments = ['dev', 'qa', 'auto', 'staging', 'prod'];
|
|
283
|
-
environments.forEach(env => {
|
|
284
|
-
const config = { ...baseConfig, environment: env, baseUrl: `https://${env}.example.com`, apiUrl: `https://api-${env}.example.com` };
|
|
285
|
-
fs.writeFileSync(path.join(projectPath, `framework.config.${env}.json`), JSON.stringify(config, null, 2));
|
|
286
|
-
});
|
|
100
|
+
// 4. Configuration Boilerplate
|
|
101
|
+
const baseConfig = { healingEnabled: true, environment: 'dev', baseUrl: 'https://example.com', apiUrl: 'https://api.example.com', timeout: 30000 };
|
|
287
102
|
fs.writeFileSync(path.join(projectPath, 'framework.config.json'), JSON.stringify(baseConfig, null, 2));
|
|
288
103
|
|
|
289
104
|
const playwrightConfig = `import { defineConfig } from '@playwright/test';
|
|
@@ -295,74 +110,6 @@ export default defineConfig({
|
|
|
295
110
|
});`;
|
|
296
111
|
fs.writeFileSync(path.join(projectPath, 'playwright.config.ts'), playwrightConfig);
|
|
297
112
|
|
|
298
|
-
const fixturesTs = `import { test as base } from '@sridharkikkeri/playwright-common';
|
|
299
|
-
import { HomePage } from '../pages/HomePage';
|
|
300
|
-
import { LoginPage } from '../pages/LoginPage';
|
|
301
|
-
|
|
302
|
-
export const test = base.extend<{ homePage: HomePage; loginPage: LoginPage }>({
|
|
303
|
-
homePage: async ({ page, orchestrator }, use) => { await use(new HomePage(page, orchestrator)); },
|
|
304
|
-
loginPage: async ({ page, orchestrator }, use) => { await use(new LoginPage(page, orchestrator)); },
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
export { expect } from '@playwright/test';`;
|
|
308
|
-
fs.writeFileSync(path.join(projectPath, 'src/fixtures/fixtures.ts'), fixturesTs);
|
|
309
|
-
|
|
310
|
-
const homePageTs = `import { Page } from '@playwright/test';
|
|
311
|
-
import { BasePage } from '../core/pages/BasePage';
|
|
312
|
-
import { ActionOrchestrator } from '../core/selfhealing/ActionOrchestrator';
|
|
313
|
-
|
|
314
|
-
export class HomePage extends BasePage {
|
|
315
|
-
constructor(page: Page, orchestrator?: ActionOrchestrator) {
|
|
316
|
-
super(page, { pageName: 'HomePage', orchestrator });
|
|
317
|
-
}
|
|
318
|
-
private readonly searchBtn = this.element('button[type="submit"]');
|
|
319
|
-
async clickSearch() { await this.searchBtn.click('Click Search Button'); }
|
|
320
|
-
}
|
|
321
|
-
`;
|
|
322
|
-
fs.writeFileSync(path.join(projectPath, 'src/pages/HomePage.ts'), homePageTs);
|
|
323
|
-
|
|
324
|
-
const loginPageTs = `import { Page } from '@playwright/test';
|
|
325
|
-
import { BasePage } from '../core/pages/BasePage';
|
|
326
|
-
import { ActionOrchestrator } from '../core/selfhealing/ActionOrchestrator';
|
|
327
|
-
|
|
328
|
-
export class LoginPage extends BasePage {
|
|
329
|
-
constructor(page: Page, orchestrator?: ActionOrchestrator) {
|
|
330
|
-
super(page, { pageName: 'LoginPage', orchestrator });
|
|
331
|
-
}
|
|
332
|
-
private readonly userBox = this.element('#username');
|
|
333
|
-
private readonly passBox = this.element('#password');
|
|
334
|
-
private readonly submit = this.element('button.login');
|
|
335
|
-
|
|
336
|
-
async login(u: string, p: string) {
|
|
337
|
-
await this.userBox.fill(u, 'Enter user');
|
|
338
|
-
await this.passBox.fill(p, 'Enter pass');
|
|
339
|
-
await this.submit.click('Submit login');
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
`;
|
|
343
|
-
fs.writeFileSync(path.join(projectPath, 'src/pages/LoginPage.ts'), loginPageTs);
|
|
344
|
-
|
|
345
|
-
const visualTest = `import { test, expect } from '../fixtures/fixtures';
|
|
346
|
-
|
|
347
|
-
test.describe('Enterprise Visual Regression', () => {
|
|
348
|
-
test('HP Visual Verification', async ({ page }) => {
|
|
349
|
-
await page.goto('https://playwright.dev');
|
|
350
|
-
await expect(page).toHaveScreenshot('homepage.png', {
|
|
351
|
-
mask: [page.locator('.navbar')],
|
|
352
|
-
threshold: 0.1
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
});`;
|
|
356
|
-
fs.writeFileSync(path.join(projectPath, 'src/tests/visual.spec.ts'), visualTest);
|
|
357
|
-
|
|
358
|
-
const sampleTest = `import { test, expect } from '../fixtures/fixtures';
|
|
359
|
-
|
|
360
|
-
test('Standard Smoke Test', async ({ page, loginPage }) => {
|
|
361
|
-
await page.goto('https://playwright.dev');
|
|
362
|
-
await expect(page).toHaveTitle(/Playwright/);
|
|
363
|
-
});`;
|
|
364
|
-
fs.writeFileSync(path.join(projectPath, 'src/tests/sample.spec.ts'), sampleTest);
|
|
365
|
-
|
|
366
113
|
const tsConfig = {
|
|
367
114
|
compilerOptions: {
|
|
368
115
|
target: 'ES2020', module: 'commonjs', lib: ['ES2020', 'DOM'],
|
|
@@ -372,43 +119,17 @@ const tsConfig = {
|
|
|
372
119
|
};
|
|
373
120
|
fs.writeFileSync(path.join(projectPath, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2));
|
|
374
121
|
|
|
375
|
-
const gitignore = `node_modules
|
|
376
|
-
allure-results/
|
|
377
|
-
allure-report/
|
|
378
|
-
test-results/
|
|
379
|
-
playwright-report/
|
|
380
|
-
.env
|
|
381
|
-
*.log
|
|
382
|
-
dist/
|
|
383
|
-
`;
|
|
122
|
+
const gitignore = `node_modules/\nallure-results/\nallure-report/\n.env\n*.log\n`;
|
|
384
123
|
fs.writeFileSync(path.join(projectPath, '.gitignore'), gitignore);
|
|
385
124
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
## Overview
|
|
389
|
-
Enterprise automation test project powered by **@sridharkikkeri/playwright-common**.
|
|
390
|
-
|
|
391
|
-
## Getting Started
|
|
392
|
-
\`\`\`bash
|
|
393
|
-
npm install
|
|
394
|
-
npm run test:dev
|
|
395
|
-
\`\`\`
|
|
396
|
-
|
|
397
|
-
## Features
|
|
398
|
-
- **AI Self-Healing**: Powered by ActionOrchestrator
|
|
399
|
-
- **Visual Testing**: Automatic screenshot comparison
|
|
400
|
-
- **Enterprise Reporting**: Built-in Allure integration
|
|
401
|
-
`;
|
|
402
|
-
fs.writeFileSync(path.join(projectPath, 'README.md'), readme);
|
|
403
|
-
|
|
404
|
-
console.log('ā
Full Enterprise Project Structure Created');
|
|
405
|
-
console.log('\nš¦ Installing dependencies...\n');
|
|
125
|
+
console.log('\nā
Project structure created "as it is" from framework source.');
|
|
126
|
+
console.log('š¦ Installing dependencies...\n');
|
|
406
127
|
|
|
407
128
|
try {
|
|
408
129
|
execSync('npm install', { cwd: projectPath, stdio: 'inherit' });
|
|
409
130
|
console.log('\nā
Dependencies installed');
|
|
410
131
|
} catch (error) {
|
|
411
|
-
console.log('\nā ļø npm install failed.
|
|
132
|
+
console.log('\nā ļø npm install failed. Run manually.');
|
|
412
133
|
}
|
|
413
134
|
|
|
414
|
-
console.log(`\nš Project ready! cd ${projectName} and try: npm run test
|
|
135
|
+
console.log(`\nš Project ready! cd ${projectName} and try: npm run test\n`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sridharkikkeri/playwright-common",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.22",
|
|
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",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"dist",
|
|
15
|
+
"src",
|
|
15
16
|
"create-healthedge-tests.js",
|
|
16
17
|
"README.md",
|
|
17
18
|
"HEALING_CACHE_STRATEGY.md",
|