Skip to content

Commit

Permalink
fix(analytics-browser): form tracking accesses element attributes thr…
Browse files Browse the repository at this point in the history
…ough getAttribute (#959)
  • Loading branch information
Dogfalo authored Feb 14, 2025
1 parent ab16340 commit 28305b1
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,31 @@ export const formInteractionTracking = (): EnrichmentPlugin => {
let hasFormChanged = false;

addEventListener(form, 'change', () => {
const formDestination = extractFormAction(form);
if (!hasFormChanged) {
amplitude.track(DEFAULT_FORM_START_EVENT, {
[FORM_ID]: stringOrUndefined(form.id),
[FORM_NAME]: stringOrUndefined(form.name),
[FORM_DESTINATION]: form.action,
[FORM_DESTINATION]: formDestination,
});
}
hasFormChanged = true;
});

addEventListener(form, 'submit', () => {
const formDestination = extractFormAction(form);
if (!hasFormChanged) {
amplitude.track(DEFAULT_FORM_START_EVENT, {
[FORM_ID]: stringOrUndefined(form.id),
[FORM_NAME]: stringOrUndefined(form.name),
[FORM_DESTINATION]: form.action,
[FORM_DESTINATION]: formDestination,
});
}

amplitude.track(DEFAULT_FORM_SUBMIT_EVENT, {
[FORM_ID]: stringOrUndefined(form.id),
[FORM_NAME]: stringOrUndefined(form.name),
[FORM_DESTINATION]: form.action,
[FORM_DESTINATION]: formDestination,
});
hasFormChanged = false;
});
Expand Down Expand Up @@ -143,3 +145,15 @@ export const stringOrUndefined = <T>(name: T): T extends string ? string : undef

return name as T extends string ? string : undefined;
};

// Extracts the form action attribute, and normalizes it to a valid URL to preserve the previous behavior of accessing the action property directly.
export const extractFormAction = (form: HTMLFormElement): string | null => {
let formDestination = form.getAttribute('action');
try {
// eslint-disable-next-line no-restricted-globals
formDestination = new URL(encodeURI(formDestination ?? ''), window.location.href).href;
} catch {
//
}
return formDestination;
};
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,30 @@ describe('formInteractionTracking', () => {
expect(amplitude.track).toHaveBeenCalledTimes(1);
});

test('should return current location if form action attribute is missing', async () => {
// setup
const config = createConfigurationMock();
const plugin = formInteractionTracking();
await plugin.setup?.(config, amplitude);
window.dispatchEvent(new Event('load'));

// Remove form action
document.getElementById('my-form-id')?.removeAttribute('action');
// trigger change event
document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));
// assert first event was tracked
expect(amplitude.track).toHaveBeenCalledTimes(1);
expect(amplitude.track).toHaveBeenNthCalledWith(1, '[Amplitude] Form Started', {
[FORM_ID]: 'my-form-id',
[FORM_NAME]: 'my-form-name',
[FORM_DESTINATION]: 'http://localhost/',
});
// trigger change event again
document.getElementById('my-form-id')?.dispatchEvent(new Event('change'));
// assert second event was not tracked
expect(amplitude.track).toHaveBeenCalledTimes(1);
});

test('should track form_start event for a dynamically added form tag', async () => {
// setup
const config = createConfigurationMock();
Expand Down

0 comments on commit 28305b1

Please sign in to comment.