Skip to content

Commit 23016bc

Browse files
committed
Add some automated tests.
1 parent 0991b5f commit 23016bc

8 files changed

Lines changed: 484 additions & 9 deletions

File tree

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Prioritized Test Plan for `Universal-Federated-Analytics.js`
2+
3+
## Priority 1
4+
5+
These cover the highest-value public behavior with the least setup risk.
6+
7+
1. `gas()` legacy API
8+
- `gas('send','pageview', ...)` emits `page_view`
9+
- `gas('send','pageview', ..., title)` uses explicit title
10+
- `gas('send','event', ...)` emits `dap_event`
11+
- `gas('send','event', ...)` defaults `event_value` to `0` when missing or invalid
12+
- `gas('send','event', ..., nonInteraction=true)` maps `non_interaction`
13+
- invalid `gas()` calls do not emit unexpected events
14+
15+
2. `gas4()` core helper coverage
16+
- `gas4('page_view', {...})` emits `page_view`
17+
- unsupported `gas4()` name falls back to `dap_event`
18+
- supported event with empty params object still emits event
19+
- `gas4()` with malformed args does not emit
20+
- `gas4('view_search_results', ...)` explicit call emits expected event
21+
22+
3. Autotracker link classifications
23+
- internal `mailto:` emits `email_click`
24+
- external `mailto:` emits `email_click`
25+
- formatted telephone link emits `telephone_click`
26+
- invalid or ignored telephone link does not emit
27+
- generic external link emits `click`
28+
- social share link emits `share`
29+
30+
4. Existing config behavior hardening
31+
- agency-only config sets expected defaults
32+
- omitted site topic/platform fall back to `unspecified:<domain>`
33+
- autotracker toggle off suppresses tracked click classes beyond downloads
34+
35+
## Priority 2
36+
37+
These cover important user-visible functionality but need a bit more page interaction logic.
38+
39+
1. `gas4()` event family matrix
40+
- `social_click`
41+
- `share`
42+
- `navigation_click`
43+
- `accordion_click`
44+
- `faq_click`
45+
- `cta_click`
46+
- `content_view`
47+
- `sort`
48+
- `filter`
49+
- `error`
50+
- `was_this_helpful_submit`
51+
52+
2. Parameter-shape resilience
53+
- “incorrect parameter” examples still emit the supported event name
54+
- emitted payload preserves only provided keys
55+
- invalid event name plus valid payload falls back to `dap_event`
56+
57+
3. Search and querystring handling
58+
- page URL with search param emits `view_search_results`
59+
- search term is preserved in event payload
60+
- non-search query params are scrubbed from tracked page location
61+
- allowlisted agency query params remain in tracked page location
62+
- disallowed query params are removed
63+
64+
4. Dynamic DOM tracking
65+
- dynamically inserted links are tracked by autotracker
66+
- dynamic downloadable link emits `file_download`
67+
68+
## Priority 3
69+
70+
These are valuable but slower, more brittle, or likely to need harness work.
71+
72+
1. HTML5 media tracking
73+
- video start
74+
- video pause
75+
- video progress milestone
76+
- video complete
77+
- audio start/pause/progress/complete if applicable on page
78+
79+
2. YouTube tracking
80+
- YouTube enabled loads tracker and emits `video_start`
81+
- emits `video_play`
82+
- emits `video_pause`
83+
- emits `video_progress`
84+
- emits `video_complete`
85+
- handles player error with `video_error`
86+
87+
3. Environment/config toggles
88+
- `youtube=true` enables YouTube tracking
89+
- `htmlvideo=false` suppresses HTML5 media tracking
90+
- `webvitals=true` or homepage conditions inject/report vitals behavior
91+
- dev env switches GA property ID as expected
92+
- production/staging query handling stays correct
93+
94+
4. Parallel/custom-dimension variants
95+
- parallel tracker custom dimension mapping
96+
- alternate dimension names via query params
97+
- script source / protocol / hostname dimensions present when expected
98+
99+
## Priority 4
100+
101+
These are lower ROI or better suited to unit-style tests around pure helpers.
102+
103+
1. URL/PII sanitization internals
104+
- scrub email-like values from URLs
105+
- scrub phone-like values
106+
- nested querystring redaction
107+
- allowed-querystring merging behavior
108+
- object-to-query / query-to-object round trips where relied upon
109+
110+
2. Defensive/error-tolerance paths
111+
- malformed URLs do not break tracking
112+
- missing `dataLayer` initialization path recovers
113+
- bad media state changes do not throw
114+
- missing banner element is harmless
115+
116+
## Recommended Rollout
117+
118+
1. Add `10-15` Priority 1 scenarios first.
119+
2. Add `10-12` Priority 2 scenarios next.
120+
3. Decide whether media/video coverage belongs in Cucumber or a thinner harness.
121+
4. Cover the remaining helper/sanitization logic with lower-level tests if possible.

