Skip to content

Commit 20ead3b

Browse files
authored
Merge pull request #527 from GSA/1828-feedback
1828: add prototype feedback link scan
2 parents 8127570 + ccea6f9 commit 20ead3b

9 files changed

Lines changed: 102 additions & 1 deletion

File tree

entities/core-result.entity.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,18 @@ export class CoreResult {
380380
})
381381
requiredLinksText?: string;
382382

383+
@Column({ nullable: true })
384+
@Expose({ name: 'feedback_links_text' })
385+
@Exclude()
386+
@Transform(({ value }: { value: string }) => {
387+
if (value) {
388+
return value.split(',');
389+
} else {
390+
return null;
391+
}
392+
})
393+
feedbackLinksText?: string;
394+
383395
@Column({ nullable: true })
384396
@Expose({ name: 'login_provider' })
385397
loginProvider?: string;

entities/scan-data.entity.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ export type RequiredLinksScan = {
121121
requiredLinksText: string;
122122
};
123123

124+
export type FeedbackLinksScan = {
125+
feedbackLinksText: string;
126+
};
127+
124128
export type SearchScan = {
125129
searchDetected: boolean;
126130
searchgov: boolean;

entities/scan-page.entity.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type PrimaryScans = {
2525
loginScan: ScanData.LoginScan;
2626
cmsScan: ScanData.CmsScan;
2727
requiredLinksScan: ScanData.RequiredLinksScan;
28+
feedbackLinksScan: ScanData.FeedbackLinksScan;
2829
searchScan: ScanData.SearchScan;
2930
mobileScan: ScanData.MobileScan;
3031
toolingScan: ScanData.ToolingScan;

libs/core-scanner/src/core-scanner.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export class CoreScannerService implements Scanner<
120120
pageLogger.warn(
121121
`Page '${page}' does not include page filter '${input.page}'; skipping page.`,
122122
);
123+
return false;
123124
}
124125

125126
private createSkippedResult(): PageScanFailure {

libs/core-scanner/src/pages/primary.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
createOutboundRequestsExtractor,
1616
} from './extractors';
1717
import { buildRequiredLinksResult } from '../scans/required-links';
18+
import { buildFeedbackLinksResult } from '../scans/feedback-links';
1819
import { buildCookieResult } from '../scans/cookies';
1920
import { buildSearchResult } from '../scans/search';
2021
import { buildMobileResult } from '../scans/mobile';
@@ -97,7 +98,14 @@ const primaryScan = async (
9798
input,
9899
pageLogger,
99100
buildRequiredLinksResult,
100-
'Required LinksScan',
101+
'RequiredLinksScan',
102+
url,
103+
);
104+
const wrappedFeedbackLinksResult = runScan(
105+
input,
106+
pageLogger,
107+
buildFeedbackLinksResult,
108+
'FeedbackLinksScan',
101109
url,
102110
);
103111
const wrappedSearchResult = runScan(
@@ -132,6 +140,7 @@ const primaryScan = async (
132140
loginScan,
133141
cmsScan,
134142
requiredLinksScan,
143+
feedbackLinksScan,
135144
searchScan,
136145
mobileScan,
137146
toolingScan,
@@ -145,6 +154,7 @@ const primaryScan = async (
145154
wrappedLoginResult(response),
146155
wrappedCmsResult(response),
147156
wrappedRequiredLinksResult(page),
157+
wrappedFeedbackLinksResult(page),
148158
wrappedSearchResult(page),
149159
wrappedMobileResult(page),
150160
wrappedToolingResult(page),
@@ -160,6 +170,7 @@ const primaryScan = async (
160170
loginScan,
161171
cmsScan,
162172
requiredLinksScan,
173+
feedbackLinksScan,
163174
searchScan,
164175
mobileScan,
165176
toolingScan,
@@ -233,5 +244,6 @@ const primaryScan = async (
233244
pageLogger.warn(
234245
`Scan '${scanName}' does not include scan filter '${input.scan}'; skipping scan.`,
235246
);
247+
return false;
236248
}
237249
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { browserInstance, newTestPage } from '../test-helper';
2+
import { buildFeedbackLinksResult } from './feedback-links';
3+
import pino from 'pino';
4+
5+
const mockLogger = pino();
6+
7+
describe('feedback links scan', () => {
8+
it('detects feedback links strings in href attribute and a element text', async () => {
9+
await newTestPage(async ({ page }) => {
10+
expect(await buildFeedbackLinksResult(mockLogger, page)).toEqual({
11+
feedbackLinksText: '',
12+
});
13+
});
14+
});
15+
16+
afterAll(async () => {
17+
if (browserInstance) {
18+
await browserInstance.close();
19+
}
20+
});
21+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Page } from 'puppeteer';
2+
import { FeedbackLinksScan } from 'entities/scan-data.entity';
3+
import { Logger } from 'pino';
4+
5+
export async function buildFeedbackLinksResult(
6+
parentLogger: Logger,
7+
page: Page,
8+
): Promise<FeedbackLinksScan> {
9+
const feedbackLinksResults = await page.evaluate(() => {
10+
const feedbackLinksTextContents = [
11+
'feedback',
12+
'contact',
13+
'support',
14+
'help',
15+
'suggestion',
16+
'customer-service',
17+
'tell us what you think',
18+
'let us know',
19+
'survey',
20+
];
21+
22+
const feedbackLinksText = feedbackLinksTextContents
23+
.filter((string) => {
24+
let stringDetected = false;
25+
26+
document.querySelectorAll('a').forEach((el) => {
27+
if (el.textContent.toLowerCase() === string) {
28+
stringDetected = true;
29+
}
30+
});
31+
32+
return stringDetected;
33+
})
34+
.join(',');
35+
36+
return { feedbackLinksText };
37+
});
38+
39+
return feedbackLinksResults;
40+
}

libs/database/src/core-results/core-result.service.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ describe('CoreResultService', () => {
166166
requiredLinksUrl: null,
167167
requiredLinksText: null,
168168
},
169+
feedbackLinksScan: {
170+
feedbackLinksText: null,
171+
},
169172
searchScan: {
170173
searchDetected: null,
171174
searchgov: null,
@@ -374,6 +377,9 @@ describe('CoreResultService', () => {
374377
requiredLinksUrl: null,
375378
requiredLinksText: null,
376379
},
380+
feedbackLinksScan: {
381+
feedbackLinksText: null,
382+
},
377383
searchScan: { searchDetected: null, searchgov: null },
378384
mobileScan: { viewportMetaTag: false },
379385
toolingScan: { tooling: null },

libs/database/src/core-results/core-result.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ export class CoreResultService {
213213
coreResult.requiredLinksUrl = result.requiredLinksScan.requiredLinksUrl;
214214
coreResult.requiredLinksText = result.requiredLinksScan.requiredLinksText;
215215

216+
// Feedback links scan
217+
coreResult.feedbackLinksText = result.feedbackLinksScan.feedbackLinksText;
218+
216219
// Search scan
217220
coreResult.searchDetected = result.searchScan.searchDetected;
218221
coreResult.searchgov = result.searchScan.searchgov;
@@ -283,6 +286,7 @@ export class CoreResultService {
283286
coreResult.cms = null;
284287
coreResult.requiredLinksUrl = null;
285288
coreResult.requiredLinksText = null;
289+
coreResult.feedbackLinksText = null;
286290
coreResult.searchDetected = null;
287291
coreResult.searchgov = null;
288292
coreResult.viewportMetaTag = null;

0 commit comments

Comments
 (0)