Pass codeception test name to browserstack - codeception

I want to pass my test names to browserstack, so that they are logged in the session value (name) within the browserstack interface
In my Acceptance helper I have the following method defined
/**
* HOOK: before test
*
* We use this method to set the test name which will be logged in BrowserStack
* https://www.browserstack.com/automate/capabilities
* #param \Codeception\TestInterface $test
*/
public function _before(\Codeception\TestInterface $test)
{
codecept_debug('_before');
codecept_debug($this->getModule('WebDriver')->_getConfig()['capabilities']);
$config['capabilities'] = $this->getModule('WebDriver')->_getConfig()['capabilities'];
$config['capabilities']['name'] = $test->getName();
$this->getModule('WebDriver')->_setConfig($config);
codecept_debug($this->getModule('WebDriver')->_getConfig()['capabilities']);
}
There are a few issues with my approach
This event seems to fire after the test is logged in browserstack (which is my main issue - I'm looking for the right place to inject this name value)
The tests would sometimes be logged under the wrong names - several tests will use the same name
Which event should I use to achieve my goals?

Looking through codeception and in particular webdriver source code, I saw this:
https://github.com/Codeception/Codeception/blob/2.5/src/Codeception/Module/WebDriver.php#L394
/**
* Change capabilities of WebDriver. Should be executed before starting a new browser session.
* This method expects a function to be passed which returns array or [WebDriver Desired Capabilities](https://github.com/facebook/php-webdriver/blob/community/lib/Remote/DesiredCapabilities.php) object.
* Additional [Chrome options](https://github.com/facebook/php-webdriver/wiki/ChromeOptions) (like adding extensions) can be passed as well.
*
* ```php
* <?php // in helper
* public function _before(TestInterface $test)
* {
* $this->getModule('WebDriver')->_capabilities(function($currentCapabilities) {
* // or new \Facebook\WebDriver\Remote\DesiredCapabilities();
* return \Facebook\WebDriver\Remote\DesiredCapabilities::firefox();
* });
* }
* ```
*
* to make this work load `\Helper\Acceptance` before `WebDriver` in `acceptance.suite.yml`:
*
* ```yaml
* modules:
* enabled:
* - \Helper\Acceptance
* - WebDriver
* ```
*
* For instance, [**BrowserStack** cloud service](https://www.browserstack.com/automate/capabilities) may require a test name to be set in capabilities.
* This is how it can be done via `_capabilities` method from `Helper\Acceptance`:
*
* ```php
* <?php // inside Helper\Acceptance
* public function _before(TestInterface $test)
* {
* $name = $test->getMetadata()->getName();
* $this->getModule('WebDriver')->_capabilities(function($currentCapabilities) use ($name) {
* $currentCapabilities['name'] = $name;
* return $currentCapabilities;
* });
* }
* ```
* In this case, please ensure that `\Helper\Acceptance` is loaded before WebDriver so new capabilities could be applied.
This seems to produce the same bugs as my original question in that,
Some tests don't have their names set
Some tests have the name of the previous test set
EDIT:
The reason the above was happening, was because in my environment file/definition of the device there was a declaration of
modules:
enabled:
- WebDriver
Removing the enabled and webdriver definition allows the fall back on the acceptance.suite.yml which then works correctly as intended

Related

Restler not accepting boolean false

In my Restler API class I have an object defined like so (with lots of other params)
class PatchTaskObj extends TaskObj {
/**
* #var bool|null Whether or not this Task should be pinned to the top of the list {#required false}
*/
public $pinned = null;
}
And then I attempt to use it in my PATCH method:
/**
* Updates an existing Task record.
*
* #param int $id The SQL ident of the task you wish to update. {#min 1} {#from path}
* #param PatchTaskObj $info The properties of the Task to update.
*
* #throws RestException 412 Thrown if at least one update isn't passed in.
*
* #status 204
*/
function patch($id, PatchTaskObj $info)
If I pass in true for the pinned property it works fine, but if I pass false then I get a 400 from Restler with the message:
Bad Request: Invalid value specified for info[pinned]
OK, discovered that Restler's Validator.php is failing to parse the #var property the way it's written. If you remove the |null part then it works as expected. I've submitted an issue to the github site.

Expected ' ' to be an inline constant. Java -> Groovy

I am using a custom annotation in my groovy script:
#Retention(RetentionPolicy.RUNTIME)
public #interface ScriptManifest {
/**
* Sets the scripts publicity mode.
* #return ScriptMode
*/
ScriptMode mode();
/**
* Sets the type of script we are using.
* #return ScriptType
*/
Class<? extends ScriptContext>[] type();
/**
* Sets the name of the script.
* #return name
*/
String script_name();
/**
* Sets the author of the script.
* #return author
*/
String author();
}
Creating the test script, my IntelliJ shows the error " Expected 'ScriptMode.PUBLIC' to be an inline constant" and same for TestContext.class. The script functions and runs fine I just am not sure as to why it is showing this for me as if it is an error.
#ScriptManifest(mode = ScriptMode.PUBLIC, type = TestContext.class, script_name = "Test", author = "Jake")
class Test extends Script {
#Override
void prepare() {
println "no" + getName()
}
}
Fixed the issue doing the following: I was trying to compile it in my Maven project with the javac, I added a new groovy module and compiled it with groovyc and it works fine now.

