How to call another test during my test in Cypress - automation

I have a problem when creating test with Cypress
I am creating a test to which is required that the user should be in logged on his account to be able to run the test.
I have another test to test the log in function.
How can I run the test (Create account) so i dont need to have the code in the beginning of every test to log in first as in the example.
I start always with the log in script before I run the test.As u see I have the username and the password for each test.
I want to be able to run the log in first and then the rest.
cy.visit('https://devcloudarena.devtest.fastighet.vitec.se/test/mina-sidor/logga-in')
cy.contains('Mina sidor').click()
cy.contains('Logga in').click()
cy.get('#UserId').click();
cy.get('#UserId').type('19380412-6526');
cy.get('#Password').click();
cy.get('#Password').type('Vitec.Test20');
cy.get('.ml-auto > .button').click();
cy.wait('#getActivities').then((xhr) => { });
cy.url().should('contains', 'https://devcloudarena.devtest.fastighet.vitec.se/test/mina-sidor');
cy.get('.d-block .col-9').click();
cy.url().should('contains', 'https://devcloudarena.devtest.fastighet.vitec.se/test/mina-sidor/min-profil');
cy.get('.object-description-cc > a').click();
cy.url().should('contains', 'https://devcloudarena.devtest.fastighet.vitec.se/test/mina-sidor/uppdatera-kontaktuppgifter');
cy.get('.form-group > .button').click();
cy.get('#RegisterForm').submit();
cy.url().should('contains', 'https://devcloudarena.devtest.fastighet.vitec.se/test/mina-sidor');

You can put it as a Custom command and it will be reusable in every test with a simple command call.

To add to Rosen Mihaylov's answer, the user could convert the login script into a custom command and also use hooks to implement the pre-condition of the test by calling that specific custom command.
custom command pertaining to support/command.js
Cypress.Commands.add('login', (email, pw) => {})
using the custom command in the spec file
beforeEach(() => {
cy.login()
})

Related

Unable to call a function from Fixture.before Method

I am trying to implement a fixture with multiple tests where all depend on each other
Therefore I want to clean the Database and perform login only one time from the Fixture.before Method
So it will look like this:
fixture `testProject`.page(baseUrl)
.before(async t => {
await loginPM.login()
await base.clearDB()
})
.beforeEach(async t => {
// some steps before each test
})
test 1
test 2
test 3
This scenario throws the following exception:
Error in fixture.before hook - Cannot implicitly resolve the test run in the context of which the test controller action should be executed. Use test function's 't' argument instead
Any ideas why testcafe not support calling functions from a Fixture.before Method
The fixture.before hook runs between tests and doesn't have access to the tested page. Please refer to the following help topic for details on its use: Fixture.before Method. If you need to execute test actions (click, typeText, etc) once per fixture before you start all tests, see this module: testcafe-once-hook module. Here is an example of how to use it: https://github.com/AlexKamaev/testcafe-once-hook-example.

Using tags ( Smoke, regression) with TestCafe

Using testcafe grep patterns would partially solve our problem of using tags but it would still display those tags on the spec report ...!!!
Is there a way to include tags in the test/fixture names and use grep patterns but skip those tags to be displayed in the execution report ??
import { Selector } from 'testcafe';
fixture `Getting Started`
.page `http://devexpress.github.io/testcafe/example`;
test('My first test --tags {smoke, regression}', async t => {
// Test code
});
test('My Second test --tags {smoke}', async t => {
// Test code
});
test('My first test --tags {regression}', async t => {
// Test code
});
testcafe chrome test.js -F "smoke"
The above snippet would trigger the smoke only tests for me though but the report will display the test names along with those tags
Is there an alternative way to deal with tags or a solution to not display the tags in the test execution report?
It appears in a recent release (v0.23.1) of testcafe you can now filter with metadata via the commandline.
You can now run only those tests or fixtures whose metadata contains a specific set of values. Use the --test-meta and --fixture-meta flags to specify these values.
testcafe chrome my-tests --test-meta device=mobile,env=production
or
testcafe chrome my-tests --fixture-meta subsystem=payments,type=regression
Read more at https://devexpress.github.io/testcafe/blog/testcafe-v0-23-1-released.html
I think the best solution in this case is to use test/fixture metadata. Please refer the following article: http://devexpress.github.io/testcafe/documentation/test-api/test-code-structure.html#specifying-testing-metadata
For now, you can't filter by metadata, but this feature is in the pull request: https://github.com/DevExpress/testcafe/pull/2841. So, after this PR is merged, you will be able to add any metadata to tests and filter by this metadata in a command line.

Laravel Reset Database after Test

