How to fix 'ArgumentCountError' while using page object model in behat - automation

I am trying to use page object model in my behat framework . Here is my code snippet.
HomePage.php
use Behat\Behat\Context\Context;
use SensioLabs\Behat\PageObjectExtension\PageObject\Page;
class HomePage extends Page implements Context{
protected $path = '/';
}
FeatureContext.php
use Behat\Behat\Context\Context;
use SensioLabs\Behat\PageObjectExtension\PageObject\Page;
class FeatureContext extends Page implements Context, \Behat\Behat\Context\SnippetAcceptingContext
{
private $homepage;
public function __construct(HomePage $homepage)
{
$this->homepage = $homepage;
}
/**
* #Given /^(?:|I )visited (?:|the )(?P<pageName>.*?)$/
*/
public function iVisitedThe($pageName)
{
if (!isset($this->$pageName)) {
throw new \RuntimeException(sprintf('Unrecognised page: "%s".', $pageName));
}
$this->$pageName->open();
}
}
But while executing the behat tests I am getting the following error ->"ArgumentCountError: Too few arguments to function SensioLabs\Behat\PageObjectExtension\PageObject\Page::__construct(), 0 passed and at least 2 expected"

The setup should be like this:
feature > contexts > page objects
Feature file uses definitions that are defined in the context files and a Context file implements the actual step by calling actions from different page objects.
Your page object should extend just Page.
The Feature context should extend MinkContext and implement Context.
All the other contexts should just implement Context.
Ps: take a look again at the page object extension documentation on Working with page objects topic.

Related

DunglasApiBundle - Trying to get the bundle to use Named Constructors rather than public constructor

I'm using the Dunglas api-platform bundle (https://github.com/api-platform/api-platform) for a new app.
Setup and installation went fine, GET requests are working.
While trying to create new objects using POST requests, I received errors about having a private constructor. My models are all made using a private constructor, and using named constructors instead.
Ideally i'm either looking for a way to have the bundle call my Named constructors, ... or someone to tell me my approach is completely wrong.
Services.yml
services:
resource.player:
parent: "api.resource"
arguments: [ "Name\\Space\\Player" ]
tags: [ { name: "api.resource" } ]
Player Object
class Player
{
private $name;
private function __construct()
{
}
public static function withName($playerName)
{
$player = new Player();
$player->name = $playerName;
return $player;
}
public function getName()
{
return $this->name;
}
}
Settings are pretty much all out of the box, following the introduction and setup in the documentation. I've skimmed through the Factory thing briefly - hoping that i'd be able to use a factory to create the objects, allowing me to call my own named constructors - but that doesn't seem to do what i think it does.
Any input regarding the use, boundaries or the setup is well appreciated.
API Platform (like most Symfony and Doctrine related libraries) is not designed to work with immutable objects like this one.
I suggest to create a typical mutable Entity as suggested in the doc:
class Player
{
private $name;
public static function setName($playerName)
{
$this->name = $playerName;
}
public function getName()
{
return $this->name;
}
}
If you really want to keep your immutable model, you'll need to implement yourself the Symfony\Component\PropertyAccess\PropertyAccessorInterface and use a CompilerPass to make API Platform using your own implementation. You will probably need to submit a patch to API Platform and to the Symfony Serializer Component to update the reference of the given object too because currently, both serializers actually update the current object and will not use the new instance returned by your with method.
I strongly encourage you to switch to typical mutable entities.

How to hook into beforeSuite event with Codeception for API Acceptance tests?

I am building API Acceptance tests with Codeception.
I am familiar with Unit tests there and I used the setUp method in those classes for all logic required before running all the tests of the class.
However I didn't find anything like this for Acceptance Tests.
Notice that I am using the "Class" approach, not the procedural way.
So I have a class like this...
class ResourceCest {
public function _beforeSuite(ApiTester $I)
{
// Ideally this would work, but it doesn't.
}
public function _before(ApiTester $I)
{
$I->am('Api Tester');
}
public function somethingThatIWantToExecute(ApiTester $I)
{
$I->sendGet('something');
// etc
}
}
I can make a method like setUp, but then Codeception executes it as a test and thus outputting something when running the tests.
You shouldn't define the _beforeSuite inside your Cest classes. Instead, you should use the Helper class inside _support.
Assuming you have a suite called api, you should have a ApiHelper.php class inside _support. There, you can define your methods, for instance:
<?php
namespace Codeception\Module;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class ApiHelper extends \Codeception\Module
{
public function _beforeSuite($I) {
var_dump($I);
die();
}
}
This should do the trick.

Phalcon Initialize() is not working

I have 2 Controllers, TEST1Controller and TEST2Controller
In TEST2Controller I have a initialize() function setting value of a property.
If I try to access TEST2Controller directly from the browser, everything works perfectly.
But when I call a TEST2Controller method from TEST1Controller, it seems that initialize() function is not being called in TEST2Controller.
TEST1Controller:
namespace Modcont\Controller;
use Modcont\Controller\Test2Controller;
class Test1Controller extends BaseController
{
function gettestAction()
{
$t = new Test2Controller(); // calling TEST2 Controller Method Within TEST1 Controller
echo $t->dotestAction(" MYAPP ");
}
}
TEST2Controller:
namespace Modcont\Controller;
class Test2Controller extends BaseController
{
public $prefix;
function initialize()
{
$this->prefix = 'your name is';
}
function dotestAction($name)
{
return $this->prefix.' : '.$name;
}
}
Phalcon offers two ways for controller initialization, thy are the initialize and onContruct methods. The basic difference between these two methods is that initialize is called only when a controller is created by the framework to proceed with the execution of an action. Since you instantiating a controller object ad-hoc, initialize will not be called, only onConstruct will. So you'll need to put your initialization logic there:
function onConstruct()
{
$this->prefix = 'your name is';
}
Also, implementing native constructors in controller is discouraged, but if you do so, make sure to call the parent constructor in your own constructor: parent::__construct();.
All this information can be found in the Docs.

