froth-webdriverio-framework 7.0.119-dev1.1 โ†’ 7.0.119-dev1.10

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 (44) hide show
  1. package/README.md +245 -0
  2. package/allure-report-utils/allure-helper.js +226 -0
  3. package/allure-report-utils/froth-report.js +142 -0
  4. package/allure-report-utils/generate-allure-report.js +167 -0
  5. package/allure-report-utils/open-allure-report.js +97 -0
  6. package/allure-screenshots/Recorded_Scripts_Recorded_test_steps_success.png +0 -0
  7. package/allure-screenshots/Recorded_Scripts_Recorded_test_steps_success_2026-06-19T08-07-53-694Z.png +0 -0
  8. package/allure-screenshots/Recorded_Scripts_Recorded_test_steps_success_2026-06-19T08-10-50-605Z.png +0 -0
  9. package/allure-screenshots/action_001_setWindowSize_2026-06-19T08-10-35-850Z.png +0 -0
  10. package/allure-screenshots/action_001_url.png +0 -0
  11. package/allure-screenshots/action_002_click.png +0 -0
  12. package/allure-screenshots/action_002_url_2026-06-19T08-10-37-002Z.png +0 -0
  13. package/allure-screenshots/action_003_clearValue.png +0 -0
  14. package/allure-screenshots/action_003_setValue.png +0 -0
  15. package/allure-screenshots/action_003_waitForExist_2026-06-19T08-10-42-230Z.png +0 -0
  16. package/allure-screenshots/action_004_click.png +0 -0
  17. package/allure-screenshots/action_004_waitForExist_2026-06-19T08-10-42-353Z.png +0 -0
  18. package/allure-screenshots/action_005_clearValue.png +0 -0
  19. package/allure-screenshots/action_005_click_2026-06-19T08-10-43-186Z.png +0 -0
  20. package/allure-screenshots/action_005_setValue.png +0 -0
  21. package/allure-screenshots/action_006_click_2026-06-19T08-10-43-301Z.png +0 -0
  22. package/allure-screenshots/action_007_clearValue_2026-06-19T08-10-43-974Z.png +0 -0
  23. package/allure-screenshots/action_008_clearValue_2026-06-19T08-10-44-058Z.png +0 -0
  24. package/allure-screenshots/action_009_addValue_2026-06-19T08-10-44-559Z.png +0 -0
  25. package/allure-screenshots/action_010_addValue_2026-06-19T08-10-44-656Z.png +0 -0
  26. package/allure-screenshots/action_011_setValue_2026-06-19T08-10-44-779Z.png +0 -0
  27. package/allure-screenshots/action_012_setValue_2026-06-19T08-10-44-905Z.png +0 -0
  28. package/allure-screenshots/action_013_click_2026-06-19T08-10-45-787Z.png +0 -0
  29. package/allure-screenshots/action_014_click_2026-06-19T08-10-45-892Z.png +0 -0
  30. package/allure-screenshots/action_015_clearValue_2026-06-19T08-10-46-549Z.png +0 -0
  31. package/allure-screenshots/action_016_clearValue_2026-06-19T08-10-46-635Z.png +0 -0
  32. package/allure-screenshots/action_017_addValue_2026-06-19T08-10-46-868Z.png +0 -0
  33. package/allure-screenshots/action_018_addValue_2026-06-19T08-10-46-997Z.png +0 -0
  34. package/allure-screenshots/action_019_setValue_2026-06-19T08-10-47-080Z.png +0 -0
  35. package/allure-screenshots/action_020_setValue_2026-06-19T08-10-47-163Z.png +0 -0
  36. package/allure-screenshots/action_021_click_2026-06-19T08-10-47-377Z.png +0 -0
  37. package/allure-screenshots/action_022_click_2026-06-19T08-10-47-472Z.png +0 -0
  38. package/froth_configs/base.config.js +47 -3
  39. package/froth_configs/commonhook.js +53 -0
  40. package/froth_configs/local/mobile.config.js +57 -9
  41. package/froth_configs/local/web.config.js +139 -33
  42. package/froth_configs/screenshot-service.js +157 -0
  43. package/froth_configs/wdio.common.conf.js +112 -1
  44. package/package.json +62 -50
