Skip to content

Conversation

@pkalsi97
Copy link
Contributor

What?

This PR implements page.goBack() and page.goForward() to allow users to navigate through the browser's session history.

I have kept the implementation inline with Reload() and followed guidelines mentioned in the issue.

Why?

This functionality was missing and users had to rely on page.evaluate(() => window.history.back()), which is racy and unreliable for testing purposes as mentioned in the issue #5400

Example

import { browser } from 'k6/browser';
import { check } from 'k6';

export const options = {
    scenarios: {
        ui: {
            executor: 'shared-iterations',
            options: {
                browser: {
                    type: 'chromium',
                },
            },
        },
    },
};

export default async function () {
    const page = await browser.newPage();

    try {
        await page.goto('data:text/html,<h1>Page 1</h1>');
        await page.goto('data:text/html,<h1>Page 2</h1>');

        await page.goBack();
        const url1 = await page.url();
        check(url1, {
            'goBack navigated to Page 1': (u) => u.includes('Page 1') || u.includes('Page%201'),
        });

        await page.goForward();
        const url2 = await page.url();
        check(url2, {
            'goForward navigated to Page 2': (u) => u.includes('Page 2') || u.includes('Page%202'),
        });

        const nullResp = await page.goForward();
        check(nullResp, {
            'goForward at boundary returns null': (r) => r === null,
        });

    } finally {
        await page.close();
    }
}

Checklist

  • I have performed a self-review of my code.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests for my changes.
  • I have run linter and tests locally (make check) and all pass.

Checklist: Documentation (only for k6 maintainers and if relevant)

Please do not merge this PR until the following items are filled out.

  • I have added the correct milestone and labels to the PR.
  • I have updated the release notes: link
  • I have updated or added an issue to the k6-documentation: grafana/k6-docs#NUMBER if applicable
  • I have updated or added an issue to the TypeScript definitions: grafana/k6-DefinitelyTyped#NUMBER if applicable

Related PR(s)/Issue(s)

Closes #5400

@pkalsi97 pkalsi97 requested a review from a team as a code owner December 11, 2025 14:42
@pkalsi97 pkalsi97 requested review from inancgumus and mstoykov and removed request for a team December 11, 2025 14:42
Copy link
Contributor

@inancgumus inancgumus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution ❤️ Please watch the test results, and see if they pass, as I ran them. I have some suggestions.

@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing December 11, 2025 18:43 — with GitHub Actions Inactive
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing December 11, 2025 18:46 — with GitHub Actions Inactive
@pkalsi97
Copy link
Contributor Author

pkalsi97 commented Dec 11, 2025

@inancgumus Thanks a lot for the review and feedback.

Can you add a test with a page containing iframes? I'm suspicious that returning true from here might not work as expected. Also, please add a test that goes back in a frame (if possible 🙇) 🤞

Regarding this, indeed you are right. The test are timing out. I overlooked this.
I'll take some time to investigate and resolve this.

@pkalsi97
Copy link
Contributor Author

pkalsi97 commented Dec 12, 2025

@inancgumus, I have implemented all the suggestions, thanks for pointing out a critical issue with the implementation.

  1. Fixed the GoBack and GoForward
  2. Removed unnecessary comments
  3. Refactored integration test to use helper functions
  4. Added iframe integration test for GoBack and GoForward

What ?

GoBack and GoForward methods were timing out when navigating between real HTML pages, similar was observed with iframes.

FIX

Changed the implementation to poll for URL change instead of waiting for EventFrameNavigation:

  1. Get the target URL from the browser's navigation history (we know where we're going)
  2. Execute NavigateToHistoryEntry()
  3. Poll every 50ms checking if mainFrame.URL() == targetURL

Also I am not sure why 2 test were failing in ci. please guide me here.

@pkalsi97 pkalsi97 requested a review from inancgumus December 12, 2025 05:12
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing December 12, 2025 08:15 — with GitHub Actions Inactive
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing December 12, 2025 08:17 — with GitHub Actions Inactive
Copy link
Contributor

@inancgumus inancgumus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes @pkalsi97.

I have some suggestions, and we need to fix the git conflicts.

Don't mind those flaky tests. Your PR is fine as long as your tests pass.

@pkalsi97 pkalsi97 requested a review from inancgumus December 12, 2025 17:46
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 6, 2026 11:18 — with GitHub Actions Inactive
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 6, 2026 11:20 — with GitHub Actions Inactive
@inancgumus inancgumus added this to the v1.6.0 milestone Jan 6, 2026
@inancgumus
Copy link
Contributor

Hi @pkalsi97, can you fix the linter issue?

@pkalsi97
Copy link
Contributor Author

@inancgumus Done.

@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 13, 2026 21:48 — with GitHub Actions Inactive
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 13, 2026 21:50 — with GitHub Actions Inactive
Copy link
Contributor

@inancgumus inancgumus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this work, @pkalsi97 🙇 Can you merge the Page.GoBack and Page.GoForward methods into a single method called Page.GoBackForward. We'll still keep the mapping layer intact (i.e., goBack and goForward). Thanks again!

@pkalsi97
Copy link
Contributor Author

