Skip to content

Commit 3b253bc

Browse files
committed
Merge remote-tracking branch 'origin/AC-14607' into spartans_pr_04082025
2 parents edee5b1 + d079feb commit 3b253bc

File tree

3 files changed

+315
-2
lines changed

3 files changed

+315
-2
lines changed
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* Copyright © Magento, Inc. All rights reserved.
3-
* See COPYING.txt for license details.
2+
* Copyright 2011 Adobe
3+
* All Rights Reserved.
44
*/
55

66
var config = {
@@ -10,5 +10,12 @@ var config = {
1010
addToWishlist: 'Magento_Wishlist/js/add-to-wishlist',
1111
wishlistSearch: 'Magento_Wishlist/js/search'
1212
}
13+
},
14+
config: {
15+
mixins: {
16+
'Magento_Wishlist/js/view/wishlist': {
17+
'Magento_Wishlist/js/view/wishlist-mixin': true
18+
}
19+
}
1320
}
1421
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright 2025 Adobe
3+
* All Rights Reserved.
4+
*/
5+
6+
define(['jquery', 'Magento_Customer/js/customer-data'], function ($, customerData) {
7+
'use strict';
8+
9+
return function (WishlistComponent) {
10+
return WishlistComponent.extend({
11+
initialize: function () {
12+
this._super();
13+
14+
customerData.reload(['wishlist'], true);
15+
16+
const wishlist = customerData.get('wishlist'),
17+
selector = '.wishlist .counter.qty, .customer-menu .wishlist .counter, .link.wishlist .counter';
18+
19+
wishlist.subscribe(function (updatedWishlist) {
20+
if (typeof updatedWishlist.counter !== 'undefined') {
21+
const counters = $(selector);
22+
23+
if (counters.length && counters.first().text().trim() !== updatedWishlist.counter.toString()) {
24+
counters.text(updatedWishlist.counter);
25+
}
26+
}
27+
});
28+
29+
return this;
30+
}
31+
});
32+
};
33+
});
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
/**
2+
* Copyright 2025 Adobe
3+
* All Rights Reserved.
4+
*/
5+
6+
define([
7+
'jquery',
8+
'Magento_Customer/js/customer-data',
9+
'Magento_Wishlist/js/view/wishlist-mixin'
10+
], function ($, customerData, wishlistMixin) {
11+
'use strict';
12+
13+
describe('Magento_Wishlist/js/view/wishlist-mixin', function () {
14+
var WishlistComponent, mixin, customerDataMock, wishlistDataMock, subscribeCallback;
15+
16+
beforeEach(function () {
17+
// Mock customerData
18+
customerDataMock = {
19+
reload: jasmine.createSpy('reload'),
20+
get: jasmine.createSpy('get')
21+
};
22+
23+
// Helper function to set up subscribe callback
24+
function setupSubscribeCallback(callback) {
25+
subscribeCallback = callback;
26+
}
27+
28+
wishlistDataMock = {
29+
subscribe: jasmine.createSpy('subscribe').and.callFake(setupSubscribeCallback)
30+
};
31+
32+
customerDataMock.get.and.returnValue(wishlistDataMock);
33+
34+
// Mock the customerData module
35+
spyOn(customerData, 'reload').and.callFake(customerDataMock.reload);
36+
spyOn(customerData, 'get').and.callFake(customerDataMock.get);
37+
38+
// Create a proper mock WishlistComponent with extend method and _super
39+
WishlistComponent = function () {};
40+
WishlistComponent.prototype = {
41+
initialize: function () {
42+
return this;
43+
}
44+
};
45+
46+
// Add the extend method that Magento components typically have
47+
WishlistComponent.extend = function (extensions) {
48+
var ExtendedComponent = function () {},
49+
key,
50+
methodName,
51+
originalMethod;
52+
53+
ExtendedComponent.prototype = Object.create(WishlistComponent.prototype);
54+
55+
// Copy the extensions to the prototype
56+
for (key in extensions) {
57+
if (extensions.hasOwnProperty(key)) {
58+
ExtendedComponent.prototype[key] = extensions[key];
59+
}
60+
}
61+
62+
// Add the extend method to the new component
63+
ExtendedComponent.extend = WishlistComponent.extend;
64+
65+
// Add _super method for each extended method
66+
for (methodName in extensions) {
67+
if (!extensions.hasOwnProperty(methodName) || typeof extensions[methodName] !== 'function') {
68+
continue;
69+
}
70+
71+
originalMethod = WishlistComponent.prototype[methodName];
72+
if (!originalMethod) {
73+
continue;
74+
}
75+
76+
// Use IIFE to create proper closure for _super method
77+
(function (method) {
78+
ExtendedComponent.prototype['_super'] = function () {
79+
return method.apply(this, arguments);
80+
};
81+
})(originalMethod);
82+
}
83+
84+
return ExtendedComponent;
85+
};
86+
87+
// Apply the mixin
88+
mixin = wishlistMixin(WishlistComponent);
89+
});
90+
91+
describe('Initialization', function () {
92+
it('should call _super() during initialization', function () {
93+
var instance = new mixin();
94+
95+
spyOn(instance, '_super').and.callThrough();
96+
instance.initialize();
97+
98+
expect(instance._super).toHaveBeenCalled();
99+
});
100+
101+
it('should reload wishlist customer data on initialization', function () {
102+
var instance = new mixin();
103+
104+
instance.initialize();
105+
expect(customerData.reload).toHaveBeenCalledWith(['wishlist'], true);
106+
});
107+
108+
it('should get wishlist data from customer data', function () {
109+
var instance = new mixin();
110+
111+
instance.initialize();
112+
expect(customerData.get).toHaveBeenCalledWith('wishlist');
113+
});
114+
115+
it('should return the instance after initialization', function () {
116+
var instance = new mixin(),
117+
result = instance.initialize();
118+
119+
expect(result).toBe(instance);
120+
});
121+
});
122+
123+
describe('Wishlist subscription', function () {
124+
it('should subscribe to wishlist data updates', function () {
125+
var instance = new mixin();
126+
127+
instance.initialize();
128+
expect(wishlistDataMock.subscribe).toHaveBeenCalledWith(jasmine.any(Function));
129+
});
130+
131+
it('should handle undefined counter gracefully', function () {
132+
var instance = new mixin();
133+
134+
instance.initialize();
135+
// Call with undefined counter
136+
expect(function () {
137+
subscribeCallback({ counter: undefined });
138+
}).not.toThrow();
139+
});
140+
141+
it('should handle null counter gracefully', function () {
142+
var instance = new mixin();
143+
144+
instance.initialize();
145+
// Call with null counter
146+
expect(function () {
147+
subscribeCallback({ counter: null });
148+
}).not.toThrow();
149+
});
150+
151+
it('should handle missing counter property gracefully', function () {
152+
var instance = new mixin();
153+
154+
instance.initialize();
155+
// Call with no counter property
156+
expect(function () {
157+
subscribeCallback({});
158+
}).not.toThrow();
159+
});
160+
});
161+
162+
describe('Subscription callback behavior', function () {
163+
it('should handle counter updates when counters exist', function () {
164+
var instance = new mixin();
165+
166+
instance.initialize();
167+
// Call with counter update
168+
expect(function () {
169+
subscribeCallback({ counter: 3 });
170+
}).not.toThrow();
171+
});
172+
173+
it('should handle string counter values', function () {
174+
var instance = new mixin();
175+
176+
instance.initialize();
177+
// Call with string counter
178+
expect(function () {
179+
subscribeCallback({ counter: '7' });
180+
}).not.toThrow();
181+
});
182+
183+
it('should handle zero counter value', function () {
184+
var instance = new mixin();
185+
186+
instance.initialize();
187+
// Call with zero counter
188+
expect(function () {
189+
subscribeCallback({ counter: 0 });
190+
}).not.toThrow();
191+
});
192+
193+
it('should handle multiple counter updates', function () {
194+
var instance = new mixin();
195+
196+
instance.initialize();
197+
// Multiple updates
198+
expect(function () {
199+
subscribeCallback({ counter: 1 });
200+
subscribeCallback({ counter: 2 });
201+
subscribeCallback({ counter: 0 });
202+
}).not.toThrow();
203+
});
204+
205+
it('should handle rapid counter updates', function () {
206+
var instance = new mixin(),
207+
i;
208+
209+
instance.initialize();
210+
// Rapid updates
211+
expect(function () {
212+
for (i = 0; i < 10; i++) {
213+
subscribeCallback({ counter: i });
214+
}
215+
}).not.toThrow();
216+
});
217+
});
218+
219+
describe('Mixin functionality', function () {
220+
it('should extend the WishlistComponent correctly', function () {
221+
var instance = new mixin();
222+
223+
expect(instance).toBeDefined();
224+
expect(typeof instance.initialize).toBe('function');
225+
});
226+
227+
it('should maintain the original component structure', function () {
228+
var instance = new mixin();
229+
230+
// The mixin should add functionality but not break the original
231+
expect(instance.initialize).toBeDefined();
232+
});
233+
234+
it('should handle initialization multiple times', function () {
235+
var instance = new mixin(),
236+
result1 = instance.initialize(), // First initialization
237+
result2 = instance.initialize(); // Second initialization
238+
239+
expect(result1).toBe(instance);
240+
expect(result2).toBe(instance);
241+
});
242+
});
243+
244+
describe('Error handling', function () {
245+
it('should throw error when customerData.get returns null', function () {
246+
var instance = new mixin();
247+
248+
customerDataMock.get.and.returnValue(null);
249+
expect(function () {
250+
instance.initialize();
251+
}).toThrow();
252+
});
253+
254+
it('should throw error when customerData.get returns undefined', function () {
255+
var instance = new mixin();
256+
257+
customerDataMock.get.and.returnValue(undefined);
258+
expect(function () {
259+
instance.initialize();
260+
}).toThrow();
261+
});
262+
263+
it('should throw error when wishlist data has no subscribe method', function () {
264+
var instance = new mixin();
265+
266+
customerDataMock.get.and.returnValue({});
267+
expect(function () {
268+
instance.initialize();
269+
}).toThrow();
270+
});
271+
});
272+
});
273+
});

0 commit comments

Comments
 (0)