diff --git a/packages/playwright-core/src/client/errors.ts b/packages/playwright-core/src/client/errors.ts index 27bb6734bf605..884cc4a908933 100644 --- a/packages/playwright-core/src/client/errors.ts +++ b/packages/playwright-core/src/client/errors.ts @@ -15,7 +15,7 @@ */ import { isError } from '@isomorphic/rtti'; -import { parseSerializedValue, parseSystemErrorFields, serializeSystemErrorFields, serializeValue, systemErrorMessage } from '@protocol/serializers'; +import { parseSerializedValue, serializeValue, systemErrorCode, systemErrorMessage } from '@protocol/serializers'; import type { SerializedError } from './channels'; @@ -51,7 +51,7 @@ export function isTargetClosedError(error: Error) { export function serializeError(e: any): SerializedError { if (isError(e)) - return { error: { message: systemErrorMessage(e), stack: e.stack, name: e.name, ...serializeSystemErrorFields(e) } }; + return { error: { message: systemErrorMessage(e), stack: e.stack, name: e.name, code: systemErrorCode(e) } }; return { value: serializeValue(e, value => ({ fallThrough: value })) }; } @@ -71,6 +71,7 @@ export function parseError(error: SerializedError): PlaywrightError { else e = Object.assign(new PlaywrightError(error.error.message), { name: error.error.name }); e.stack = error.error.stack || ''; - parseSystemErrorFields(error.error, e); + if (error.error.code !== undefined) + (e as any).code = error.error.code; return e; } diff --git a/packages/playwright-core/src/server/errors.ts b/packages/playwright-core/src/server/errors.ts index d250a5cfac07e..a6f057135ef5e 100644 --- a/packages/playwright-core/src/server/errors.ts +++ b/packages/playwright-core/src/server/errors.ts @@ -15,7 +15,7 @@ */ import { isError } from '@isomorphic/rtti'; -import { parseSerializedValue, parseSystemErrorFields, serializeSystemErrorFields, serializeValue, systemErrorMessage } from '@protocol/serializers'; +import { parseSerializedValue, serializeValue, systemErrorCode, systemErrorMessage } from '@protocol/serializers'; import { rewriteErrorMessage } from '@utils/stackTrace'; import { isProtocolError } from './protocolError'; @@ -66,7 +66,7 @@ export function rewriteErrorForClosedTarget(error: Error, closeReason: string | export function serializeError(e: any): SerializedError { if (isError(e)) - return { error: { message: systemErrorMessage(e), stack: e.stack, name: e.name, ...serializeSystemErrorFields(e) } }; + return { error: { message: systemErrorMessage(e), stack: e.stack, name: e.name, code: systemErrorCode(e) } }; return { value: serializeValue(e, value => ({ fallThrough: value })) }; } @@ -79,6 +79,7 @@ export function parseError(error: SerializedError): Error { const e = new Error(error.error.message); e.stack = error.error.stack || ''; e.name = error.error.name; - parseSystemErrorFields(error.error, e); + if (error.error.code !== undefined) + (e as any).code = error.error.code; return e; } diff --git a/packages/protocol/spec/serialized.yml b/packages/protocol/spec/serialized.yml index 0b82544a8daeb..374e1edba574a 100644 --- a/packages/protocol/spec/serialized.yml +++ b/packages/protocol/spec/serialized.yml @@ -116,11 +116,6 @@ SerializedError: message: string name: string stack: string? - # See https://nodejs.org/api/errors.html#class-systemerror + # See https://nodejs.org/api/errors.html#errorcode code: string? - errno: int? - syscall: string? - address: string? - port: int? - hostname: string? value: SerializedValue? diff --git a/packages/protocol/src/serializers.ts b/packages/protocol/src/serializers.ts index ef59330e6eac8..a932bd00fb06c 100644 --- a/packages/protocol/src/serializers.ts +++ b/packages/protocol/src/serializers.ts @@ -14,34 +14,11 @@ * limitations under the License. */ -import type { SerializedError, SerializedValue } from '@protocol/structs'; +import type { SerializedValue } from '@protocol/structs'; -type SerializedSystemError = NonNullable; - -// Structured fields of a Node.js system error, see https://nodejs.org/api/errors.html#class-systemerror. -const systemErrorFields: { [key in keyof SerializedSystemError]?: 'string' | 'number' } = { - code: 'string', - errno: 'number', - syscall: 'string', - address: 'string', - port: 'number', - hostname: 'string', -}; - -export function serializeSystemErrorFields(error: any): Partial { - const result: any = {}; - for (const [field, type] of Object.entries(systemErrorFields)) { - if (typeof error[field] === type) - result[field] = error[field]; - } - return result; -} - -export function parseSystemErrorFields(error: SerializedSystemError, target: Error) { - for (const [field, type] of Object.entries(systemErrorFields)) { - if (typeof (error as any)[field] === type) - (target as any)[field] = (error as any)[field]; - } +// See https://nodejs.org/api/errors.html#errorcode. +export function systemErrorCode(error: any): string | undefined { + return typeof error.code === 'string' ? error.code : undefined; } export function systemErrorMessage(error: any): string { diff --git a/packages/protocol/src/structs.d.ts b/packages/protocol/src/structs.d.ts index 1d230fda89c07..0569d8d19b372 100644 --- a/packages/protocol/src/structs.d.ts +++ b/packages/protocol/src/structs.d.ts @@ -319,11 +319,6 @@ export type SerializedError = { name: string, stack?: string, code?: string, - errno?: number, - syscall?: string, - address?: string, - port?: number, - hostname?: string, }, value?: SerializedValue, }; diff --git a/packages/protocol/src/validator.ts b/packages/protocol/src/validator.ts index 0e6061c6adbd7..9b8fb0cbcaf90 100644 --- a/packages/protocol/src/validator.ts +++ b/packages/protocol/src/validator.ts @@ -3066,11 +3066,6 @@ scheme.SerializedError = tObject({ name: tString, stack: tOptional(tString), code: tOptional(tString), - errno: tOptional(tInt), - syscall: tOptional(tString), - address: tOptional(tString), - port: tOptional(tInt), - hostname: tOptional(tString), })), value: tOptional(tType('SerializedValue')), }); diff --git a/tests/library/global-fetch.spec.ts b/tests/library/global-fetch.spec.ts index fffd04cb1e45a..2a714a4145ace 100644 --- a/tests/library/global-fetch.spec.ts +++ b/tests/library/global-fetch.spec.ts @@ -719,7 +719,7 @@ it('should retry ECONNRESET', { await request.dispose(); }); -it('should expose node error fields on network errors', { +it('should expose node error code on network errors', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/42532' } }, async ({ playwright, server }) => { // Reset the connection so that node reports a system error instead of a plain 'socket hang up'. @@ -728,8 +728,8 @@ it('should expose node error fields on network errors', { const error = await request.get(server.PREFIX + '/reset', { maxRetries: 0 }).catch(e => e); expect(error.message).toContain('ECONNRESET'); expect(error.code).toBe('ECONNRESET'); - expect(error.syscall).toBe('read'); - expect(typeof error.errno).toBe('number'); + expect(error.syscall).toBe(undefined); + expect(error.errno).toBe(undefined); await request.dispose(); });