Selenium 1 - switch to iframe without ID

The page i crape have removed the ID from their iframe, so I have a problem switching to the iframe, and I can't find any documentation to help me, so maybe there is someone here on Stack?
The url of the page is: http://www.klappen.se/boka/onlinebokning/
I'm using Selenium 1 and my code looks like this:
$this->_driver->switchTo()->getFrameByName("mainframe");
In my TargetLocator.php i have these functions:
<?php
// Copyright 2012-present Nearsoft, Inc
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace SeleniumClient;
require_once 'WebDriver.php';
class TargetLocator
{
private $_driver;
public function __construct(WebDriver $driver)
{
$this->_driver = $driver;
}
#region TargetLocator members
/**
* Move to a different frame using its index
* #param Integer $frameIndex
* #return current WebDriver
*/
public function getFrameByIndex($frameIndex)
{
$this->_driver->getFrame($frameIndex);
return $this->_driver;
}
/**
* Move to different frame using its name
* #param String $frameName
* #return current WebDriver
*/
public function getFrameByName($frameName)
{
//We should validate that frameName is string
/*
if ($frameName == null)
{
throw new ArgumentNullException("frameName", "Frame name cannot be null");
}
*/
$this->_driver->getFrame($frameName);
return $this->_driver;
}
/**
* Move to a frame element.
* #param WebElement $frameElement
* #return current WebDriver
*/
public function getFrameByWebElement(WebElement $frameElement)
{
//We should validate that frameElement is string
/*
if (frameElement == null)
{
throw new ArgumentNullException("frameElement", "Frame element cannot be null");
}
RemoteWebElement convertedElement = frameElement as RemoteWebElement;
if (convertedElement == null)
{
throw new ArgumentException("frameElement cannot be converted to RemoteWebElement", "frameElement");
}
*/
$frameId = $frameElement->getElementId();
$target = array('ELEMENT' => $frameId);
$this->_driver->getFrame($target);
return $this->_driver;
}
/**
* Change to the Window by passing in the name
* #param String $windowName
* #return current WebDriver
*/
public function getWindow($windowName)
{
$this->_driver->getWindow($windowName);
return $this->_driver;
}
/**
* Change the active frame to the default
* #return current WebDriver
*/
public function getDefaultFrame()
{
$this->_driver->getFrame(null);
return $this->_driver;
}
/**
* Finds the active element on the page and returns it
* #return WebElement
*/
public function getActiveElement()
{
$webElement = null;
$webElement = $this->_driver->getActiveElement();
return $webElement;
}
/**
* Switches to the currently active modal dialog for this particular driver instance.
* #return \SeleniumClient\Alert
*/
public function getAlert()
{
// N.B. We only execute the GetAlertText command to be able to throw
// a NoAlertPresentException if there is no alert found.
//$this->_driver->getAlertText();
return new Alert($this->_driver); //validate that the Alert object can be created, if not throw an exception, try to use a factory singleton o depency of injection to only use 1 instance
}
#endregion
}
I have tried them all, but can't get it to work. Is there anybody out there who can help:-)?
Thanks in advance.
As far as i see you are looking for this iFrame:
<iframe src="http://dlbookit3.dlsystems.se/dlbookitKSR/bmlogifilt/logifilt.aspx" style="height:700px; width:100%; border:0;"></iframe>
right? So you have a method like getFrameByWebElement(WebElement) which accepts a WebElement. I think you can use an xpath to find the webElement e.g.:
WebElement element = find(By.xpath("//iframe"));
getFrameByWebElement(element);
so far in theory this could work (this is Java, you have to adapt it for your php code). But if I analyze the HTML code of the page with chrome I cannot locate the webElement by using the xpath //iframe.
Still you can try... but it looks like that the page owner doesn't want its iFrame to be locateable anymore :-)
There is only 1 IFRAME on the page so you can just find it by tag name. The page loaded very slowly for me but I'm in the US so that may have something to do with it. You may have to wait for the IFRAME to become available and then get a handle to it.

Tx_Extbase_Domain_Repository_FrontendUserRepository->findAll() not working in typo3 4.5.30?

