How to use Behat in Cake Php? - testing

I have this feature
Feature: User accesses Appointments Dashboard
Scenario:
Given I am on "User Dashboard Page"
And I should see "APPOINTMENTS"
And I should see "PRE-ENROLMENTS"
When I press "APPOINTMENTS"
Then I am on "Appointments Dashboard"
And I should see "Booking Reference"
And I should see "Book Another Appointment"
And I have these steps
--- FeatureContext has missing steps. Define them with these snippets:
/**
* #Given I am on :arg1
*/
public function iAmOn($arg1)
{
throw new PendingException();
}
/**
* #Given I should see :arg1
*/
public function iShouldSee($arg1)
{
throw new PendingException();
}
/**
* #When I press :arg1
*/
public function iPress($arg1)
{
throw new PendingException();
}
How do I complete the steps and run it with Behat in Cake Php ?
So, that my tests pass ??

If you want access to yuor CakePHP internals, then you'll probably want to have an instance of CakePHP application in your Context (e.g.
App\Application or Cake\Http\Server, look at your index.php on it's done). Then, hopefully you'll be able to access all of the usual application internals via default Service Container of CakePHP.

Related

How can I invoke callback while login in Google in .net core?

I am coding a third-party login-in with Google.
Here is the tutorial of Microsoft:
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-3.0
I did what it said by using the Secret Manager and AddAuthentication
When I click the Login button on the website, it will redirect to google login successfully.
Now the next step is the invoke the callback. However, I don't know how to invoke it after login.
The tutorial of Microsoft only shows these two class:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.google.googleoptions?view=aspnetcore-2.2
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.remoteauthenticationoptions.callbackpath?view=aspnetcore-2.2
But does not say something more about that yet. I even don't know how to use it and I can't find any other tutorial about it.
Would you please tell me how can I invoke the callback? Thank you.
You can use like below. Login user on External login method then get the result with confirmlogin method.
[HttpGet]
public async Task<object> ExternalLogin()
{
string redirectUrl = "api/account/ConfirmLogin&Provider=Google";
await AuthenticationProperties properties =
SignInManager.ConfigureExternalAuthenticationProperties("Google", redirectUrl);
return new ChallengeResult(provider, properties);
}
[HttpGet]
public async Task ConfirmLoginAsync(string Provider)
{
/*
make your checks
*/
Request.HttpContext.Response.Redirect(url);
}
Also you need to register your url like :
registerUrl
I hope it helps.

How do i use Behat with Mink and WebApiContext?

The project i'm working on has a api behind a login.
I'm using behat with mink to login:
Scenario: Login
Given I am on "/login/"
And I should see "Login"
When I fill in "_username" with "test"
And I fill in "_password" with "test"
And I press "_submit"
Then I should be on "/"
This works..
However, the login session is not stored whenever i want to do the following using the WebApiContext:
Scenario: Getting the list of pages
When I send a GET request to "/api/pages.json"
Then print response
I'm using both scenarios in the same feature. My FeatureContext class looks something like this:
class FeatureContext extends MinkContext
{
public function __construct(array $parameters)
{
$context = new WebApiContext($parameters['base_url']);
$context->getBrowser()->getClient()->setCookieJar(new \Buzz\Util\CookieJar());
$this->useContext('web', $context);
}
}
I added the cookiejar idea from this issue without success.. When i print the response i just see the HTML page from the login screen..
Does anyone have any idea if i'm going at this totally the wrong way or am i somewhat in the right direction?
I am successfully using the same method. I don't think there's a standard way of doing this. As far as you understand the cookie basics you should be able to implement the solution.
In a common scenario, a client sends an authentication request to the server with some credentials, the servers validates it, starts an authenticated session and sends back a cookie with that session id. All following requests contain that id, so the server can recognise the callee. A specific header can be used instead of the cookie, or a database can be used instead of the session, but the principle is the same and you can (relatively) easily simulate it with Mink.
/**
* Start a test session, set the authenticated user and set the client's cookie.
*
* #Given /^I am signed in$/
*/
signIn()
{
session_start();
$_SESSION['user'] = 'jos';
$this->getSession()->getDriver()->setCookie(session_name(), session_id());
session_commit();
}
The above step definition (Behat 3) is the basics of it, you manually create the authenticated session and set to the client it's id. That must be also what the other example illustrates.
PHP's sessions can be problematic when you start doing more complex things and there are a couple of big underwater rocks with this solution. If you want to run assertions from both perspectives (the client and the server) you might often need to have your sessions synced. This can be done by updating the cookie before all Mink steps and reloading the session after.
/**
* #beforeStep
* #param BeforeStepScope $scope
*/
public function synchroniseClientSession(BeforeStepScope $scope)
{
// Setup session id and Xdebug cookies to synchronise / enable both.
$driver = $this->getSession()->getDriver();
// Cookie must be set for a particular domain.
if ($driver instanceof Selenium2Driver && $driver->getCurrentUrl() === 'data:,') {
$driver->visit($this->getMinkParameter('base_url'));
}
// Also enables the debugging support.
$driver->setCookie(session_name(), session_id());
$driver->setCookie('XDEBUG_SESSION', 'PHPSTORM');
}
/**
* #afterStep
* #param AfterStepScope $scope
*/
public function synchroniseServerSession(AfterStepScope $scope)
{
$driver = $this->getSession()->getDriver();
// Only browser kit driver, only initiated requests, only not repeating requests.
if (!$driver instanceof BrowserKitDriver) {
return;
} elseif (($request = $driver->getClient()->getRequest()) === null) {
return;
} elseif ($request === self::$request) {
return;
}
// Your logic for reloading the session.
self::$request = $request;
}
The biggest problem I had was the session reloading. This might be due to my framework of choice, which I doubt. The very first code snippet has session_commit(), which saves and closes the session. In theory in the following step definitions you must be able to session_id(/* session id from the cookie… */); and session_start();, but in practice that didn't work and no session data was actually loaded from the file, though the session did start. To solve this I created a custom session manager with reload() method using session save handler.
Second problem is where you cannot simply close the session without either writing it or destroying it (the support is added in PHP 5.6) on which relies the reloading itself. I reinvented the wheel with a flag for the session manager which tells it whether to write or just to close it.
:)

