@jrpool/kilotest 46.0.7 → 46.0.11
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/.devin/config.local.json +3 -1
- package/.github/workflows/ci.yml +32 -0
- package/alerts.test.js +137 -0
- package/api/listDiagnoses.test.js +44 -0
- package/api/listIssues.js +1 -1
- package/api/listIssues.test.js +10 -0
- package/api/listReports.test.js +6 -2
- package/api/listViolators.test.js +35 -0
- package/api/requestTest.test.js +7 -0
- package/api/routes.test.js +63 -0
- package/api/util.js +8 -10
- package/api/util.test.js +68 -2
- package/apiIntegration.test.js +92 -0
- package/docs/CI.json +55 -0
- package/docs/SERVICE.md +25 -1
- package/index.js +109 -66
- package/index.test.js +1152 -0
- package/indexBalances.test.js +188 -0
- package/indexFallback.test.js +33 -0
- package/indexServe.test.js +59 -0
- package/indexWorkers.test.js +79 -0
- package/mcp.js +2 -2
- package/mcp.test.js +281 -0
- package/package.json +11 -5
- package/routes.test.js +69 -0
- package/routing.test.js +13 -3
- package/smokeTest.js +123 -0
- package/test/fixtures/buildFixtures.js +83 -0
- package/test/fixtures/db/reports/260101T0008-mul.json +137 -0
- package/test/fixtures/db/reports/260101T0009-brd.json +147 -0
- package/test/setup.cjs +14 -0
- package/util.js +16 -6
- package/util.test.js +886 -3
- package/web/ai0BalanceForm/ai0BalanceForm.test.js +88 -0
- package/web/expungeReportsForm/expungeReportsForm.test.js +114 -0
- package/web/hideReportForm/hideReportForm.test.js +82 -0
- package/web/listDiagnoses/listDiagnoses.test.js +160 -0
- package/web/listIssues/listIssues.test.js +109 -0
- package/web/listReports/listReports.test.js +139 -3
- package/web/listRules/listRules.test.js +103 -0
- package/web/listTopIssues/listTopIssues.test.js +126 -0
- package/web/listViolators/index.js +1 -2
- package/web/listViolators/listViolators.test.js +256 -0
- package/web/pruneReportsForm/pruneReportsForm.test.js +86 -0
- package/web/reannotate/reannotate.test.js +144 -0
- package/web/reannotateForm/reannotateForm.test.js +134 -0
- package/web/renewWCAG/renewWCAG.test.js +124 -0
- package/web/requestRetest/requestRetest.test.js +119 -0
- package/web/requestRetestForm/requestRetestForm.test.js +62 -0
- package/web/requestTest/requestTest.test.js +115 -0
- package/web/requestTestForm/requestTestForm.test.js +40 -0
- package/web/rewindReportsForm/rewindReportsForm.test.js +86 -0
- package/web/tutorial/tutorial.test.js +97 -0
- package/web/unhideReportForm/unhideReportForm.test.js +135 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/*
|
|
2
|
+
requestTest.test.js
|
|
3
|
+
Unit tests for web/requestTest/index.js, covering the success path of answer.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {test, before, after, beforeEach} = require('node:test');
|
|
9
|
+
const assert = require('node:assert/strict');
|
|
10
|
+
const fs = require('node:fs/promises');
|
|
11
|
+
const path = require('node:path');
|
|
12
|
+
const {parse} = require('node-html-parser');
|
|
13
|
+
|
|
14
|
+
// CONSTANTS
|
|
15
|
+
|
|
16
|
+
const fixtureDBDir = path.join(__dirname, '..', '..', 'test', 'fixtures', 'db');
|
|
17
|
+
const recsPath = path.join(fixtureDBDir, 'jobs', 'recs.json');
|
|
18
|
+
|
|
19
|
+
// SETUP AND TEARDOWN
|
|
20
|
+
|
|
21
|
+
before(async () => {
|
|
22
|
+
process.env.DB_DIR = fixtureDBDir;
|
|
23
|
+
process.env.AUTH_CODE = 'test-auth-code';
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
// Reset recs.json and clean job directories before each test.
|
|
28
|
+
await fs.writeFile(recsPath, '{}\n');
|
|
29
|
+
for (const sub of ['claimed', 'queue', 'failed']) {
|
|
30
|
+
const dir = path.join(fixtureDBDir, 'jobs', sub);
|
|
31
|
+
await fs.mkdir(dir, {recursive: true});
|
|
32
|
+
const files = await fs.readdir(dir).catch(() => []);
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
try {
|
|
35
|
+
await fs.unlink(path.join(dir, file));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Ignore cleanup errors for files that may not exist.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
after(async () => {
|
|
45
|
+
// Restore recs.json and clean job directories after all tests.
|
|
46
|
+
await fs.writeFile(recsPath, '{}\n');
|
|
47
|
+
for (const sub of ['claimed', 'queue', 'failed']) {
|
|
48
|
+
const dir = path.join(fixtureDBDir, 'jobs', sub);
|
|
49
|
+
await fs.mkdir(dir, {recursive: true});
|
|
50
|
+
const files = await fs.readdir(dir).catch(() => []);
|
|
51
|
+
for (const file of files) {
|
|
52
|
+
try {
|
|
53
|
+
await fs.unlink(path.join(dir, file));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Ignore cleanup errors for files that may not exist.
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// TESTS
|
|
63
|
+
|
|
64
|
+
test('answer returns ok with a populated answer page for a valid test request', async () => {
|
|
65
|
+
// Require the module after DB_DIR is set.
|
|
66
|
+
const {answer} = require('./index');
|
|
67
|
+
const result = await answer(
|
|
68
|
+
'Test Page', 'https://example.com/test-success', 'Because accessibility'
|
|
69
|
+
);
|
|
70
|
+
assert.equal(result.status, 'ok');
|
|
71
|
+
assert.ok(result.answerPage, 'answerPage should be present');
|
|
72
|
+
// Verify the placeholders were replaced.
|
|
73
|
+
assert.ok(result.answerPage.includes('Test Page'));
|
|
74
|
+
assert.ok(result.answerPage.includes('Because accessibility'));
|
|
75
|
+
assert.ok(!result.answerPage.includes('__target__'));
|
|
76
|
+
assert.ok(!result.answerPage.includes('__why__'));
|
|
77
|
+
// Verify the HTML is well-formed.
|
|
78
|
+
const doc = parse(result.answerPage);
|
|
79
|
+
const h1 = doc.querySelector('h1');
|
|
80
|
+
assert.ok(h1);
|
|
81
|
+
assert.ok(h1.textContent.includes('Test Page'));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('answer returns an error when the URL is already queued', async () => {
|
|
85
|
+
const {answer} = require('./index');
|
|
86
|
+
// Create a queued job with the target URL.
|
|
87
|
+
const queueDir = path.join(fixtureDBDir, 'jobs', 'queue');
|
|
88
|
+
const jobPath = path.join(queueDir, 'queuedJob.json');
|
|
89
|
+
await fs.writeFile(jobPath, JSON.stringify({
|
|
90
|
+
id: 'queuedJob',
|
|
91
|
+
target: {what: 'Queued Page', url: 'https://example.com/queued'}
|
|
92
|
+
}));
|
|
93
|
+
try {
|
|
94
|
+
const result = await answer(
|
|
95
|
+
'Queued Page', 'https://example.com/queued', 'Because accessibility'
|
|
96
|
+
);
|
|
97
|
+
assert.equal(result.status, 'error');
|
|
98
|
+
assert.ok(result.message.includes('queued'));
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
try {
|
|
102
|
+
await fs.unlink(jobPath);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Ignore cleanup errors.
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('answer returns an error for an invalid recommendation', async () => {
|
|
111
|
+
const {answer} = require('./index');
|
|
112
|
+
const result = await answer('', 'not-a-url', 'why');
|
|
113
|
+
assert.equal(result.status, 'error');
|
|
114
|
+
assert.equal(result.message, 'Invalid recommendation');
|
|
115
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
requestTestForm.test.js
|
|
3
|
+
Unit tests for web/requestTestForm/index.js.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {test} = require('node:test');
|
|
9
|
+
const assert = require('node:assert/strict');
|
|
10
|
+
const {parse} = require('node-html-parser');
|
|
11
|
+
const {answer} = require('./index');
|
|
12
|
+
|
|
13
|
+
// TESTS
|
|
14
|
+
|
|
15
|
+
test('requestTestForm returns an ok status with valid HTML', async () => {
|
|
16
|
+
const result = await answer();
|
|
17
|
+
assert.equal(result.status, 'ok');
|
|
18
|
+
assert.ok(result.answerPage);
|
|
19
|
+
const html = parse(result.answerPage);
|
|
20
|
+
assert.equal(html.querySelector('title').text, 'Test recommendation | Kilotest');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('requestTestForm includes a form that posts to /requestTest.html', async () => {
|
|
24
|
+
const result = await answer();
|
|
25
|
+
const html = parse(result.answerPage);
|
|
26
|
+
const form = html.querySelector('form');
|
|
27
|
+
assert.ok(form);
|
|
28
|
+
assert.equal(form.getAttribute('action'), '/requestTest.html');
|
|
29
|
+
assert.equal(form.getAttribute('method'), 'post');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('requestTestForm includes required inputs for what, url, and why', async () => {
|
|
33
|
+
const result = await answer();
|
|
34
|
+
const html = parse(result.answerPage);
|
|
35
|
+
const inputs = html.querySelectorAll('input');
|
|
36
|
+
const names = inputs.map(input => input.getAttribute('name'));
|
|
37
|
+
assert.ok(names.includes('what'));
|
|
38
|
+
assert.ok(names.includes('url'));
|
|
39
|
+
assert.ok(names.includes('why'));
|
|
40
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*
|
|
2
|
+
rewindReportsForm.test.js
|
|
3
|
+
Unit tests for web/rewindReportsForm/index.js.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {test, before, after} = require('node:test');
|
|
9
|
+
const assert = require('node:assert/strict');
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const fs = require('fs/promises');
|
|
12
|
+
const {parse} = require('node-html-parser');
|
|
13
|
+
const {answer} = require('./index');
|
|
14
|
+
const {reportsPath} = require('../../util');
|
|
15
|
+
|
|
16
|
+
// SETUP AND TEARDOWN
|
|
17
|
+
|
|
18
|
+
const savedAuthCode = process.env.AUTH_CODE;
|
|
19
|
+
const savedDBDir = process.env.DB_DIR;
|
|
20
|
+
const fixtureDBDir = path.join(__dirname, '..', '..', 'test', 'fixtures', 'db');
|
|
21
|
+
|
|
22
|
+
before(() => {
|
|
23
|
+
process.env.AUTH_CODE = 'test-auth-code';
|
|
24
|
+
process.env.DB_DIR = fixtureDBDir;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
after(async () => {
|
|
28
|
+
if (savedAuthCode !== undefined) {
|
|
29
|
+
process.env.AUTH_CODE = savedAuthCode;
|
|
30
|
+
}
|
|
31
|
+
if (savedDBDir !== undefined) {
|
|
32
|
+
process.env.DB_DIR = savedDBDir;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// TESTS
|
|
37
|
+
|
|
38
|
+
test('rewindReportsForm displays a list of reports when no submission', async () => {
|
|
39
|
+
const result = await answer(null, '');
|
|
40
|
+
assert.equal(result.status, 'ok');
|
|
41
|
+
assert.ok(result.answerPage);
|
|
42
|
+
const html = parse(result.answerPage);
|
|
43
|
+
assert.ok(html.querySelector('title'));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('rewindReportsForm returns an error for an invalid auth code', async () => {
|
|
47
|
+
const result = await answer(null, 'authCode=wrong&report=260202T0000-new');
|
|
48
|
+
assert.equal(result.status, 'error');
|
|
49
|
+
assert.equal(result.message, 'Invalid authorization code');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('rewindReportsForm returns an error when deleting a nonexistent report', async () => {
|
|
53
|
+
const result = await answer(null, 'authCode=test-auth-code&report=999999T9999-nope');
|
|
54
|
+
assert.equal(result.status, 'error');
|
|
55
|
+
assert.ok(result.message.includes('Deleting latest superseding reports'));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('rewindReportsForm deletes a latest superseding report with valid auth code', async () => {
|
|
59
|
+
// 260202T0000-new is the latest report for its URL, superseding 260101T0000-mix.
|
|
60
|
+
const reportPath = path.join(reportsPath(), '260202T0000-new.json');
|
|
61
|
+
const backup = await fs.readFile(reportPath, 'utf8');
|
|
62
|
+
try {
|
|
63
|
+
const result = await answer(null, 'authCode=test-auth-code&report=260202T0000-new');
|
|
64
|
+
assert.equal(result.status, 'ok');
|
|
65
|
+
await fs.access(reportPath).then(
|
|
66
|
+
() => {throw new Error('Report should have been deleted');},
|
|
67
|
+
() => {}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await fs.writeFile(reportPath, backup);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('rewindReportsForm returns an error when a report file is corrupt', async () => {
|
|
76
|
+
const reportPath = path.join(reportsPath(), '260101T0001-ct.json');
|
|
77
|
+
const backup = await fs.readFile(reportPath, 'utf8');
|
|
78
|
+
try {
|
|
79
|
+
await fs.writeFile(reportPath, 'not valid json');
|
|
80
|
+
const result = await answer(null, '');
|
|
81
|
+
assert.equal(result.status, 'error');
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
await fs.writeFile(reportPath, backup);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
tutorial.test.js
|
|
3
|
+
Unit tests for web/tutorial/index.js, covering the answer and handleComment exports.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {test, before, after} = require('node:test');
|
|
9
|
+
const assert = require('node:assert/strict');
|
|
10
|
+
const fs = require('node:fs/promises');
|
|
11
|
+
const path = require('node:path');
|
|
12
|
+
const {answer, handleComment} = require('./index');
|
|
13
|
+
|
|
14
|
+
// CONSTANTS
|
|
15
|
+
|
|
16
|
+
const commentsPath = path.join(__dirname, 'comments.json');
|
|
17
|
+
|
|
18
|
+
// SETUP AND TEARDOWN
|
|
19
|
+
|
|
20
|
+
let originalComments;
|
|
21
|
+
|
|
22
|
+
before(async () => {
|
|
23
|
+
originalComments = await fs.readFile(commentsPath, 'utf8').catch(() => null);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
after(async () => {
|
|
27
|
+
if (originalComments !== null) {
|
|
28
|
+
await fs.writeFile(commentsPath, originalComments);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
await fs.unlink(commentsPath).catch(() => {});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// TESTS
|
|
36
|
+
|
|
37
|
+
test('answer returns the tutorial page with status ok', async () => {
|
|
38
|
+
const result = await answer();
|
|
39
|
+
assert.equal(result.status, 'ok');
|
|
40
|
+
assert.ok(result.answerPage);
|
|
41
|
+
assert.ok(result.answerPage.length > 0);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('handleComment returns an error for empty content', async () => {
|
|
45
|
+
const result = await handleComment('');
|
|
46
|
+
assert.equal(result.status, 'error');
|
|
47
|
+
assert.equal(result.message, 'No content provided');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('handleComment returns an error for non-string content', async () => {
|
|
51
|
+
const result = await handleComment(null);
|
|
52
|
+
assert.equal(result.status, 'error');
|
|
53
|
+
assert.equal(result.message, 'No content provided');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('handleComment returns an error for content that is empty after sanitization', async () => {
|
|
57
|
+
const result = await handleComment('<script></script>');
|
|
58
|
+
assert.equal(result.status, 'error');
|
|
59
|
+
assert.equal(result.message, 'Comment is empty after sanitization');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('handleComment saves a sanitized comment and returns ok', async () => {
|
|
63
|
+
// Replace comments with an empty array for a clean test.
|
|
64
|
+
await fs.writeFile(commentsPath, '[]\n');
|
|
65
|
+
const result = await handleComment('This is a <b>test</b> comment.');
|
|
66
|
+
assert.equal(result.status, 'ok');
|
|
67
|
+
const comments = JSON.parse(await fs.readFile(commentsPath, 'utf8'));
|
|
68
|
+
assert.equal(comments.length, 1);
|
|
69
|
+
assert.equal(comments[0].content, 'This is a test comment.');
|
|
70
|
+
assert.ok(comments[0].timeStamp);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('handleComment strips HTML tags and control characters', async () => {
|
|
74
|
+
await fs.writeFile(commentsPath, '[]\n');
|
|
75
|
+
const result = await handleComment('<img src=x onerror=alert(1)>\x00\x07Hello');
|
|
76
|
+
assert.equal(result.status, 'ok');
|
|
77
|
+
const comments = JSON.parse(await fs.readFile(commentsPath, 'utf8'));
|
|
78
|
+
assert.equal(comments[0].content, 'Hello');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('handleComment truncates content to 500 characters', async () => {
|
|
82
|
+
await fs.writeFile(commentsPath, '[]\n');
|
|
83
|
+
const longComment = 'x'.repeat(600);
|
|
84
|
+
const result = await handleComment(longComment);
|
|
85
|
+
assert.equal(result.status, 'ok');
|
|
86
|
+
const comments = JSON.parse(await fs.readFile(commentsPath, 'utf8'));
|
|
87
|
+
assert.equal(comments[0].content.length, 500);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('handleComment creates comments.json when it does not exist', async () => {
|
|
91
|
+
await fs.unlink(commentsPath).catch(() => {});
|
|
92
|
+
const result = await handleComment('Test comment for missing file');
|
|
93
|
+
assert.equal(result.status, 'ok');
|
|
94
|
+
const comments = JSON.parse(await fs.readFile(commentsPath, 'utf8'));
|
|
95
|
+
assert.equal(comments.length, 1);
|
|
96
|
+
assert.equal(comments[0].content, 'Test comment for missing file');
|
|
97
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/*
|
|
2
|
+
unhideReportForm.test.js
|
|
3
|
+
Unit tests for web/unhideReportForm/index.js.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// IMPORTS
|
|
7
|
+
|
|
8
|
+
const {test, before, after, beforeEach} = require('node:test');
|
|
9
|
+
const assert = require('node:assert/strict');
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const fs = require('fs/promises');
|
|
12
|
+
const {parse} = require('node-html-parser');
|
|
13
|
+
const {answer} = require('./index');
|
|
14
|
+
const {reportsPath, hiddenReportsPath} = require('../../util');
|
|
15
|
+
|
|
16
|
+
// CONSTANTS
|
|
17
|
+
|
|
18
|
+
const hiddenFile = '260101T0007-hid.json';
|
|
19
|
+
|
|
20
|
+
// SETUP AND TEARDOWN
|
|
21
|
+
|
|
22
|
+
const savedAuthCode = process.env.AUTH_CODE;
|
|
23
|
+
const savedDBDir = process.env.DB_DIR;
|
|
24
|
+
const fixtureDBDir = path.join(__dirname, '..', '..', 'test', 'fixtures', 'db');
|
|
25
|
+
|
|
26
|
+
const getPaths = () => ({
|
|
27
|
+
hidden: path.join(hiddenReportsPath(), hiddenFile),
|
|
28
|
+
report: path.join(reportsPath(), hiddenFile)
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
before(() => {
|
|
32
|
+
process.env.AUTH_CODE = 'test-auth-code';
|
|
33
|
+
process.env.DB_DIR = fixtureDBDir;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
beforeEach(async () => {
|
|
37
|
+
// Ensure the hidden report is in the hidden directory before each test.
|
|
38
|
+
const {hidden, report} = getPaths();
|
|
39
|
+
try {
|
|
40
|
+
await fs.rename(report, hidden);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Report may already be hidden.
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
after(async () => {
|
|
48
|
+
// Restore the hidden report if it was moved.
|
|
49
|
+
const {hidden, report} = getPaths();
|
|
50
|
+
try {
|
|
51
|
+
await fs.rename(report, hidden);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Report may already be hidden.
|
|
55
|
+
}
|
|
56
|
+
if (savedAuthCode !== undefined) {
|
|
57
|
+
process.env.AUTH_CODE = savedAuthCode;
|
|
58
|
+
}
|
|
59
|
+
if (savedDBDir !== undefined) {
|
|
60
|
+
process.env.DB_DIR = savedDBDir;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// TESTS
|
|
65
|
+
|
|
66
|
+
test('unhideReportForm displays a list of hidden reports when no submission', async () => {
|
|
67
|
+
const result = await answer(null, '');
|
|
68
|
+
assert.equal(result.status, 'ok');
|
|
69
|
+
assert.ok(result.answerPage);
|
|
70
|
+
const html = parse(result.answerPage);
|
|
71
|
+
const radios = html.querySelectorAll('input[type="radio"]');
|
|
72
|
+
assert.ok(radios.length > 0);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('unhideReportForm returns an error for an invalid auth code', async () => {
|
|
76
|
+
const result = await answer(null, 'authCode=wrong&report=260101T0007-hid');
|
|
77
|
+
assert.equal(result.status, 'error');
|
|
78
|
+
assert.equal(result.message, 'Invalid authorization code');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('unhideReportForm unhides a report with valid auth code', async () => {
|
|
82
|
+
const {report} = getPaths();
|
|
83
|
+
const result = await answer(null, 'authCode=test-auth-code&report=260101T0007-hid');
|
|
84
|
+
assert.equal(result.status, 'ok');
|
|
85
|
+
// The report should now be in the reports directory.
|
|
86
|
+
await fs.access(report);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('unhideReportForm returns an error when unhiding a nonexistent report', async () => {
|
|
90
|
+
const result = await answer(null, 'authCode=test-auth-code&report=999999T9999-nope');
|
|
91
|
+
assert.equal(result.status, 'error');
|
|
92
|
+
assert.ok(result.message.includes('Unhiding report'));
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('unhideReportForm sorts hidden reports with the same page name by timeStamp', async () => {
|
|
96
|
+
const {hidden} = getPaths();
|
|
97
|
+
// Add a second hidden report with the same what as the existing one.
|
|
98
|
+
const existing = JSON.parse(await fs.readFile(hidden, 'utf8'));
|
|
99
|
+
// Create a copy with a different timeStamp but same target.what.
|
|
100
|
+
const copy = JSON.parse(JSON.stringify(existing));
|
|
101
|
+
copy.id = '260101T0010-hid2';
|
|
102
|
+
const copyPath = path.join(hiddenReportsPath(), '260101T0010-hid2.json');
|
|
103
|
+
await fs.writeFile(copyPath, JSON.stringify(copy));
|
|
104
|
+
try {
|
|
105
|
+
const result = await answer(null, '');
|
|
106
|
+
assert.equal(result.status, 'ok');
|
|
107
|
+
// Both reports should appear in the form.
|
|
108
|
+
assert.ok(result.answerPage.includes('260101T0007-hid'));
|
|
109
|
+
assert.ok(result.answerPage.includes('260101T0010-hid2'));
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
await fs.unlink(copyPath).catch(() => {});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('unhideReportForm sorts hidden reports with different page names alphabetically', async () => {
|
|
117
|
+
const {hidden} = getPaths();
|
|
118
|
+
// Add a second hidden report with a different what.
|
|
119
|
+
const existing = JSON.parse(await fs.readFile(hidden, 'utf8'));
|
|
120
|
+
const copy = JSON.parse(JSON.stringify(existing));
|
|
121
|
+
copy.id = '260101T0011-hid3';
|
|
122
|
+
copy.target.what = 'A Different Page';
|
|
123
|
+
const copyPath = path.join(hiddenReportsPath(), '260101T0011-hid3.json');
|
|
124
|
+
await fs.writeFile(copyPath, JSON.stringify(copy));
|
|
125
|
+
try {
|
|
126
|
+
const result = await answer(null, '');
|
|
127
|
+
assert.equal(result.status, 'ok');
|
|
128
|
+
// Both reports should appear in the form.
|
|
129
|
+
assert.ok(result.answerPage.includes('260101T0007-hid'));
|
|
130
|
+
assert.ok(result.answerPage.includes('260101T0011-hid3'));
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
await fs.unlink(copyPath).catch(() => {});
|
|
134
|
+
}
|
|
135
|
+
});
|