Implementing the Page Object Model

I am building a test automation project using Perl and Selenium. I am using the Page Object Model. I am somewhat unsure about where the Selenium driver would fit into the implementation of the page object model.
Should each page object 'have' a driver ? The way I am thinking is that each page object represents a set of services that the page offers to a user. With this concept in mind , a page object does not have a 'has-a' relationship with a driver. A page object interacts with a driver. However, I am still looking for suggestions. Should I have the driver as part of each page object in the web-application?
Thanks!
This answer won't be any much different from #zodvik, and your thought process, but is another optional approach. Instead of passing the driver around, you can create an abstract class that each page object can then inherit from. From the abstract class, can also contain some common functional methods that you will find yourself often using.
This is at least how I do it in Java language.
I always include driver as part of every Page Object. The way I thought about driver was that it represents the state of the current page. It gives access to the URL, Page Source, etc.
Now, each page has a a current URL, a page source code, a page title which are all accessible through the driver.
In the way, I implemented the framework. I used the driver in the commonFactory.class that contains commonly used elements. Each page was implemented as a child class of the commonFactory.class. so you don't have to implement the driver in each and every class. Since the driver is independent of the test scenarios it's better to have it in a separate way.
As I understand, there are No set rules/standards for implementing POM.
However, the general thumb rule is to create a BaseTest and BasePage class in your Framework where each respective webpage (like Login) will represent by its PageClass(LoginPage).
Similarly, all your Page classes will extend your BasePage and all tests will extend your BaseTest class.
Below is a rough idea of its implementation ->
public class BaseTest{
#BeforeSuite()
setupMethod(){
initialize your WebDriver here
}
}
------------------------------------------
public class BasePage {
//create constructor
public BasePage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(this.driver, Duration.ofSeconds(TIMEOUT));
PageFactory.initElements(new AjaxElementLocatorFactory(this.driver, TIMEOUT), this);
}
//other common methods which can be utilized in your respective child Page classes
}
----------------------------------------------------
public class LoginPage extends BasePage {
//Your Locators and Weblelements
private static final LOGIN_ID = "login";
//Constructor to supply webdriver
public LoginPage(WebDriver driver) {
super(driver);
}
//your action methods
public void loginToApp(){
driver.findbyelement(By.ID(LOGIN_ID)).click
}
}
----------------------------------------------------
public class LoginTest extends BaseTest{
public LoginPage login;
BeforeAll()
{
login = new LoginPage(driver);
}
#Test
public void verifyLogin(){
login.loginToApp();
}
}

wicket and AtUnit

I've started playing with Wicket and I've chosen Guice as dependency injection framework. Now I'm trying to learn how to write a unit test for a WebPage object.
I googled a bit and I've found this post but it mentioned AtUnit so I decided to give it a try.
My WebPage class looks like this
public class MyWebPage extends WebPage
{
#Inject MyService service;
public MyWebPage()
{
//here I build my components and use injected object.
service.get(id);
....
}
}
I created mock to replace any production MyServiceImpl with it and I guess that Guice in hand with AtUnit should inject it.
Now the problems are:
AtUnit expects that I mark target object with #Unit - that is all right as I can pass already created object to WicketTester
#Unit MyWebPage page = new MyWebPage();
wicketTester.startPage(page);
but usually I would call startPage with class name.
I think AtUnit expects as well that a target object is market with #Inject so AtUnit can create and manage it - but I get an org.apache.wicket.WicketRuntimeException: There is no application attached to current thread main. Can I instruct AtUnit to use application from wicketTester?
Because I don't use #Inject at MyWebPage (I think) all object that should be injected by Guice are null (in my example the service reference is null)
I really can't find anything about AtUnit inside Wicket environment. Am I doing something wrong, am I missing something?
I don't know AtUnit but I use wicket with guice and TestNG. I imagine that AtUnit should work the same way. The important point is the creation of the web application with the use of guice.
Here how I bind all this stuff together for my tests.
I have an abstract base class for all my tests:
public abstract class TesterWicket<T extends Component> {
#BeforeClass
public void buildMockedTester() {
System.out.println("TesterWww.buildMockedTester");
injector = Guice.createInjector(buildModules());
CoachWebApplicationFactory instance =
injector.getInstance(CoachWebApplicationFactory.class);
WebApplication application = instance.buildWebApplication();
tester = new WicketTester(application);
}
protected abstract List<Module> buildModules();
The initialization is done for every test class. The subclass defines the necessary modules for the test in the buildModules method.
In my IWebApplicationFactory I add the GuiceComponentInjector. That way, after all component instantiation, the fields annotated with #Inject are filled by Guice:
public class CoachWebApplicationFactory implements IWebApplicationFactory {
private static Logger LOG = LoggerFactory.getLogger(CoachWebApplicationFactory.class);
private final Injector injector;
#Inject
public CoachWebApplicationFactory(Injector injector) {
this.injector = injector;
}
public WebApplication createApplication(WicketFilter filter) {
WebApplication app = injector.getInstance(WebApplication.class);
Application.set(app);
app.addComponentInstantiationListener(new GuiceComponentInjector(app, injector));
return app;
}
}