testilo 38.0.2 → 39.0.1
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/README.md +7 -7
- package/package.json +1 -1
- package/procs/compare/tcp43/index.html +42 -0
- package/procs/compare/tcp43/index.js +84 -0
- package/procs/track/ttp40/index.js +1 -3
- package/procs/track/ttp43/index.html +116 -0
- package/procs/track/ttp43/index.js +100 -0
- package/summarize.js +4 -1
package/README.md
CHANGED
|
@@ -786,10 +786,14 @@ To test the `digest` module, in the project directory you can execute the statem
|
|
|
786
786
|
|
|
787
787
|
### Summarization
|
|
788
788
|
|
|
789
|
-
The `summarize` module of Testilo can summarize a scored report. The summary is an object that contains these properties from the report: `id`, `endTime`, `sources`, and `score` (the value of the `score.total` property of the report).
|
|
789
|
+
The `summarize` module of Testilo can summarize a scored report. The summary is an object that contains these properties from the report: `id`, `endTime`, `targetWhat` (description of the target), `url` (of the target), `sources`, and `score` (only the value of the `score.total` property of the report).
|
|
790
|
+
|
|
791
|
+
Report summaries make some operations more efficient by allowing other modules to get needed data from summaries instead of from reports. The size of a summary tends to be about 0.01% of the size of a report.
|
|
790
792
|
|
|
791
793
|
#### Invocation
|
|
792
794
|
|
|
795
|
+
The `summarize` module summarizes one report when invoked by a module, but the `call` module invoked by a user can call `summarize` multiple times to summarize multiple reports and combine those summaries into a file.
|
|
796
|
+
|
|
793
797
|
##### By a module
|
|
794
798
|
|
|
795
799
|
A module can invoke `summarize()` in this way:
|
|
@@ -819,10 +823,6 @@ When a user invokes `summarize` in this example, the `call` module:
|
|
|
819
823
|
- creates a _summary report_, an object containing three properties: `id` (an ID), `what` (a description, such as `'divisions'`), and `summaries` (the array of summaries).
|
|
820
824
|
- writes the summary report in JSON format to the `summarized` subdirectory of the `REPORTDIR` directory, using the ID as the base of the file name.
|
|
821
825
|
|
|
822
|
-
#### Summary reports
|
|
823
|
-
|
|
824
|
-
A summary report serves as a necessary input to the `compare` and `track` modules described below. When a user invokes the `compare` module, a summary report is produced. A module can create a summary report by invoking `compare` multiple times on different scored reports, assembling the resulting summaries into an array, and creating an object like the one the `call` module creates for a user.
|
|
825
|
-
|
|
826
826
|
### Comparison
|
|
827
827
|
|
|
828
828
|
If you use Testilo to perform a battery of tests on multiple targets, you may want a single report that compares the total scores received by the targets. Testilo can produce such a _comparison_.
|
|
@@ -833,7 +833,7 @@ The `compare` module compares the scores in a summary report. The `compare()` fu
|
|
|
833
833
|
|
|
834
834
|
The comparison function defines the rules for generating an HTML file comparing the scored reports. The Testilo package contains a `procs/compare` directory, in which there are subdirectories containing modules that export comparison functions. You can use one of those functions, or you can create your own.
|
|
835
835
|
|
|
836
|
-
|
|
836
|
+
The built-in comparison functions compare all of the scores in the summary report. Thus, if the summary report contains multiple scores for the same target, based on tests performed at various times, those scores will all appear in the comparison, labeled identically with the `what` description of the target. If you want only one score per target to appear, you can create a new summary report that includes only one summary per target in its `summaries` array.
|
|
837
837
|
|
|
838
838
|
#### Invocation
|
|
839
839
|
|
|
@@ -864,7 +864,7 @@ node call compare 'state legislators' tcp99 240813
|
|
|
864
864
|
|
|
865
865
|
When a user invokes `compare` in this example, the `call` module:
|
|
866
866
|
- gets the comparison module from subdirectory `tcp99` of the subdirectory `compare` in the `FUNCTIONDIR` directory.
|
|
867
|
-
- gets the
|
|
867
|
+
- gets the last summary report whose file name begins with `'240813'` from the `summarized` subdirectory of the `REPORTDIR` directory.
|
|
868
868
|
- creates an ID for the comparison.
|
|
869
869
|
- creates the comparison as an HTML document.
|
|
870
870
|
- writes the comparison in the `comparative` subdirectory of the `REPORTDIR` directory, with `state legislators` as a description and the ID as the base of the file name.
|
package/package.json
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<!DOCTYPE HTML>
|
|
2
|
+
<html lang="en-US">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="author" content="Testilo">
|
|
7
|
+
<meta name="creator" content="Testilo">
|
|
8
|
+
<meta name="publisher" name="Testilo">
|
|
9
|
+
<meta name="description" content="comparison of accessibility scores">
|
|
10
|
+
<meta name="keywords" content="accessibility a11y web testing">
|
|
11
|
+
<title>Accessibility score comparison: __what__</title>
|
|
12
|
+
<link rel="icon" href="favicon.ico">
|
|
13
|
+
<link rel="stylesheet" href="style.css">
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<main>
|
|
17
|
+
<header>
|
|
18
|
+
<h1>Accessibility score comparison: __what__</h1>
|
|
19
|
+
</header>
|
|
20
|
+
<h2>Introduction</h2>
|
|
21
|
+
<p>This is comparison __id__.</p>
|
|
22
|
+
<p>The table below compares __pageCount__ web pages on <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/">accessibility</a>. The page names are links to the pages on the web. The scores are links to digests that explain in detail how the scores were computed.</p>
|
|
23
|
+
<p>The pages were tested by <a href="https://www.npmjs.com/package/testaro">Testaro</a>. Testaro used ten tools (Alfa, ASLint, Axe, Editoria11y, Equal Access, HTML CodeSniffer, Nu Html Checker, QualWeb, Testaro, and WAVE) to perform about 900 automated accessibility tests.</p>
|
|
24
|
+
<p><a href="https://www.npmjs.com/package/testilo">Testilo</a> classified the problems found by these tests into <dfn>issues</dfn> and assigned a <dfn>score</dfn> to each page. A perfect score would be 0. Higher scores indicate more issues, more instances of them, more serious issues, and more of the tools reporting instances of issues.</p>
|
|
25
|
+
<h2>Comparison</h2>
|
|
26
|
+
<table class="allBorder redBar">
|
|
27
|
+
<caption>Accessibility scores of web pages</caption>
|
|
28
|
+
<thead>
|
|
29
|
+
<tr><th scope="col">Page</th><th scope="col" colspan="2">Score (from best to worst)</tr>
|
|
30
|
+
</thead>
|
|
31
|
+
<tbody class="linkSmaller secondCellRight">
|
|
32
|
+
__tableBody__
|
|
33
|
+
</tbody>
|
|
34
|
+
</table>
|
|
35
|
+
<h2>Disclaimer</h2>
|
|
36
|
+
<p>Other procedures would yield different scores and rank orders among these pages.</p>
|
|
37
|
+
<footer>
|
|
38
|
+
<p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
|
|
39
|
+
</footer>
|
|
40
|
+
</main>
|
|
41
|
+
</body>
|
|
42
|
+
</html>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
index
|
|
25
|
+
Compares scores in a summary report.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
// ########## IMPORTS
|
|
29
|
+
|
|
30
|
+
// Module to access files.
|
|
31
|
+
const fs = require('fs/promises');
|
|
32
|
+
const {getBarCell, getNowDate, getNowDateSlash} = require('../../util');
|
|
33
|
+
|
|
34
|
+
// CONSTANTS
|
|
35
|
+
|
|
36
|
+
// Newlines with indentations.
|
|
37
|
+
const innestJoiner = '\n ';
|
|
38
|
+
|
|
39
|
+
// ########## FUNCTIONS
|
|
40
|
+
|
|
41
|
+
// Returns the maximum score.
|
|
42
|
+
const getMaxScore = summaryReport => summaryReport.summaries.reduce(
|
|
43
|
+
(max, result) => Math.max(max, result.score), 0
|
|
44
|
+
);
|
|
45
|
+
// Converts summary report data to a table body.
|
|
46
|
+
const getTableBody = async summaryReport => {
|
|
47
|
+
const maxScore = getMaxScore(summaryReport);
|
|
48
|
+
const rows = summaryReport.summaries
|
|
49
|
+
.sort((a, b) => a.score - b.score)
|
|
50
|
+
.map(result => {
|
|
51
|
+
const {id, score, targetWhat, url} = result;
|
|
52
|
+
const pageCell = `<th scope="row"><a href="${url}">${targetWhat}</a></th>`;
|
|
53
|
+
const scoreDestination = process.env.DIGEST_URL.replace('__id__', id);
|
|
54
|
+
const numCell = `<td class="num"><a href="${scoreDestination}">${score}</a></td>`;
|
|
55
|
+
// Make the bar width proportional.
|
|
56
|
+
const barCell = getBarCell(score, maxScore, 25, false);
|
|
57
|
+
const row = `<tr>${pageCell}${numCell}${barCell}</tr>`;
|
|
58
|
+
return row;
|
|
59
|
+
});
|
|
60
|
+
return rows.join(innestJoiner);
|
|
61
|
+
};
|
|
62
|
+
// Populates a query for a comparative table.
|
|
63
|
+
const populateQuery = exports.populateQuery = async (id, what, summaryReport, query) => {
|
|
64
|
+
query.id = id;
|
|
65
|
+
query.what = what;
|
|
66
|
+
query.pageCount = summaryReport.summaries.length;
|
|
67
|
+
query.tableBody = await getTableBody(summaryReport);
|
|
68
|
+
query.dateISO = getNowDate();
|
|
69
|
+
query.dateSlash = getNowDateSlash();
|
|
70
|
+
};
|
|
71
|
+
// Returns a comparison.
|
|
72
|
+
exports.comparer = async (id, what, summaryReport) => {
|
|
73
|
+
// Create a query to replace placeholders.
|
|
74
|
+
const query = {};
|
|
75
|
+
populateQuery(id, what, summaryReport, query);
|
|
76
|
+
// Get the template.
|
|
77
|
+
let template = await fs.readFile(`${__dirname}/index.html`, 'utf8');
|
|
78
|
+
// Replace its placeholders.
|
|
79
|
+
Object.keys(query).forEach(param => {
|
|
80
|
+
template = template.replace(new RegExp(`__${param}__`, 'g'), query[param]);
|
|
81
|
+
});
|
|
82
|
+
// Return the comparison.
|
|
83
|
+
return template;
|
|
84
|
+
};
|
|
@@ -53,12 +53,10 @@ const populateQuery = async (id, what, summaryReport, query) => {
|
|
|
53
53
|
// JSON of summary report.
|
|
54
54
|
const {summaries} = summaryReport;
|
|
55
55
|
query.summaryReportJSON = JSON.stringify(summaryReport);
|
|
56
|
-
// Legend.
|
|
57
|
-
|
|
58
56
|
// Get an array of target descriptions and assign to each an ID.
|
|
59
57
|
const rows = [];
|
|
60
58
|
const targets = Array
|
|
61
|
-
.from(new Set(summaries.map(result => result.
|
|
59
|
+
.from(new Set(summaries.map(result => result.targetWhat)))
|
|
62
60
|
.sort()
|
|
63
61
|
.map((targetWhat, index) => [alphaNumOf(index), targetWhat]);
|
|
64
62
|
const targetIDs = {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<!DOCTYPE HTML>
|
|
2
|
+
<html lang="en-US">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="author" content="Testilo">
|
|
7
|
+
<meta name="creator" content="Testilo">
|
|
8
|
+
<meta name="publisher" name="Testilo">
|
|
9
|
+
<meta name="description" content="report of accessibility testing of web pages">
|
|
10
|
+
<meta name="keywords" content="accessibility a11y web testing">
|
|
11
|
+
<title>Accessibility tracking report</title>
|
|
12
|
+
<link rel="icon" href="favicon.ico">
|
|
13
|
+
<link rel="stylesheet" href="style.css">
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<main>
|
|
17
|
+
<header>
|
|
18
|
+
<h1>Accessibility tracking report</h1>
|
|
19
|
+
</header>
|
|
20
|
+
<h2>Introduction</h2>
|
|
21
|
+
<p>This is tracking report <code>__id__</code>, for __what__.</p>
|
|
22
|
+
<p>It tracks accessibility scores over time. A perfect score is 0. The tracking was performed by Testilo procedure <code>__tp__</code>.</p>
|
|
23
|
+
<p>The results are presented first as a graph, and then as a table.</p>
|
|
24
|
+
<h2>Results as a graph</h2>
|
|
25
|
+
<h3>Legend</h3>
|
|
26
|
+
<ul id="legendItems">
|
|
27
|
+
__legendItems__
|
|
28
|
+
</ul>
|
|
29
|
+
<h3>Line graph</h3>
|
|
30
|
+
<figure id="graph">
|
|
31
|
+
<figcaption>Accessibility scores</figcaption>
|
|
32
|
+
</figure>
|
|
33
|
+
<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
|
|
34
|
+
<script src="https://cdn.jsdelivr.net/npm/@observablehq/plot@0.6"></script>
|
|
35
|
+
<script type="module" defer>
|
|
36
|
+
const summaryReportJSON = '__summaryReportJSON__';
|
|
37
|
+
const summaryReport = JSON.parse(summaryReportJSON);
|
|
38
|
+
const graphData = [];
|
|
39
|
+
const targetIDs = {};
|
|
40
|
+
Array.from(document.getElementById('legendItems').children).forEach(li => {
|
|
41
|
+
const targetData = li.textContent.split(': ');
|
|
42
|
+
targetIDs[targetData[1]] = targetData[0];
|
|
43
|
+
});
|
|
44
|
+
summaryReport.summaries.forEach(result => {
|
|
45
|
+
const {what} = result.sources.target;
|
|
46
|
+
graphData.push({
|
|
47
|
+
targetID: targetIDs[what],
|
|
48
|
+
targetWhat: what,
|
|
49
|
+
time: new Date(`20${result.endTime}Z`),
|
|
50
|
+
score: result.score
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
const svg = Plot.plot({
|
|
54
|
+
style: 'overflow: visible;',
|
|
55
|
+
height: 600,
|
|
56
|
+
y: {grid: true},
|
|
57
|
+
marks: [
|
|
58
|
+
Plot.ruleY([0]),
|
|
59
|
+
Plot.lineY(graphData, {
|
|
60
|
+
x: 'time',
|
|
61
|
+
y: 'score',
|
|
62
|
+
stroke: 'targetID'
|
|
63
|
+
}),
|
|
64
|
+
Plot.dot(graphData, {
|
|
65
|
+
x: 'time',
|
|
66
|
+
y: 'score',
|
|
67
|
+
z: 'targetID',
|
|
68
|
+
r: 9
|
|
69
|
+
}),
|
|
70
|
+
Plot.text(graphData, {
|
|
71
|
+
x: 'time',
|
|
72
|
+
y: 'score',
|
|
73
|
+
z: 'targetID',
|
|
74
|
+
text: 'targetID',
|
|
75
|
+
textAnchor: 'middle'
|
|
76
|
+
}),
|
|
77
|
+
Plot.text(graphData, Plot.selectFirst({
|
|
78
|
+
x: 'time',
|
|
79
|
+
y: 'score',
|
|
80
|
+
z: 'targetID',
|
|
81
|
+
text: 'targetWhat',
|
|
82
|
+
textAnchor: 'start',
|
|
83
|
+
dx: 15
|
|
84
|
+
})),
|
|
85
|
+
Plot.text(graphData, Plot.selectLast({
|
|
86
|
+
x: 'time',
|
|
87
|
+
y: 'score',
|
|
88
|
+
z: 'targetID',
|
|
89
|
+
text: 'targetWhat',
|
|
90
|
+
textAnchor: 'start',
|
|
91
|
+
dx: 15
|
|
92
|
+
}))
|
|
93
|
+
]
|
|
94
|
+
});
|
|
95
|
+
document.getElementById('graph').insertAdjacentElement('beforeend', svg);
|
|
96
|
+
</script>
|
|
97
|
+
<h2>Results as a table</h2>
|
|
98
|
+
<table class="allBorder secondCellRight">
|
|
99
|
+
<caption>Accessibility scores</caption>
|
|
100
|
+
<thead>
|
|
101
|
+
<tr>
|
|
102
|
+
<th>Date and time</th>
|
|
103
|
+
<th>Score</th>
|
|
104
|
+
<th>Target</th>
|
|
105
|
+
</tr>
|
|
106
|
+
</thead>
|
|
107
|
+
<tbody>
|
|
108
|
+
__scoreRows__
|
|
109
|
+
</tbody>
|
|
110
|
+
</table>
|
|
111
|
+
<footer>
|
|
112
|
+
<p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
|
|
113
|
+
</footer>
|
|
114
|
+
</main>
|
|
115
|
+
</body>
|
|
116
|
+
</html>
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// index: tracker for tracking procedure ttp43.
|
|
24
|
+
|
|
25
|
+
// IMPORTS
|
|
26
|
+
|
|
27
|
+
// Module to keep secrets.
|
|
28
|
+
require('dotenv').config();
|
|
29
|
+
// Module to process files.
|
|
30
|
+
const fs = require('fs/promises');
|
|
31
|
+
// Utility module.
|
|
32
|
+
const {alphaNumOf, getNowDate, getNowDateSlash} = require('../../util');
|
|
33
|
+
|
|
34
|
+
// CONSTANTS
|
|
35
|
+
|
|
36
|
+
// Tracker ID.
|
|
37
|
+
const trackerID = 'ttp43';
|
|
38
|
+
// Newline with indentations.
|
|
39
|
+
const innerJoiner = '\n ';
|
|
40
|
+
// Digest URL.
|
|
41
|
+
const digestURL = process.env.DIGEST_URL;
|
|
42
|
+
|
|
43
|
+
// FUNCTIONS
|
|
44
|
+
|
|
45
|
+
// Adds parameters to a query for a tracking report.
|
|
46
|
+
const populateQuery = async (id, what, summaryReport, query) => {
|
|
47
|
+
// General parameters.
|
|
48
|
+
query.id = id;
|
|
49
|
+
query.what = what;
|
|
50
|
+
query.tp = trackerID;
|
|
51
|
+
query.dateISO = getNowDate();
|
|
52
|
+
query.dateSlash = getNowDateSlash();
|
|
53
|
+
// JSON of summary report.
|
|
54
|
+
const {summaries} = summaryReport;
|
|
55
|
+
query.summaryReportJSON = JSON.stringify(summaryReport);
|
|
56
|
+
// Get an array of target descriptions and assign to each an ID.
|
|
57
|
+
const rows = [];
|
|
58
|
+
const targets = Array
|
|
59
|
+
.from(new Set(summaries.map(result => result.targetWhat)))
|
|
60
|
+
.sort()
|
|
61
|
+
.map((targetWhat, index) => [alphaNumOf(index), targetWhat]);
|
|
62
|
+
const targetIDs = {};
|
|
63
|
+
targets.forEach(target => {
|
|
64
|
+
targetIDs[target[1]] = target[0];
|
|
65
|
+
});
|
|
66
|
+
// Add legend items to the query.
|
|
67
|
+
const legendItems = targets.map(target => `<li>${target[0]}: ${target[1]}</li>`);
|
|
68
|
+
query.legendItems = legendItems.join('\n ');
|
|
69
|
+
// For each result:
|
|
70
|
+
summaries.forEach(result => {
|
|
71
|
+
const {endTime, id, score, targetWhat, url} = result;
|
|
72
|
+
// Create a date-time cell.
|
|
73
|
+
const timeCell = `<td>${endTime}</td>`;
|
|
74
|
+
// Create a score cell.
|
|
75
|
+
const digestLinkDestination = digestURL.replace('__id__', id);
|
|
76
|
+
const scoreCell = `<td><a href=${digestLinkDestination}>${score}</a></td>`;
|
|
77
|
+
// Create a target cell.
|
|
78
|
+
const targetLink = `<a href="${url}">${targetWhat}</a>`;
|
|
79
|
+
const targetCell = `<td>${targetIDs[targetWhat]}: ${targetLink}</td>`;
|
|
80
|
+
const row = `<tr>${[timeCell, scoreCell, targetCell].join('')}</tr>`;
|
|
81
|
+
// Add the row to the array of rows.
|
|
82
|
+
rows.push(row);
|
|
83
|
+
});
|
|
84
|
+
// Add the rows to the query.
|
|
85
|
+
query.scoreRows = rows.join(innerJoiner);
|
|
86
|
+
};
|
|
87
|
+
// Returns a tracking report.
|
|
88
|
+
exports.tracker = async (id, what, summaryReport) => {
|
|
89
|
+
// Create a query to replace placeholders.
|
|
90
|
+
const query = {};
|
|
91
|
+
await populateQuery(id, what, summaryReport, query);
|
|
92
|
+
// Get the template.
|
|
93
|
+
let template = await fs.readFile(`${__dirname}/index.html`, 'utf8');
|
|
94
|
+
// Replace its placeholders.
|
|
95
|
+
Object.keys(query).forEach(param => {
|
|
96
|
+
template = template.replace(new RegExp(`__${param}__`, 'g'), query[param]);
|
|
97
|
+
});
|
|
98
|
+
// Return the tracking report.
|
|
99
|
+
return template;
|
|
100
|
+
};
|
package/summarize.js
CHANGED
|
@@ -34,9 +34,12 @@ require('dotenv').config();
|
|
|
34
34
|
|
|
35
35
|
// Returns a report summary.
|
|
36
36
|
exports.summarize = report => {
|
|
37
|
-
const {id, jobData, score, sources} = report;
|
|
37
|
+
const {id, jobData, score, sources, target} = report;
|
|
38
|
+
const foundTarget = target || sources.target;
|
|
38
39
|
const summary = {
|
|
39
40
|
id: id || null,
|
|
41
|
+
url: foundTarget && (foundTarget.url || foundTarget.which) || null,
|
|
42
|
+
targetWhat: foundTarget.what || null,
|
|
40
43
|
endTime: jobData && jobData.endTime || null,
|
|
41
44
|
sources: sources || null,
|
|
42
45
|
score: score && score.summary && score.summary.total || null
|