Skip to content

Commit

Permalink
Allow enableFormTracking to capture dynamic form changes (close #748)
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Boocock committed Jan 6, 2022
1 parent 974a51e commit 7b401e3
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 27 deletions.
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@snowplow/browser-plugin-form-tracking",
"comment": "Allow enableFormTracking to capture dynamic form changes (#748)",
"type": "none"
}
],
"packageName": "@snowplow/browser-plugin-form-tracking"
}
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@snowplow/javascript-tracker",
"comment": "Allow enableFormTracking to capture dynamic form changes (#748)",
"type": "none"
}
],
"packageName": "@snowplow/javascript-tracker"
}
58 changes: 32 additions & 26 deletions plugins/browser-plugin-form-tracking/src/helpers.ts
Expand Up @@ -75,6 +75,8 @@ export type transformFn = (x: string | null, elt: ElementData | TrackedHTMLEleme

export const innerElementTags: Array<keyof TrackedHTMLElementTagNameMap> = ['textarea', 'input', 'select'];

type TrackedHTMLElementWithMarker = TrackedHTMLElement & Record<string, boolean>;

const defaultTransformFn: transformFn = (x) => x;

interface FormConfiguration {
Expand All @@ -92,34 +94,38 @@ export function addFormListeners(tracker: BrowserTracker, configuration: FormTra
trackingMarker = tracker.id + 'form',
config = getConfigurationForOptions(options);

Array.prototype.slice.call(document.getElementsByTagName('form')).forEach(function (form) {
if (config.formFilter(form) && !form[trackingMarker]) {
Array.prototype.slice.call(innerElementTags).forEach(function (tagname) {
Array.prototype.slice.call(form.getElementsByTagName(tagname)).forEach(function (innerElement) {
if (
config.fieldFilter(innerElement) &&
!(innerElement as any)[trackingMarker] &&
innerElement.type.toLowerCase() !== 'password'
) {
addEventListener(
innerElement,
'focus',
getFormChangeListener(tracker, config, 'focus_form', context),
false
);
addEventListener(
innerElement,
'change',
getFormChangeListener(tracker, config, 'change_form', context),
false
);
(innerElement as any)[trackingMarker] = true;
}
});
Array.prototype.slice.call(document.getElementsByTagName('form')).forEach(function (form: HTMLFormElement) {
if (config.formFilter(form)) {
Array.prototype.slice.call(innerElementTags).forEach(function (tagname: keyof TrackedHTMLElementTagNameMap) {
Array.prototype.slice
.call(form.getElementsByTagName(tagname))
.forEach(function (innerElement: TrackedHTMLElementWithMarker) {
if (
config.fieldFilter(innerElement) &&
!innerElement[trackingMarker] &&
innerElement.type.toLowerCase() !== 'password'
) {
addEventListener(
innerElement,
'focus',
getFormChangeListener(tracker, config, 'focus_form', context),
false
);
addEventListener(
innerElement,
'change',
getFormChangeListener(tracker, config, 'change_form', context),
false
);
innerElement[trackingMarker] = true;
}
});
});

addEventListener(form, 'submit', getFormSubmissionListener(tracker, config, trackingMarker, context));
form[trackingMarker] = true;
if (!form[trackingMarker]) {
addEventListener(form, 'submit', getFormSubmissionListener(tracker, config, trackingMarker, context));
form[trackingMarker] = true;
}
}
});
}
Expand Down
34 changes: 34 additions & 0 deletions trackers/javascript-tracker/test/integration/autoTracking.test.ts
Expand Up @@ -39,6 +39,8 @@ const isMatchWithCallback = F.isMatchWith((lt, rt) => (F.isFunction(rt) ? rt(lt)
const SAFARI_EXPECTED_FIRST_NAME = 'Alex';
const SAFARI_EXPECTED_MESSAGE = 'Changed message';

declare var addField: () => void;

describe('Auto tracking', () => {
if (F.isMatch({ browserName: 'internet explorer', version: '9' }, browser.capabilities)) {
fit('Skip IE9', () => {}); // Automated tests for IE autotracking features
Expand Down Expand Up @@ -296,6 +298,14 @@ describe('Auto tracking', () => {

browser.pause(1000);

browser.execute(() => {
addField();
});

$('#newfield').click();

browser.pause(1000);

loadUrlAndWait('/form-tracking.html?filter=exclude');

$('#fname').click();
Expand Down Expand Up @@ -331,6 +341,30 @@ describe('Auto tracking', () => {
);
});

it('should send focus_form for the dynamically added form element', () => {
expect(
logContains({
event: {
event: 'unstruct',
app_id: 'autotracking',
unstruct_event: {
data: {
schema: 'iglu:com.snowplowanalytics.snowplow/focus_form/jsonschema/1-0-0',
data: {
formId: 'myForm',
elementId: 'newfield',
nodeName: 'INPUT',
elementType: 'text',
elementClasses: [],
value: 'new',
},
},
},
},
})
).toBe(true);
});

it('should send focus_form and change_form on text input', () => {
// Safari 12.1 doesn't fire onchange events when clearing
// However some browsers don't support setValue
Expand Down
16 changes: 15 additions & 1 deletion trackers/javascript-tracker/test/pages/form-tracking.html
Expand Up @@ -14,14 +14,28 @@
return query;
}
</script>
<script type="text/javascript">
function addField() {
var fields = document.getElementById('fields');
fields.appendChild(document.createTextNode('New Field: '));
var input = document.createElement('input');
input.type = 'text';
input.id = 'newfield';
input.name = 'newfield';
input.value = 'new';
fields.appendChild(input);
fields.appendChild(document.createElement('br'));
snowplow('enableFormTracking');
}
</script>
</head>

<body>
<p id="title">Page for Form Tracking testing with Snowplow Micro</p>
<div id="init"></div>

<form id="myForm" class="formy-mcformface" action="/form-tracking.html">
<fieldset>
<fieldset id="fields">
<legend>Personal Info:</legend>
<label for="fname">First name:</label><br />
<input type="text" id="fname" name="fname" value="John" class="test" /><br />
Expand Down

0 comments on commit 7b401e3

Please sign in to comment.