@@ -0,0 +1,167 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { execSync } = require('child_process');
4
+
5
+ /**
6
+ * Generate Allure HTML report automatically after test execution
7
+ * Uses BROWSERSTACK_BUILD_NAME environment variable for report naming
8
+ */
9
+
10
+ const REPORTS_DIR = './reports/allure';
11
+ const OUTPUT_DIR = './allure-report';
12
+
13
+ function findLatestReportDir() {
14
+ if (!fs.existsSync(REPORTS_DIR)) {
15
+ console.log('โŒ No Allure reports directory found.');
16
+ console.log('๐Ÿ’ก Reports are generated in: ./reports/allure/');
17
+ return null;
18
+ }
19
+
20
+ const directories = fs.readdirSync(REPORTS_DIR)
21
+ .map(file => path.join(REPORTS_DIR, file))
22
+ .filter(file => {
23
+ const stat = fs.statSync(file);
24
+ return stat.isDirectory();
25
+ })
26
+ .sort((a, b) => {
27
+ // Sort by modification time, newest first
28
+ return fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs;
29
+ });
30
+
31
+ return directories.length > 0 ? directories[0] : null;
32
+ }
33
+
34
+ function generateAllureReport(reportDir) {
35
+ try {
36
+ console.log('๐ŸŽฏ Allure Report Generator');
37
+ console.log('================================\n');
38
+ console.log(`๐Ÿ“ Using results from: ${reportDir}`);
39
+ console.log(`๐Ÿท๏ธ Build Name: ${process.env.BROWSERSTACK_BUILD_NAME || 'local-build'}\n`);
40
+
41
+ // Get directory name and extract build name (remove timestamp)
42
+ const dirName = path.basename(reportDir);
43
+ const timestampIndex = dirName.lastIndexOf('-');
44
+ const buildName = timestampIndex > 0 ? dirName.substring(0, timestampIndex) : dirName;
45
+
46
+ // Generate HTML report folder named after build name
47
+ const reportFolderName = buildName + '_report';
48
+ const outputDir = path.join(reportDir, reportFolderName);
49
+
50
+ // Clean existing report directory if it exists
51
+ if (fs.existsSync(outputDir)) {
52
+ console.log('๐Ÿงน Cleaning existing report directory...');
53
+ fs.rmSync(outputDir, { recursive: true, force: true });
54
+ }
55
+
56
+ // Generate Allure HTML report
57
+ console.log('๐Ÿ“Š Generating Allure HTML report...');
58
+ console.log(`๐Ÿ“‚ Report folder: ${reportFolderName}\n`);
59
+ const historyPath = path.join(reportDir, 'history');
60
+
61
+ let command = `npx allure generate ${reportDir} -o ${outputDir} --clean`;
62
+
63
+ // Add history if available
64
+ if (fs.existsSync(historyPath)) {
65
+ command = `npx allure generate ${reportDir} -o ${outputDir} --clean --history ${historyPath}`;
66
+ }
67
+
68
+ execSync(command, { stdio: 'inherit' });
69
+
70
+ // Create a simple server start script in the report folder
71
+ const startScriptPath = path.join(outputDir, 'start-server.sh');
72
+ const startScriptContent = `#!/bin/bash
73
+ echo "๐ŸŒ Starting Allure Report Server..."
74
+ echo "๐Ÿ“ Report: ${outputDir}"
75
+ echo "๐Ÿ”— Open: http://localhost:8080"
76
+ echo ""
77
+ echo "Press Ctrl+C to stop the server"
78
+ echo ""
79
+ npx allure open "${outputDir}" --port 8080
80
+ `;
81
+ fs.writeFileSync(startScriptPath, startScriptContent, { mode: 0o755 });
82
+
83
+ // Create a Windows batch file
84
+ const batchScriptPath = path.join(outputDir, 'start-server.bat');
85
+ const batchScriptContent = `@echo off
86
+ echo ๐ŸŒ Starting Allure Report Server...
87
+ echo ๐Ÿ“ Report: ${outputDir}
88
+ echo ๐Ÿ”— Open: http://localhost:8080
89
+ echo.
90
+ echo Press Ctrl+C to stop the server
91
+ echo.
92
+ npx allure open "${outputDir}" --port 8080
93
+ `;
94
+ fs.writeFileSync(batchScriptPath, batchScriptContent);
95
+
96
+ // Create a README
97
+ const readmePath = path.join(outputDir, 'README.md');
98
+ const readmeContent = `# Allure Test Report
99
+
100
+ ## ๐ŸŒ How to View This Report
101
+
102
+ ### Option 1: Double-click the start script (Easiest)
103
+ - **Mac/Linux:** Double-click \`start-server.sh\`
104
+ - **Windows:** Double-click \`start-server.bat\`
105
+ - Report will open at: http://localhost:8080
106
+
107
+ ### Option 2: Use npm script
108
+ From the project root, run:
109
+ \`\`\`bash
110
+ npm run report:open
111
+ \`\`\`
112
+
113
+ ### Option 3: Manual command
114
+ \`\`\`bash
115
+ npx allure open "${outputDir}" --port 8080
116
+ \`\`\`
117
+
118
+ ## โ— Why can't I just open index.html?
119
+
120
+ Allure reports use JavaScript to dynamically load test data from JSON files.
121
+ When you open index.html directly (file:// protocol), browsers block this for security reasons (CORS).
122
+
123
+ You need a web server to view the report properly - that's what the start scripts do!
124
+
125
+ ## ๐Ÿ“Š Test Results
126
+
127
+ - **Build Name:** ${process.env.BROWSERSTACK_BUILD_NAME || 'local-build'}
128
+ - **Generated:** ${new Date().toISOString()}
129
+ - **Report Location:** ${outputDir}
130
+ `;
131
+
132
+ fs.writeFileSync(readmePath, readmeContent);
133
+
134
+ console.log('\nโœ… Allure report generated successfully!');
135
+ console.log(`๐Ÿ“ Location: ${path.resolve(outputDir)}`);
136
+ console.log(`๐Ÿ“‚ Results directory: ${path.resolve(reportDir)}`);
137
+ console.log('\n๐ŸŒ To view the report:');
138
+ console.log(' 1. Run: npx froth-report open');
139
+ console.log(' 2. Or double-click: start-server.sh (Mac/Linux) / start-server.bat (Windows)');
140
+ console.log(' 3. Report opens at: http://localhost:8080');
141
+ console.log('\n๐Ÿ’ก Press Ctrl+C to stop the server when done viewing.');
142
+
143
+ return true;
144
+ } catch (error) {
145
+ console.error(`โŒ Error generating report: ${error.message}`);
146
+ return false;
147
+ }
148
+ }
149
+
150
+ function main() {
151
+ const reportDir = findLatestReportDir();
152
+
153
+ if (!reportDir) {
154
+ console.log('โŒ No Allure results found. Please run tests first.');
155
+ console.log('๐Ÿ’ก Results are saved in: ./reports/allure/');
156
+ process.exit(1);
157
+ }
158
+
159
+ generateAllureReport(reportDir);
160
+ }
161
+
162
+ // Run the script
163
+ if (require.main === module) {
164
+ main();
165
+ }
166
+
167
+ module.exports = { generateAllureReport, findLatestReportDir };
@@ -0,0 +1,97 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { execSync } = require('child_process');
4
+
5
+ /**
6
+ * Find and open the latest Allure HTML report
7
+ */
8
+
9
+ const REPORTS_DIR = './reports/allure';
10
+
11
+ function findLatestReport() {
12
+ if (!fs.existsSync(REPORTS_DIR)) {
13
+ console.log('โŒ No Allure reports directory found.');
14
+ console.log('๐Ÿ’ก Reports are generated in: ./reports/allure/');
15
+ return null;
16
+ }
17
+
18
+ const directories = fs.readdirSync(REPORTS_DIR)
19
+ .map(file => path.join(REPORTS_DIR, file))
20
+ .filter(file => fs.statSync(file).isDirectory())
21
+ .filter(file => {
22
+ // Check if any subdirectory ending with _report exists
23
+ const subdirs = fs.readdirSync(file)
24
+ .map(sub => path.join(file, sub))
25
+ .filter(sub => {
26
+ const stat = fs.statSync(sub);
27
+ return stat.isDirectory() && path.basename(sub).endsWith('_report');
28
+ });
29
+ return subdirs.length > 0;
30
+ })
31
+ .sort((a, b) => {
32
+ return fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs;
33
+ });
34
+
35
+ return directories.length > 0 ? directories[0] : null;
36
+ }
37
+
38
+ function openReport(reportDir) {
39
+ // Find the report folder ending with _report
40
+ const reportSubdirs = fs.readdirSync(reportDir)
41
+ .map(sub => path.join(reportDir, sub))
42
+ .filter(sub => {
43
+ const stat = fs.statSync(sub);
44
+ return stat.isDirectory() && path.basename(sub).endsWith('_report');
45
+ });
46
+
47
+ if (reportSubdirs.length === 0) {
48
+ console.log('โŒ No HTML report found in:', reportDir);
49
+ return false;
50
+ }
51
+
52
+ const htmlReportPath = reportSubdirs[0];
53
+ const indexPath = path.join(htmlReportPath, 'index.html');
54
+
55
+ if (!fs.existsSync(indexPath)) {
56
+ console.log('โŒ No index.html found at:', indexPath);
57
+ return false;
58
+ }
59
+
60
+ try {
61
+ console.log('๐ŸŽฏ Opening Allure Report');
62
+ console.log('========================\n');
63
+ console.log(`๐Ÿ“ Report location: ${htmlReportPath}`);
64
+ console.log(`๐Ÿท๏ธ Build: ${path.basename(reportDir)}\n`);
65
+
66
+ // Use Allure CLI to open the report
67
+ console.log('๐ŸŒ Opening report in browser on http://localhost:8080');
68
+ console.log('๐Ÿ’ก Press Ctrl+C to stop the server\n');
69
+
70
+ execSync(`npx allure open ${htmlReportPath} --port 8080`, { stdio: 'inherit' });
71
+
72
+ return true;
73
+ } catch (error) {
74
+ console.error(`โŒ Error opening report: ${error.message}`);
75
+ console.log(`\n๐Ÿ’ก To view manually, open: file://${path.resolve(indexPath)}`);
76
+ return false;
77
+ }
78
+ }
79
+
80
+ function main() {
81
+ const reportDir = findLatestReport();
82
+
83
+ if (!reportDir) {
84
+ console.log('โŒ No Allure HTML reports found. Please run tests first.');
85
+ console.log('๐Ÿ’ก Reports are generated in: ./reports/allure/');
86
+ process.exit(1);
87
+ }
88
+
89
+ openReport(reportDir);
90
+ }
91
+
92
+ // Run the script
93
+ if (require.main === module) {
94
+ main();
95
+ }
96
+
97
+ module.exports = { findLatestReport, openReport };
@@ -11,13 +11,11 @@ module.exports = {
11
11
  specs: require(SUITE_FILE).tests,
12
12
  exclude: [],
13
13
 
14
-
15
14
  logLevel: 'info',
16
15
  coloredLogs: true,
17
16
  screenshotPath: './errorShots/',
18
17
  baseUrl: '',
19
18
 
20
-
21
19
  waitforTimeout: 90000,
22
20
  connectionRetryTimeout: 90000,
23
21
  connectionRetryCount: 3,
@@ -27,5 +25,51 @@ module.exports = {
27
25
  mochaOpts: {
28
26
  ui: 'bdd',
29
27
  timeout: 300000
28
+ },
29
+
30
+ // Enable screenshot capture for Allure (WDIO built-in)
31
+ screenshotOnSave: true,
32
+
33
+ // Test hooks
34
+ before: async function() {
35
+ console.log('๐Ÿ”ง BEFORE hook triggered in base config');
36
+ },
37
+
38
+ // Capture final screenshot directly in the report folder
39
+ after: async function(results) {
40
+ console.log('๐Ÿ”ง AFTER hook triggered in base config');
41
+
42
+ // Only process if running locally
43
+ if (process.env.PLATFORM === 'local') {
44
+ try {
45
+ const fs = require('fs');
46
+ const nodePath = require('path');
47
+
48
+ // Find the most recent Allure results directory
49
+ const reportsBaseDir = './reports/allure';
50
+ if (fs.existsSync(reportsBaseDir)) {
51
+ const dirs = fs.readdirSync(reportsBaseDir)
52
+ .map(file => nodePath.join(reportsBaseDir, file))
53
+ .filter(file => fs.statSync(file).isDirectory())
54
+ .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
55
+
56
+ if (dirs.length > 0) {
57
+ const latestDir = dirs[0];
58
+ console.log(`๐Ÿ“ Report directory: ${latestDir}`);
59
+
60
+ // Save final screenshot directly to the report directory
61
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
62
+ const screenshotName = `Test_Suite_Completion_${timestamp}.png`;
63
+ const screenshotPath = nodePath.join(latestDir, screenshotName);
64
+
65
+ console.log(`๐Ÿ“ธ Saving final screenshot directly to report: ${screenshotName}`);
66
+ await browser.saveScreenshot(screenshotPath);
67
+ console.log(`โœ… Screenshot saved in report folder: ${screenshotName}`);
68
+ }
69
+ }
70
+ } catch (error) {
71
+ console.error('โŒ Error saving screenshot to report folder:', error.message);
72
+ }
73
+ }
30
74
  }
31
- };
75
+ };
@@ -90,6 +90,52 @@ async function pushComment(msg) {
90
90
  if (!global.TEST_COMMENTS) global.TEST_COMMENTS = [];
91
91
  global.TEST_COMMENTS.push(msg);
92
92
  }
