diff --git a/packages/puppeteer-core/src/bidi/Connection.ts b/packages/puppeteer-core/src/bidi/Connection.ts index 4948704207f..2e4b41b2328 100644 --- a/packages/puppeteer-core/src/bidi/Connection.ts +++ b/packages/puppeteer-core/src/bidi/Connection.ts @@ -97,6 +97,10 @@ export interface Commands { params: Bidi.BrowsingContext.SetViewportParameters; returnType: Bidi.EmptyResult; }; + 'browsingContext.traverseHistory': { + params: Bidi.BrowsingContext.TraverseHistoryParameters; + returnType: Bidi.EmptyResult; + }; 'input.performActions': { params: Bidi.Input.PerformActionsParameters; diff --git a/packages/puppeteer-core/src/bidi/Page.ts b/packages/puppeteer-core/src/bidi/Page.ts index 325b544f7c4..c516a595dd3 100644 --- a/packages/puppeteer-core/src/bidi/Page.ts +++ b/packages/puppeteer-core/src/bidi/Page.ts @@ -31,6 +31,7 @@ import { import type {CDPSession} from '../api/CDPSession.js'; import type {BoundingBox} from '../api/ElementHandle.js'; import type {WaitForOptions} from '../api/Frame.js'; +import type {HTTPResponse} from '../api/HTTPResponse.js'; import { Page, PageEvent, @@ -65,6 +66,7 @@ import type {Viewport} from '../common/Viewport.js'; import {assert} from '../util/assert.js'; import {Deferred} from '../util/Deferred.js'; import {disposeSymbol} from '../util/disposable.js'; +import {isErrorLike} from '../util/ErrorLike.js'; import type {BidiBrowser} from './Browser.js'; import type {BidiBrowserContext} from './BrowserContext.js'; @@ -905,12 +907,40 @@ export class BidiPage extends Page { throw new UnsupportedOperation(); } - override goBack(): never { - throw new UnsupportedOperation(); + override async goBack( + options: WaitForOptions = {} + ): Promise { + return await this.#go(-1, options); } - override goForward(): never { - throw new UnsupportedOperation(); + override async goForward( + options: WaitForOptions = {} + ): Promise { + return await this.#go(+1, options); + } + + async #go( + delta: number, + options: WaitForOptions + ): Promise { + try { + const result = await Promise.all([ + this.waitForNavigation(options), + this.#connection.send('browsingContext.traverseHistory', { + delta, + context: this.mainFrame()._id, + }), + ]); + return result[0]; + } catch (err) { + // TODO: waitForNavigation should be cancelled if an error happens. + if (isErrorLike(err)) { + if (err.message.includes('no such history entry')) { + return null; + } + } + throw err; + } } override waitForDevicePrompt(): never { diff --git a/test/TestExpectations.json b/test/TestExpectations.json index fcde0bd80d7..ada36304258 100644 --- a/test/TestExpectations.json +++ b/test/TestExpectations.json @@ -131,12 +131,6 @@ "parameters": ["webDriverBiDi"], "expectations": ["PASS"] }, - { - "testIdPattern": "[navigation.spec] navigation Page.goBack *", - "platforms": ["darwin", "linux", "win32"], - "parameters": ["webDriverBiDi"], - "expectations": ["FAIL"] - }, { "testIdPattern": "[network.spec] network *", "platforms": ["darwin", "linux", "win32"], @@ -767,6 +761,18 @@ "parameters": ["webDriverBiDi"], "expectations": ["FAIL"] }, + { + "testIdPattern": "[navigation.spec] navigation Page.goBack *", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["chrome", "webDriverBiDi"], + "expectations": ["PASS"] + }, + { + "testIdPattern": "[navigation.spec] navigation Page.goBack *", + "platforms": ["darwin", "linux", "win32"], + "parameters": ["firefox", "webDriverBiDi"], + "expectations": ["FAIL"] + }, { "testIdPattern": "[navigation.spec] navigation Page.goto should fail when navigating to bad SSL", "platforms": ["darwin", "linux", "win32"],