I have just started using Laravel Dusk to test my project and need some guidance. After I run all the tests available, I want to be able to reset my database back to before I run the tests. (If there were any entries in my database before I run the tests, I would still like to see them after I run the tests. However, any entires created during the test, I would not like to see them after the tests finish running.) Any pointers on how I would achieve this? Thank you!
Update:
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class UserRegisterTest extends DuskTestCase
{
use DatabaseTransactions;
/**
* A test for user registration.
* #group register
* #return void
*/
public function testRegisterUser()
{
//Register with all info filled out correctly
$this->browse(function ($browser){
$browser->visit('/register')
->type('firstName', 'JenLogin')
->type('lastName', 'Zhou')
->type('email', 'testLogin#gmail.com')
->type('bio', 'Hello, this user is for testing login purposes!')
->type('location_zip', '11111')
->type('password', '123456')
->type('password_confirmation', '123456')
->click('.btn-primary')
->assertPathIs('/home')
->click('.dropdown-toggle')
->click('.dropdown-menu li:last-child');
});
$this->assertDatabaseHas('users', ['firstName' => 'JenLogin', 'lastName' => 'Zhou', 'email' => 'testLogin#gmail.com']);
}
/**
* Register with duplicate user
* #group register
* #return void
*/
public function testRegisterDuplicateUser(){
$this->browse(function ($browser){
$browser->visit('/register')
->type('firstName', 'JenLoginDup')
->type('lastName', 'Zhou')
->type('email', 'testLogin#gmail.com')
->type('bio', 'Hello, this user is for testing login purposes!')
->type('location_zip', '11111')
->type('password', '123456')
->type('password_confirmation', '123456')
->click('.btn-primary')
->assertPathIs('/register')
->assertSee('The email has already been taken.');
});
$this->assertDatabaseMissing('users', ['firstName' => 'JenLoginDup', 'lastName' => 'Zhou', 'email' => 'testLogin#gmail.com']);
}
/**
* Register with incorrect password confirmation
* #group register
* #return void
*/
public function testRegisterUserNoPassConfirm(){
$this->browse(function ($browser){
$browser->visit('/register')
->type('firstName', 'JenLoginPass')
->type('lastName', 'Zhou')
->type('email', 'testLoginPass#gmail.com')
->type('bio', 'Hello, this user is for testing login purposes!')
->type('location_zip', '11111')
->type('password', '123456')
->type('password_confirmation', '888888')
->click('.btn-primary')
->assertPathIs('/register')
->assertSee('The password confirmation does not match.');
});
$this->assertDatabaseMissing('users', ['firstName' => 'JenLoginPass', 'lastName' => 'Zhou', 'email' => 'testLoginPass#gmail.com']);
}
}
You are looking for the DatabaseTransactions trait. Use it in your test class like this and it will automatically rollback all database transactions made during your tests.
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use DatabaseTransactions;
// test methods here
}
This will keep track of all transactions made during your test and undo them upon completion.
note: this trait only works on default database connections
First of all, when you are running tests you should use completely different database than your live (or dev) database. For this you should create .env.dusk and set in there:
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=testing_database
DB_USERNAME=root
DB_PASSWORD=pass
to database used for tests only.
Second thing is that for Laravel Dusk you cannot use just DatabaseTransactions. You should in fact use DatabaseMigrations for Dusk tests otherwise you will get unexpected results.
There is no sane workflow for running tests on live/dev db with data and reverting changes back, done by tests.
Therefore your approach fails here, instead you should:
Create separate test schema/db for tests
Switch to test db, before running tests - this can be somehow automated depending on your configuration in phpunit and .env.dusk, but it depends on your local setup.
Then in your tests you will create all from scratch on clean db (run migrations, seeds, factories)
Run tests against this test db
For development switch back to your base db with current data, which will not be affected by tests.
Next time you will run your tests all starts again from point zero - clean database, this will be done by in tests:
use CreatesApplication;
use DatabaseMigrations;
parent::setUp();etc.
Read more about these methods...
Side Notes:
With this approach, it will be easy, to test your app in CI environments also.
Never write your tests which depend on data on your dev/live db. For tests all required data should be provided by seeds or ewentually factories!
You can use the RefreshDatabase trait in your test classes.After each test the database will be like before test.
In Fact it will drop all tables and migrate again.
If you would not loose your data you can use one separate schema for test.
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
}
For multiple databases, this helped me
class MyTest extends TestCase {
// Reset the DB between tests
use DatabaseTransactions;
// Setting this allows both DB connections to be reset between tests
protected $connectionsToTransact = ['mysql', 'myOtherConnection'];
}
I think this is a great question. I found an Artisan tool that may be what you are looking for. You can use it to take a snapshot of the database before you run the test and then use it again to load that snapshot restoring your database to the previous state. I gave it a run(using MYSQL) and it worked great. Hope this is what you are looking for. Here is a link...
https://github.com/spatie/laravel-db-snapshots
phpunit.xml file is your solution there, you can set a .env variables in this file like so
<env name="DB_CONNECTION" value="testing_mysql"/>
<env name="DB_DATABASE_TEST" value="test"/>
now you can run your tests on a separate database.
Plus you can run a .php file every time before tests in automation, you just need to tell it to unittests
<phpunit
...
bootstrap="tests/autoload.php"
>
You can put any cleaners or seeders there or something like
echo 'Migration -begin-' . "\n";
echo shell_exec('php artisan migrate:fresh --seed');
echo 'Migration -end-' . "\n";

