I am trying to re-use a Geb Spec test I wrote in another Geb Spec so I won't need to re-write code. I always need the product number in different pages so I would like to do something similar to the following;
class BasePageGebSpec extends GebReportingSpec {
def firstProductOnBrowsePage(){
when:
to BrowsePage
then:
waitFor { BrowsePage }
productId { $("meta", 0, itemprop: "mpn").#content }
return productID // ???
}
}
And in another GebSpec I wish to use the above firstProductOnBrowsePage like below:
class ProductDetailsPageGebSpec extends BasePageGebSpec {
def "See first products details page"(){
when:
to ProductDetailsPage, productId: firstProductOnBrowsePage()
then:
waitFor { $("h2", class:"title").size() != 0 }
assert true
}
}
Any help would be appreciated,
Thank you!
With traits you can almost get what you want (tests don't work within a trait however). You might also consider creating a spec class that tests the product number for every page you have, and then not worrying about testing this functionality within each individual page's spec class.
trait BasePageGebSpec extends GebReportingSpec {
def testingFirstBrowse() {
waitFor { BrowsePage }
productId { $("meta", 0, itemprop: "mpn").#content }
return productID
}
}
class ProductDetailsPageGebSpec implements BasePageGebSpec {
def firstProductOnBrowsePage(){
when:
to BrowsePage
then:
testingFirstBrowse()
}
}
Add productId as content on the BrowsePage:
class BrowsePage extends Page {
static content = {
productId { $("meta", 0, itemprop: "mpn").#content }
}
}
and then use it in your spec:
class ProductDetailsPageGebSpec extends BasePageGebSpec {
def "See first products details page"(){
when:
to ProductDetailsPage, productId: to(BrowsePage).productId
then:
waitFor { $("h2", class:"title").size() != 0 }
}
}
Related
I am trying to write a simple test with GEB and Spock. Following is the Page and Spec test:
Page
import geb.Page
class DashboardPage extends Page {
static url = "?root=dashboard"
static at = { pageTitle.text() == "Dashboard Content Area" }
static content = {
pageTitle(wait: 25) { $("div#content-view-title>h1") }
leaderBoardPeriodCombo { $("#leaderboardPeriod") }
//manualsMenu { module(ManualsMenuModule) }
}
def selectLeaderBoardPeriod(periodValue) {
leaderBoardPeriodCombo.value(periodValue)
}
}
Spec Test:
import geb.spock.GebSpec
import pages.DashboardPage
class LeaderboardSpec extends GebSpec {
def "change LeaderBoard type value"() {
when: to DashboardPage
then: at DashboardPage
when: DashboardPage.selectLeaderBoardPeriod("monthly")
then: at DashboardPage
}
}
But i am getting the following error:
groovy.lang.MissingMethodException:
No signature of method: static pages.DashboardPage.selectLeaderBoardPeriod() is applicable for argument types: (java.lang.String) values: [monthly]
Possible solutions: selectLeaderBoardPeriod(java.lang.String)
at specs.LeaderboardSpec.change LeaderBoard type value(LeaderboardSpec.groovy:13)
Results :
Tests in error:
LeaderboardSpec.change LeaderBoard type value:13 MissingMethod No signature of...
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
The signature of the selectLeaderBoardPeriod it have a parameter. I tried to define explicitly the type as String but i am getting the same error.
Can someone spot what i am doing wrong?
Thank you in advance.
Best Regards
Your spec needs to be something like:
class LeaderboardSpec extends GebSpec {
def "change LeaderBoard type value"() {
when:
def page = to DashboardPage
and:
page.selectLeaderBoardPeriod("monthly")
then:
at DashboardPage
}
}
I am new to writing geb specs for funcational testing and appreciate your help with this issue. I am also new to Groovy, and the "Not Initialized" error might be to do with basic inexperience in that. I am trying to build a module to log me in automatically, at which point I can proceed with further tests, but I receive a geb.error.ModuleInstanceNotInitializedException. Previously, not using a module, I was able to log in to my page using only a spec. I was refactoring this to a module approach based on the answer on rcgeorge23's response here:
How to refactor common Geb test sequences.
The spec:
import spock.lang.Unroll
class FlowSpecs extends GebReportingSpec {
#Unroll
def "setup Spec"() {
given:
to QUserPage
when:
authModule.signIn("mwalle","password")
then:
assert { $("span", "class":"login-text z-label")[3].text() == "mwalle" }
}
the page:
package pages.app
import geb.Page
import AuthModule
class QUserPage extends Page {
static url = "/qsystem/quser"
static at = { title == "QSystem" }
static content = {
authModule { module AuthModule }
}
}
and the module:
import geb.Module
class AuthModule extends Module {
def idUser = js."zk.Widget.\$('\$usr').uuid" + "-real"
def idPass = js."zk.Widget.\$('\$pwd').uuid"
static content = {
loginUser { $("input", id:idUser) }
loginPass { $("input", id:idPass) }
loginButton { $("button",class:"login-button z-button")[0] }
}
void signIn(String username = "mwalle", String password = "password") {
loginUser.value(user)
loginPass.value(pass)
loginButton.click()
}
}
The full error is:
geb.error.ModuleInstanceNotInitializedException: Instance of module class AuthModule has not been initialized. Please pass it to Navigable.module() or Navigator.module() before using it.
at geb.Module.uninitializedException(Module.groovy:757)
at geb.Module.getJs(Module.groovy:96)
at AuthModule.<init>(AuthModule.groovy:5)
at geb.navigator.AbstractNavigator.module(AbstractNavigator.groovy:356)
at geb.content.NavigableSupport.module(NavigableSupport.groovy:207)
at geb.content.PageContentTemplateFactoryDelegate.module(PageContentTemplateFactoryDelegate.groovy:31)
at pages.app.QUserPage._clinit__closure2$_closure3(QUserPage.groovy:12)
at pages.app.QUserPage._clinit__closure2$_closure3(QUserPage.groovy)
at geb.content.PageContentTemplate.invokeFactory(PageContentTemplate.groovy:97)
at geb.content.PageContentTemplate.create_closure1(PageContentTemplate.groovy:59)
at geb.content.PageContentTemplate.create_closure1(PageContentTemplate.groovy)
at geb.content.PageContentTemplate.create(PageContentTemplate.groovy:82)
at geb.content.PageContentTemplate.get(PageContentTemplate.groovy:54)
at geb.content.DefaultPageContentSupport.getContent(DefaultPageContentSupport.groovy:42)
at geb.content.PageContentSupport.propertyMissing(PageContentSupport.groovy:39)
at geb.Page.propertyMissing(Page.groovy:112)
at geb.Browser.propertyMissing(Browser.groovy:216)
at geb.spock.GebSpec.propertyMissing(GebSpec.groovy:60)
at FlowSpecs.setup Spec(FlowSpecs.groovy:23)
The problem are these lines
def idUser = js."zk.Widget.\$('\$usr').uuid" + "-real"
def idPass = js."zk.Widget.\$('\$pwd').uuid"
js needs an initialized navigator, as you can see with at geb.Module.getJs(Module.groovy:96)
I would strongly advise to use another selector (css or otherwise) if you can instead of using javascript to lookup the id. If you cannot then move the lookup code into the content block.
static content = {
loginUser { $("input", id: js."zk.Widget.\$('\$usr').uuid" + "-real") }
loginPass { $("input", id: js."zk.Widget.\$('\$pwd').uuid") }
loginButton { $("button",class:"login-button z-button")[0] }
}
I work with tests on geb and I have problem. I need to save/print the address of the current page (function SaveUrl()).
Spock Test:
class TestSpec extends GebReportingSpec {
def "Google"() {
given: "go to google.com"
to GooglePage
when: "we at Google home page"
at GooglePage
then: "Search Yahoo"
Search("Yahoo")
SaveUrl()
}
}
GooglePage:
class GooglePage extends Page {
static url = "http://www.google.by"
static at = { $("title").text() == "Google"}
static content = {
theModule { module SearchModule }
}
def Search(String arg0) {
theModule.field.value(arg0)
theModule.search.click()
}
def SaveUrl() {
// need implement
}
}
Modile:
class SearchModule extends Module {
static content = {
field { $("input", name: "q") }
search { $("input", name: "btnK") }
}
}
Please help save/print current URL.
Thank You!
You can use the current url getter on WebDriver class. A WebDriver instance is stored as driver property on Browser. So in a Geb Spock test it is as simple as saying:
driver.currentUrl
EDIT
Since Geb 0.9.3 there is also a current url getter available on Browser.
I have a Page class as
class SignUpPage extends Page {
static url = "signup"
static at = { waitFor { title.startsWith("Join") } }
static content = {
firstNameField { $("input", name:"firstName") }
lastNameField { $("input", name:"lastName") }
emailField { $("input", name:"email") }
passwordField { $("input", name:"password") }
}
}
I want to add a populateFields method to this class. This will allow me to call this method to populate the text fields from my test cases. This method has one argument passed in - a Map that allows me to override certain field values as necessary from my test cases.
The problem is that I don't know how I can iterate over the 'content' of the page. To make this clearer look at the code below:
class SignUpPage extends Page {
static url = "signup"
// .. as defined above ..
def populateFields(customValues = [:]) {
// I want to iterate of the textFields here
// Something like...
textFields = this.metaclass.methods.findAll {
it.name.endsWith("Field")
}
textFields.each {
// populate with data
}
}
}
This doesn't work.
How do I get the content of the closure 'content'?
I think that there is a much easier way of implementing it and you don't need to iterate over contents of your page object. Given the keys in your map are name attributes of the inputs you want to modify, you can do the following:
def populateFields(customValues = [:]) {
def form = $('form') //can be any element that is enclosing all of your inputs
customValues.each { key, value ->
form[key] = value
}
}
Have a look at the section on form control shortcuts in the manual to understand how it works.
If content becomes too complicated to use the available tools you could always create a list of the page contents in your content.
static content = {
username { module $(... }
contactTitle { $(... }
contactGivenName { $(... }
contactFamilyName { moduleList $(... }
pageFields {
[
username,
contactTitle,
contactGivenName,
contactFamilyName,
]
}
}
def populateFields(valueList) {
pageFields.each {
it.value(somevaluefromList)
}
}
I have simple Groovy category class which adds method to String instances:
final class SampleCategory {
static String withBraces(String self) {
"($self)"
}
}
I want to use this category in my unit tests (for example). It looks like this:
class MyTest {
#Test
void shouldDoThis() {
use (SampleCategory) {
assert 'this'.withBraces() == '(this)'
}
}
#Test
void shouldDoThat() {
use (SampleCategory) {
assert 'that'.withBraces() == '(that)'
}
}
}
What I'd like to achieve, however, is ability to specify that category SampleCategory is used in scope of each and every instance method of MyTest so I don't have to specify use(SampleCategory) { ... } in every method.
Is it possible?
You can use mixin to apply the category directly to String's metaClass. Assign null to the metaClass to reset it to groovy defaults. For example:
#Before void setUp() {
String.mixin(SampleCategory)
}
#After void tearDown() {
String.metaClass = null
}
#Test
void shouldDoThat() {
assert 'that'.withBraces() == '(that)'
}
Now you have the option to use extension modules instead of categories:
http://mrhaki.blogspot.se/2013/01/groovy-goodness-adding-extra-methods.html
On the plus side Intellij will recognize the extensions. I've just noticed that it doesn't even need to be a separate module as suggested by the link, just add META-INF/services/org.codehaus.groovy.runtime.ExtensionModule to the project:
# File: src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
moduleName = module
moduleVersion = 1.0
extensionClasses = SampleExtension
The extension class is pretty much defined like a normal category:
class SampleExtension {
static String withBraces(String self) {
"($self)"
}
}
Can be used like:
def "Sample extension"() {
expect: 'this'.withBraces() == '(this)'
}
If you are using Spock there is a #Use annotation that can be used on the specifications. The drawback with that is that Intellij will not recognize it.