Skip to content
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

BrowserKit back/forward behaviour not consistent with other browsers #20138

Closed
MPV opened this issue Oct 3, 2016 · 2 comments

Comments

Projects
None yet
2 participants
@MPV
Copy link

commented Oct 3, 2016

I’ve got an application that only allows you to visit a url once (doing the same request again takes you elsewhere).

For example, imagine a wizard (or a purchase flow), something like this:

Step 1 > Step 2 > Step 3 > Step 4

...where between each step, the user POSTs a form and gets redirected to the next page using a standard Post/Redirect/Get flow.

...and the system is built so that going back/forward unexpectedly in the flow should take me to step 1.

For example:

  • browser back button should take me to step 1
  • browser back + forward button should take me to step 1

When I’m using BrowserKit to write a test for my application, it doesn't seem to do the same thing as my browser does.

This is how my regular browser (Chrome/Firefox) behaves (with HTTP requests in parentheses):

  1. I visit the first page (GET /wizard-view-step-1)
  2. I submit my choices (POST /wizard-complete-step-1)
  3. I get redirected to the next page (GET /wizard-view-step-2)
  4. I submit my choices (POST /wizard-complete-step-2)
  5. I get redirected to the next page (GET /wizard-view-step-3)
  6. I click my browser's back button (GET /wizard-view-step-2) <-- notice the skipping of the previous POST (no 4 above) and going directly to the last GET request (no 3 above), as per the Post/Redirect/Get pattern.
  7. I get redirected to the first page (GET /wizard-view-step-1)
  8. I click my browser's forward button (GET /wizard-view-step-3) <-- notice that my browser still remembers the page I've "already been to in the future" and takes me there.
  9. I get redirected to the first page (GET /wizard-view-step-1)

...however...

When I do this with BrowserKit, there are 2 major differences compared to my regular graphical browser:

A) History->back() doesn't follow "PRG" (Post/Redirect/Get) flows correctly. It only steps backwards 1 step in my history, not skipping the POST requests that returned a redirect (HTTP status 3xx).

B) Being redirected differently when going back clears "future history". In BrowserKit (assuming that I manually skip the POST requests), when I go back (no 6 above), get redirected (no 7) and then try to go forward again I get a \LogicException with You are already on the last page.

Here's a simplified unit test (for BrowserKit\History) to illustrate "B" above (assuming we're keeping PRG flows out of the equation for now):

    public function testBackAndForward()
    {
        $history = new History();

        $history->add(new Request('http://www.example.com/wizard-view-step-1', 'get'));
        $history->add(new Request('http://www.example2a.com/wizard-view-step-2', 'get'));
        $history->add(new Request('http://www.example2a.com/wizard-view-step-3', 'get'));

        $history->back();

        $history->add(new Request('http://www.example.com/wizard-view-step-1', 'get'));

        $history->forward();

        $this->assertSame(
            'http://www.example.com/wizard-view-step-3', 
            $history->current()->getUri(), 
            '->forward() returns the next request in the history'
        );
    }
@MPV

This comment has been minimized.

Copy link
Author

commented Oct 3, 2016

Here's one way of implementing support for the "back + forward" functionality (albeit not catering properly for Post/Redirect/Get flows yet):

@@ -45,9 +45,8 @@ class History
      */
     public function add(Request $request)
     {
-        $this->stack = array_slice($this->stack, 0, $this->position + 1);
-        $this->stack[] = clone $request;
-        $this->position = count($this->stack) - 1;
+        array_splice($this->stack, $this->position+1, 0, [clone $request]);
+        $this->position++;
     }

☝️ Here, with array_splice we just insert new requests at the current position, instead of only keeping previous requests (and discarding future ones) when adding new requests to the History.

@javiereguiluz

This comment has been minimized.

Copy link
Member

commented Jul 9, 2017

Closing it as fixed by #22341.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.