@inancgumus done, yes this completely makes sense ! thanks.

@pkalsi97 pkalsi97 requested a review from inancgumus January 14, 2026 18:04
@inancgumus inancgumus requested a review from ankur22 January 14, 2026 20:16
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 14, 2026 20:22 — with GitHub Actions Inactive
Copy link
Contributor

@inancgumus inancgumus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! 🚀

@inancgumus
Copy link
Contributor

@pkalsi97, it would be great if you could provide updates to k6-docs and TypeScript definitions for this feature. Thanks!

@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 14, 2026 20:24 — with GitHub Actions Inactive
@pkalsi97
Copy link
Contributor Author

@inancgumus sure. Will do by tomorrow.

Copy link
Contributor

@ankur22 ankur22 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @pkalsi97 for the work on goBack and goForward! I think most of it looks good. I think I would like some clarification on a question and rethink on how we can work with lifecycle events. I took a look at Playwright's implementation and they seem to be waiting on navigation events.

Comment on lines +1546 to +1547
// Poll for URL change, don't rely on lifecycle events since bfcache
// restorations don't re-fire them.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure about this change to working with polling.

  1. Why can't we rely on the lifecycle event?
  2. The WaitUntil option isn't used anywhere in the GoBackForward method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ankur22 Thanks for the review!

  1. my initial implementation did use lifecycle events similar to Reload(), but test keep on timing out for real html pages and iframes, as per my knowledge EventFrameNavigation wasn't being emitted for history navigations (due to Chrome's bfcache), when we try to navigate forward or backward chrome often restore pages from memory snapshots instead or reloading them Page.frameNavigated only fires when bfcache navigation fails.

polling was used here as we know the target URL from navigation history and it updates immediately after NavigateToHistoryEntry(), making it reliable regardless of bfcache state.

  1. Regarding WaitUntil you're right, I can remove it from the options since it's not applicable with the polling approach.

I'm fairly new to this , i'll greatly appreciate if you could fill me in on an approach that does not use polling/ any other approach that you think will be a better implementation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pkalsi97 I'll need to take a close look at this PR and the problem you've outlined to understand why we can't work with lifecycle events and why they weren't firing -- I can see why that might be the case due to the cache. What's not clear is whether Playwright is also hitting this issue and how they have resolved it, this is important since the behaviour of k6 browser should match Playwright's if we're copying their API. I'll add my findings in this PR once I've got an answer for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll also look into it and figure it out.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not certain if we are still waiting on this?
cc @ankur22 @inancgumus Shall we merge this as is?

@pkalsi97 pkalsi97 requested a review from ankur22 January 18, 2026 07:02
@inancgumus inancgumus added the blocked issue's resolution is blocked label Jan 28, 2026
Copy link
Contributor

@mstoykov mstoykov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM apart from one nit and the discussion by @ankur22 on lifcycle events.

Comment on lines +1535 to +1544
wrapTimeoutError := func(err error) error {
if errors.Is(err, context.DeadlineExceeded) {
err = &k6ext.UserFriendlyError{
Err: err,
Timeout: opts.Timeout,
}
}
p.logger.Debugf("Page:GoBackForward", "timeoutCtx done: %v", err)
return fmt.Errorf("navigating %s to history entry %d: %w", direction, historyEntryID, err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this eitehr needs to be a helper function or just be inlined in the opne place it is actually used in this function

Comment on lines +1546 to +1547
// Poll for URL change, don't rely on lifecycle events since bfcache
// restorations don't re-fire them.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not certain if we are still waiting on this?
cc @ankur22 @inancgumus Shall we merge this as is?

@inancgumus
Copy link
Contributor

@pkalsi97, we can merge this PR if you fix the conflicts (they happened in the meantime). Thank you!

@codebien codebien modified the milestones: v1.6.0, v1.7.0 Jan 28, 2026
@codebien
Copy link
Contributor

@pkalsi97 @inancgumus I moved this pull request to v1.7.0 release. If in the meantime we manage to fix the conflicts then we'll move back to the upcoming v1.6.0 release.

@pkalsi97
Copy link
Contributor Author

pkalsi97 commented Jan 28, 2026

@mstoykov Thanks for the review! @inancgumus @codebien i'll work on this shortly and try to fix it. Thanks

@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 28, 2026 17:26 — with GitHub Actions Inactive
@pkalsi97 pkalsi97 temporarily deployed to azure-trusted-signing January 28, 2026 17:28 — with GitHub Actions Inactive
@AgnesToulet AgnesToulet merged commit 2fec46b into grafana:master Jan 29, 2026
49 checks passed
@AgnesToulet AgnesToulet modified the milestones: v1.7.0, v1.6.0 Jan 29, 2026
@inancgumus
Copy link
Contributor

Hi @pkalsi97, since we merged the PR, can you work on the Typescript definitions and k6-docs for this feature if possible? Thank you!

@pkalsi97
Copy link
Contributor Author

@inancgumus Already implemented! Thanks

grafana/k6-docs#2166
grafana/k6-DefinitelyTyped#110

@inancgumus inancgumus removed the blocked issue's resolution is blocked label Jan 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Page.goBack and Page.goForward

6 participants