plum-e2e 1.0.1 → 1.0.3
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/.prettierrc +15 -15
- package/README.md +5 -5
- package/backend/_scaffold/pages/LoginPage.js +22 -22
- package/backend/_scaffold/step_definitions/LoginSteps.js +9 -9
- package/backend/_scaffold/utils/constants.js +3 -3
- package/backend/_scaffold/utils/hooks.js +65 -65
- package/backend/_scaffold/utils/utils.js +10 -10
- package/backend/app.js +37 -37
- package/backend/config/scripts/create-settings.js +60 -60
- package/backend/config/scripts/generate-report.js +135 -135
- package/backend/config/scripts/run-tests.js +37 -37
- package/backend/cucumber.json +6 -6
- package/backend/package.json +29 -29
- package/backend/playwright.config.js +97 -97
- package/backend/routes/cron.routes.js +127 -127
- package/backend/routes/reports.routes.js +42 -42
- package/backend/routes/schedules.routes.js +32 -32
- package/backend/routes/tests.routes.js +33 -33
- package/backend/server.js +39 -39
- package/backend/services/cronService.js +127 -127
- package/backend/services/envService.js +43 -43
- package/backend/services/reportService.js +50 -50
- package/backend/services/scheduleService.js +34 -34
- package/backend/services/testService.js +70 -70
- package/backend/websockets/socketHandler.js +46 -46
- package/bin/plum.js +198 -198
- package/docker-compose.yml +41 -41
- package/frontend/jsconfig.json +13 -13
- package/frontend/package.json +26 -26
- package/frontend/postcss.config.js +23 -23
- package/frontend/src/app.css +35 -35
- package/frontend/src/app.html +28 -28
- package/frontend/src/lib/index.js +18 -18
- package/frontend/src/routes/+layout.svelte +34 -34
- package/frontend/src/routes/+page.svelte +188 -188
- package/frontend/src/routes/components/Navigation.svelte +53 -53
- package/frontend/src/routes/reports/+page.svelte +160 -160
- package/frontend/src/routes/scheduled-tests/+page.svelte +363 -363
- package/frontend/svelte.config.js +30 -30
- package/frontend/tailwind.config.js +44 -44
- package/frontend/vite.config.js +23 -23
- package/license-config.json +37 -37
- package/package.json +32 -28
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of Plum.
|
|
3
|
-
*
|
|
4
|
-
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
-
* it under the terms of the GNU General Public License as published by
|
|
6
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
* (at your option) any later version.
|
|
8
|
-
*
|
|
9
|
-
* Plum is distributed in the hope that it will be useful,
|
|
10
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
* GNU General Public License for more details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License
|
|
15
|
-
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const fs = require('fs');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
const cron = require('node-cron');
|
|
21
|
-
const { spawn } = require('child_process');
|
|
22
|
-
|
|
23
|
-
const CRON_JOBS_FILE = path.join(__dirname, '../config/cron-jobs.json');
|
|
24
|
-
let cronJobs = {};
|
|
25
|
-
|
|
26
|
-
const loadCronJobs = () => {
|
|
27
|
-
if (fs.existsSync(CRON_JOBS_FILE)) {
|
|
28
|
-
cronJobs = JSON.parse(fs.readFileSync(CRON_JOBS_FILE, 'utf8'));
|
|
29
|
-
|
|
30
|
-
// Schedule all loaded cron jobs and store only necessary data in memory
|
|
31
|
-
Object.keys(cronJobs).forEach((taskName) => {
|
|
32
|
-
const { cronExpression, tags } = cronJobs[taskName];
|
|
33
|
-
const scheduledCronJob = cron.schedule(cronExpression, () => {
|
|
34
|
-
console.log(`Running new task: ${taskName}`);
|
|
35
|
-
|
|
36
|
-
const task = spawn('npm', ['run', 'test'], {
|
|
37
|
-
env: { ...process.env, TAG: tags, TRIGGER: taskName }
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
task.stdout.on('data', (data) => console.log(data.toString()));
|
|
41
|
-
task.stderr.on('data', (data) => console.error(data.toString()));
|
|
42
|
-
task.on('close', (code) => console.log(`Task ${taskName} finished with code ${code}`));
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Store the reference to the cron job only in memory
|
|
46
|
-
cronJobs[taskName].cronJob = scheduledCronJob;
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const saveCronJobs = () => {
|
|
52
|
-
// Save only cron job data (not the reference to the cron job object) to the file
|
|
53
|
-
const cronJobsData = Object.keys(cronJobs).reduce((acc, taskName) => {
|
|
54
|
-
const { cronExpression, tags } = cronJobs[taskName];
|
|
55
|
-
acc[taskName] = { cronExpression, tags }; // Exclude the cronJob reference
|
|
56
|
-
return acc;
|
|
57
|
-
}, {});
|
|
58
|
-
|
|
59
|
-
fs.writeFileSync(CRON_JOBS_FILE, JSON.stringify(cronJobsData, null, 2), 'utf8');
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const getAllCronJobs = () =>
|
|
63
|
-
Object.keys(cronJobs).map((taskName) => ({
|
|
64
|
-
taskName,
|
|
65
|
-
cronExpression: cronJobs[taskName].cronExpression,
|
|
66
|
-
tags: cronJobs[taskName].tags
|
|
67
|
-
}));
|
|
68
|
-
|
|
69
|
-
const addCronJob = ({ cronExpression, taskName, tags }) => {
|
|
70
|
-
if (!cronExpression || !taskName || !tags) {
|
|
71
|
-
return { status: 400, message: 'Missing required parameters' };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
cronJobs[taskName] = { cronExpression, tags };
|
|
75
|
-
saveCronJobs();
|
|
76
|
-
loadCronJobs(); // Re-load and schedule the new cron job
|
|
77
|
-
return { status: 201, message: `Cron job ${taskName} added` };
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const removeCronJob = (taskName) => {
|
|
81
|
-
if (!cronJobs[taskName]) {
|
|
82
|
-
return { status: 404, message: `Cron job ${taskName} not found` };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Stop the cron job before removing
|
|
86
|
-
cronJobs[taskName].cronJob.stop();
|
|
87
|
-
|
|
88
|
-
delete cronJobs[taskName];
|
|
89
|
-
saveCronJobs();
|
|
90
|
-
loadCronJobs(); // Re-load and re-schedule cron jobs without the removed one
|
|
91
|
-
return { status: 200, message: `Cron job ${taskName} deleted` };
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const updateCronJob = (taskName, { cronExpression, tags }) => {
|
|
95
|
-
if (!cronJobs[taskName]) {
|
|
96
|
-
return { status: 404, message: `Cron job ${taskName} not found` };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Stop the old cron job
|
|
100
|
-
cronJobs[taskName].cronJob.stop();
|
|
101
|
-
|
|
102
|
-
// Update the cron job with new values
|
|
103
|
-
cronJobs[taskName] = { cronExpression, tags };
|
|
104
|
-
|
|
105
|
-
// Reschedule the updated cron job and store the reference
|
|
106
|
-
const scheduledCronJob = cron.schedule(cronExpression, () => {
|
|
107
|
-
console.log(`Running updated task: ${taskName}`);
|
|
108
|
-
|
|
109
|
-
const task = spawn('npm', ['run', 'test'], {
|
|
110
|
-
env: { ...process.env, TAG: tags, TRIGGER: taskName }
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
task.stdout.on('data', (data) => console.log(data.toString()));
|
|
114
|
-
task.stderr.on('data', (data) => console.error(data.toString()));
|
|
115
|
-
task.on('close', (code) => console.log(`Task ${taskName} finished with code ${code}`));
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Store the new cron job reference in memory
|
|
119
|
-
cronJobs[taskName].cronJob = scheduledCronJob;
|
|
120
|
-
|
|
121
|
-
saveCronJobs(); // Save the updated cron jobs to file (excluding cron job references)
|
|
122
|
-
return { status: 200, message: `Cron job ${taskName} updated` };
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
loadCronJobs(); // Initial load and scheduling of cron jobs
|
|
126
|
-
|
|
127
|
-
module.exports = { getAllCronJobs, addCronJob, removeCronJob, updateCronJob };
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const cron = require('node-cron');
|
|
21
|
+
const { spawn } = require('child_process');
|
|
22
|
+
|
|
23
|
+
const CRON_JOBS_FILE = path.join(__dirname, '../config/cron-jobs.json');
|
|
24
|
+
let cronJobs = {};
|
|
25
|
+
|
|
26
|
+
const loadCronJobs = () => {
|
|
27
|
+
if (fs.existsSync(CRON_JOBS_FILE)) {
|
|
28
|
+
cronJobs = JSON.parse(fs.readFileSync(CRON_JOBS_FILE, 'utf8'));
|
|
29
|
+
|
|
30
|
+
// Schedule all loaded cron jobs and store only necessary data in memory
|
|
31
|
+
Object.keys(cronJobs).forEach((taskName) => {
|
|
32
|
+
const { cronExpression, tags } = cronJobs[taskName];
|
|
33
|
+
const scheduledCronJob = cron.schedule(cronExpression, () => {
|
|
34
|
+
console.log(`Running new task: ${taskName}`);
|
|
35
|
+
|
|
36
|
+
const task = spawn('npm', ['run', 'test'], {
|
|
37
|
+
env: { ...process.env, TAG: tags, TRIGGER: taskName }
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
task.stdout.on('data', (data) => console.log(data.toString()));
|
|
41
|
+
task.stderr.on('data', (data) => console.error(data.toString()));
|
|
42
|
+
task.on('close', (code) => console.log(`Task ${taskName} finished with code ${code}`));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Store the reference to the cron job only in memory
|
|
46
|
+
cronJobs[taskName].cronJob = scheduledCronJob;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const saveCronJobs = () => {
|
|
52
|
+
// Save only cron job data (not the reference to the cron job object) to the file
|
|
53
|
+
const cronJobsData = Object.keys(cronJobs).reduce((acc, taskName) => {
|
|
54
|
+
const { cronExpression, tags } = cronJobs[taskName];
|
|
55
|
+
acc[taskName] = { cronExpression, tags }; // Exclude the cronJob reference
|
|
56
|
+
return acc;
|
|
57
|
+
}, {});
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(CRON_JOBS_FILE, JSON.stringify(cronJobsData, null, 2), 'utf8');
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const getAllCronJobs = () =>
|
|
63
|
+
Object.keys(cronJobs).map((taskName) => ({
|
|
64
|
+
taskName,
|
|
65
|
+
cronExpression: cronJobs[taskName].cronExpression,
|
|
66
|
+
tags: cronJobs[taskName].tags
|
|
67
|
+
}));
|
|
68
|
+
|
|
69
|
+
const addCronJob = ({ cronExpression, taskName, tags }) => {
|
|
70
|
+
if (!cronExpression || !taskName || !tags) {
|
|
71
|
+
return { status: 400, message: 'Missing required parameters' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
cronJobs[taskName] = { cronExpression, tags };
|
|
75
|
+
saveCronJobs();
|
|
76
|
+
loadCronJobs(); // Re-load and schedule the new cron job
|
|
77
|
+
return { status: 201, message: `Cron job ${taskName} added` };
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const removeCronJob = (taskName) => {
|
|
81
|
+
if (!cronJobs[taskName]) {
|
|
82
|
+
return { status: 404, message: `Cron job ${taskName} not found` };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Stop the cron job before removing
|
|
86
|
+
cronJobs[taskName].cronJob.stop();
|
|
87
|
+
|
|
88
|
+
delete cronJobs[taskName];
|
|
89
|
+
saveCronJobs();
|
|
90
|
+
loadCronJobs(); // Re-load and re-schedule cron jobs without the removed one
|
|
91
|
+
return { status: 200, message: `Cron job ${taskName} deleted` };
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const updateCronJob = (taskName, { cronExpression, tags }) => {
|
|
95
|
+
if (!cronJobs[taskName]) {
|
|
96
|
+
return { status: 404, message: `Cron job ${taskName} not found` };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Stop the old cron job
|
|
100
|
+
cronJobs[taskName].cronJob.stop();
|
|
101
|
+
|
|
102
|
+
// Update the cron job with new values
|
|
103
|
+
cronJobs[taskName] = { cronExpression, tags };
|
|
104
|
+
|
|
105
|
+
// Reschedule the updated cron job and store the reference
|
|
106
|
+
const scheduledCronJob = cron.schedule(cronExpression, () => {
|
|
107
|
+
console.log(`Running updated task: ${taskName}`);
|
|
108
|
+
|
|
109
|
+
const task = spawn('npm', ['run', 'test'], {
|
|
110
|
+
env: { ...process.env, TAG: tags, TRIGGER: taskName }
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
task.stdout.on('data', (data) => console.log(data.toString()));
|
|
114
|
+
task.stderr.on('data', (data) => console.error(data.toString()));
|
|
115
|
+
task.on('close', (code) => console.log(`Task ${taskName} finished with code ${code}`));
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Store the new cron job reference in memory
|
|
119
|
+
cronJobs[taskName].cronJob = scheduledCronJob;
|
|
120
|
+
|
|
121
|
+
saveCronJobs(); // Save the updated cron jobs to file (excluding cron job references)
|
|
122
|
+
return { status: 200, message: `Cron job ${taskName} updated` };
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
loadCronJobs(); // Initial load and scheduling of cron jobs
|
|
126
|
+
|
|
127
|
+
module.exports = { getAllCronJobs, addCronJob, removeCronJob, updateCronJob };
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of Plum.
|
|
3
|
-
*
|
|
4
|
-
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
-
* it under the terms of the GNU General Public License as published by
|
|
6
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
* (at your option) any later version.
|
|
8
|
-
*
|
|
9
|
-
* Plum is distributed in the hope that it will be useful,
|
|
10
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
* GNU General Public License for more details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License
|
|
15
|
-
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const fs = require('fs');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
|
|
21
|
-
/* -----------------------------------------------------
|
|
22
|
-
* .env Generator
|
|
23
|
-
* Description:
|
|
24
|
-
* If .env file doesn't exist, this will create
|
|
25
|
-
* a .env file in root with sauce demo's base URL
|
|
26
|
-
* ------------------------------------------------------ */
|
|
27
|
-
const envPath = path.join(__dirname, '../.env');
|
|
28
|
-
|
|
29
|
-
if (!fs.existsSync(envPath)) {
|
|
30
|
-
const envContent = 'BASE_URL=https://www.saucedemo.com/v1/\nIS_HEADLESS=false';
|
|
31
|
-
fs.writeFileSync(envPath, envContent);
|
|
32
|
-
console.log('.env file created in the root directory');
|
|
33
|
-
} else {
|
|
34
|
-
let envContent = fs.readFileSync(envPath, 'utf8');
|
|
35
|
-
|
|
36
|
-
if (!envContent.includes('IS_HEADLESS=')) {
|
|
37
|
-
envContent += '\nIS_HEADLESS=false';
|
|
38
|
-
fs.writeFileSync(envPath, envContent);
|
|
39
|
-
console.log('IS_HEADLESS=false added to .env');
|
|
40
|
-
} else {
|
|
41
|
-
console.log('.env file already contains IS_HEADLESS setting');
|
|
42
|
-
}
|
|
43
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
/* -----------------------------------------------------
|
|
22
|
+
* .env Generator
|
|
23
|
+
* Description:
|
|
24
|
+
* If .env file doesn't exist, this will create
|
|
25
|
+
* a .env file in root with sauce demo's base URL
|
|
26
|
+
* ------------------------------------------------------ */
|
|
27
|
+
const envPath = path.join(__dirname, '../.env');
|
|
28
|
+
|
|
29
|
+
if (!fs.existsSync(envPath)) {
|
|
30
|
+
const envContent = 'BASE_URL=https://www.saucedemo.com/v1/\nIS_HEADLESS=false';
|
|
31
|
+
fs.writeFileSync(envPath, envContent);
|
|
32
|
+
console.log('.env file created in the root directory');
|
|
33
|
+
} else {
|
|
34
|
+
let envContent = fs.readFileSync(envPath, 'utf8');
|
|
35
|
+
|
|
36
|
+
if (!envContent.includes('IS_HEADLESS=')) {
|
|
37
|
+
envContent += '\nIS_HEADLESS=false';
|
|
38
|
+
fs.writeFileSync(envPath, envContent);
|
|
39
|
+
console.log('IS_HEADLESS=false added to .env');
|
|
40
|
+
} else {
|
|
41
|
+
console.log('.env file already contains IS_HEADLESS setting');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of Plum.
|
|
3
|
-
*
|
|
4
|
-
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
-
* it under the terms of the GNU General Public License as published by
|
|
6
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
* (at your option) any later version.
|
|
8
|
-
*
|
|
9
|
-
* Plum is distributed in the hope that it will be useful,
|
|
10
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
* GNU General Public License for more details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License
|
|
15
|
-
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const fs = require('fs');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
|
|
21
|
-
const REPORTS_DIR = path.join(__dirname, '../reports');
|
|
22
|
-
|
|
23
|
-
const getAllReports = () => {
|
|
24
|
-
const files = fs.readdirSync(REPORTS_DIR);
|
|
25
|
-
|
|
26
|
-
// Get all files ending with '.html'
|
|
27
|
-
const htmlFiles = files.filter((file) => file.endsWith('.html'));
|
|
28
|
-
|
|
29
|
-
// Sort files by modification time (latest first)
|
|
30
|
-
const sortedFiles = htmlFiles.sort((a, b) => {
|
|
31
|
-
const aStats = fs.statSync(path.join(REPORTS_DIR, a));
|
|
32
|
-
const bStats = fs.statSync(path.join(REPORTS_DIR, b));
|
|
33
|
-
return bStats.mtime - aStats.mtime; // Sort in descending order of modification time
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
return sortedFiles;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const getLatestReport = () => {
|
|
40
|
-
const reportFiles = getAllReports()
|
|
41
|
-
.map((file) => ({
|
|
42
|
-
file,
|
|
43
|
-
time: fs.statSync(path.join(REPORTS_DIR, file)).mtime.getTime()
|
|
44
|
-
}))
|
|
45
|
-
.sort((a, b) => b.time - a.time);
|
|
46
|
-
|
|
47
|
-
return reportFiles.length ? reportFiles[0].file : null;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
module.exports = { getAllReports, getLatestReport };
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const REPORTS_DIR = path.join(__dirname, '../reports');
|
|
22
|
+
|
|
23
|
+
const getAllReports = () => {
|
|
24
|
+
const files = fs.readdirSync(REPORTS_DIR);
|
|
25
|
+
|
|
26
|
+
// Get all files ending with '.html'
|
|
27
|
+
const htmlFiles = files.filter((file) => file.endsWith('.html'));
|
|
28
|
+
|
|
29
|
+
// Sort files by modification time (latest first)
|
|
30
|
+
const sortedFiles = htmlFiles.sort((a, b) => {
|
|
31
|
+
const aStats = fs.statSync(path.join(REPORTS_DIR, a));
|
|
32
|
+
const bStats = fs.statSync(path.join(REPORTS_DIR, b));
|
|
33
|
+
return bStats.mtime - aStats.mtime; // Sort in descending order of modification time
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return sortedFiles;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getLatestReport = () => {
|
|
40
|
+
const reportFiles = getAllReports()
|
|
41
|
+
.map((file) => ({
|
|
42
|
+
file,
|
|
43
|
+
time: fs.statSync(path.join(REPORTS_DIR, file)).mtime.getTime()
|
|
44
|
+
}))
|
|
45
|
+
.sort((a, b) => b.time - a.time);
|
|
46
|
+
|
|
47
|
+
return reportFiles.length ? reportFiles[0].file : null;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
module.exports = { getAllReports, getLatestReport };
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of Plum.
|
|
3
|
-
*
|
|
4
|
-
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
-
* it under the terms of the GNU General Public License as published by
|
|
6
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
* (at your option) any later version.
|
|
8
|
-
*
|
|
9
|
-
* Plum is distributed in the hope that it will be useful,
|
|
10
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
* GNU General Public License for more details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License
|
|
15
|
-
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const fs = require('fs');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
|
|
21
|
-
const SETTINGS_PATH = path.join(__dirname, '../config/settings.json');
|
|
22
|
-
|
|
23
|
-
const getAllSchedules = () => {
|
|
24
|
-
try {
|
|
25
|
-
const fileContent = fs.readFileSync(SETTINGS_PATH, 'utf8');
|
|
26
|
-
const settings = JSON.parse(fileContent);
|
|
27
|
-
return settings.cronJobSchedules || [];
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.error('Error reading or parsing the settings file:', error);
|
|
30
|
-
return [];
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
module.exports = { getAllSchedules };
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const SETTINGS_PATH = path.join(__dirname, '../config/settings.json');
|
|
22
|
+
|
|
23
|
+
const getAllSchedules = () => {
|
|
24
|
+
try {
|
|
25
|
+
const fileContent = fs.readFileSync(SETTINGS_PATH, 'utf8');
|
|
26
|
+
const settings = JSON.parse(fileContent);
|
|
27
|
+
return settings.cronJobSchedules || [];
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('Error reading or parsing the settings file:', error);
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
module.exports = { getAllSchedules };
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* This file is part of Plum.
|
|
3
|
-
*
|
|
4
|
-
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
-
* it under the terms of the GNU General Public License as published by
|
|
6
|
-
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
-
* (at your option) any later version.
|
|
8
|
-
*
|
|
9
|
-
* Plum is distributed in the hope that it will be useful,
|
|
10
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
-
* GNU General Public License for more details.
|
|
13
|
-
*
|
|
14
|
-
* You should have received a copy of the GNU General Public License
|
|
15
|
-
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
const fs = require('fs');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
|
|
21
|
-
const FEATURES_DIR = path.join(__dirname, '../tests/features');
|
|
22
|
-
|
|
23
|
-
const getTestSuites = () => {
|
|
24
|
-
const suites = [];
|
|
25
|
-
|
|
26
|
-
const files = fs.readdirSync(FEATURES_DIR).filter((file) => file.endsWith('.feature'));
|
|
27
|
-
|
|
28
|
-
files.forEach((file) => {
|
|
29
|
-
const content = fs.readFileSync(path.join(FEATURES_DIR, file), 'utf8');
|
|
30
|
-
|
|
31
|
-
let suiteName = '';
|
|
32
|
-
let suiteTags = [];
|
|
33
|
-
const tests = [];
|
|
34
|
-
|
|
35
|
-
// Suites Tag Extractor
|
|
36
|
-
const featureMatch = content.match(/Feature:\s*(.+)/);
|
|
37
|
-
if (featureMatch) {
|
|
38
|
-
suiteName = featureMatch[1].trim();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const suiteTagsMatch = content.match(/^(@[^\n]+)/m);
|
|
42
|
-
if (suiteTagsMatch) {
|
|
43
|
-
suiteTags = suiteTagsMatch[0].split(/\s+/).filter((tag) => tag.trim() !== ''); // Remove empty elements
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Test Cases Tag Extractor
|
|
47
|
-
const scenarioMatches = [...content.matchAll(/(@[^\n]+)\s*Scenario:\s*(.+)/g)];
|
|
48
|
-
scenarioMatches.forEach((match) => {
|
|
49
|
-
const tags = match[1].split(/\s+/).filter((tag) => tag.trim() !== ''); // Remove empty elements
|
|
50
|
-
const scenarioText = match[2].trim();
|
|
51
|
-
|
|
52
|
-
if (tags.length === 0) return; // Skip if there are no valid tags
|
|
53
|
-
|
|
54
|
-
const testId = tags.shift(); // Extract the first tag as testId
|
|
55
|
-
|
|
56
|
-
tests.push({
|
|
57
|
-
id: tags.length > 0 ? [testId, ...tags] : testId, // Ensure testId is correctly structured
|
|
58
|
-
testCase: scenarioText
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
if (suiteName && tests.length) {
|
|
63
|
-
suites.push({ suiteName, suiteId: suiteTags.length > 1 ? suiteTags : suiteTags[0], tests });
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return { suites };
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
module.exports = { getTestSuites };
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
const FEATURES_DIR = path.join(__dirname, '../tests/features');
|
|
22
|
+
|
|
23
|
+
const getTestSuites = () => {
|
|
24
|
+
const suites = [];
|
|
25
|
+
|
|
26
|
+
const files = fs.readdirSync(FEATURES_DIR).filter((file) => file.endsWith('.feature'));
|
|
27
|
+
|
|
28
|
+
files.forEach((file) => {
|
|
29
|
+
const content = fs.readFileSync(path.join(FEATURES_DIR, file), 'utf8');
|
|
30
|
+
|
|
31
|
+
let suiteName = '';
|
|
32
|
+
let suiteTags = [];
|
|
33
|
+
const tests = [];
|
|
34
|
+
|
|
35
|
+
// Suites Tag Extractor
|
|
36
|
+
const featureMatch = content.match(/Feature:\s*(.+)/);
|
|
37
|
+
if (featureMatch) {
|
|
38
|
+
suiteName = featureMatch[1].trim();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const suiteTagsMatch = content.match(/^(@[^\n]+)/m);
|
|
42
|
+
if (suiteTagsMatch) {
|
|
43
|
+
suiteTags = suiteTagsMatch[0].split(/\s+/).filter((tag) => tag.trim() !== ''); // Remove empty elements
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Test Cases Tag Extractor
|
|
47
|
+
const scenarioMatches = [...content.matchAll(/(@[^\n]+)\s*Scenario:\s*(.+)/g)];
|
|
48
|
+
scenarioMatches.forEach((match) => {
|
|
49
|
+
const tags = match[1].split(/\s+/).filter((tag) => tag.trim() !== ''); // Remove empty elements
|
|
50
|
+
const scenarioText = match[2].trim();
|
|
51
|
+
|
|
52
|
+
if (tags.length === 0) return; // Skip if there are no valid tags
|
|
53
|
+
|
|
54
|
+
const testId = tags.shift(); // Extract the first tag as testId
|
|
55
|
+
|
|
56
|
+
tests.push({
|
|
57
|
+
id: tags.length > 0 ? [testId, ...tags] : testId, // Ensure testId is correctly structured
|
|
58
|
+
testCase: scenarioText
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (suiteName && tests.length) {
|
|
63
|
+
suites.push({ suiteName, suiteId: suiteTags.length > 1 ? suiteTags : suiteTags[0], tests });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return { suites };
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
module.exports = { getTestSuites };
|