Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,43 @@ describe('FacebookPixel init tests', () => {
});
});

describe('FacebookPixel multiple destinations bootstrap guard', () => {
const mockAnalytics = {};

beforeEach(() => {
delete window.fbq;
delete window._fbq;
});
Comment on lines +88 to +100

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. I now capture the previous window.fbq and window._fbq in beforeEach and restore them in an afterEach, so this suite no longer leaks global state into the sibling describes.


test('does not re-bootstrap the global fbq shim when a second destination initializes', () => {
// First destination bootstraps the global fbq shim.
const firstPixel = new FacebookPixel({ pixelId: '111111111' }, mockAnalytics, destinationInfo);
firstPixel.init();

const shimAfterFirstInit = window.fbq;
expect(typeof shimAfterFirstInit).toBe('function');
expect(window.fbq.version).toBe('2.0');

// Simulate the loaded SDK taking over: mark the shim and enqueue an event.
window.fbq.version = 'preserved-by-loaded-sdk';
window.fbq.queue.push('event-from-first-destination');

// Second destination initializes. Its init() must NOT reset the global shim.
const secondPixel = new FacebookPixel({ pixelId: '222222222' }, mockAnalytics, destinationInfo);
secondPixel.init();

// The guard preserves the already established shim: version and queue are untouched.
expect(window.fbq).toBe(shimAfterFirstInit);
expect(window.fbq.version).toBe('preserved-by-loaded-sdk');
expect(window.fbq.queue).toContain('event-from-first-destination');

// The second pixel still registers itself via its own init call.
expect(window.fbq.queue).toContainEqual(
expect.objectContaining({ 0: 'init', 1: '222222222' }),
);
});
});

describe('FacebookPixel page', () => {
let facebookPixel;
const mockAnalytics = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,28 @@ class FacebookPixel {
}

init() {
window._fbq = function () {
if (window.fbq.callMethod) {
window.fbq.callMethod.apply(window.fbq, arguments);
} else {
window.fbq.queue.push(arguments);
}
};
// Bootstrap the global fbq shim only once per page. When multiple Meta Pixel
// destinations are configured, each one calls init(), and re-running this block
// mutates the already loaded fbevents.js SDK (resetting fbq.version, fbq.queue, etc.),
// which makes Meta log "Multiple pixels with conflicting versions were detected"
// and prevents the second pixel from initializing. Guard it like Meta's own snippet.
if (!window.fbq) {
window._fbq = function () {
if (window.fbq.callMethod) {
window.fbq.callMethod.apply(window.fbq, arguments);
} else {
window.fbq.queue.push(arguments);
}
};

window.fbq = window.fbq || window._fbq;
window.fbq.push = window.fbq;
window.fbq.loaded = true;
window.fbq.disablePushState = true; // disables automatic pageview tracking
window.fbq.allowDuplicatePageViews = true; // enables fb
window.fbq.version = '2.0';
window.fbq.queue = [];
window.fbq = window.fbq || window._fbq;
window.fbq.push = window.fbq;
window.fbq.loaded = true;
window.fbq.disablePushState = true; // disables automatic pageview tracking
window.fbq.allowDuplicatePageViews = true; // enables fb
window.fbq.version = '2.0';
window.fbq.queue = [];
Comment on lines +61 to +74

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I moved disablePushState and allowDuplicatePageViews out of the one-time guard so they run on every init(), including when window.fbq was already bootstrapped by the host page or an earlier destination. Only the shim creation and version/queue setup (the parts that cause the version conflict) stay guarded. Added a test covering the pre-existing fbq case.

}
window.fbq('set', 'autoConfig', this.autoConfig, this.pixelId); // toggle autoConfig : sends button click and page metadata
if (this.advancedMapping) {
if (this.useUpdatedMapping) {
Expand Down