Protractor - Create Sanity test that includes login

I'm creating automated tests in Protractor for our site.
you have to login first in order to do anything on the site.
my problem is that for specific test (spec) - I can (have) to add 'login' - currently located in Page Object page.
the problem is that when creating a sanity test that uses multiple tests (using 'Suite') - I currently have to login for every specific test and then logout at the end so the next test will work properly (since it login at first).
what is the right way to do it?
on one hand I want that every test will work on its own (login at first) - but on the other hand - when using it in sanity test- I want to login and logout only once during the sanity test.
this is the suite part from the conf.js file:
suites:{
sanity: ['*/AccountSettingsTest.js','*/createApptest.js','*/openSourcePageTest.js','*/whatsNewTest.js']
},
specs: ['*/AccountSettingsTest.js'],
This is how I currently use the login:
var LoginPage = require('../global/LoginPage');
...
var login = new LoginPage();
...
login.clickLogin();
Thanks.
I'm afraid there is no beforeSuite() and afterSuite() if this is what you are asking about.
One thing that might work for you is to put the "logging in" part into onPrepare():
onPrepare: function () {
browser.get("myurl");
return loginPage.login(username, password); // login may also return a promise
},

Protractor - How to separate each test to one file and separate variabiles

I have some komplex protractor test written but everything is in one file.
Where I'm on top of it loading all variabiles like:
var userLogin = "John";
and after that somewhere in code I use it together.
What I need to do is
1. Separate all variabiles to aditional file (some config file)
2. Each test to one file
1- I try to make config.js where I add all variabiles and i required it in protractor.conf.js it load correctly problem is that when i use any of this variabiles in some test it's not working (test fail with "userName is not defined")
I know there is a way where i requre config.file in each test script but that's really not best option in my eyes.
2- How can I know what I did in last script if it's separate, like for example how to know I am logged in?
Thanks.
There are multiple things you can make use of.
2) How can I know what I did in last script if it's separate, like for example how to know I am logged in?
This is where beforeEach(), afterEach() can help:
To help a test suite DRY up any duplicated setup and teardown code,
Jasmine provides the global beforeEach and afterEach functions. As the
name implies, the beforeEach function is called once before each spec
in the describe is run, and the afterEach function is called once
after each spec.
There are also beforeAll(), afterAll() available in jasmine 2, or via jasmine-beforeAll third-party for jasmine 1:
The beforeAll function is called only once before all the specs in
describe are run, and the afterAll function is called after all specs
finish. These functions can be used to speed up test suites with
expensive setup and teardown.
1) I try to make config.js where I add all variabiles and i required
it in protractor.conf.js it load correctly problem is that when i use
any of this variabiles in some test it's not working (test fail with
"userName is not defined") I know there is a way where i requre
config.file in each test script but that's really not best option in
my eyes.
One option which I've personally used would be to create a config.js file with all the reusable configuration variables you would need in multiple tests and require the file once - in the protractor config - then set it as a params configuration key value:
var config = require("./config.js");
exports.config = {
...
params: config,
...
};
where config.js is, for example:
var config;
config = {
user: {
login: "user",
password: "password"
}
};
module.exports = config;
Then, you would not need to require config.js in every test, but instead, you'll use browser.params. For example:
expect(browser.params.user.login).toEqual("user");
Also, if you need some sort of a global test preparation step, you can do it in onPrepare() function, see Setting Up the System Under Test. Example configuration that performs a "global" login step is available here.
And an another quick note: you can have custom globally defined variables (like built-in browser or protractor), set them using global in onPrepare. For example, I've defined protractor.ExpectedConditions as a custom global variable:
onPrepare: function () {
global.EC = protractor.ExpectedConditions;
}
Then, in tests, don't require anything, `EC variable would be available in the scope, e.g.:
browser.wait(EC.invisibilityOf(scope.page.dropdown), 5000)
Also, organizing your tests using "Page Object Pattern" would also help to solve the reusability and modularity problem.