mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(esm): show codeframe when errors get reported (#15262)
This commit is contained in:
parent
4de14e7d2c
commit
3d1d723c56
@ -15,11 +15,9 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { StackUtils } from '../utilsBundle';
|
||||
import { parseStackTraceLine } from '../utilsBundle';
|
||||
import { isUnderTest } from './';
|
||||
|
||||
const stackUtils = new StackUtils();
|
||||
|
||||
export function rewriteErrorMessage<E extends Error>(e: E, newMessage: string): E {
|
||||
const lines: string[] = (e.stack?.split('\n') || []).filter(l => l.startsWith(' at '));
|
||||
e.message = newMessage;
|
||||
@ -82,17 +80,11 @@ export function captureStackTrace(rawStack?: string): ParsedStackTrace {
|
||||
inCore: boolean;
|
||||
};
|
||||
let parsedFrames = stack.split('\n').map(line => {
|
||||
const frame = stackUtils.parseLine(line);
|
||||
if (!frame || !frame.file)
|
||||
const { frame, fileName } = parseStackTraceLine(line);
|
||||
if (!frame || !frame.file || !fileName)
|
||||
return null;
|
||||
if (isInternalFileName(frame.file, frame.function))
|
||||
return null;
|
||||
// Workaround for https://github.com/tapjs/stack-utils/issues/60
|
||||
let fileName: string;
|
||||
if (frame.file.startsWith('file://'))
|
||||
fileName = new URL(frame.file).pathname;
|
||||
else
|
||||
fileName = path.resolve(process.cwd(), frame.file);
|
||||
if (isTesting && fileName.includes(COVERAGE_PATH))
|
||||
return null;
|
||||
const inCore = fileName.startsWith(CORE_LIB) || fileName.startsWith(CORE_SRC);
|
||||
|
@ -14,6 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import url from 'url';
|
||||
import path from 'path';
|
||||
|
||||
export const colors: typeof import('../bundles/utils/node_modules/colors/safe') = require('./utilsBundleImpl').colors;
|
||||
export const debug: typeof import('../bundles/utils/node_modules/@types/debug') = require('./utilsBundleImpl').debug;
|
||||
export const getProxyForUrl: typeof import('../bundles/utils/node_modules/@types/proxy-from-env').getProxyForUrl = require('./utilsBundleImpl').getProxyForUrl;
|
||||
@ -28,10 +31,27 @@ export const program: typeof import('../bundles/utils/node_modules/commander').p
|
||||
export const progress: typeof import('../bundles/utils/node_modules/@types/progress') = require('./utilsBundleImpl').progress;
|
||||
export const rimraf: typeof import('../bundles/utils/node_modules/@types/rimraf') = require('./utilsBundleImpl').rimraf;
|
||||
export const SocksProxyAgent: typeof import('../bundles/utils/node_modules/socks-proxy-agent').SocksProxyAgent = require('./utilsBundleImpl').SocksProxyAgent;
|
||||
export const StackUtils: typeof import('../bundles/utils/node_modules/@types/stack-utils') = require('./utilsBundleImpl').StackUtils;
|
||||
export const ws: typeof import('../bundles/utils/node_modules/@types/ws') = require('./utilsBundleImpl').ws;
|
||||
export const wsServer: typeof import('../bundles/utils/node_modules/@types/ws').WebSocketServer = require('./utilsBundleImpl').wsServer;
|
||||
export const wsReceiver = require('./utilsBundleImpl').wsReceiver;
|
||||
export const wsSender = require('./utilsBundleImpl').wsSender;
|
||||
export type { Command } from '../bundles/utils/node_modules/commander';
|
||||
export type { WebSocket, WebSocketServer, RawData as WebSocketRawData, EventEmitter as WebSocketEventEmitter } from '../bundles/utils/node_modules/@types/ws';
|
||||
|
||||
const StackUtils: typeof import('../bundles/utils/node_modules/@types/stack-utils') = require('./utilsBundleImpl').StackUtils;
|
||||
const stackUtils = new StackUtils();
|
||||
|
||||
export function parseStackTraceLine(line: string): { frame: import('../bundles/utils/node_modules/@types/stack-utils').StackLineData | null, fileName: string | null } {
|
||||
const frame = stackUtils.parseLine(line);
|
||||
if (!frame)
|
||||
return { frame: null, fileName: null };
|
||||
let fileName = null;
|
||||
if (frame.file) {
|
||||
// ESM files return file:// URLs, see here: https://github.com/tapjs/stack-utils/issues/60
|
||||
fileName = frame.file.startsWith('file://') ? url.fileURLToPath(frame.file) : path.resolve(process.cwd(), frame.file);
|
||||
}
|
||||
return {
|
||||
frame,
|
||||
fileName,
|
||||
};
|
||||
}
|
||||
|
@ -14,14 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { colors, ms as milliseconds } from 'playwright-core/lib/utilsBundle';
|
||||
import { colors, ms as milliseconds, parseStackTraceLine } from 'playwright-core/lib/utilsBundle';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { StackUtils } from 'playwright-core/lib/utilsBundle';
|
||||
import type { FullConfig, TestCase, Suite, TestResult, TestError, Reporter, FullResult, TestStep, Location } from '../../types/testReporter';
|
||||
import type { FullConfigInternal } from '../types';
|
||||
import { codeFrameColumns } from '../babelBundle';
|
||||
const stackUtils = new StackUtils();
|
||||
|
||||
export type TestResultOutput = { chunk: string | Buffer, type: 'stdout' | 'stderr' };
|
||||
export const kOutputSymbol = Symbol('output');
|
||||
@ -411,10 +409,9 @@ export function prepareErrorStack(stack: string, file?: string): {
|
||||
const stackLines = lines.slice(firstStackLine);
|
||||
let location: Location | undefined;
|
||||
for (const line of stackLines) {
|
||||
const parsed = stackUtils.parseLine(line);
|
||||
if (!parsed || !parsed.file)
|
||||
const { frame: parsed, fileName: resolvedFile } = parseStackTraceLine(line);
|
||||
if (!parsed || !resolvedFile)
|
||||
continue;
|
||||
const resolvedFile = path.join(process.cwd(), parsed.file);
|
||||
if (!file || resolvedFile === file) {
|
||||
location = { file: resolvedFile, column: parsed.column || 0, line: parsed.line || 0 };
|
||||
break;
|
||||
|
@ -148,7 +148,6 @@ test('should use source maps', async ({ runInlineTest, nodeVersion }) => {
|
||||
});
|
||||
|
||||
test('should show the codeframe in errors', async ({ runInlineTest, nodeVersion }) => {
|
||||
test.fixme();
|
||||
// We only support experimental esm mode on Node 16+
|
||||
test.skip(nodeVersion.major < 16);
|
||||
const result = await runInlineTest({
|
||||
@ -163,17 +162,31 @@ test('should show the codeframe in errors', async ({ runInlineTest, nodeVersion
|
||||
expect(1).toBe(2);
|
||||
expect(testInfo.project.name).toBe('foo');
|
||||
});
|
||||
|
||||
test('foobar', async ({}) => {
|
||||
const error = new Error('my-message');
|
||||
error.name = 'FooBarError';
|
||||
throw error;
|
||||
});
|
||||
`
|
||||
}, { reporter: 'list' });
|
||||
}, { reporter: 'list' }, {
|
||||
FORCE_COLOR: '0',
|
||||
});
|
||||
|
||||
const output = stripAnsi(result.output);
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(result.failed).toBe(1);
|
||||
expect(result.failed).toBe(2);
|
||||
expect(output, 'error carrot—via source maps—is positioned appropriately').toContain(
|
||||
[
|
||||
` > 8 | expect(1).toBe(2);`,
|
||||
` | ^`
|
||||
].join('\n'));
|
||||
expect(result.output).toContain('FooBarError: my-message');
|
||||
expect(result.output).not.toContain('at a.test.ts');
|
||||
expect(result.output).toContain(` 12 | test('foobar', async ({}) => {`);
|
||||
expect(result.output).toContain(`> 13 | const error = new Error('my-message');`);
|
||||
expect(result.output).toContain(' | ^');
|
||||
expect(result.output).toContain(' 14 | error.name = \'FooBarError\';');
|
||||
});
|
||||
|
||||
test('should filter by line', async ({ runInlineTest, nodeVersion }) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user