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

Refactor and improve browser stack trace printing #141

Merged
merged 2 commits into from
Jul 7, 2021
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: 5 additions & 0 deletions .changeset/tough-windows-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'pleasantest': patch
---

Refactor and improve browser stack trace printing
41 changes: 24 additions & 17 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import _ansiRegex from 'ansi-regex';
import { fileURLToPath } from 'url';
import type { PleasantestUser } from './user';
import { pleasantestUser } from './user';
import { assertElementHandle, removeFuncFromStackTrace } from './utils';
import {
assertElementHandle,
printStackLine,
removeFuncFromStackTrace,
} from './utils';
import { createModuleServer } from './module-server';
import { cleanupClientRuntimeServer } from './module-server/client-runtime-server';
import { Console } from 'console';
Expand Down Expand Up @@ -311,7 +315,6 @@ const createTab = async ({
'Failed to load runJS code (most likely due to a transpilation error)';

const parsedStack = parseStackTrace(stack);
let isFirst = true;
const modifiedStack = parsedStack.map(async (stackItem) => {
if (stackItem.raw.startsWith(stack.slice(0, stack.indexOf('\n'))))
return null;
Expand All @@ -325,7 +328,18 @@ const createTab = async ({
const id = `.${url.pathname}`;
const transformResult = requestCache.get(id);
const map = typeof transformResult === 'object' && transformResult.map;
if (!map) return stackItem.raw;
if (!map) {
let p = url.pathname;
const npmPrefix = '/@npm/';
if (p.startsWith(npmPrefix))
p = path.join(
process.cwd(),
'node_modules',
p.slice(npmPrefix.length),
);
return printStackLine(p, line, column, stackItem.name);
}

const { SourceMapConsumer } = await import('source-map');
const consumer = await new SourceMapConsumer(map as any);
const sourceLocation = consumer.originalPositionFor({ line, column });
Expand All @@ -335,20 +349,13 @@ const createTab = async ({
const mappedColumn = sourceLocation.column + 1;
const mappedLine = sourceLocation.line;
const mappedPath = sourceLocation.source || url.pathname;
// If the stack frame has a name (i.e. function name), then display it
// _unless_ the stack frame is the first frame
// because if the function name is displayed in the first stack frame,
// then Jest cannot parse the stack trace to display the code frame
const location =
stackItem.name && !isFirst // Have to use isFirst instead of array loop index because function has early returns
? `${stackItem.name} (${mappedPath}:${mappedLine}:${mappedColumn})`
: `${
// The first line has to be an absolute path,
// otherwise Jest won't recognize it for the code frame
isFirst ? path.join(process.cwd(), mappedPath) : mappedPath
}:${mappedLine}:${mappedColumn}`;
isFirst = false;
return ` at ${location}`;
return printStackLine(
// For the code frames, Jest will only recognize absolute paths
path.join(process.cwd(), mappedPath),
mappedLine,
mappedColumn,
stackItem.name,
);
});
const errorName = stack.slice(0, stack.indexOf(':')) || 'Error';
const specializedErrors = {
Expand Down
12 changes: 12 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,15 @@ export const removeFuncFromStackTrace = (
Error.captureStackTrace(error, fn);
return error;
};

export const printStackLine = (
path: string,
line: number,
column: number,
fnName?: string,
) => {
const location = fnName
? `${fnName} (${path}:${line}:${column})`
: `${path}:${line}:${column}`;
return ` at ${location}`;
};