how effectively i can use ui automation recorded test cases for other releases of the application - selenium

I've web application, I want recorded test cases and play back that cases.
1st release of the application, I've login module which has user name and password and recorded 500 test cases for entire application. Among 500 test cases 200 test cases are using logging by username and password.
2nd release of the application, I've login module which has only username, so I want use previous recorded test cases by modifications not like go to all the test cases change the password field. Here I'm having some requirements for the testing framework
Can I get what are test cases will effect by changing field like in above example?
Is there any way to update in simple, not going like in all the files and changing
I've used different UI Automation testing tools and record & Play back options are very nice, but I could not find the way I want in the UI Automation test framework.
Is there any Framework available which does the job for me?
Thanks in advance.

This is a prime example of why you never should record a selenium test case. Whenever you want to update something like login you have to change them all.
What you should do is create a test harness/framework for your application.
1.Start with creating a class for each webpage with 1 function for each element you want to be able to reach.
public By username(){
return By.cssSelector("input[id$='username']"); }
2.Create helper classes where you create sequences which you use often.
public void login(String username, String password){
items.username().sendkeys(username);
items.password().sendkeys(password);
}
3.In your common test setup add your login function
#BeforeMethod(alwaysRun = true)
public void setUp() {
helper.login("user","password");
}
This give you the opportunity to programmaticly create your test cases. So for example if you want to use the same test cases for a different login module where password element is not present it could be changed like this.
items.username().sendkeys(username);
if(isElementPresent(items.password())
items.password().sendkeys(password);
The function "isElementPresent" could look like this
public boolean isElementPresent(By locator){
try {
driver.findElement(locator);
logger.trace( "Element " + stripBy(locator) + " found");
} catch (NoSuchElementException e) {
logger.trace( "Element " + stripBy(locator) + " not found");
return false;
}
return true;
}

Related

Selenium: Best way to test app-features with 2 different users (NUnit, C#)

Im looking for a clean way to test all features on the webpage with 2 different users.
One user is the admin, the second one a normal user.
Here is the overview of my selenium tests:
As you can see, we have 3 different features on the webpage:
UnlockInstruction
Tac
UploadCodes
Each of these features has its own Test class with its own webDriver so im able to run the tests in parallel.
Each of these test files, is calling the Login Class inside the SetUp.
What the Login Class is doing is:
Open Website with goToUrl
Gets the username and password which is stored in a Password Manager tool
Use selenium to enter username, password and click on login
Wait until page after login is loaded and go back to test methods
Everything works perfectly when i test it for one user. All the test run in parallel.
Now i want to test all the same features with the admin user.
The only way which comes into my mind is, to just create another Login class, which gets the other users credentials and copy also the 3 test classes, so all the 6 tests run in parallel.
But in my opinion its not clean, because i would copy 4 files which would have nearly 1:1 the same code.
I'd make the user id and password arguments to the fixtures.
Use a parameterized TestFixture (one with arguments)
Give the same argument types to the constructor so that NUnit can pass them to you.
Your four files will then result in six instances being constructed.
[TestFixture("normalUser", "normalUserPassword")]
[TestFixture("adminUser", "adminUserPassword")]
public class SomeFixture
{
private string User { get; }
private string Password { get; }
public SomeFixture(string user, string password)
{
User = user;
Password = password;
}
[OneTimeSetUp]
public void SetUpTheFixture()
{
// Create the driver
}
...
}
If you prefer to lookup the password, then just make the user id the only argument and look up the password when you need it.
[TestFixture("normalUser")]
[TestFixture("adminUser")]
public class SomeFixture
{
private string User { get; }
public SomeFixture(string user)
{
User = user;
}
[OneTimeSetUp]
public void SetUpTheFixture()
{
// Look up password
// Create driver
}
...
}

Assert name field of registration process with sendKeys java selenium

I have an automation running on a website with registration process.
I need to assert all fields on registration: name, email, pass, confirmPass.
If for example I run my test as follows it always fails since the Actual always remains empty. what am I missing here with the sendKeys ?
InsertXpathAndClick
InsertIDAndKeysToSend
etc are shortcuts to find elements and click or send keys (they operate as expected on other parts of my program)
#Test
public void TestAssertName() {
SingeltonDriver.driver.navigate().to("https://buyme.co.il");
SingeltonDriver.driver.manage().window().maximize();
SingeltonDriver.driver.manage().timeouts().implicitlyWait(7, TimeUnit.SECONDS);
InsertXpathAndClick("//*[#id=\"ember676\"]/div/ul[1]/li[3]/a/span[2]");
InsertXpathAndClick("//*[#id=\"ember650\"]/div/div[1]/div/div/div[3]/p/span");
SingeltonDriver.driver.manage().timeouts().implicitlyWait(5,TimeUnit.SECONDS);
//This is the interesting part of checking the name val that i sent VS the one that i get by getText.
InsertIDAndKeysToSend("ember1179", "Kate");
WebElement ActualName = SingeltonDriver.driver.findElement(By.id("ember1179"));
String ActualNameUpdated = ActualName.getText();
Assert.assertEquals("Kate", ActualNameUpdated);
}

Spring shell 2.0 how to read inputs with mask

Is there any way to mask user inputs in Spring Shell 2.0.x ?
I need to collect password from user.. did not find any shell api to do that.
Thanks!!
Found that LineReader#readLine(msg,mask) provides that option.
All you have to do is inject the LineReader bean.
If you don't want to rely on third party libraries, you can always do a standard Java console input, something like:
private String inputPassword() {
Console console = System.console();
return new String(console.readPassword());
}
Note though that when running this in an IDE, the System.console() might be null. So you should probably handle that if running in an IDE is something you want to support (for testing for example..) something like:
private String inputPassword() {
Console console = System.console();
// Console can be null when running in an IDE
if (console == null) {
System.out.println("WARNING - CAN'T HIDE PASSWORD");
return new Scanner(System.in).next();
}
return new String(console.readPassword());
}

TDD Best Practice In Using Restful Api in Yii application

I'm constantly looking for the best way to use TDD in Yii app development. Nowday most web app are composed by a fronted, an API layer (usually JSON) to provide async calls to the server and a backend. By my side, most used test in this of app are unit tests and functional ones. The latter the most widely showed in guides and books leverage PHPUnit + Selenium, but Behat + Mink seems very cool too (but I'm not really confident with it yet)
If you ever used functional tests that use a browser (like Selenium) you know that the less you have to run them the better you feel. This cause they're slower, harder to maintain and sometimes (like the popup FB Login using JS SDK) are painful.
When working with a single web page application I care about testing JSON output of my apis. I'd like to test these functionalities with a unit test like approach in order to have faster tests that are easier to maintain. Considering that most of my Controller's action are availaible to Logged only user using accessControl filter I wondered on the best ways to have my tests up and running.
At this moment I think to have two ways to accomplish this
use cUrl toward the desired enpoint to get the JSON directly invoke
the controller's function
In the first scenario I can use fixtures but I got no way to mock CWebUser class (to emulate a logged user), using Apache when the cUrl comes it gets executed by an instance of my CWebApplication that is not the one executed by PHPUnit. I can get rid of this problem by making all my API calls stateless and, as a consequence, removing accessControl filter.
In the second one the only way I found to mock CWebUser class is to override it in the test class that I'm executing. This approach pays until I dont need to test use cases requiring different type of user, and I got no way to change at runtime (or at setup time) my webuser mock. The only way I found to mock my webuser is the one you can find below, this cause $this->getMock('WebUser') doesnt affect anyway CWebApplication's WebUser (read-only) singleton defined in the configuration file.
Here comes a concrete example:
class UserControllerTest extends CDbTestCase
{
public $fixtures=array(
/* NEEDED FIXTURES*/
);
public function testUserCanGetFavouriteStore() {
$controller = new UserController(1);
$result = json_decode($controller->actionAjaxGetFavStore());
$this->assertInternalType('array', $result->data);
$model = $result->data[0];
$this->assertEquals($model->name, "Nome dello Store");
}
}
class WebUser extends CWebUser {
public function getId() {
return 1;
}
public function getIsGuest() {
return false;
}
};
I was wondering if being able to authenticate with the api interface, either by an API key or a user/password combo could be useful.
This is ok if I move toward a almost stateless API integration, but most of the time I just have controller's actions (permitted to logged user only) that returns Json data to populate the frontend.
Anyone can suggest me a better method? Maybe it's just useless to test this kind of JSON output?
Best Regards
Maybe I'm oversimplifying your problem. It sounds like you want to emulate user logins before running the test? If that's the case, why not just create a User object in your fixture and actually log them in before running a test, and log them out after?
Something like:
/**
* Sets up before each test method runs.
* This mainly sets the base URL for the test application.
*/
protected function setUp()
{
parent::setUp();
// login as registered user
$loginForm = new UserLoginForm();
$loginForm->email = USER_EMAIL; // use your fixture
$loginForm->password = USER_PASSWORD; // use your fixture
if(!$loginForm->login()) {
throw new Exception("Could not login in setup");
}
}
protected function tearDown()
{
parent::tearDown();
Yii::app()->user->logout(true);
}
Ok actually the only solution that me and my team found is creating a stub WebUser class.
Rewriting WebUser class in this way you can authenticate a user without having Yii relying on the session.
class WebUserMock extends WebUser {
public function login($identity,$duration=0)
{
$id=$identity->getId();
$states=$identity->getPersistentStates();
if($this->beforeLogin($id,$states,false))
{
$this->changeIdentity($id,$identity->getName(),$states);
$duration = 0;
if($duration>0)
{
if($this->allowAutoLogin)
$this->saveToCookie($duration);
else
throw new CException(Yii::t('yii','{class}.allowAutoLogin must be set true in order to use cookie-based authentication.',
array('{class}'=>get_class($this))));
}
$this->afterLogin(false);
}
return !$this->getIsGuest();
}
public function changeIdentity($id,$name,$states)
{
$this->setId($id);
$this->setName($name);
$this->loadIdentityStates($states);
}
// Load user model.
protected function loadUser() {
$id = Yii::app()->user->id;
if ($id!==null)
$this->_model=User::model()->findByPk($id);
return $this->_model;
}
};
In the setUp method of your test class you can login any user (in this case leveraging my fixtures)
//a piece of your setUp() method....
$identity = new UserIdentity($this->users('User_2')->email, md5('demo'));
$identity->authenticate();
if($identity->errorCode===UserIdentity::ERROR_NONE)
Yii::app()->user->login($identity);
As a final thing to do just override the user component in the test configuration file and tell him to use this one:
protected/config/test.php
'user'=>array(
'class' => 'application.tests.mock.WebUserMock',
'allowAutoLogin'=>false,
),
Still not sure that this is the best way to handle it but seems to work fine

Is it possible to skip tests if an element doesn't exists?

I'm writing a test script for a website. The website has tabs (navigation link).
Let's say, the element of that tab is id=email.
If that doesn't exist, is it possible to skip the whole test. All test cases are based on that tab (id=email).
Right now, I have:
if($this->isElementPresent("id=email") == true) {
perform these steps
}
And all the test scripts are like that, so it's just opening the browser and closing it without testing anything. It's passing them all. Is it possible to skip tests if that element doesn't exists?
I would configure the test to use the same setting to see if the fields exist or not, instead of skipping tests. Mock your configuration, and set to disabled, then the tests should look for the absence of the fields, and test accordingly. Then, set the configuration to be enabled, and test that the field is there and test accordingly.
When the field is set to be disabled, you can also use the $this->markTestSkipped(). It is documented in the PHPUnit help Chapter 9. Incomplete and Skipped Tests.
Sample:
public function testEmailIdAbsent()
{
if($this->MockConfiguration['Email'] == 'disabled') // Or however your configuration looks
{
$this->assertFalse($Foo->IsElementPresent("id=email", "Email ID is present when disabled.");
...
}
}
public function testEmailIdPresent()
{
if($this->MockConfiguration['Email'] == 'enabled') // Or however your configuration looks
{
$this->assertTrue($Foo->IsElementPresent("id=email", "Email ID is not present when enabled.");
...
}
}
public function testEmailId()
{
if($this->MockConfiguration['Email'] == 'disabled') // Or however your configuration looks
{
$this->markTestSkipped('Email configuration is disabled.');
}
}