Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Fix missing second frame in QUnit.stack() in Safari #1776

Merged
merged 1 commit into from
Jul 5, 2024
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
5 changes: 4 additions & 1 deletion src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ extend(QUnit, {

stack: function (offset) {
offset = (offset || 0) + 2;
return sourceFromStacktrace(offset);
// Support Safari: Use temp variable to avoid TCO for consistent cross-browser result
// https://bugs.webkit.org/show_bug.cgi?id=276187
const source = sourceFromStacktrace(offset);
return source;
}
});

Expand Down
59 changes: 25 additions & 34 deletions test/main/stacktrace.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,33 @@
function fooParent () {
return fooCurrent();
}
function fooMain () {
return fooParent();
}

function fooInternal () {
function barInternal () {
return QUnit.stack(2);
}
function fooPublic () {
return fooInternal();
function barPublic () {
return barInternal();
}
function barCaller () {
return fooPublic();
function quuxCaller () {
return barPublic();
}

function norm (str) {
// CRLF
// Windows path
return str.replace(/\\/g, '/');
}

function shorten (str) {
return norm(str)
// Remove browser-specific formatting and line numbers
.replace(/^.*((?:foo|bar|quux)[A-z]+).*$/gm, '$1')
// Remove anything below our entry point
.replace(/(fooMain|quuxCaller)[\s\S\n]*/, '$1');
}

QUnit.test('QUnit.stack()', function (assert) {
var simple = norm(QUnit.stack());
assert.pushResult({
Expand All @@ -36,38 +47,18 @@
message: 'stacktrace cleaning stops before qunit.js'
});

var nested = norm(fooParent());
assert.pushResult({
result: nested.indexOf('fooCurrent') !== -1,
actual: nested,
message: 'include current function'
});
assert.pushResult({
result: nested.indexOf('fooParent') !== -1,
actual: nested,
message: 'include parent function'
});
var fooStack = shorten(fooMain()).split('\n');
assert.deepEqual(fooStack, [
'fooCurrent',
'fooParent',
'fooMain'
]);
});

QUnit.test('QUnit.stack(offset)', function (assert) {
var stack = norm(barCaller());
var line = stack.split('\n')[0];
var barStack = shorten(quuxCaller()).split('\n');

assert.pushResult({
result: line.indexOf('/main/stacktrace.js') !== -1,
actual: line,
message: 'current file'
});
assert.pushResult({
result: line.indexOf('barCaller') !== -1,
actual: line,
message: 'start at offset'
});
assert.pushResult({
result: stack.indexOf('fooInternal') === -1,
actual: stack,
message: 'skip internals'
});
assert.deepEqual(barStack, ['quuxCaller']);
});

// Some browsers support 'stack' only when caught (see sourceFromStacktrace).
Expand Down