Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit d8fca15

Browse files
committed
fixup 2
- Unify the clean-up paths for tests with/without jQuery, using `angular.element.cleanData()`. - Remove redundant calls to `.off().removeData()`. - Fix bug in `testabilityPatch.js`, where `cleanData()` was called with an array of jqLite/jQuery elements (instead of "raw" nodes).
1 parent b972a12 commit d8fca15

File tree

3 files changed

+52
-72
lines changed

3 files changed

+52
-72
lines changed

src/ngMock/angular-mocks.js

+4-10
Original file line numberDiff line numberDiff line change
@@ -2602,16 +2602,10 @@ if (window.jasmine || window.mocha) {
26022602
currentSpec = null;
26032603

26042604
if (injector) {
2605-
var cleanUpElems = [originalRootElement];
2606-
var $rootElement = injector.get('$rootElement');
2607-
if ($rootElement !== originalRootElement) cleanUpElems.push($rootElement);
2608-
cleanUpElems.forEach(function(elem) {
2609-
// The `$rootElement` might not have been created or
2610-
// a mocked `$rootElement` might not have the standard methods
2611-
if (elem && elem.off) elem.off();
2612-
if (elem && elem.removeData) elem.removeData();
2613-
});
2614-
if (window.jQuery) window.jQuery.cleanData(cleanUpElems);
2605+
var cleanUpElems = [originalRootElement[0]];
2606+
var rootNode = injector.get('$rootElement')[0];
2607+
if (rootNode && (rootNode !== originalRootElement[0])) cleanUpElems.push(rootNode);
2608+
angular.element.cleanData(cleanUpElems);
26152609

26162610
injector.get('$rootScope').$destroy();
26172611
}

test/helpers/testabilityPatch.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,8 @@ function dealoc(obj) {
139139
}
140140

141141
function cleanup(element) {
142-
element.off().removeData();
143-
if (window.jQuery) {
144-
// jQuery 2.x doesn't expose the cache storage; ensure all element data
145-
// is removed during its cleanup.
146-
jQuery.cleanData([element]);
147-
}
142+
angular.element.cleanData(element);
143+
148144
// Note: We aren't using element.contents() here. Under jQuery, element.contents() can fail
149145
// for IFRAME elements. jQuery explicitly uses (element.contentDocument ||
150146
// element.contentWindow.document) and both properties are null for IFRAMES that aren't attached

test/ngMock/angular-mocksSpec.js

+46-56
Original file line numberDiff line numberDiff line change
@@ -2419,23 +2419,19 @@ describe('make sure that we can create an injector outside of tests', function()
24192419

24202420
describe('`afterEach` clean-up', function() {
24212421
describe('undecorated `$rootElement`', function() {
2422-
var jQuery = window.jQuery;
24232422
var prevRootElement;
2424-
var prevRemoveDataSpy;
24252423
var prevCleanDataSpy;
24262424

24272425

24282426
it('should set up spies so the next test can verify `$rootElement` was cleaned up', function() {
24292427
module(function($provide) {
24302428
$provide.decorator('$rootElement', function($delegate) {
2431-
// Spy on `$rootElement.removeData()` and `jQuery.cleanData()`,
2432-
// so the next test can verify that they have been called as necessary
24332429
prevRootElement = $delegate;
2434-
prevRemoveDataSpy = spyOn($delegate, 'removeData').andCallThrough();
24352430

2436-
if (jQuery) {
2437-
prevCleanDataSpy = spyOn(jQuery, 'cleanData').andCallThrough();
2438-
}
2431+
// Spy on `angular.element.cleanData()`, so the next test can verify
2432+
// that it has been called as necessary
2433+
prevCleanDataSpy = spyOn(angular.element, 'cleanData').andCallThrough();
2434+
// prevCleanDataSpy = mockCleanData([prevRootElement[0]]);
24392435

24402436
return $delegate;
24412437
});
@@ -2451,51 +2447,35 @@ describe('`afterEach` clean-up', function() {
24512447
it('should clean up `$rootElement` after each test', function() {
24522448
// One call is made by `testabilityPatch`'s `dealoc()`
24532449
// We want to verify the subsequent call, made by `angular-mocks`
2454-
// (Since `testabilityPatch` re-wrapps `$rootElement` and because jQuery returns a different
2455-
// object when re-wrapping, we don't capture the 1st call when using jQuery)
2456-
expect(prevRemoveDataSpy.callCount).toBe(jQuery ? 1 : 2);
2457-
2458-
if (jQuery) {
2459-
// One call is made by `testabilityPatch`'s `dealoc()`
2460-
// We want to verify the subsequent call, made by `angular-mocks`
2461-
expect(prevCleanDataSpy.callCount).toBe(2);
2462-
2463-
var cleanUpElems = prevCleanDataSpy.calls[1].args[0];
2464-
expect(cleanUpElems.length).toBe(1);
2465-
expect(cleanUpElems[0][0]).toBe(prevRootElement[0]);
2466-
}
2450+
expect(prevCleanDataSpy.callCount).toBe(2);
2451+
2452+
var cleanUpElems = prevCleanDataSpy.calls[1].args[0];
2453+
expect(cleanUpElems.length).toBe(1);
2454+
expect(cleanUpElems[0]).toBe(prevRootElement[0]);
24672455
});
24682456
});
24692457

24702458

24712459
describe('decorated `$rootElement`', function() {
2472-
var jQuery = window.jQuery;
24732460
var prevOriginalRootElement;
2474-
var prevOriginalRemoveDataSpy;
24752461
var prevRootElement;
2476-
var prevRemoveDataSpy;
24772462
var prevCleanDataSpy;
24782463

24792464

24802465
it('should set up spies so the next text can verify `$rootElement` was cleaned up', function() {
24812466
module(function($provide) {
24822467
$provide.decorator('$rootElement', function($delegate) {
2483-
// Mock `$rootElement` to be able to verify that the correct object is cleaned up
2484-
var mockRootElement = angular.element('<div></div>');
2485-
2486-
// Spy on `$rootElement.removeData()` and `jQuery.cleanData()`,
2487-
// so the next test can verify that they have been called as necessary
24882468
prevOriginalRootElement = $delegate;
2489-
prevOriginalRemoveDataSpy = spyOn($delegate, 'removeData').andCallThrough();
24902469

2491-
prevRootElement = mockRootElement;
2492-
prevRemoveDataSpy = spyOn(mockRootElement, 'removeData').andCallThrough();
2470+
// Mock `$rootElement` to be able to verify that the correct object is cleaned up
2471+
prevRootElement = angular.element('<div></div>');
24932472

2494-
if (jQuery) {
2495-
prevCleanDataSpy = spyOn(jQuery, 'cleanData').andCallThrough();
2496-
}
2473+
// Spy on `angular.element.cleanData()`, so the next test can verify
2474+
// that it has been called as necessary
2475+
prevCleanDataSpy = spyOn(angular.element, 'cleanData').andCallThrough();
2476+
// prevCleanDataSpy = mockCleanData([prevRootElement[0], prevOriginalRootElement[0]]);
24972477

2498-
return mockRootElement;
2478+
return prevRootElement;
24992479
});
25002480
});
25012481

@@ -2511,33 +2491,43 @@ describe('`afterEach` clean-up', function() {
25112491
// This is a false alarm, because `angular-mocks` would have cleaned up in a subsequent
25122492
// `afterEach` block
25132493
prevOriginalRootElement.removeData();
2514-
prevOriginalRemoveDataSpy.reset();
2515-
2516-
expect(prevOriginalRemoveDataSpy.callCount).toBe(0);
25172494
});
25182495
});
25192496

25202497

25212498
it('should clean up `$rootElement` (both original and decorated) after each test', function() {
2522-
// Only `angular-mocks` cleans up after the original `$rootElement`, not `testabilityPatch`
2523-
expect(prevOriginalRemoveDataSpy.callCount).toBe(1);
2524-
25252499
// One call is made by `testabilityPatch`'s `dealoc()`
25262500
// We want to verify the subsequent call, made by `angular-mocks`
2527-
// (Since `testabilityPatch` re-wrapps `$rootElement` and because jQuery returns a different
2528-
// object when re-wrapping, we don't capture the 1st call when using jQuery)
2529-
expect(prevRemoveDataSpy.callCount).toBe(jQuery ? 1 : 2);
2530-
2531-
if (jQuery) {
2532-
// One call is made by `testabilityPatch`'s `dealoc()`
2533-
// We want to verify the subsequent call, made by `angular-mocks`
2534-
expect(prevCleanDataSpy.callCount).toBe(2);
2535-
2536-
var cleanUpElems = prevCleanDataSpy.calls[1].args[0];
2537-
expect(cleanUpElems.length).toBe(2);
2538-
expect(cleanUpElems[0][0]).toBe(prevOriginalRootElement[0]);
2539-
expect(cleanUpElems[1][0]).toBe(prevRootElement[0]);
2540-
}
2501+
expect(prevCleanDataSpy.callCount).toBe(2);
2502+
2503+
var cleanUpElems = prevCleanDataSpy.calls[1].args[0];
2504+
expect(cleanUpElems.length).toBe(2);
2505+
expect(cleanUpElems[0]).toBe(prevOriginalRootElement[0]);
2506+
expect(cleanUpElems[1]).toBe(prevRootElement[0]);
25412507
});
25422508
});
2509+
2510+
2511+
// Helpers
2512+
function mockCleanData(expectedNodes) {
2513+
var callIdx = -1;
2514+
2515+
var cleanData_ = angular.element.cleanData;
2516+
var cleanDataSpy = spyOn(angular.element, 'cleanData').andCallFake(function(cleanUpElems) {
2517+
var expectedNode = expectedNodes[++callIdx % expectedNodes.length];
2518+
var actualNode = cleanUpElems[0];
2519+
if (actualNode !== expectedNode) {
2520+
throw new Error('Unexpected node for clean-up: ' + actualNode.outerHTML);
2521+
}
2522+
2523+
cleanData_.apply(angular.element, arguments);
2524+
2525+
var data = angular.element(actualNode).data();
2526+
if (Object.keys(data).length) {
2527+
throw new Error('Data clean-up failed on: ' + actualNode.outerHTML);
2528+
}
2529+
});
2530+
2531+
return cleanDataSpy;
2532+
}
25432533
});

0 commit comments

Comments
 (0)