Firstly, there is absolutely nothing in Gherkin that prevents you from writing specifications in any order, you can even produce compound specifications such as
Given ...
When...
Then ...
When ...
Then ...
Given ...
When ...
Then ...
So why would you want to do this?
Well first lets consider a fourth variant of your scenario
Scenario: User logs in and buys a product
Given I am on the login screen
When I enter the valid username "myUsername"
And I enter the valid password "myPassword"
And I press the login button
Then I should see the login successful page
When I purchase the product "myProduct"
Then I should have "myProduct" in the product inventory
This is of course just a compound of 1 and 2. You might have written this because you had finished testing login and wanted to quickly write and test buying a product. You already have the code for the Binding
s in scenario one and now simply need to write the bindings for scenario two. You might consider this your simplest pragmatic change, and you will refactor it later. This nothing wrong with it, running the tests could be quicker, but also its not exactly ideal.
Now imagine that due to the nature of your shop you have written many tests that test different buying processes. We could be testing what happens when you add the same item again to your basket, or if you try to buy something out of stock, or different checkout experiences if you want special delivery. In fact your shop is so successful that you need to be really secure on the web and change your login process. Unfortunately you now have those three lines
Given I am on the login screen
When I enter the valid username "myUsername"
And I enter the valid password "myPassword"
repeated throughout your scenarios. If we accidentally break our login process with some bad code, suddenly all of our tests fail. You are presented with a wall of red and can't really narrow down where to start looking at the problems. Because we are dependant on logging in before we run our scenario we cannot isolate login from purchase.
This really is the difference between a Given
and a When
. A When
is there to indicate that we are performing a process, a Given
is a means of directly affecting the run time environment so that we simply have the correct state. It's basically the difference between
//Given
isLoggedIn = true
//When
if CheckValidPasswordForUser(user, password)
isLoggedIn = true
The Given
has no way to fail.
So coming all the way back to your original question,
Can you re-use Given
s as When
s? Yes, but it in the long term it will confuse you.
But if you ask Can you re-use When
s as Given
s? then I would definitely advise you not to. This will hide the fact that something that could break is being tested.
Finally there is one other thing to consider and that is the domain of your specification. Dan North has a really good article on this Whose Domain is it anyway?, but the general gist as applied to your example here is that when you are looking at product buying you can simply write
Given I am logged in as a customer
or
Given I am logged in as an administrator
because the username and password parts are to with login and not products, and that way you are protected from re-writing all your scenarios when you change your login process to use something else.