I am getting the following error when trying to run a geb test as a part of a Maven build in Eclipse:
Scenario: Perform login Time elapsed: 0.009 sec <<< FAILURE!
geb.error.RequiredPageContentNotPresent: The required page content 'userName - SimplePageContent (owner: LoginPage, args: [], value: null)' is not present
The only pattern to the error seems to be that it is thrown every time I try to use the geb selector to select/find some page content, but using the selector should work out-of-the-box, right?
I am using the following tools and libraries:
Eclipse Mars Java EE ID (version: 4.5.1)
geb (version 0.12.2)
Selenium (version 2.48.2)
Groovy (version 2.4.5)
Cucumber (version 1.2.4)
Here is my .feature file:
Feature: Login
Scenario: Perform login
Given the user is at the login page
When the user enters <some_uid> and <some_pwd>
Then the user should be logged in
Here is my steps definition:
package stepdefs
import pages.LoginPage
import static cucumber.api.groovy.EN.*
Given(~"the user is at the login page") { ->
to LoginPage
assert at(LoginPage)
}
When(~"the user enters (.*) (.*)") { user, password ->
at LoginPage
page.doLogin(user,password)
}
Then(~"the user should be logged in"){ ->
assert at(LoginResultPage)
}
Here is my page definition:
package pages
import geb.Page
class LoginPage extends Page {
static url = "/TSADG_BORGER/loginpin.do"
static at = { title == "TastSelv Borger" }
static content = {
loginForm { $($/form/$,id:"mainForm") }
userName { loginForm.find("input",id:"pnr") }
pass { loginForm.find("input",id:"tastselvKode") }
buttonLogin { loginForm.find("input",id:"bt1") }
}
def doLogin(user, password) {
userName = user
pass = password
buttonLogin.click()
}
}
Here is the HTML for the form:
<form id="mainForm" action="/TSADG_BORGER/loginpin.do" role="form" method="post" autocomplete="off">
<input type="hidden" name="dispatch" value="Valider">
<div class="row skts-centered-padding">
<div class="col-sm-12">
<h1>Log på med TastSelv-kode</h1>
</div>
<div class="col-sm-6">
<div class="skts-process-form-section skts-required ">
<p><label for="pnr">Cpr-nummer</label></p>
<div>
<input id="pnr" type="text" value="" class="form-control skts-required-val" name="pnr" size="16" maxlength="14" data-validation-event="blur" data-show-type="string" data-show-facets="pattern" data-show-facet-values="/(^\d{10}$)|(^\d{6}\-\d{4}$)/" aria-required="true" aria-invalid="false" aria-describedby="pnrError " autocomplete="off">
</div>
</div>
<div class="skts-process-form-section skts-required">
<p><label for="tastselvKode">TastSelv-kode</label></p>
<div>
<input id="tastselvKode" type="password" value="" class="form-control skts-required-val" name="tastselvKode" size="16" maxlength="16" data-show-type="string" data-show-facets="pattern" data-show-facet-values="/^[^]{7,16}$/" data-validation-event="blur" aria-required="true" aria-invalid="false" aria-describedby="tastSelvKodeError " autocomplete="off">
</div>
</div>
<br>
<p>
<input type="submit" id="bt1" class="btn btn-primary skts-validate" value="Fortsæt" autocomplete="off">
</p>
</div>
</div>
</form>
Any help and input is appreciated.
I would rearrange your content section a bit:
static content = {
loginForm { $("form#mainForm"") }
userName { $("input#pnr") }
pass { $("input#tastselvKode") }
buttonLogin { $("input#bt1") }
}
Use jQuery selectors in Geb! They are very handy. Note that if you use unique ids $("#mainForm"") will have the same effect as $("form#mainForm""). First version is easier, second is more expressive ;)
More info: http://www.w3schools.com/jquery/jquery_ref_selectors.asp
And: http://www.gebish.org/manual/current/#the-jquery-ish-navigator-api
The problem has been resolved.
I was so convinced that it had to be a problem with the selectors, so it took me a while to get my head out of the sand and take a step back. When I did that, I realised that the URL in the "LoginPage" class actually did a redirect to another page, which I was not expecting. The page I was redirected to did obviously not contain any of the objects I was looking for in my contents section. So, when the error message stated that "The required page content...is not present", then that was absolutely correct.
Really silly mistake on my part...
Related
I am trying to create a custom register view/form and have it work with auth.register(), but so far I've had no luck. I mainly have two problems.
If I don't include response.view = 'register.html' in my controller the link register.html defaults to web2py's default register page (which works, but I don't want to use).
If I removed the response.view = 'register.html' from my controller func, then my custom form/view appears, but doesn't submit/validate. It just keeps popping the on-fail message "Oops something went wrong submitting the form"
Every thread I've read about this just says to specify the form=auth.register() in the controller and use the {{=form.custom.end}} in the view, but that doesn't seem to work. Am I missing something?
I also tried specifying the callback action for the form to action="{{=URL('default', 'register')}}, but if I add this the page won't do anything on submit either.
Here's my code:
Controller: (In default.py)
def register():
response.view = 'register.html'
db.auth_user.first_name.readable = db.auth_user.first_name.writable = False
db.auth_user.last_name.readable = db.auth_user.last_name.writable = False
return dict(form=auth.register())
View (default/register.html)
<body class="body-4">
<div class="form-block w-form">
<form id="email-form" name="email-form" data-name="Email Form">
<h1 class="heading-5">Register</h1>
<input type="email" class="text-field w-input" maxlength4="256" name="Email" data-name="Email" placeholder="Enter your email" id="Email" required="">
<input type="password" class="text-field w-input" maxlength="256" name="Password" data-name="Password" placeholder="Enter your password" id="Password" required="">
<input type="password" class="text-field w-input" maxlength="256" name="Password-2" data-name="Password 2" placeholder="Confirm your password" id="Password-2" required="">
<input type="submit" value="Register" data-wait="Please wait..." class="submit-button w-button">
{{=form.custom.end}}
<div class="w-form-done">
<div>Thank you! Your submission has been received!</div>
</div>
<div class="w-form-fail">
<div>Oops! Something went wrong while submitting the form.</div>
</div>
</div>
<script src="{{=URL('static','js/webflow.js')}}" type="text/javascript"></script>
<!-- [if lte IE 9]><script src="https://cdnjs.cloudflare.com/ajax/libs/placeholders/3.0.2/placeholders.min.js"></script><![endif] -->
</body>
You need to put the viewer code into the file default/register.html instead of register.html .
Then it works for me. You can see the resulting entry in the database.
How to validate a form in angular 4 by clicking on external link (ie out side from tag). If the form is valid do some actions with form data else show validation messages. If form is valid I don't want to submit the form just need to get the form field values.
This is my answer post to another question:
The easy way is to use reactive forms, like this:
Code:
import {ReactiveForm, FormBuilder, Validators} from '#angular/form';
export class SignupFormComponent implements OnInit {
userForm: FormGroup;
firstName: string;
constructor(private _formBuilder:FormBuilder){}
ngOnInit() {
this.userForm = this._formBuilder.group({
'firstName': ['',[Validators.required,Validators.minLength(5)]]
});
}
onSubmit() {
console.log(this.firstName);
}
}
HTML:
<form [formGroup]="userForm" (ngSubmit)="onSubmit()" name="userForm">
<div class="form-group">
<label>First Name</label>
<input type="text" [(ngModel)]="firstName" class="form-control" formControlName="firstName">
<p *ngIf="userForm.controls.firstName.invalid && (userForm.controls.firstName.dirty || userForm.controls.firstName.touched)"> Error message </p>
</div>
<button type="submit" class="btn btn-primary" [disabled]="userForm.invalid">Submit </button>
</form>
I am new to Angular 2.
I have created a simple template which has two text field, I want to required field validate those two fields.
Login Form
<form #loginForm="ngForm" (ngSubmit)="onSubmit(loginForm)" novalidate>
<div class="container">
<div class="form-group">
ooooo <label><b>Username</b></label>
<input type="text" placeholder="Enter Username" name="uname" required [(ngModel)]="UserData.uname" #uname="ngModel">
<div *ngIf="loginForm.invalid" class="alert alert-danger">
<div [hidden]="!uname.errors.required"> Name is required </div>
</div>
</div>
<div class="form-group">
<label><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="pwd" required [(ngModel)]="UserData.pwd" #pwd="ngModel">
<div *ngIf="UserData.pwd.errors && (UserData.pwd.dirty || UserData.pwd.touched)" class="alert alert-danger">
<div [hidden]="!UserData.pwd.errors.required">Password is required </div>
</div>
<button type="submit" >Login</button>
</div>
</div>
</form>
My Component
import { Component } from "#angular/core"
import { User } from "./UserModel"
#Component({
selector: 'my-login',
templateUrl:"app/Login/login.html"
})
export class LoginComponent
{
//alert: any("hello");
UserData: User = new User("", "");
submitted = false;
onSubmit(form: any) {
alert("dfsdfsd" + form);
if (!form.invalid) {
alert(this.UserData.uname);
alert(this.UserData.pwd);
this.submitted = true;
}
}
}
What i want to implement is-
When the form loads no validation message should appear?
When user clicks on the submit button then the required message should appear?
In both the textbox i have applied different type of checks to show the message that is inconsistent? so there should be a consistent way to solve this.
Many thanks for the help.
Maybe make use of the submitted variable, and use that in template, to not show message, until submitted is true, which we set it as in the submit function.
Also you wouldn't really need the two-way-binding here, since the object your form produces is directly assignable to your UserData.
The validation messages I'd just set then simply like this, where we are targeting the username:
<div *ngIf="uname.errors?.required && submitted"> Name is required </div>
in your submit function I'd pass loginForm.value as parameter instead of just loginForm. This way you get the form object ready to be used :)
And in your function you can assign the object to your UserData variable.
onSubmit(form: any) {
this.submitted = true;
this.UserData = form;
}
If you do want to keep the two-way-binding, it's of course totally possible! :)
DEMO
I have a template based form in my Angular2 app for user registration. There, I am passing the form instance to the Submit function and I reset the from once the async call to the server is done.
Following are some important part from the form.
<form class="form-horizontal" #f="ngForm" novalidate (ngSubmit)="onSignUpFormSubmit(f.value, f.valid, newUserCreateForm, $event)" #newUserCreateForm="ngForm">
<div class="form-group">
<label class="control-label col-sm-3" for="first-name">First Name:</label>
<div class="col-sm-9">
<input type="text" class="form-control" placeholder="Your First Name" name="firstName" [(ngModel)]="_userCreateForm.firstName"
#firstName="ngModel" required>
<small [hidden]="firstName.valid || (firstName.pristine && !f.submitted)" class="text-danger">
First Name is required !
</small>
</div>
</div>
.......
.......
<div class="form-group">
<div class="col-sm-offset-3 col-sm-12">
<button type="submit" class="btn btn-default">Submit</button>
<button type="reset" class="btn btn-link">Reset</button>
</div>
</div>
</form>
In my component file, I have written following function.
onSignUpFormSubmit(model: UserCreateForm, isValid: boolean, form: FormGroup, event:Event) {
event.preventDefault();
if (isValid) {
this._userEmail = model.email;
this._authService.signUp(this._userCreateForm).subscribe(
res => {
console.log("In component res status = "+res.status);
if(res.status == 201){
//user creation sucess, Go home or Login
console.log("res status = 201");
this._status = 201;
}else if(res.status == 409){
//there is a user for given email. conflict, Try again with a different email or reset password if you cannot remember
this._status = 409;
}else{
//some thing has gone wrong, pls try again
this._serverError = true;
console.log("status code in server error = "+res.status);
}
form.reset();
alert("async call done");
}
);
}
}
If I submit an empty form, I get all validations working correctly. But, when I submit a valid form, Once the form submission and the async call to the server is done, I get all the fields of the form invalid again.
See the following screen captures.
I cannot understand why this is happening. If I comment out form.reset(), I do not get the issue. But form contains old data i submitted.
How can I fix this issue?
I solved this By adding these lines:
function Submit(){
....
....
// after submit to db
// reset the form
this.userForm.reset();
// reset the errors of all the controls
for (let name in this.userForm.controls) {
this.userForm.controls[name].setErrors(null);
}
}
You can just initialize a new model to the property the form is bound to and set submitted = false like:
public onSignUpFormSubmit() {
...
this.submitted = false;
this._userCreateForm = new UserCreateForm();
}
You need to change the button type submit to button as following.
<div class="form-group">
<div class="col-sm-offset-3 col-sm-12">
<button type="button" class="btn btn-default">Submit</button>
<button type="reset" class="btn btn-link">Reset</button>
</div>
</div>
Reseting the form in simple javascript is the solution for now.
var form : HTMLFormElement =
<HTMLFormElement>document.getElementById('id');
form.reset();
this is how finally I had achieved this. I am using Angular5.
I have created a form group named ="firstFormGrop".
If you are not using form groups you can name the form as follow:
<form #myNgForm="ngForm">
In the html doc:
<form [formGroup]="firstFormGroup">
<button mat-button (click)='$event.preventDefault();this.clearForm();'>
<span class="font-medium">Create New</span>
</button>
</form>
In the .ts file:
this.model = new MyModel();
this.firstFormGroup.reset();
if you where using #myNgForm="ngForm then use instead:
myNgForm.reset();
// or this.myNgForm.reset()
This is a very common issue that after clicking the reset button we created the validators are not reset to its initial state, and it looks ugly.
To avoid that we have two options,the button is outside the form, or we prevent the submission when the button is tagged inside the form.
To prevent this default behaviour we need to call $event.preventDefault() before whatever method we are choosing to clear the form.
$event.preventDefault() is the key point.
The solution:
TEMPLATE:
<form
action=""
[formGroup]="representativeForm"
(submit)="register(myform)"
#myform="ngForm"
>
*ngIf="registrationForm.get('companyName').errors?.required && myform.submitted"
COMPONENT:
register(form) {
form.submitted = false;
}
Try changing the button type from "submit" to "button", e.g. :
<button type="button">Submit</button>
And move the submit method to click event of the button. Worked for me!
I'm a beginner in the AngularJs and MongoDb world (i started learning today!!)
Actually i'm trying to do something very basic : Display a list of record, with an add button and a edit link with each record.
I'm using this lib https://github.com/pkozlowski-opensource/angularjs-mongolab to connect to mongoweb.
Actually my data is displayed, when i try to add a record it works, but the problem is when i try to display the edit form!
Here is my index.html file, in which i display the data with a form to add a record and with the edit links :
<div ng-controller="AppCtrl">
<ul>
<li ng-repeat="team in teams">
{{team.name}}
{{team.description}}
edit
</li>
</ul>
<form ng-submit="addTeam()">
<input type="text" ng-model="team.name" size="30" placeholder="add new team here">
<input type="text" ng-model="team.description" size="30" placeholder="add new team here">
<input class="btn-primary" type="submit" value="add">
</form>
</div>
And here is my edit.html code, which displays an edit form :
<div ng-controller="EditCtrl">
<form ng-submit="editTeam()">
<input type="text" name="name" ng-model="team.name" size="30" placeholder="edit team here">
<input type="text" name="description" ng-model="team.description" size="30" placeholder="edit team here">
<input class="btn-primary" type="submit" value="validate edit">
</form>
</div>
And finally my js code:
var app = angular.module('app', ['mongolabResource']);
app.constant('API_KEY', '____________________________');
app.constant('DB_NAME', 'groups');
app.factory('Teams', function ($mongolabResource) {
return $mongolabResource('teams');
});
app.controller('AppCtrl', function ($scope, Teams) {
$scope.teams = Teams.query();
$scope.addTeam = function() {
varteam = {
name: $scope.team.name,
description: $scope.team.description
};
$scope.teams.push(varteam);
Teams.save($scope.team);
$scope.team.name = '';
$scope.team.description = '';
};
});
app.controller('EditCtrl', function ($scope, Teams) {
//????????
});
My AppCtrl works perfecty, it displays the data w add records perfectly.
Now i want to add the js code for the edit, but i don't even know form where to start ? how do i a get the id parameter in the url ? how do i tell the view to fill out the form fields from the values from the database ? And finally how do i update the databse.
I know that i asked a lot of question but i'm really lost! thank you
There are of course many possible solutions.
One solution is to use angularjs routing. See http://docs.angularjs.org/tutorial/step_07 for a tutorial.
Basically replace your ul list with something like:
<ul>
<li ng-repeat="team in teams">
{{team.name}}
{{team.description}}
edit
</li>
</ul>
Then you can create a route that responde to your url:
yourApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/teams', {
templateUrl: 'partials/team-list.html',
controller: 'TeamListCtrl'
}).
when('/teams/:teamId', {
templateUrl: 'partials/team-detail.html',
controller: 'TeamDetailCtrl'
}).
otherwise({
redirectTo: '/teams'
});
}]);
In this way from the detail controller (that will replace your EditCtrl) you can access the id parameter using: $routeParams.teamId
Anyway I suggest to study well all the tutorials for a better overview.