@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.
@@ -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
- // Comprehensive Directory Structure
13
- const dirs = [
14
- 'src/core/api/auth',
15
- 'src/core/config',
16
- 'src/core/i18n',
17
- 'src/core/pages',
18
- 'src/core/reporting',
19
- 'src/core/selfhealing',
20
- 'src/core/utils',
21
- 'src/core/visual',
22
- 'src/core/wrappers',
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/assets',
31
- 'api-docs/classes',
32
- 'api-docs/interfaces',
33
- 'api-docs/types',
34
- 'api-docs/variables'
39
+ 'api-docs'
35
40
  ];
36
41
 
37
- dirs.forEach(idr => {
38
- fs.mkdirSync(path.join(projectPath, idr), { recursive: true });
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 NEW project
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 Playwright Test Project',
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.21',
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
- // --- "FULL PROXY" CORE EXTENSION BOILERPLATE ---
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
- const readme = `# ${projectName}
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. Please run manually.');
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:dev\n`);
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.21",
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",