Skip to content

Commit 95e119a

Browse files
authored
Merge pull request #125 from levinmr/feature/add_integration_tests
[Feature] Add automated integration test framework
2 parents 237c125 + aa272f6 commit 95e119a

8 files changed

Lines changed: 2749 additions & 102 deletions

File tree

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
## Digital Analytics Program (DAP) - a Federal Government-wide Analytics Solution
22

3-
DAP provides a JavaScript file for US federal agencies to link or embed in their website(s) to participate in the Digital Analytics Program. Participating agencies are granted access to the reporting portal with real-time and historical summary and detailed-level data by GSA's DAP team. DAP top-level summary real-time and historical data are also reported publicly on https://analytics.usa.gov/
3+
DAP provides a JavaScript file for US federal agencies to link or embed in their website(s) to participate in the Digital Analytics Program. Participating agencies are granted access to the reporting portal with real-time and historical summary and detailed-level data by GSA's DAP team. DAP top-level summary real-time and historical data are also reported publicly on https://analytics.usa.gov/
44

55
### DAP Participation is a Requirement
66

77
On September 22, 2023, the Office of Management and Budget (OMB) released a memorandum on ["Delivering a Digital-First Public Experience"](https://www.whitehouse.gov/wp-content/uploads/2023/09/M-23-22-Delivering-a-Digital-First-Public-Experience.pdf), which requires federal agencies to implement the DAP javascript code on all public-facing federal websites. The requirement was originally introduced on November 8, 2016, in the OMB memorandum M-17-06 "Policies for Federal Agency Public Websites and Digital Services."
88

99
### DAP Code
1010

11-
DAP offers a central hosting server for its minified JavaScript file at `https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js`. As of August 2018, the file is gzipped and served compressed by default, but will be served uncompressed where `Accept-Encoding: gzip` is not present in the viewer.
11+
DAP offers a central hosting server for its minified JavaScript file at `https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js`. As of August 2018, the file is gzipped and served compressed by default, but will be served uncompressed where `Accept-Encoding: gzip` is not present in the viewer.
1212

1313
The latest version 8.1 of DAP GA code contains GA4 tracking only. DAP UA data collection and reporting was removed on June 24, 2024 in prepration for a global sunset of UA on July 1, 2024.
1414

@@ -108,4 +108,31 @@ This repository is maintained in its own GitHub organization, `digital-analytics
108108

109109
Only Digital Analytics Program staff have been granted write access to this repository.
110110

111+
### Local development
112+
113+
#### Prerequistites
114+
115+
* NodeJS > v20.x
116+
117+
#### Install dependencies
118+
119+
```bash
120+
npm install
121+
```
122+
123+
#### Linting
124+
125+
This repo uses Eslint and Prettier for code static analysis and formatting. Run
126+
the linter with:
127+
128+
```bash
129+
npm run lint
130+
```
131+
132+
#### Run integration tests
133+
134+
```bash
135+
npm run cucumber
136+
```
137+
111138
**All members of the digital-analytics-program GitHub organization are required to have two-factor authentication enabled.**

cucumber.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
default:
2+
forceExit: true
3+
order: random
4+
strict: true

features/basic_page_load.feature

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Feature: Test a basic page with DAP code loaded
2+
3+
Background:
4+
Given I load an empty browser
5+
And I set the browser to intercept outbound requests
6+
7+
Scenario: Loading the page with the DAP code without further action
8+
When I set the page content with "static_page_with_dap.html" HTML file
9+
Then there are no unexpected requests
10+
11+
Scenario: Loading the page with the DAP code and clicking a button
12+
When I set the page content with "static_page_with_dap.html" HTML file
13+
And I click on element with selector "#test-button"
14+
Then there are no unexpected requests

features/support/hooks.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { After } from "@cucumber/cucumber";
2+
3+
After(async function () {
4+
if (this.browser) {
5+
this.browser.close();
6+
}
7+
delete this.browser;
8+
delete this.page;
9+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<script async
6+
type="text/javascript"
7+
src="https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js?agency=TEST"
8+
id="_fed_an_ua_tag">
9+
</script>
10+
</head>
11+
12+
<body>
13+
<button id="test-button">click me</button>
14+
</body>
15+
</html>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Given, When, Then } from "@cucumber/cucumber";
2+
import puppeteer from 'puppeteer';
3+
import path from 'path';
4+
import * as chai from 'chai'
5+
import * as fs from 'fs'
6+
const expect = chai.expect;
7+
8+
import { fileURLToPath } from 'url';
9+
import { dirname } from 'path';
10+
const __filename = fileURLToPath(import.meta.url);
11+
const __dirname = dirname(__filename);
12+
13+
function delay(milliseconds) {
14+
return new Promise((resolve) => {
15+
setTimeout(resolve, milliseconds);
16+
});
17+
}
18+
19+
Given("I load an empty browser", async function () {
20+
this.browser = await puppeteer.launch();
21+
this.page = await this.browser.newPage();
22+
});
23+
24+
Given("I set the browser to intercept outbound requests", async function () {
25+
await this.page.setRequestInterception(true);
26+
this.requests = [];
27+
this.responses = [];
28+
29+
this.page.on('request', (request) => {
30+
this.requests.push({ method: request.method(), headers: request.headers(), url: request.url() });
31+
request.continue();
32+
});
33+
34+
this.page.on('response', (response) => {
35+
this.responses.push(response);
36+
})
37+
});
38+
39+
When("I set the page content with {string} HTML file", async function (fileName) {
40+
await this.page.setContent(fs.readFileSync(path.join(__dirname, `..`, fileName), 'utf8'));
41+
});
42+
43+
// This is still in progress. GA requests don't currently occur after clicking a button element.
44+
When("I click on element with selector {string}", async function (elementSelector) {
45+
await this.page.locator(elementSelector).click();
46+
await delay(2000)
47+
})
48+
49+
Then("there are no unexpected requests", function () {
50+
this.requests.forEach((request) => {
51+
let isAllowed = false;
52+
if (request.url.includes('https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js') || request.url.includes("https://www.googletagmanager.com/gtag/js?id=G-CSLL4ZEK4L")) {
53+
isAllowed = true;
54+
}
55+
expect(isAllowed).to.equal(true)
56+
})
57+
})
58+

0 commit comments

Comments
 (0)