I have been using Geb and Spock along side with Spring Boot it's all fine untill I decided to use Geb Page classes. Below is my spec test class details
#SpringBootTest(webEnvironment =
SpringBootTest.WebEnvironment.RANDOM_PORT)
#ContextConfiguration
#Category(IntegrationTest.class)
class LoginSpec extends GebSpec{
#LocalServerPort
private int port
//....
}
The following test works
def "User should with valid username and password "() {
def username
def password
def loginUrl
given: "A valid username and password"
username = "user"
password = "password"
loginUrl = "http://localhost:" +port+"/hello"
when:
go loginUrl
then:
browser.page.title == "Login"
when:
$("#loginForm input[name=username]").value(username)
$("#loginForm input[name=password]").value(password)
$("#loginForm input[type=submit]").click()
then:
$("h1", text: iContains("Hello $username"))
}
I have defined the LoginPage class as the following
import geb.Page
class ModeledLoginPage extends Page{
static url = '/login'
static at = { title == "Login"}
static content = {
loginForm { $("#loginForm")}
formUsername { $("#loginForm input[name=username]") }
formPassword { $("#loginForm input[name=password]") }
formSubmitButton {
loginForm.find("input", type: "submit")
}
errors {
$(".alert-danger")
}
invalidUsernameOrPasswordError {
errors.filter(text:contains("Invalid username and/or password"))
}
}
}
When I do a sad path of the same test that worked above with the following:
def "User should not be able to login with wrong Username or Wrong Password " (){
def uname
def passwd
given: "A wrong username and a correct password"
uname = "wronguser"
passwd = "password"
baseUrl = "http://localhost:"+port
when: "User navigates to the login page"
to ModeledLoginPage
then:
at ModeledLoginPage
when: "User enters the wrong username and correct password and clicked on submbit button"
ModeledLoginPage.formUsername.value(uname)
ModeledLoginPage.formPassword.value(passwd)
ModeledLoginPage.formSubmitButton.click()
then: "We are redirected back to login page and there is an error message wrong: Invalid username and/or password "
at ModeledLoginPage
ModeledLoginPage.invalidUsernameOrPasswordError.present
}
I have the following error : groovy.lang.MissingPropertyException: No such property: formUsername for class: net.myname.tutorials.springbootsecurity.ModeledLoginPage at net.myname.tutorials.springbootsecurity.LoginSpec.User should not be able to login with wrong Username or Wrong Password (LoginSpec.groovy:80)
I am a little bit lost here not able to pin point where the issue is. I have checked various post on StackOverflow and the Geb Book.
Below are my dependencies:
dependencies {
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("com.h2database:h2")
testCompile("junit:junit")
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.security:spring-security-test')
testCompile 'org.spockframework:spock-spring:1.0-groovy-2.4'
testCompile 'org.codehaus.groovy:groovy-all:2.4.11'
testCompile "org.gebish:geb-core:2.1"
testCompile "org.gebish:geb-spock:2.1"
testCompile "org.seleniumhq.selenium:selenium-firefox-driver:3.6.0"
testCompile "org.seleniumhq.selenium:selenium-support:3.6.0"
}
Most grateful if anyone can shed some lights on this .Thanks
You should change your code to:
when: "User enters the wrong username and correct password and clicked on submbit button"
formUsername.value(uname)
formPassword.value(passwd)
formSubmitButton.click()
then: "We are redirected back to login page and there is an error message wrong: Invalid username and/or password "
at ModeledLoginPage
invalidUsernameOrPasswordError.present
See http://gebish.org/manual/current/#spock-junit-testng and http://gebish.org/manual/current/#the-page for an explanation.
If you wish to track current page type in order to get better authoring support from your IDE (mainly IntelliJ, see http://gebish.org/manual/current/#authoring-assistance-autocomplete-and-navigation), you might want to rewrite it to:
then:
def modeledLoginPage = at ModeledLoginPage
when: "User enters the wrong username and correct password and clicked on submbit button"
modeledLoginPage.formUsername.value(uname)
modeledLoginPage.formPassword.value(passwd)
modeledLoginPage.formSubmitButton.click()
then: "We are redirected back to login page and there is an error message wrong: Invalid username and/or password "
at(ModeledLoginPage).invalidUsernameOrPasswordError.present
Related
I want to get email address using social plugin of grails . I am using facebook plugin compile ':spring-security-oauth-facebook:0.1' and configured properly in Config.groovy like below.
oauth {
debug = true
providers {
facebook {
api = org.scribe.builder.api.FacebookApi
key = 'here is my-key'
secret = 'my-secret-key'
successUri = '/oauth/facebook/success'
failureUri = '/oauth/facebook/failure'
callback = "${baseURL}/oauth/facebook/callback"
scopes = "email"
}
}
}
After get successfully response, below method is called.
def onSuccess(String provider) {
if (!provider) {
log.warn "The Spring Security OAuth callback URL must include the 'provider' URL
parameter"
throw new OAuthLoginException("The Spring Security OAuth callback URL must include the
'provider' URL parameter")
}
def sessionKey = oauthService.findSessionKeyForAccessToken(provider)
if (!session[sessionKey]) {
log.warn "No OAuth token in the session for provider '${provider}'"
throw new OAuthLoginException("Authentication error for provider '${provider}'")
}
}
OAuthToken oAuthToken = springSecurityOAuthService.createAuthToken(provider,
session[sessionKey])
println "oAuthToken.principal = "+oAuthToken.principal.toString();
println "oAuthToken.socialId = "+oAuthToken.socialId;
println "oAuthToken.properties= "+oAuthToken.properties
println "oAuthToken.properties= "+oAuthToken.name
println "oAuthToken.properties= "+oAuthToken.toString();
How to get email address by using this. I successfully get response from facebook but it is same number for Username,socialId,profileId but i need email Address like myemailid#gmail.com
please help me.
I'm running a simple Geb test like so:
class IndexPage extends Page {
//static url = "http://localhost:8080/sampleGrailsApp"
static at = { title == "sampleGrailsApp" }
static content = {
signInButton { $("div", 0, class: "container-fluid").find("button", 0) }
modalFooterSignInButton(wait: true, to: MyPage) { $("footer", 0, class: "modal-footer").find("input", 0, class: "btn-primary") }
modalFooterUsernameInput { $("form").username = it }
modalFooterPasswordInput { $("form").password = it }
signIn { username, password ->
signInButton.click()
waitFor { modalFooterSignInButton.present }
modalFooterUsernameInput username
modalFooterPasswordInput password
modalFooterSignInButton.click()
}
}
}
In my test, the page is called as follows:
def "sigin"() {
given: "User is at index page"
at IndexPage
when: "User signs in"
signIn "username","password"
then: "Goes to MyPage"
at MyPage
}
On some occasions, the modalFooterSignInButton.click() happens before the username has been entered completely therefore failing the test. Has anyone encountered this before? How do I wait for input to complete first before click is activated? I'm using Geb 0.9.2.
Thanks in advance.
Try using isDisplayed() instead of present as present means is present in the code but isDisplayed() means it appears in the UI. Hope the following stuffs would solve your problem!
waitFor { modalFooterSignInButton.isDisplayed()}
Also, use waitFor{} in case of critical situations as I don't know anything about your app.
You could do something like :
waitFor { $(<username-input>).text().contains("username") } // after username is entered.
waitFor { $(<password-input>).text().contains("password") } // after password is entered.
before calling modalFooterSignInButton.click()
Also, is this behavior specific to any browser or it happens in all the browsers?
I am trying to send an email from a grails app. I tried with recommended settings using gmail and it worked fine. I sent mail successfully. But I want to override the username and password dynamically. I don't know how can I do it. Can anybody help?
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "faruq#gmail.com" // Want to change dynamically like variable ${branch.mail}
password = "12345" // Want to change dynamically like variable ${branch.pass}
props = [
"mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"
]
}
}
I use this process for overriding the username from the controller
grailsApplication.config.grails.mail.username = Branch.get(2).mail
by this process username successfully changes
here Branch is my domain class and mail is property
but an authentication problem comes up:
javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted
Now what can I do?
You can use an external configuration file - put placeholder values in the main Config.groovy
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "<changeme>"
password = "<changeme>"
props = [
"mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"
]
}
}
and then override them with the correct values in the external config:
grails {
mail {
username = "faruq#gmail.com"
password = "12345"
}
}
To be able to change the credentials dynamically at run time it gets rather more complicated. Under the covers the mail plugin creates a Spring bean which is an instance of JavaMailSenderImpl to handle the actual sending of emails, and this bean is configured by default with static settings from the config. But at runtime this class appears to call its own getUsername() and getPassword() every time it needs to send a message. So you could replace this bean with your own custom subclass of JavaMailSenderImpl that overrides these methods to pull the details from the request context (code example, not tested, and imports/error handling omitted):
src/groovy/com/example/RequestCredentialsMailSender.groovy
class RequestCredentialsMailSender extends JavaMailSenderImpl {
public String getUsername() {
return RequestContextHolder.requestAttributes?.currentRequest?.mailUsername ?: super.getUsername()
}
public String getPassword() {
return RequestContextHolder.requestAttributes?.currentRequest?.mailPassword ?: super.getPassword()
}
}
You'd have to register this bean in your resources.groovy, and duplicate a fair bit of the configuration from the mail plugin itself, which is less than ideal:
grails-app/conf/spring/resources.groovy
beans = {
mailSender(com.example.RequestCredentialsMailSender) {
def mailConf = application.config.grails.mail
host = mailConf.host
port = mailConf.port
username = mailConf.username // the default, if not set in request
password = mailConf.password
protocol = mailConf.protocol
javaMailProperties = mailConf.props
}
}
Now when you need to send mail from a controller you can do
request.mailUsername = Branch.get(2).mail
request.mailPassword = Branch.get(2).mailPassword
sendMail { ... }
Just wanted to verify Ian's answer and expand it.
In the default Config.groovy file I have the added external config line:
grails.config.locations = [
"file:./${appName}-config.groovy",
"classpath:${appName}-config.groovy"
]
....
// and here is the mail config as above
grails{
mail{
....
In the config file at the root level I have my config file: TestApp-config.groovy (where TestApp is the name of my app) as above:
grails {
mail {
username = "faruq#gmail.com"
password = "12345"
}
}
Didn't need anything past this and it worked great.
We can also use replyTo field if our aim is only to get the reply back on specific Email Id. We can dynamically pass an email id to "replyTo" field and can expect an email back on the same.
Example :
asynchronousMailService.sendMail
{
to ["xyz#gmail.com","pqr#gmail.com"]
subject "Subject Text"
if(ccs) cc ["xyz1#gmail.com","pqr1#gmail.com"]
if(bccs) bcc ["xyz2#gmail.com","pqr2#gmail.com"]
if(replyTo) replyTo "xyz#gmail.com"
if(attachBytes) attachBytes attachBytes
}
NOTE: Adding "replyTo" will only allow us to get the emails back on the specified email-id and will not send the email from the configured email.
It was suitable in my use case. Hope it helps !
I'm trying to write a simple Geb/Spock test using Grails but I am receiving the following test failure.
| Failure: login works correctly(...UserAuthAcceptanceSpec)
| Condition not satisfied:
at HomePage
|
null
I can follow the test through with a debugger using a browser and can see that the application works as expected and the correct heading is being shown. However, the test is failing when I try to invoke the at checker. Can anyone tell me why the final assertion in the test might be failing and why the 'at' checker appears to be null?
Here is my code: (Geb v0.9.0, Grails 2.2.2)
Spock Specification:
class UserAuthAcceptanceSpec extends GebReportingSpec {
def "login works correctly"() {
given: "the correct credentials"
def theCorrectUsername = "admin"
def theCorrectPassword = "password"
when: "logging in"
to LoginPage
username = theCorrectUsername
password = theCorrectPassword
submitButton.click() //([HomePage, LoginPage])
then: "the welcome page is shown"
heading =~ /(?i)Welcome.*/ // <- same as 'at' checker in HomePage
and: "the 'at' checker works"
at HomePage // <- fails
}
LoginPage:
class LoginPage extends Page {
final String path = "/login/auth"
static content = {
heading(required: false, wait:true) { $("h1").text() }
username { $("input", name:"j_username") }
password { $("input", name:"j_password") }
submitButton { $("input", id:"submit") }
}
static at = {
title =~ /Login.*/
}
}
HomePage:
class HomePage extends Page {
final String path = "/"
static content = {
heading(required: false, wait:true) { $("h1").text() }
}
static at = {
heading =~ /(?i)Welcome.*/
}
}
The at checker should use ==~ rather than =~.
Geb's implicit assertions mean the statements:
heading1 =~ /(?i)Welcome.*/
heading2 ==~ /(?i)Welcome.*/
effectively become:
assert (heading1 =~ /(?i)Welcome.*/) == true // [1]
assert (heading2 ==~ /(?i)Welcome.*/) == true // [2]
[2] will evaluate to a boolean and pass/fail as expected, whereas [1] evaluates to a java.util.regex.Matcher causing the failure.
See the Groovy Regex FAQ for an explanation of the difference between the two syntaxes.
I have this plugin installed, I want to send mails from a Service/Domain class method , I was doing like this
class TrainingService {
def mailService
public def sendMail() {
mailService.sendMail {
multipart true
to "abc#xyz.com"
subject "Hello,"
body 'How are you?'
}
}
I got error "Cannot invoke method sendMail() on null object", How to resolve this
I am missing the "from" attribute and if you're using multipart email, you should also fill in additional parts of the email, snippet from my code:
mailService.sendMail {
multipart true
from '"Some account" <someaccount#email.com>'
to 'anotheremail#somedomain.com'
bcc emailAddresses.toArray()
subject dto.title
body emailPart1
html g.render(
template: 'emailNotification',
model: [ name: dto.name ]
)
}
Have you configured your SMTP server. You need these entries in your config file for mail to work. Do you have these ?
grails {
mail {
host = "hostname"
pop_port = 25
username = "username"
password = "password"
type = "pop3"
}
}
you can find more information about the configuration here
I got this error when I was passing variables called 'from' and 'to' into the method that was using sendMail. Try renaming the sendMail method and making sure that you don't have any conflicting variable names.