Convert clearStack from a function to an object

This commit is contained in:
Steve Gravrock
2025-11-11 11:43:18 -08:00
parent e930622548
commit 7b2807b321
9 changed files with 242 additions and 210 deletions

View File

@@ -55,7 +55,7 @@ var getJasmineRequireObj = (function() {
j$.private.Anything = jRequire.Anything(j$); j$.private.Anything = jRequire.Anything(j$);
j$.private.CallTracker = jRequire.CallTracker(j$); j$.private.CallTracker = jRequire.CallTracker(j$);
j$.private.MockDate = jRequire.MockDate(j$); j$.private.MockDate = jRequire.MockDate(j$);
j$.private.getClearStack = jRequire.clearStack(j$); j$.private.getStackClearer = jRequire.StackClearer(j$);
j$.private.Clock = jRequire.Clock(); j$.private.Clock = jRequire.Clock();
j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
j$.private.Deprecator = jRequire.Deprecator(j$); j$.private.Deprecator = jRequire.Deprecator(j$);
@@ -1244,7 +1244,7 @@ getJasmineRequireObj().Env = function(j$) {
const realSetTimeout = global.setTimeout; const realSetTimeout = global.setTimeout;
const realClearTimeout = global.clearTimeout; const realClearTimeout = global.clearTimeout;
const clearStack = j$.private.getClearStack(global); const stackClearer = j$.private.getStackClearer(global);
this.clock = new j$.private.Clock( this.clock = new j$.private.Clock(
global, global,
function() { function() {
@@ -1525,7 +1525,7 @@ getJasmineRequireObj().Env = function(j$) {
}; };
function runQueue(options) { function runQueue(options) {
options.clearStack = options.clearStack || clearStack; options.clearStack = options.clearStack || stackClearer;
options.timeout = { options.timeout = {
setTimeout: realSetTimeout, setTimeout: realSetTimeout,
clearTimeout: realClearTimeout clearTimeout: realClearTimeout
@@ -2919,131 +2919,6 @@ getJasmineRequireObj().CallTracker = function(j$) {
return CallTracker; return CallTracker;
}; };
getJasmineRequireObj().clearStack = function(j$) {
'use strict';
const maxInlineCallCount = 10;
function browserQueueMicrotaskImpl(global) {
const unclampedSetTimeout = getUnclampedSetTimeout(global);
const { queueMicrotask } = global;
let currentCallCount = 0;
return function clearStack(fn) {
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
queueMicrotask(fn);
} else {
currentCallCount = 0;
unclampedSetTimeout(fn);
}
};
}
function nodeQueueMicrotaskImpl(global) {
const { queueMicrotask } = global;
return function(fn) {
queueMicrotask(fn);
};
}
function messageChannelImpl(global) {
const { setTimeout } = global;
const postMessage = getPostMessage(global);
let currentCallCount = 0;
return function clearStack(fn) {
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
postMessage(fn);
} else {
currentCallCount = 0;
setTimeout(fn);
}
};
}
function getUnclampedSetTimeout(global) {
const { setTimeout } = global;
if (!global.MessageChannel) {
return setTimeout;
}
const postMessage = getPostMessage(global);
return function unclampedSetTimeout(fn) {
postMessage(function() {
setTimeout(fn);
});
};
}
function getPostMessage(global) {
const { MessageChannel, setTimeout } = global;
const channel = new MessageChannel();
let head = {};
let tail = head;
let taskRunning = false;
channel.port1.onmessage = function() {
head = head.next;
const task = head.task;
delete head.task;
if (taskRunning) {
setTimeout(task, 0);
} else {
try {
taskRunning = true;
task();
} finally {
taskRunning = false;
}
}
};
return function postMessage(fn) {
tail = tail.next = { task: fn };
channel.port2.postMessage(0);
};
}
function getClearStack(global) {
const NODE_JS =
global.process &&
global.process.versions &&
typeof global.process.versions.node === 'string';
// Windows builds of WebKit have a fairly generic user agent string when no application name is provided:
// e.g. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)"
const SAFARI_OR_WIN_WEBKIT =
global.navigator &&
/(^((?!chrome|android).)*safari)|(Win64; x64\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)$)/i.test(
global.navigator.userAgent
);
if (NODE_JS) {
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
// so we avoid the overhead.
return nodeQueueMicrotaskImpl(global);
} else if (SAFARI_OR_WIN_WEBKIT || !global.MessageChannel /* tests */) {
// queueMicrotask is dramatically faster than MessageChannel in Safari
// and other WebKit-based browsers, such as the one distributed by Playwright
// to test Safari-like behavior on Windows.
// Some of our own integration tests provide a mock queueMicrotask in all
// environments because it's simpler to mock than MessageChannel.
return browserQueueMicrotaskImpl(global);
} else {
// MessageChannel is faster than queueMicrotask in supported browsers
// other than Safari.
return messageChannelImpl(global);
}
}
return getClearStack;
};
getJasmineRequireObj().Clock = function() { getJasmineRequireObj().Clock = function() {
'use strict'; 'use strict';
@@ -8663,11 +8538,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
} }
this.onComplete = attrs.onComplete || emptyFn; this.onComplete = attrs.onComplete || emptyFn;
this.clearStack = this.clearStack = attrs.clearStack || {
attrs.clearStack || clearStack(fn) {
function(fn) {
fn(); fn();
}; }
};
this.onException = attrs.onException || emptyFn; this.onException = attrs.onException || emptyFn;
this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone; this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
this.userContext = attrs.userContext || new j$.private.UserContext(); this.userContext = attrs.userContext || new j$.private.UserContext();
@@ -8847,7 +8722,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
} }
} }
this.clearStack(() => { this.clearStack.clearStack(() => {
this.globalErrors.popListener(this.handleFinalError); this.globalErrors.popListener(this.handleFinalError);
if (this.errored_) { if (this.errored_) {
@@ -10783,6 +10658,139 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
return SpyStrategy; return SpyStrategy;
}; };
getJasmineRequireObj().StackClearer = function(j$) {
'use strict';
const maxInlineCallCount = 10;
function browserQueueMicrotaskImpl(global) {
const unclampedSetTimeout = getUnclampedSetTimeout(global);
const { queueMicrotask } = global;
let currentCallCount = 0;
return {
clearStack(fn) {
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
queueMicrotask(fn);
} else {
currentCallCount = 0;
unclampedSetTimeout(fn);
}
}
};
}
function nodeQueueMicrotaskImpl(global) {
const { queueMicrotask } = global;
return {
clearStack(fn) {
queueMicrotask(fn);
}
};
}
function messageChannelImpl(global) {
const { setTimeout } = global;
const postMessage = getPostMessage(global);
let currentCallCount = 0;
return {
clearStack(fn) {
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
postMessage(fn);
} else {
currentCallCount = 0;
setTimeout(fn);
}
}
};
}
function getUnclampedSetTimeout(global) {
const { setTimeout } = global;
if (!global.MessageChannel) {
return setTimeout;
}
const postMessage = getPostMessage(global);
return function unclampedSetTimeout(fn) {
postMessage(function() {
setTimeout(fn);
});
};
}
function getPostMessage(global) {
const { MessageChannel, setTimeout } = global;
const channel = new MessageChannel();
let head = {};
let tail = head;
let taskRunning = false;
channel.port1.onmessage = function() {
head = head.next;
const task = head.task;
delete head.task;
if (taskRunning) {
setTimeout(task, 0);
} else {
try {
taskRunning = true;
task();
} finally {
taskRunning = false;
}
}
};
return function postMessage(fn) {
tail = tail.next = { task: fn };
channel.port2.postMessage(0);
};
}
function getStackClearer(global) {
const NODE_JS =
global.process &&
global.process.versions &&
typeof global.process.versions.node === 'string';
// Windows builds of WebKit have a fairly generic user agent string when no application name is provided:
// e.g. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)"
const SAFARI_OR_WIN_WEBKIT =
global.navigator &&
/(^((?!chrome|android).)*safari)|(Win64; x64\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)$)/i.test(
global.navigator.userAgent
);
if (NODE_JS) {
// Unlike browsers, Node doesn't require us to do a periodic setTimeout
// so we avoid the overhead.
return nodeQueueMicrotaskImpl(global);
} else if (SAFARI_OR_WIN_WEBKIT || !global.MessageChannel /* tests */) {
// queueMicrotask is dramatically faster than MessageChannel in Safari
// and other WebKit-based browsers, such as the one distributed by Playwright
// to test Safari-like behavior on Windows.
// Some of our own integration tests provide a mock queueMicrotask in all
// environments because it's simpler to mock than MessageChannel.
return browserQueueMicrotaskImpl(global);
} else {
// MessageChannel is faster than queueMicrotask in supported browsers
// other than Safari.
return messageChannelImpl(global);
}
}
return getStackClearer;
};
getJasmineRequireObj().StackTrace = function(j$) { getJasmineRequireObj().StackTrace = function(j$) {
'use strict'; 'use strict';

View File

@@ -486,7 +486,7 @@ describe('QueueRunner', function() {
errorListeners.pop(); errorListeners.pop();
} }
}, },
clearStack = jasmine.createSpy('clearStack'), clearStack = jasmine.createSpyObj('clearStack', ['clearStack']),
onException = jasmine.createSpy('onException'), onException = jasmine.createSpy('onException'),
queueRunner = new privateUnderTest.QueueRunner({ queueRunner = new privateUnderTest.QueueRunner({
queueableFns: [queueableFn], queueableFns: [queueableFn],
@@ -498,10 +498,10 @@ describe('QueueRunner', function() {
queueRunner.execute(); queueRunner.execute();
jasmine.clock().tick(); jasmine.clock().tick();
expect(clearStack).toHaveBeenCalled(); expect(clearStack.clearStack).toHaveBeenCalled();
expect(errorListeners.length).toEqual(1); expect(errorListeners.length).toEqual(1);
errorListeners[0](error); errorListeners[0](error);
clearStack.calls.argsFor(0)[0](); clearStack.clearStack.calls.argsFor(0)[0]();
expect(onException).toHaveBeenCalledWith(error); expect(onException).toHaveBeenCalledWith(error);
}); });
}); });
@@ -908,22 +908,22 @@ describe('QueueRunner', function() {
}, },
afterFn = { fn: jasmine.createSpy('afterFn') }, afterFn = { fn: jasmine.createSpy('afterFn') },
completeCallback = jasmine.createSpy('completeCallback'), completeCallback = jasmine.createSpy('completeCallback'),
clearStack = jasmine.createSpy('clearStack'), clearStack = jasmine.createSpyObj('clearStack', ['clearStack']),
queueRunner = new privateUnderTest.QueueRunner({ queueRunner = new privateUnderTest.QueueRunner({
queueableFns: [asyncFn, afterFn], queueableFns: [asyncFn, afterFn],
clearStack: clearStack, clearStack: clearStack,
onComplete: completeCallback onComplete: completeCallback
}); });
clearStack.and.callFake(function(fn) { clearStack.clearStack.and.callFake(function(fn) {
fn(); fn();
}); });
queueRunner.execute(); queueRunner.execute();
jasmine.clock().tick(); jasmine.clock().tick();
expect(afterFn.fn).toHaveBeenCalled(); expect(afterFn.fn).toHaveBeenCalled();
expect(clearStack).toHaveBeenCalled(); expect(clearStack.clearStack).toHaveBeenCalled();
clearStack.calls.argsFor(0)[0](); clearStack.clearStack.calls.argsFor(0)[0]();
expect(completeCallback).toHaveBeenCalled(); expect(completeCallback).toHaveBeenCalled();
}); });
}); });