93
+
94
+ /* ----------------- AUTO REPORT GENERATION ----------------- */
95
+ async function generateLocalReport() {
96
+ try {
97
+ const buildName = process.env.BROWSERSTACK_BUILD_NAME || 'local-build';
98
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
99
+ const reportDir = `./reports/mochawesome/${buildName}-${timestamp}`;
100
+ const jsonFile = path.join(process.cwd(), reportDir, 'mochawesome.json');
101
+
102
+ // Check if JSON report exists
103
+ if (!fs.existsSync(jsonFile)) {
104
+ console.log(`โš ๏ธ No JSON report found at: ${jsonFile}`);
105
+ console.log('๐Ÿ’ก Skipping report generation. Ensure tests ran successfully.');
106
+ return;
107
+ }
108
+
109
+ console.log(`๐Ÿ“Š Generating HTML report from: ${jsonFile}`);
110
+
111
+ // Use marge to generate HTML report
112
+ const { execSync } = require('child_process');
113
+ execSync(`npx marge "${jsonFile}" -o "${reportDir}"`, {
114
+ stdio: 'inherit',
115
+ cwd: process.cwd()
116
+ });
117
+
118
+ const htmlFile = path.join(reportDir, 'mochawesome.html');
119
+ console.log(`โœ… HTML report generated successfully!`);
120
+ console.log(`๐Ÿ“ Location: ${htmlFile}`);
121
+
122
+ // Auto-open report in browser
123
+ if (fs.existsSync(htmlFile)) {
124
+ console.log(`๐ŸŒ Opening report in browser...`);
125
+ try {
126
+ const openCommand = process.platform === 'darwin' ? 'open' :
127
+ process.platform === 'win32' ? 'start' :
128
+ 'xdg-open';
129
+ execSync(`${openCommand} "${htmlFile}"`, { stdio: 'ignore' });
130
+ } catch (error) {
131
+ console.log(`๐Ÿ’ก To view report manually, open: ${htmlFile}`);
132
+ }
133
+ }
134
+ } catch (error) {
135
+ console.error(`โŒ Error generating local report: ${error.message}`);
136
+ // Don't fail the entire process if report generation fails
137
+ }
138
+ }
93
139
  /* ------------------ COMMON CONFIG ------------------ */