I am trying to run a simple query off of the Tx_Extbase_Domain_Repository_FrontendUserRepository. I cannot get anything to work except findByUid(), not even findAll().
In my controller I have this code which seems to work:
/**
* #var Tx_Extbase_Domain_Repository_FrontendUserRepository
*/
protected $userRepository;
/**
* Inject the user repository
* #param Tx_Extbase_Domain_Repository_FrontendUserRepository $userRepository
* #return void */
public function injectFrontendUserRepository(Tx_Extbase_Domain_Repository_FrontendUserRepository $userRepository) {
$this->userRepository = $userRepository;
}
/**
* action create
*
* #param Tx_BpsCoupons_Domain_Model_Coupon $newCoupon
* #return void
*/
public function createAction(Tx_BpsCoupons_Domain_Model_Coupon $newCoupon) {
...... some code .....
$user = $this->userRepository->findByUid(($GLOBALS['TSFE']->fe_user->user[uid]));
$newCoupon->setCreator($user);
...... some code .....
}
but in another function I want to look up a user not by uid but by a fe_users column called vipnumber (an int column) so I tried
/**
* check to see if there is already a user with this vip number in the database
* #param string $vip
* #return bool
*/
public function isVipValid($vip) {
echo "<br/>" . __FUNCTION__ . __LINE__ . "<br/>";
echo "<br/>".$vip."<br/>";
//$ret = $this->userRepository->findByUid(15); //this works!! but
$query = $this->userRepository->createQuery();
$query->matching($query->equals('vip',$vip) );
$ret = $query->execute(); //no luck
.................
and neither does this
$ret = $this->userRepository->findAll();
How can one work but not the others? In my setup I already put
config.tx_extbase.persistence.classes.Tx_Extbase_Domain_Model_FrontendUser.mapping.recordType >
which seems to be necessary for the fiondByUid to work, is i t preventing the other from working?
I am using typo3 v 4.5.30 with extbase 1.3
Thanks
If $this->userRepository->findByUid(15); works, there is no reason why $this->userRepository->findAll(); should not. However $this->userRepository->findAll(); returns not a single Object but a collection of all objects, so you have to iterate over them.
If you add a column to the fe_users, you have to add it to TCA and to your extbase model (you need a getter and a setter), too! After that you can call findByProperty($property) in your repository. In your case that would be
$user = $this->userRepository->findByVipnumber($vip);
This will return all UserObjects that have $vip set as their Vipnumber. If you just want to check if that $vip is already in use, you can call
$user = $this->userRepository->countByVipnumber($vip);
instead. Which obviously returns the number of Users that have this $vip;
You never use $query = $this->createQuery(); outside your Repository.
To add the property to the fronenduser Model you create your own model Classes/Domain/Model/FronendUser.php:
class Tx_MyExt_Domain_Model_FrontendUser extends Tx_Extbase_Domain_Model_FrontendUser {
/**
* #var string/integer
*/
protected $vipnumber;
}
Add a getter and a setter. Now you create your own FrontendUserRepository and extend the extbase one like you did with the model. You use this repository in your Controller. Now you're almost there: Tell Extbase via typoscript, that your model is using the fe_users table and everything should work:
config.tx_extbase {
persistence{
Tx_MyExt_Domain_Model_FrontendUser{
mapping {
tableName = fe_users
}
}
}
}
To disable storagePids in your repository in general, you can use this code inside your repository:
/**
* sets query settings repository-wide
*
* #return void
*/
public function initializeObject() {
$querySettings = $this->objectManager->create('Tx_Extbase_Persistence_Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($querySettings);
}
After this, your Querys will work for all PIDs.
I didn't have the opportunity to work with frontend users yet, so I don't know if the following applies in this case:
In a custom table I stumbled uppon the fact, that extbase repositories automatically have a look at the pids stored in each entry and check it against a set storage pid (possibly also the current pid if not set). Searching for a uid usually means you have a specific dataset in mind so automatic checks for other values could logically be ignored which would support your experiences. I'd try to set the storage pid for your extension to the place the frontend users are stored in ts-setup:
plugin.[replace_with_extkey].persistence.storagePid = [replace_with_pid]

Lack of response and typing info in API Explorer

I am using the latest version of Restler v3 (commit 0d79cd8) but I'm having some problems having my Swagger-based UI look the same as in the examples. The two problems I'm noticing are that variable typing and #return objects are not being displayed.
On the Restler site, here's a good example of both of these working:
example
Instead, in my Actions class I get this:
And yet as you can see from definition of the class both type information and a response object is specified:
class Actions {
/**
* LIST action types
*
* List all the action-types available
*
* #url GET /
*/
function list_actions() {
throw new RestException(501);
}
/**
* GET today's Actions
*
* Get the set of actions done today
*
* #url GET /{user_id}
* #param integer $user_id The user_id for whom the actions apply; you can insert the text "self" and it will resolve to the current/default user
* #param string $time_of_day {#from url} Allow's you to optionally set a time-of-day; if set then actions are only returned after that. Time should be in the format of HH:MM:SS
* #return ActionList
*/
public function action_today ($user_id, $time_of_day = false )
{
throw new RestException(501, "Today's actions for user '{$user_id}' not implemented.");
}
and my definition of ActionList class is:
class ActionList {
/**
* Unique identifier of action
*
* #var integer
*/
public $action_id;
/**
* String based unique identifier
*
* #var string
*/
public $action_slug;
}
If your class is versioned, e.g. in the namespace v1\Actions, you have to annotate the return type in the namespace too, e.g. #return v1\ActionList