Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion dist/adobe-client-data-layer.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/adobe-client-data-layer.min.js.map

Large diffs are not rendered by default.

27 changes: 25 additions & 2 deletions src/scripts/DataLayerListenerManagerFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,36 @@ ListenerManagerFactory.create = function(dataLayerManager) {
* @private
*/
function _selectorMatches(listener, item) {
if (listener.path && item.data) {
return has(item.data, listener.path);
if (item.data && listener.path) {
return (has(item.data, listener.path) || _ancestorRemoved(item.data, listener.path));
}

return true;
}

/**
* Checks if the object contains an ancestor that is set to null or undefined.
*
* @param {Object} object The object to check.
* @param {String} path The path to check.
* @returns {Boolean} true if the object contains an ancestor that is set to null or undefined, false otherwise.
* @private
*/
function _ancestorRemoved(object, path) {
let ancestorPath = path.substring(0, path.lastIndexOf('.'));
while (ancestorPath) {
if (has(object, ancestorPath)) {
const ancestorValue = get(object, ancestorPath);
if (ancestorValue === null || ancestorValue === undefined) {
return true;
}
}
ancestorPath = ancestorPath.substring(0, ancestorPath.lastIndexOf('.'));
}

return false;
}

/**
* Returns the index of a listener in the registry, or -1 if not present.
*
Expand Down
30 changes: 28 additions & 2 deletions src/tests/DataLayer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,25 @@ describe('Event listeners', () => {
expect(mockCallback.mock.calls.length).toBe(1);
});

test('event triggers when the ancestor is removed with null', () => {
adobeDataLayer.addEventListener.apply(adobeDataLayer, changeEventArguments);
adobeDataLayer.push(testData.componentNull);
expect(mockCallback.mock.calls.length).toBe(1);
});

test('event triggers when the ancestor is removed with undefined', () => {
adobeDataLayer.addEventListener.apply(adobeDataLayer, changeEventArguments);
adobeDataLayer.push(testData.componentUndefined);
expect(mockCallback.mock.calls.length).toBe(1);
});

test('event does not trigger when the ancestor does not exist', () => {
const changeEventArguments1 = ['adobeDataLayer:change', mockCallback, { path: 'component1.image' }];
adobeDataLayer.addEventListener.apply(adobeDataLayer, changeEventArguments1);
adobeDataLayer.push(testData.componentUndefined);
expect(mockCallback.mock.calls.length).toBe(0);
});

test('viewed event triggers on component.image', () => {
adobeDataLayer.addEventListener('viewed', mockCallback, { path: 'component.image' });
adobeDataLayer.push(testData.carousel1viewed);
Expand All @@ -363,6 +382,12 @@ describe('Event listeners', () => {
expect(mockCallback.mock.calls.length).toBe(1);
});

test('viewed event does not trigger on a non existing object', () => {
adobeDataLayer.addEventListener('viewed', mockCallback, { path: 'component.image.undefined' });
adobeDataLayer.push(testData.image1viewed);
expect(mockCallback.mock.calls.length).toBe(0);
});

test('custom event triggers on all components', () => {
adobeDataLayer.push(testData.carousel1change);
adobeDataLayer.push(testData.image1change);
Expand Down Expand Up @@ -409,6 +434,7 @@ describe('Event listeners', () => {
});

test('undefined old / new state for past events', () => {
// this behaviour is explained at: https://github.com/adobe/adobe-client-data-layer/issues/33
const isOldNewStateUndefinedFunction = function(event, oldState, newState) {
if (isEqual(oldState, undefined) && isEqual(newState, undefined)) mockCallback();
};
Expand All @@ -432,13 +458,13 @@ describe('Event listeners', () => {
expect(mockCallback.mock.calls.length).toBe(1);
});

test('handler with a static function', () => {
test('handler with an anonymous function', () => {
const mockCallback = jest.fn();

adobeDataLayer.addEventListener('carousel clicked', function() { mockCallback(); });
adobeDataLayer.removeEventListener('carousel clicked', function() { mockCallback(); });

// does not unregister the listener
// an anonymous handler cannot be unregistered (similar to EventTarget.addEventListener())

adobeDataLayer.push(testData.carousel1click);
expect(mockCallback.mock.calls.length).toBe(1);
Expand Down
8 changes: 8 additions & 0 deletions src/tests/testData.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ const testData = {
}
},

componentNull : {
component: null
},

componentUndefined : {
component: undefined
},

// Carousel 1

carousel1: carousel1,
Expand Down