94
140
 
95
141
  const commonHooks = {
@@ -348,6 +394,13 @@ const commonHooks = {
348
394
 
349
395
  await safeUpdateExecution();
350
396
  BUFFER.clear();
397
+
398
+ // Auto-generate HTML report for local execution
399
+ if (process.env.PLATFORM === 'local') {
400
+ console.log('๐Ÿ“Š Generating local test report...');
401
+ await generateLocalReport();
402
+ }
403
+
351
404
  return exitCode;
352
405
  },
353
406
 
@@ -1,11 +1,59 @@
1
- module.exports = () => ({
2
- services: ['appium'],
1
+ module.exports = () => {
2
+ // Generate unique report directory using BROWSERSTACK_BUILD_NAME
3
+ const buildName = process.env.BROWSERSTACK_BUILD_NAME || 'local-mobile-build';
4
+ // Remove spaces and special characters from build name for folder name - use underscores
5
+ const cleanBuildName = buildName.replace(/[^a-zA-Z0-9_]/g, '_');
6
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0]; // YYYY-MM-DD format
7
+ const uniqueReportDir = `./reports/allure/${cleanBuildName}-${timestamp}`;
3
8
 
9
+ console.log(`๐Ÿ“ฑ Mobile local execution configured`);
10
+ console.log(`๐Ÿ“Š Allure results will be saved in: ${uniqueReportDir}`);
11
+ console.log(`๐Ÿ’ก Report will be generated automatically after execution completes`);
4
12
 
5
- capabilities: [{
6
- platformName: 'Android',
7
- 'appium:deviceName': 'Android Emulator',
8
- 'appium:automationName': 'UiAutomator2',
9
- 'appium:app': process.env.LOCAL_APP_PATH
10
- }]
11
- });
13
+ return {
14
+ services: [
15
+ 'appium',
16
+ // Real-time screenshot capture (works even if execution stopped mid-way)
17
+ [require('../screenshot-service').ScreenshotService]
18
+ ],
19
+
20
+ capabilities: [{
21
+ platformName: 'Android',
22
+ 'appium:deviceName': 'Android Emulator',
23
+ 'appium:automationName': 'UiAutomator2',
24
+ 'appium:app': process.env.LOCAL_APP_PATH
25
+ }],
26
+
27
+ // Allure Reporter Configuration
28
+ reporters: [
29
+ ['allure', {
30
+ outputDir: uniqueReportDir,
31
+ disableWebdriverStepsReporting: false, // Enable step reporting
32
+ disableWebdriverScreenshotsReporting: false, // Enable automatic screenshot capture
33
+ useCucumberStepReporter: false,
34
+ disableMochaHooks: false,
35
+ allureCode: true,
36
+ captureAllureScreenshots: true
37
+ }]
38
+ ],
39
+
40
+ // Auto-generate report after execution completes
41
+ onComplete: async function(exitCode, config, capabilities, results) {
42
+ const { execSync } = require('child_process');
43
+ const nodePath = require('path');
44
+ try {
45
+ // Add a small delay to ensure Allure finishes writing all files
46
+ await new Promise(resolve => setTimeout(resolve, 1000));
47
+
48
+ // Resolve script path relative to framework package (works from any CWD)
49
+ const scriptPath = nodePath.resolve(__dirname, '../../allure-report-utils/generate-allure-report.js');
50
+
51
+ console.log('\n๐ŸŽฏ Generating Allure report...');
52
+ execSync(`node "${scriptPath}"`, { stdio: 'inherit', cwd: process.cwd() });
53
+ console.log('โœ… Report generation complete!');
54
+ } catch (error) {
55
+ console.error('โŒ Error generating report:', error.message);
56
+ }
57
+ }
58
+ };
59
+ };