I've configured some geb
tests to check a different messages depending on the login attempt in my web app. Since the message and the input fields will change at the third login attempt.
The login is a two step login based on password send to a specific phone number, so in the first page LoginPage the user introduces their Id and phoneNumber, then it's redirected to the second page ValidationLoginPage where the user introduces the received password.
I want to check that in the second page the user can only introduces three bad passwords and at fourth attempt the input to introduce a password will disappear and a different message indicating that there are no more attempts it's showed.
To check this I prepared a test which introduces the Id and phoneNumber at the given:
clause, and using where:
clause it introduces a bad password three times. Since where:
repeat all test I try to control the part to repeat using injected variable like in where:
so I've something like:
def "Test max loging attempts"(){
given:
if(loginAttempt == 1)
to LoginPage
loginModule.startLogin(cfg.user.id,cfg.user.phone)
}
when:
at LoginValidationPage
assert $('div.box_id_header h3').text() == 'Verify your code'
assert $('#code').css('display').contains('block')
loginModule.verifyPassword('WRONGPASSWORD')
then:
at LoginValidationPage
println "Attempt ${loginAttempt}"
if(loginAttempt == 4){
// last attempt
assert $('#code').css('display') == 'none'
assert $('#divCodeErrorMsg').text().contains('No more attempts')
}else{
assert $('#code').css('display').contains('block')
assert $('#divCodeErrorMsg').text().contains('Wrong password. Try again.')
}
where:
loginAttempt << (1..4)
}
My problem is, that cookies
are cleared for each where:
iteration, thought the message and the behavior is not which I expect. I don't want to configure autoClearCookies=false
in GebConfig.groovy
file since I've another tests where this feature is necessary. There is a way to avoid the clear cookies for this method using spock def setupSpec() {}
method and reactivate in def cleanupSpec() {}
method?
Additionally it's also possible to use where:
in a cleaner way avoiding to check the loginAttempt
variable to avoid run given:
part multiple times, or there is a better approach not using where:
at all?
The problem is that you maybe misunderstand and thus abuse Spock's where:
block. It is designed to parametrise a feature method and each run of that method comprises an independent feature. If you @Unroll
your feature, even for each set of where:
parameters a new method is generated. Because features should be independent of each other and theoretically be able run run in any given order or even in parallel, test fixtures need to be reset in order to run them. This is what happens with your cookies because you abuse the where:
feature to implement a simple loop.
There are other little problems in your code, such as the non-asserted at
check in the when:
block. Even if at
yields false
, it has no consequence there if you do not use assert
. You can only skip assert
in then:
or expect:
blocks, but not in given:
or when:
and also not inside closures or helper methods which I will both use in my sample code.
How about this?
package de.scrum_master.stackoverflow.foo
import geb.spock.GebReportingSpec
class LoginTest extends GebReportingSpec {
def loginModule = new LoginModule()
def cfg = new Config()
def "Test max login attempts"() {
given: "we are at the login page"
browser.config.autoClearCookies = false
to LoginPage
when: "logging in 4x with wrong credentials"
(1..4).each {
loginWithWrongCredentials(it, it < 4)
}
then: "we get a 'no more attempts' error message"
$('#codi').css('display') == 'none'
$('#divCodiValidacioError').text().contains('No more attempts')
}
def loginWithWrongCredentials(int loginAttempt, boolean checkForWrongPasswordMessage) {
println "Login attempt ${loginAttempt}"
loginModule.startLogin(cfg.user.id, cfg.user.phone)
assert at(LoginValidationPage)
assert $('div.box_id_header h3').text() == 'Verify your code'
assert $('#code').css('display').contains('block')
loginModule.verifyPassword('WRONGPASSWORD')
assert at(LoginValidationPage)
if (checkForWrongPasswordMessage) {
assert $('#codi').css('display').contains('block')
assert $('#divCodiErrorMsg').text().contains('Wrong password. Try again.')
}
}
}
I would also recommend to move the content asserts from loginWithWrongCredentials
into helper methods of LoginValidationPage
where they rather belong and just call them from the test.