Selenium 2 browser instances for a single test

I am using phpunit as a wrapper for selenium. I have a test that simulates two users on the same website. So I need to have two browsers open that can't share cookies - it can't just be two windows. They are the same test, so for example a user would click something in the first browser instance and the other user would look for a change in the other browser instance. Logging out and back in as the other user is not an option.
Is there a way to do this?
Disclaimer: I haven't tried this at all, but the pattern might work.
Unfortunately the PHPUnit WebDriver implementation is tightly coupled to the unit test framework code. However, you could try something like this in order to have 2 different web driver instances running in parallel:
<?php
class WebTest extends PHPUnit_Extensions_Selenium2TestCase
{
private $driver1;
private $driver2;
protected function setUp()
{
$this->driver1 = $this->createDriver();
$this->driver2 = $this->createDriver();
}
protected function createDriver()
{
$driver = new PHPUnit_Extensions_Selenium2TestCase();
$driver->setBrowser('firefox');
$driver->setBrowserUrl('http://www.example.com/');
$driver->start();
return $driver;
}
public function testTitle()
{
$this->driver1->url('http://www.example.com/');
$this->driver1->assertEquals('Example WWW Page', $this->title());
$this->driver2->url('http://www.example.com/');
$this->driver2->assertEquals('Example WWW Page', $this->title());
}
protected function tearDown() {
$this->driver1->stop();
$this->driver2->stop();
}
}
?>
Theres quite a lot that could potentially go wrong with this but you could try it.
Alternatively you could ditch the PHPUnit integration for this particular test/tests and use a dedicate PHP WebDriver API like PHP-SeleniumClient, which would give you better control over the WebDriver instances.

Testing Remember me functionality with Behat/Mink

I am trying to test a remember me functionality with Behat and Mink in a Symfony2 project. However, my approach is not working.
I tried the following:
#behat.yml
Scenario: Checking Remember me
Given I am on "/"
When I fill in "username" with "john"
And I fill in "password" with "john"
And I check "remember_me"
And I press "Login"
Then I should be logged in
When I restart the browser
Then I should be logged in
Scenario: Not Checking Remember me
Given I am on "/"
When I fill in "username" with "john"
And I fill in "password" with "john"
And I press "Login"
Then I should be logged in
When I restart the browser
Then I should be logged out
My feature context contains (among others) the following methods:
#FeatureContext.php
/**
* #Then /^I should be logged in$/
*/
public function iShouldBeLoggedIn()
{
$this->assertElementOnPage('.user-area');
}
/**
* #Given /^I should be logged out$/
*/
public function iShouldBeLoggedOut()
{
$this->assertElementNotOnPage('.user-area');
}
/**
* #When /^I restart the browser$/
*/
public function iRestartTheBrowser()
{
$driver = $this->getSession()->getDriver();
$session = new Session($driver);
$session->start();
$session->visit('/');
}
The problem lies within iRestartTheBrowser(). This is not doing what it is supposed to do. I am looking for a way to clear session data but keep cookies. Any help?
I think your spec may be better worded as
Scenario: Checking Remember me
Given I have logged in before and selected remember me
When I visit "some protected web page"
Then I should be logged in
The Given can set state for remember me, and perhaps the context for this can help you isolate the need to reset the session?
The above is also easier to read for laypeople and developers alike

User authentication using CodeIgniter

I have a problem creating authentication part for my application.
Below is the simplified version of my controllers.
The idea is that the MY_controller checks if session with user data exists.
If it doesn’t, then redirects to the index page where you have to log in.
MY_controller.php
class MY_Controller extends Controller {
function __construct()
{
parent::__construct();
$this->load->helper('url');
$this->load->library('session');
if($this->session->userdata('user') == FALSE) {
redirect('index');
} else {
redirect('search');
}
}
}
order.php - main controller
class Orders extends MY_Controller {
function __construct()
{
parent::__construct();
$this->load->helper('url');
$this->load->library('session');
}
function index()
{
// Here would be the code that validates information input by user.
// If validation is successful, it creates user session.
$this->load->view('header.html', $data); // load header
$this->load->view('index_view', $data); // load body
$this->load->view('footer.html', $data); // load footer
}
function search()
{
//different page
}
what is happening is that the browser is telling me that “The page isn’t redirecting properly. Firefox has detected that the server is redirecting the request for this address in a way that will never complete.”
It seems like the redirect() is being looped. I looked at a few other examples of user auth and they were build using similar technique.
When a user is already logged in, it appears you want to redirect them to /search/. The redirect occurs, and the constructor is called again, which recognizes that the user is already logged in, so it redirects them to /search/... you get the idea.
I would start by separating your login logic into it's own controller that doesn't extend from MY_Controller.
Also, note that when not logged in your controller redirects to 'index'. If the Index controller is also based on My_Controller, then it will redirect back to itself (until the user logs in and then Dolph Mathews' answer comes true).
You need to provide a 'safe zone' with no checking/redirecting that provides users with a login form (and note that your login controller/method has to have open access too!)
I tend to pop a gateway method into My_Controller, which is called only by private controllers/methods as required (in the constructor of completely private controllers). I'm sure there must be a better way though, perhaps like a gateway function in your My_Controller (as yours is done) but that filters for the URI path (e.g. allows index; index/login; index/logout etc)