-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
fix(runner): Properly attribute error messages to locator handlers #34074
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,21 @@ export function isTargetClosedError(error: Error) { | |
return error instanceof TargetClosedError; | ||
} | ||
|
||
export class OverriddenAPIError extends Error { | ||
public apiNameOverride: string; | ||
|
||
constructor(error: Exclude<SerializedError['error'], undefined>, apiNameOverride: string) { | ||
super(error.message); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already have 4 layers of processing of the api names and errors, adding another one for this use case will add to the confusion. |
||
this.name = error.name; | ||
this.stack = error.stack; | ||
this.apiNameOverride = apiNameOverride; | ||
} | ||
} | ||
|
||
export function isOverriddenAPIError(error: Error) { | ||
return error instanceof OverriddenAPIError; | ||
} | ||
|
||
export function serializeError(e: any): SerializedError { | ||
if (isError(e)) | ||
return { error: { message: e.message, stack: e.stack, name: e.name } }; | ||
|
@@ -47,6 +62,12 @@ export function parseError(error: SerializedError): Error { | |
throw new Error('Serialized error must have either an error or a value'); | ||
return parseSerializedValue(error.value, undefined); | ||
} | ||
if (error.error.apiNameOverride) { | ||
const e = new OverriddenAPIError(error.error, error.error.apiNameOverride); | ||
e.stack = error.error.stack; | ||
e.name = error.error.name; | ||
return e; | ||
} | ||
if (error.error.name === 'TimeoutError') { | ||
const e = new TimeoutError(error.error.message); | ||
e.stack = error.error.stack || ''; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -371,3 +371,19 @@ test('should removeLocatorHandler', async ({ page, server }) => { | |
await expect(page.locator('#interstitial')).toBeVisible(); | ||
expect(error.message).toContain('Timeout 3000ms exceeded'); | ||
}); | ||
|
||
test('should attribute errors to the locator handler', async ({ page }) => { | ||
await page.setContent(`<html><body><script>setTimeout(() => {document.body.innerHTML = '<div><ul><li>Foo</li></ul><ul><li>Bar</li></ul></div>'}, 100)</script></body></html>`); | ||
|
||
await page.addLocatorHandler(page.locator('ul'), async locator => Promise.resolve()); | ||
|
||
try { | ||
// Perform an operation that will trigger the locator handler | ||
await page.locator('ul > li').first().boundingBox(); | ||
|
||
// Unreachable | ||
expect(false).toBeTruthy(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there's a nicer way to handle testing for an exception, please let me know. I couldn't find a way for |
||
} catch (e) { | ||
expect(e.message).toContain(`page.addLocatorHandler: Error: strict mode violation: locator('ul') resolved to 2 elements:`); | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have a very good reason to change the fundamentals (channelOwner) for a niche DevX like the one in the bug. This isn't even an end-user reported feature, so I'd rather minimize the maintenance cost.