View File

@@ -1,6 +1,6 @@
describe('ClearStack', function() { describe('StackClearer', function() {
it('works in an integrationy way', function(done) { it('works in an integrationy way', function(done) {
const clearStack = privateUnderTest.getClearStack( const { clearStack } = privateUnderTest.getStackClearer(
jasmineUnderTest.getGlobal() jasmineUnderTest.getGlobal()
); );
@@ -36,7 +36,7 @@ describe('ClearStack', function() {
queueMicrotask queueMicrotask
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
for (let i = 0; i < 9; i++) { for (let i = 0; i < 9; i++) {
clearStack(function() {}); clearStack(function() {});
@@ -104,7 +104,7 @@ describe('ClearStack', function() {
...makeGlobal(), ...makeGlobal(),
MessageChannel: fakeMessageChannel MessageChannel: fakeMessageChannel
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
let called = false; let called = false;
clearStack(function() { clearStack(function() {
@@ -125,7 +125,7 @@ describe('ClearStack', function() {
return fakeChannel; return fakeChannel;
} }
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
for (let i = 0; i < 9; i++) { for (let i = 0; i < 9; i++) {
clearStack(function() {}); clearStack(function() {});
@@ -150,7 +150,7 @@ describe('ClearStack', function() {
setTimeout, setTimeout,
MessageChannel: fakeMessageChannel MessageChannel: fakeMessageChannel
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
const fn = jasmine.createSpy('second clearStack function'); const fn = jasmine.createSpy('second clearStack function');
clearStack(function() { clearStack(function() {
@@ -170,7 +170,7 @@ describe('ClearStack', function() {
fn(); fn();
} }
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
let called = false; let called = false;
clearStack(function() { clearStack(function() {
@@ -188,7 +188,7 @@ describe('ClearStack', function() {
queueMicrotask, queueMicrotask,
setTimeout setTimeout
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
for (let i = 0; i < 9; i++) { for (let i = 0; i < 9; i++) {
clearStack(function() {}); clearStack(function() {});
@@ -215,7 +215,7 @@ describe('ClearStack', function() {
fn(); fn();
} }
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
let called = false; let called = false;
clearStack(function() { clearStack(function() {
@@ -233,7 +233,7 @@ describe('ClearStack', function() {
queueMicrotask, queueMicrotask,
setTimeout setTimeout
}; };
const clearStack = privateUnderTest.getClearStack(global); const { clearStack } = privateUnderTest.getStackClearer(global);
clearStack(function() {}); clearStack(function() {});
clearStack(function() {}); clearStack(function() {});

View File

@@ -1181,7 +1181,7 @@ describe('Env integration', function() {
global: { global: {
setTimeout: function(cb, t) { setTimeout: function(cb, t) {
const stack = new Error().stack; const stack = new Error().stack;
if (stack.indexOf('ClearStack') >= 0) { if (stack.indexOf('clearStack') >= 0) {
return realSetTimeout(cb, t); return realSetTimeout(cb, t);
} else { } else {
return setTimeout(cb, t); return setTimeout(cb, t);
@@ -3259,13 +3259,11 @@ describe('Env integration', function() {
}); });
it('is resolved after the stack is cleared', function(done) { it('is resolved after the stack is cleared', function(done) {
const realClearStack = privateUnderTest.getClearStack( const stackClearer = privateUnderTest.getStackClearer(
jasmineUnderTest.getGlobal() jasmineUnderTest.getGlobal()
), );
clearStackSpy = jasmine spyOn(stackClearer, 'clearStack').and.callThrough();
.createSpy('clearStack') spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
.and.callFake(realClearStack);
spyOn(privateUnderTest, 'getClearStack').and.returnValue(clearStackSpy);
// Create a new env that has the clearStack defined above // Create a new env that has the clearStack defined above
env.cleanup_(); env.cleanup_();
@@ -3276,10 +3274,10 @@ describe('Env integration', function() {
}); });
env.execute(null).then(function() { env.execute(null).then(function() {
expect(clearStackSpy).toHaveBeenCalled(); // (many times) expect(stackClearer.clearStack).toHaveBeenCalled(); // (many times)
clearStackSpy.calls.reset(); stackClearer.clearStack.calls.reset();
setTimeout(function() { setTimeout(function() {
expect(clearStackSpy).not.toHaveBeenCalled(); expect(stackClearer.clearStack).not.toHaveBeenCalled();
done(); done();
}); });
}); });
@@ -3368,13 +3366,11 @@ describe('Env integration', function() {
}); });
it('is called after the stack is cleared', async function() { it('is called after the stack is cleared', async function() {
const realClearStack = privateUnderTest.getClearStack( const stackClearer = privateUnderTest.getStackClearer(
jasmineUnderTest.getGlobal() jasmineUnderTest.getGlobal()
), );
clearStackSpy = jasmine spyOn(stackClearer, 'clearStack').and.callThrough();
.createSpy('clearStack') spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
.and.callFake(realClearStack);
spyOn(privateUnderTest, 'getClearStack').and.returnValue(clearStackSpy);
// Create a new env that has the clearStack defined above // Create a new env that has the clearStack defined above
env.cleanup_(); env.cleanup_();
@@ -3386,12 +3382,12 @@ describe('Env integration', function() {
await env.execute(); await env.execute();
expect(clearStackSpy).toHaveBeenCalled(); // (many times) expect(stackClearer.clearStack).toHaveBeenCalled(); // (many times)
clearStackSpy.calls.reset(); stackClearer.clearStack.calls.reset();
await new Promise(resolve => setTimeout(resolve)); await new Promise(resolve => setTimeout(resolve));
expect(clearStackSpy).not.toHaveBeenCalled(); expect(stackClearer.clearStack).not.toHaveBeenCalled();
}); });
it('is called after QueueRunner timeouts are cleared', async function() { it('is called after QueueRunner timeouts are cleared', async function() {

View File

@@ -167,10 +167,11 @@ describe('Global error handling (integration)', function() {
} }
}; };
const realClearStack = privateUnderTest.getClearStack(global); const stackClearer = privateUnderTest.getStackClearer(global);
const realClearStack = stackClearer.clearStack;
const clearStackCallbacks = {}; const clearStackCallbacks = {};
let clearStackCallCount = 0; let clearStackCallCount = 0;
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) { spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
clearStackCallCount++; clearStackCallCount++;
if (clearStackCallbacks[clearStackCallCount]) { if (clearStackCallbacks[clearStackCallCount]) {
@@ -179,6 +180,9 @@ describe('Global error handling (integration)', function() {
realClearStack(fn); realClearStack(fn);
}); });
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
stackClearer
);
env.cleanup_(); env.cleanup_();
env = new privateUnderTest.Env({ global }); env = new privateUnderTest.Env({ global });
@@ -282,10 +286,11 @@ describe('Global error handling (integration)', function() {
} }
}; };
const realClearStack = privateUnderTest.getClearStack(global); const stackClearer = privateUnderTest.getStackClearer(global);
const realClearStack = stackClearer.clearStack;
const clearStackCallbacks = {}; const clearStackCallbacks = {};
let clearStackCallCount = 0; let clearStackCallCount = 0;
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) { spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
clearStackCallCount++; clearStackCallCount++;
if (clearStackCallbacks[clearStackCallCount]) { if (clearStackCallbacks[clearStackCallCount]) {
@@ -294,6 +299,9 @@ describe('Global error handling (integration)', function() {
realClearStack(fn); realClearStack(fn);
}); });
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
stackClearer
);
env.cleanup_(); env.cleanup_();
env = new privateUnderTest.Env({ global }); env = new privateUnderTest.Env({ global });
@@ -391,12 +399,13 @@ describe('Global error handling (integration)', function() {
} }
}; };
const realClearStack = privateUnderTest.getClearStack(global); const stackClearer = privateUnderTest.getStackClearer(global);
const realClearStack = stackClearer.clearStack;
let clearStackCallCount = 0; let clearStackCallCount = 0;
let jasmineDone = false; let jasmineDone = false;
const expectedErrors = []; const expectedErrors = [];
const expectedErrorsAfterJasmineDone = []; const expectedErrorsAfterJasmineDone = [];
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) { spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
clearStackCallCount++; clearStackCallCount++;
const msg = `Error in clearStack #${clearStackCallCount}`; const msg = `Error in clearStack #${clearStackCallCount}`;
@@ -409,6 +418,7 @@ describe('Global error handling (integration)', function() {
dispatchErrorEvent(global, 'error', { error: msg }); dispatchErrorEvent(global, 'error', { error: msg });
realClearStack(fn); realClearStack(fn);
}); });
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
spyOn(console, 'error'); spyOn(console, 'error');
env.cleanup_(); env.cleanup_();
@@ -507,10 +517,11 @@ describe('Global error handling (integration)', function() {
} }
}; };
const realClearStack = privateUnderTest.getClearStack(global); const stackClearer = privateUnderTest.getStackClearer(global);
const realClearStack = stackClearer.clearStack;
const clearStackCallbacks = {}; const clearStackCallbacks = {};
let clearStackCallCount = 0; let clearStackCallCount = 0;
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) { spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
clearStackCallCount++; clearStackCallCount++;
if (clearStackCallbacks[clearStackCallCount]) { if (clearStackCallbacks[clearStackCallCount]) {
@@ -519,6 +530,9 @@ describe('Global error handling (integration)', function() {
realClearStack(fn); realClearStack(fn);
}); });
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
stackClearer
);
env.cleanup_(); env.cleanup_();
env = new privateUnderTest.Env({ global }); env = new privateUnderTest.Env({ global });
@@ -624,10 +638,11 @@ describe('Global error handling (integration)', function() {
} }
}; };
const realClearStack = privateUnderTest.getClearStack(global); const stackClearer = privateUnderTest.getStackClearer(global);
const realClearStack = stackClearer.clearStack;
const clearStackCallbacks = {}; const clearStackCallbacks = {};
let clearStackCallCount = 0; let clearStackCallCount = 0;
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) { spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
clearStackCallCount++; clearStackCallCount++;
if (clearStackCallbacks[clearStackCallCount]) { if (clearStackCallbacks[clearStackCallCount]) {
@@ -636,6 +651,9 @@ describe('Global error handling (integration)', function() {
realClearStack(fn); realClearStack(fn);
}); });
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(
stackClearer
);
env.cleanup_(); env.cleanup_();
env = new privateUnderTest.Env({ global }); env = new privateUnderTest.Env({ global });
@@ -735,12 +753,13 @@ describe('Global error handling (integration)', function() {
} }
}; };
const realClearStack = privateUnderTest.getClearStack(global); const stackClearer = privateUnderTest.getStackClearer(global);
const realClearStack = stackClearer.clearStack;
let clearStackCallCount = 0; let clearStackCallCount = 0;
let jasmineDone = false; let jasmineDone = false;
const expectedErrors = []; const expectedErrors = [];
const expectedErrorsAfterJasmineDone = []; const expectedErrorsAfterJasmineDone = [];
spyOn(privateUnderTest, 'getClearStack').and.returnValue(function(fn) { spyOn(stackClearer, 'clearStack').and.callFake(function(fn) {
clearStackCallCount++; clearStackCallCount++;
const reason = `Error in clearStack #${clearStackCallCount}`; const reason = `Error in clearStack #${clearStackCallCount}`;
const expectedMsg = `Unhandled promise rejection: ${reason} thrown`; const expectedMsg = `Unhandled promise rejection: ${reason} thrown`;
@@ -754,6 +773,7 @@ describe('Global error handling (integration)', function() {
dispatchErrorEvent(global, 'unhandledrejection', { reason }); dispatchErrorEvent(global, 'unhandledrejection', { reason });
realClearStack(fn); realClearStack(fn);
}); });
spyOn(privateUnderTest, 'getStackClearer').and.returnValue(stackClearer);
spyOn(console, 'error'); spyOn(console, 'error');
env.cleanup_(); env.cleanup_();

View File

@@ -20,7 +20,7 @@ getJasmineRequireObj().Env = function(j$) {
const realSetTimeout = global.setTimeout; const realSetTimeout = global.setTimeout;
const realClearTimeout = global.clearTimeout; const realClearTimeout = global.clearTimeout;
const clearStack = j$.private.getClearStack(global); const stackClearer = j$.private.getStackClearer(global);
this.clock = new j$.private.Clock( this.clock = new j$.private.Clock(
global, global,
function() { function() {
@@ -301,7 +301,7 @@ getJasmineRequireObj().Env = function(j$) {
}; };
function runQueue(options) { function runQueue(options) {
options.clearStack = options.clearStack || clearStack; options.clearStack = options.clearStack || stackClearer;
options.timeout = { options.timeout = {
setTimeout: realSetTimeout, setTimeout: realSetTimeout,
clearTimeout: realClearTimeout clearTimeout: realClearTimeout

View File

@@ -51,11 +51,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
} }
this.onComplete = attrs.onComplete || emptyFn; this.onComplete = attrs.onComplete || emptyFn;
this.clearStack = this.clearStack = attrs.clearStack || {
attrs.clearStack || clearStack(fn) {
function(fn) {
fn(); fn();
}; }
};
this.onException = attrs.onException || emptyFn; this.onException = attrs.onException || emptyFn;
this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone; this.onMultipleDone = attrs.onMultipleDone || fallbackOnMultipleDone;
this.userContext = attrs.userContext || new j$.private.UserContext(); this.userContext = attrs.userContext || new j$.private.UserContext();
@@ -235,7 +235,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
} }
} }
this.clearStack(() => { this.clearStack.clearStack(() => {
this.globalErrors.popListener(this.handleFinalError); this.globalErrors.popListener(this.handleFinalError);
if (this.errored_) { if (this.errored_) {

View File

@@ -1,4 +1,4 @@
getJasmineRequireObj().clearStack = function(j$) { getJasmineRequireObj().StackClearer = function(j$) {
'use strict'; 'use strict';
const maxInlineCallCount = 10; const maxInlineCallCount = 10;
@@ -7,14 +7,17 @@ getJasmineRequireObj().clearStack = function(j$) {
const unclampedSetTimeout = getUnclampedSetTimeout(global); const unclampedSetTimeout = getUnclampedSetTimeout(global);
const { queueMicrotask } = global; const { queueMicrotask } = global;
let currentCallCount = 0; let currentCallCount = 0;
return function clearStack(fn) {
currentCallCount++;
if (currentCallCount < maxInlineCallCount) { return {
queueMicrotask(fn); clearStack(fn) {
} else { currentCallCount++;
currentCallCount = 0;
unclampedSetTimeout(fn); if (currentCallCount < maxInlineCallCount) {
queueMicrotask(fn);
} else {
currentCallCount = 0;
unclampedSetTimeout(fn);
}
} }
}; };
} }
@@ -22,8 +25,10 @@ getJasmineRequireObj().clearStack = function(j$) {
function nodeQueueMicrotaskImpl(global) { function nodeQueueMicrotaskImpl(global) {
const { queueMicrotask } = global; const { queueMicrotask } = global;
return function(fn) { return {
queueMicrotask(fn); clearStack(fn) {
queueMicrotask(fn);
}
}; };
} }
@@ -32,14 +37,17 @@ getJasmineRequireObj().clearStack = function(j$) {
const postMessage = getPostMessage(global); const postMessage = getPostMessage(global);
let currentCallCount = 0; let currentCallCount = 0;
return function clearStack(fn) {
currentCallCount++;
if (currentCallCount < maxInlineCallCount) { return {
postMessage(fn); clearStack(fn) {
} else { currentCallCount++;
currentCallCount = 0;
setTimeout(fn); if (currentCallCount < maxInlineCallCount) {
postMessage(fn);
} else {
currentCallCount = 0;
setTimeout(fn);
}
} }
}; };
} }
@@ -88,7 +96,7 @@ getJasmineRequireObj().clearStack = function(j$) {
}; };
} }
function getClearStack(global) { function getStackClearer(global) {
const NODE_JS = const NODE_JS =
global.process && global.process &&
global.process.versions && global.process.versions &&
@@ -120,5 +128,5 @@ getJasmineRequireObj().clearStack = function(j$) {
} }
} }
return getClearStack; return getStackClearer;
}; };

View File

@@ -31,7 +31,7 @@ var getJasmineRequireObj = (function() {
j$.private.Anything = jRequire.Anything(j$); j$.private.Anything = jRequire.Anything(j$);
j$.private.CallTracker = jRequire.CallTracker(j$); j$.private.CallTracker = jRequire.CallTracker(j$);
j$.private.MockDate = jRequire.MockDate(j$); j$.private.MockDate = jRequire.MockDate(j$);
j$.private.getClearStack = jRequire.clearStack(j$); j$.private.getStackClearer = jRequire.StackClearer(j$);
j$.private.Clock = jRequire.Clock(); j$.private.Clock = jRequire.Clock();
j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$); j$.private.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
j$.private.Deprecator = jRequire.Deprecator(j$); j$.private.Deprecator = jRequire.Deprecator(j$);