features/autotracker_links.feature

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
Feature: Autotracker reports supported non-download link interactions
2+
3+
Background:
4+
Given I load an empty browser
5+
And DAP is configured for agency "GSA"
6+
7+
Scenario: Autotracker reports external mail links
8+
Given DAP is configured with autotracking enabled
9+
When I load the test site
10+
And I click link 1 with text "mailto:test@domain.com" in the "Email Click" section
11+
Then the dataLayer contains the event "email_click"
12+
| link_url | [REDACTED_EMAIL] |
13+
| link_domain | domain.com |
14+
| link_text | mailto:[REDACTED_EMAIL] |
15+
| outbound | true |
16+
| interaction_type | Mouse Click |
17+
18+
Scenario: Autotracker reports formatted telephone links
19+
Given DAP is configured with autotracking enabled
20+
When I load the test site
21+
And I click link 1 with text "Telephone +1437-925-1855" in the "Telephone Click" section
22+
Then the dataLayer contains the event "telephone_click"
23+
| link_url | [REDACTED_TEL] |
24+
| link_text | Telephone [REDACTED_TEL] |
25+
| interaction_type | Mouse Click |
26+
27+
Scenario: Autotracker reports generic external clicks
28+
Given DAP is configured with autotracking enabled
29+
When I load the test site
30+
And I click link 1 with text "http://www.gsa.gov/travelpolicy" in the "External Links" section
31+
Then the dataLayer contains the event "click"
32+
| link_domain | gsa.gov |
33+
| outbound | true |
34+
| interaction_type | Mouse Click |
35+
36+
Scenario: Autotracker reports addtoany share links
37+
Given DAP is configured with autotracking enabled
38+
When I load the test site
39+
And I add an external share link to the page
40+
And I click the injected link with selector "#dynamicShareLink"
41+
Then the dataLayer contains the event "share"
42+
| method | facebook |
43+
| content_name | Travel Policy |
44+
| shared_via | add to any: facebook |
45+
| content_type | content |
46+
| content_url | https://gsa.gov/travelpolicy |
47+
| outbound | true |
48+
| interaction_type | Mouse Click |
49+
50+
Scenario: Autotracker disabled suppresses generic external clicks
51+
Given DAP is configured with autotracking disabled
52+
When I load the test site
53+
And I click link 1 with text "http://www.gsa.gov/travelpolicy" in the "External Links" section
54+
Then the dataLayer does not contain the event "click"

features/configuration.feature

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,13 @@ Feature: A site can load the DAP code with varying levels of customization
1919
Then DAP will set custom dimensions
2020
| agency | GSA |
2121
| site_topic | analytics |
22-
| site_platform | cloud.gov |
22+
| site_platform | cloud.gov |
23+
24+
Scenario: Load a DAP-enabled page with only agency uses the default custom dimensions
25+
Given DAP is configured for agency "GSA"
26+
When I load the test site
27+
Then DAP will set custom dimensions
28+
| agency | GSA |
29+
| subagency | LOCALHOST |
30+
| site_topic | unspecified:localhost |
31+
| site_platform | unspecified:localhost |

features/gas4_events.feature

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Feature: gas4 helper events are sent to DAP
2+
3+
Background:
4+
Given I load an empty browser
5+
And DAP is configured for agency "GSA"
6+
7+
Scenario: Clicking the official USA banner reports the banner event
8+
When I load the test site
9+
And I click on element with selector "#banner-button"
10+
Then the dataLayer contains the event "official_usa_site_banner_click"
11+
| link_text | Heres how you know |
12+
| section | header |
13+
14+
Scenario: Submitting the form interaction example reports a form_submit event
15+
When I load the test site
16+
And I click the submit button in the "gas4()" example of the "gas4() - Form Interaction" section
17+
Then the dataLayer contains the event "form_submit"
18+
| form_name | <form_name> |
19+
| form_id | <form_id> |
20+
| form_destination | <form_destination> |
21+
| section | <section> |
22+
| form_submit_text | <form_submit_text> |
23+
24+
Scenario: Unsupported gas4 event names fall back to dap_event
25+
When I load the test site
26+
And I click link 1 in the "Incorrect Event Name" example of the "gas4() - Social click" section
27+
Then the dataLayer contains the event "dap_event"
28+
| link_text | <link_text> |
29+
| link_domain | <link_domain> |
30+
| link_url | <link_url> |
31+
| link_id | <link_id> |
32+
| link_classes | <link_classes> |
33+
| social_network | <social_network> |
34+
| content_type | <content_type> |
35+
| section | <section> |
36+
37+
Scenario: gas4 page view reports the provided page title and location
38+
When I load the test site
39+
And I call gas4 "page_view" with parameters
40+
| page_location | /priority-one?page=1 |
41+
| page_title | Priority One |
42+
Then the dataLayer contains the event "page_view"
43+
| page_location | http://localhost/priority-one |
44+
| page_title | Priority One |
45+
46+
Scenario: gas4 view_search_results emits the provided search term
47+
When I load the test site
48+
And I call gas4 "view_search_results" with parameters
49+
| search_term | analytics |
50+
Then the dataLayer contains the event "view_search_results"
51+
| search_term | analytics |
52+
53+
Scenario: gas4 with an empty parameter object does not emit an event
54+
When I load the test site
55+
And I call gas4 "share" with an empty parameter object
56+
Then the dataLayer does not contain the event "share"
57+
58+
Scenario: gas4 with malformed arguments does not emit an event
59+
When I load the test site
60+
And I call gas4 with malformed arguments
61+
Then the dataLayer does not contain the event "share"

