Skip to content
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
2 changes: 0 additions & 2 deletions packages/playwright-core/src/client/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export const Events = {
},

Page: {
AgentTurn: 'agentturn',
Close: 'close',
Crash: 'crash',
Console: 'console',
Expand All @@ -79,7 +78,6 @@ export const Events = {
Worker: 'worker',
},


PageAgent: {
Turn: 'turn',
},
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/client/pageAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class PageAgent extends ChannelOwner<channels.PageAgentChannel> implement
constructor(parent: ChannelOwner, type: string, guid: string, initializer: channels.PageAgentInitializer) {
super(parent, type, guid, initializer);
this._page = Page.from(initializer.page);
this._channel.on('turn', params => this.emit(Events.Page.AgentTurn, params));
this._channel.on('turn', params => this.emit(Events.PageAgent.Turn, params));
}

async expect(expectation: string, options: channels.PageAgentExpectOptions = {}) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export class PageAgentDispatcher extends Dispatcher<SdkObject, channels.PageAgen
}

async dispose(params: channels.PageAgentDisposeParams, progress: Progress): Promise<void> {
progress.metadata.potentiallyClosesScope = true;
void this.stopPendingOperations(new Error('The agent is disposed'));
this._dispose();
}

private _eventSupport(): loopTypes.LoopEvents {
Expand Down
2 changes: 1 addition & 1 deletion packages/playwright-core/src/server/progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class ProgressController {
(error as any)[kAbortErrorSymbol] = true;
this._state = { error };
this._forceAbortPromise.reject(error);
this._controller.abort();
this._controller.abort(error);
}
await this._donePromise;
}
Expand Down
45 changes: 45 additions & 0 deletions tests/library/agent-perform.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,48 @@ test('perform reports error', async ({ context }) => {
const e = await agent.perform('click the Rabbit button').catch(e => e);
expect(e.message).toContain('Agent refused to perform action:');
});

test('should dispatch event and respect dispose()', async ({ context, server }) => {
let apiResponse;
server.setRoute('/api', (req, res) => {
apiResponse = res;
// stall
});

const apiRequestPromise = server.waitForRequest('/api');
const { page, agent } = await generateAgent(context, {
provider: {
api: 'anthropic',
apiKey: 'not a real key',
apiEndpoint: server.PREFIX + '/api',
model: 'no such model',
},
});
await page.setContent(`<button>Wolf</button>`);

const promiseCanceledByDispose = agent.perform('click the Wolf button').catch(e => e);
let promiseAfterDispose;
let eventCounter = 0;

agent.on('turn', async () => {
++eventCounter;
if (eventCounter > 1)
return;

await apiRequestPromise;
void agent.dispose();
promiseAfterDispose = agent.perform('click the Wolf button again').catch(e => e);
apiResponse.end();
});

const errorCanceledByDispose = await promiseCanceledByDispose;
expect(errorCanceledByDispose.message).toContain('The agent is disposed');
expect(errorCanceledByDispose.message).not.toContain('after being disposed');

const errorAfterDispose = await promiseAfterDispose;
expect(errorAfterDispose.message).toContain('Target page, context or browser has been closed');

// no more events after dispose
await page.waitForTimeout(1000);
expect(eventCounter).toBe(1);
});
Loading