features/gas_legacy.feature

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Feature: gas legacy helper calls are reported to DAP
2+
3+
Background:
4+
Given I load an empty browser
5+
And DAP is configured for agency "GSA"
6+
7+
Scenario: gas pageview without title reports the current document title
8+
When I load the test site
9+
And I click link 1 with text "Pageview without title" in the "gas() - Custom Events / Pageviews / Custom Dimensions / Custom Metrics (Federated Only)" section
10+
Then the dataLayer contains the event "page_view"
11+
| page_location | http://localhost/dir/virtual-page?query=term |
12+
| page_title | DAP test site |
13+
14+
Scenario: gas pageview with title reports the provided page title
15+
When I load the test site
16+
And I click link 1 with text "Pageview with title" in the "gas() - Custom Events / Pageviews / Custom Dimensions / Custom Metrics (Federated Only)" section
17+
Then the dataLayer contains the event "page_view"
18+
| page_location | http://localhost/dir/virtual-page |
19+
| page_title | virtual page title |
20+
21+
Scenario: gas event reports a dap_event payload
22+
When I load the test site
23+
And I click link 1 with text "Event" in the "gas() - Custom Events / Pageviews / Custom Dimensions / Custom Metrics (Federated Only)" section
24+
Then the dataLayer contains the event "dap_event"
25+
| event_category | category event |
26+
| event_action | action event |
27+
| event_label | label event |
28+
| event_value | 10 |
29+
30+
Scenario: gas event supports non-interaction events
31+
When I load the test site
32+
And I click link 1 with text "Custom Dimension" in the "gas() - Custom Events / Pageviews / Custom Dimensions / Custom Metrics (Federated Only)" section
33+
Then the dataLayer contains the event "dap_event"
34+
| event_category | custom dimension |
35+
| event_action | slot 9 |
36+
| event_label | dimension value |
37+
| event_value | 0 |
38+
| non_interaction | true |
39+
40+
Scenario: invalid gas calls do not emit a dap_event
41+
When I load the test site
42+
And I call gas with invalid arguments
43+
Then the dataLayer does not contain the event "dap_event"

features/support/step_definitions/dataLayer_steps.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,18 @@ import { Then } from "@cucumber/cucumber";
22
import * as chai from 'chai'
33
const expect = chai.expect;
44

5+
async function getDataLayerEvent(page, eventName) {
6+
return page.evaluate((eventName) => {
7+
return [...window.dataLayer]
8+
.reverse()
9+
.find(item => item[0] === 'event' && item[1] === eventName);
10+
}, eventName);
11+
}
12+
513
Then("DAP will set custom dimensions", async function (table) {
14+
await this.page.waitForFunction(() => {
15+
return Array.isArray(window.dataLayer) && window.dataLayer.some(item => item[0] === 'config');
16+
});
617
const configCommand = await this.page.evaluate(() => {
718
return window.dataLayer.find(item => item[0] === 'config');
819
});
@@ -12,9 +23,7 @@ Then("DAP will set custom dimensions", async function (table) {
1223
});
1324

1425
Then("the file download is reported to DAP with interaction type {string}", async function (interactionType) {
15-
const event = await this.page.evaluate(() => {
16-
return window.dataLayer.find(item => item[0] === 'event' && item[1] === 'file_download');
17-
});
26+
const event = await getDataLayerEvent(this.page, 'file_download');
1827
expect(event).to.deep.equal(
1928
{
2029
'0': 'event',
@@ -35,8 +44,22 @@ Then("the file download is reported to DAP with interaction type {string}", asyn
3544
});
3645

3746
Then("the file download is not reported to DAP", async function () {
38-
const event = await this.page.evaluate(() => {
39-
return window.dataLayer.find(item => item[0] === 'event' && item[1] === 'file_download');
40-
});
47+
const event = await getDataLayerEvent(this.page, 'file_download');
48+
expect(event).to.be.undefined;
49+
});
50+
51+
Then("the dataLayer contains the event {string}", async function (eventName, table) {
52+
await this.page.waitForFunction((eventName) => {
53+
return Array.isArray(window.dataLayer) && window.dataLayer.some(item => item[0] === 'event' && item[1] === eventName);
54+
}, {}, eventName);
55+
const event = await getDataLayerEvent(this.page, eventName);
56+
expect(event).to.exist;
57+
expect(event["0"]).to.equal("event");
58+
expect(event["1"]).to.equal(eventName);
59+
expect(event["2"]).to.include(table.rowsHash());
60+
});
61+
62+
Then("the dataLayer does not contain the event {string}", async function (eventName) {
63+
const event = await getDataLayerEvent(this.page, eventName);
4164
expect(event).to.be.undefined;
4265
});

0 commit comments

Comments
 (0)