Use CodeCeption assertion in conditional (if) statement - php

I'm totally new with CodeCeption.
I want to do an action/assertion depending on another assertion result, like this:
if ($I->see('message')){
$I->click('button_close');
}
Is something like that possible? I tried, but doesn't work.
Probably the assertion result doesn't apply to IF, but is there any alternative?
Thanks in advance!
IMPORTANT UPDATE:
Finally Codeception now has the function performOn!!
http://codeception.com/docs/modules/WebDriver#performOn

I had this same issue. Although it's not ideal, you can do this:
try {
$I->see('message');
// Continue to do this if it's present
// ...
} catch (Exception $e) {
// Do this if it's not present.
// ...
}

In tests/_support/AcceptanceHelper.php add additional method
function seePageHasElement($element)
{
try {
$this->getModule('WebDriver')->_findElements($element);
} catch (\PHPUnit_Framework_AssertionFailedError $f) {
return false;
}
return true;
}
Then to test in your acceptance test use:
if ($I->seePageHasElement("input[name=address]")) {
$I->fillField("input[name=address]", "IM");
}

You can use a workaround like this or similar combinations:
$tmp = $I->grabTextFrom('SELECTOR');
if ($tmp == 'your text') {
$I->click('button_close');
}

ULTIMATE SOLUTION!
Finally Codeception now has the function performOn, wich does exactly what I asked for!!
[Version 2.2.9]
http://codeception.com/docs/modules/WebDriver#performOn
Answering my example:
$I->performOn('.message', ['click' => '#button_close'], 30);
Waits up to 30 seconds to see the element with class='message', then click the element with id='button_close'.

Codeception now has tryTo..., e.g, tryToSee() trytoClick(), etc., so there's no need for a Try/Catch block. I find it more readable than performOn().
You need to enable it with this in acceptance.suite.yml or codeception.yml:
# enable conditional $I actions like $I->tryToSee()
step_decorators:
- \Codeception\Step\TryTo
- \Codeception\Step\ConditionalAssertion`
You can click on something that may or may not be there with:
$I->tryToClick('#save_button`);
If there's no button, the code goes on with no error message. This could also be used to click on the node to expand a section of a tree before examining it, but only if that section is closed (there should always be a class that's only there when it's closed).
Another way to go is in an if statement. The tryTo... methods all return true on success and false on failure, so you can do this, which some might consider clearer than the above (no error will be thrown):
if ($I->tryToSee('some_locator')) {
$I->click('some_locator');
}
This form is also useful if there is a sequence of actions you want to perform based on a condition, the else is optional.
if ($I->tryToSee('some_locator')) {
$I->fillField('username', 'myname');
$I->fillfield('password', 'mypassword);
$I->click('Submit');
} else {
/* Do something else */
}

Release for my project comes on weeken
/**
* https://stackoverflow.com/questions/26183792/use-codeception-assertion-in-conditional-if-statement
* #param $element
* #return bool
* #throws \Codeception\Exception\ModuleException
*/
public function seePageHasElement($element)
{
$findElement = $this->getModule('WebDriver')->_findElements($element);
return count($findElement) > 0;
}

The reason why the assertion doesn't work with conditional statements is that Codeception first executes the assertion inside the IF brackets, and in case it is not true - it fails the test right away. My way of overcoming this is using the SOFT assertions TryTo which will be ignored by Codeception if fails: https://codeception.com/docs/08-Customization#Step-Decorators
if ($I->tryToSee('message')){
$I->click('button_close');
}```

100% working solution !! Thanx me later ;)
In tests/_support/AcceptanceHelper.php add additional method
public function seePageHasElement($element)
{
try {
$this->getModule('WebDriver')->_findElements($element);
} catch (\PHPUnit_Framework_AssertionFailedError $f) {
return false;
}
return true;
}
Then to test in your acceptance test use:
if ($I->seePageHasElement($element)) {
$I->fillField($element);
}
The 'seeElement' function of WebDriver doesnot work on this case so needs little modified function as i have used one '_findElements' .Please donot forget to build your actors after any changes done.

Related

Force return statement on caller function

I am just curious if it's possible to force parent method to return a value from within method called in that parent method? Let's say I have:
public function myApiEndpoint()
{
// I DO NOT want to to have return statement here
$this->validOrUnprocessable();
// some other code
//return value
return $someValue;
}
public function validOrUnprocessable()
{
if ($condition) {
... here goes the code that forces return statement on myApiEndpoint function without putting the word `return` in front of this call...
}
}
So in other words validOrUnprocessable method, when it needs to do so forces or tricks PHP into thinking that myApiEndpoint returns the value. I do not want to use return statement when validOrUnprocessable is called or any if conditions.
I do know other ways of doing what I want to do but I wanted to know if something like that is possible. I am not interested in any workarounds as I know very well how to implement what I need to achieve in many other ways. I just need to know if this what I described is possible to do exactly how I described it.
I did try to get there with reflections and other scope related things but so far no luck. Any ideas?
Just to add. I am doing this because I want to check how far I can push it. I am building a tool for myself and I want it to be as convenient and easy to use as possible.
If it's not possible I have another idea but that's a bit out of the scope of this post.
You should throw an exception.
public function validOrUnprocessable()
{
if ($condition) {
throw Exception('foo bar');
}
}
The code calling this method should be ready to catch an exception:
public function myApiEndpoint()
{
try {
// I DO NOT want to to have return statement here
$this->validOrUnprocessable();
// some other code
//this code will never be called because of exception thrown in validOrUnprocessable
return value;
} catch (Exception $e) {
//do something else
return -1; //you can return another value as example.
}
return $someValue;
}

PHPUnit Test result type or also the result variables

during unit testing i'm always get confused about what to test.
Do i need to test the API and only the API or also the method result values.
class SomeEventHandler
{
public function onDispatch (Event $event)
{
if ($event->hasFoo)
{
$model = $this->createResponseModel('foo');
}
else
{
$model = $this->createResponseModel('bar');
}
// End.
return $model;
}
private function createResponseModel ($foo)
{
$vars = array(
'someVare' => true,
'foo' => $foo
);
// End.
return new ResponseModel($vars);
}
}
So should i test if the method onDispatch returns a instance of ResponseModel or should i also test if the variable foo is set properly?
Or is the test below just fine?
class SomeEventHandlerTest
{
// assume that a instance of SomeEventHandler is created
private $someEventHandler;
public function testOnDispatch_EventHasFoo_ReturnsResponseModel ()
{
$e = new Event();
$e->hasFoo = true;
$result = $someEventHandler->onDispatch($e);
$this->assertInstanceOf('ResponseModel', $result);
}
public function testOnDispatch_EventHasNoFoo_ReturnsResponseModel ()
{
$e = new Event();
$e->hasFoo = false;
$result = $someEventHandler->onDispatch($e);
$this->assertInstanceOf('ResponseModel', $result);
}
}
If you were checking the code by hand what is it that you would check? Just that a ResponseModel was returned or that it also had the proper values?
If you weren't writing tests and executed the code what would you look for to ensure that the code was doing what it was supposed to. You would check that the values in the returned object were correct. I would do that by using the public API of the object and verify that the values are right.
One idea is to have the tests such that if the code were deleted, you would be able to recreate all the functionality via only having the tests. Only checking the returned object could result in a function that just has return new ResponseModel();. This would pass the test but would not be what you want.
In short, what you decide to test is subjective, however you should at the minimum test all your public methods.
Many people limit their tests to public methods and simply ensure code coverage on the protected/private methods is adequate. However, feel free to test anything you think warrants a test. Generally speaking, the more tests the better.
In my opinion you should certainly test for your response data, not just the return type.
I rely on Unit Tests to let me make code changes in the future and be satisfied my changes have not created any breaks, just by running the tests.
So in your case, if the "foo" or "bar" response data is important, you should test it.
That way if you later change the response strings by accident, your tests will tell you.

Start function over, depending on results of IF statement

If I have a function that is inside of a Class, and I am returned with "invalid" how can I start back up at the top function?
function test(){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
continue ;
}
}
but I get the following error
Fatal error: Cannot break/continue 1 level in
If I am hit with "invalid" I would like to start test() back over..
You probably want to use a recursive function here:
function test(){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
return test() ; // restart process
}
}
Alternatively, this may be a (very rare) good use of the goto operator:
function test(){
start:
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
goto start;
}
}
Note that this will only work in PHP >=5.3.
I'd make use of exceptions, and let the calling scope control repeat invocations of test(). test() performs one job; it shouldn't control when it's asked to perform that job.
(Recursive approaches given in other examples don't really fit the use case [and make me nervous, thanks to languages where recursing too many times makes you run out of stack space eventually; certainly you're filling up your stack for no reason], and though goto will work fine it still gives the function itself too much power.)
function test()
{
//curl here
//other stuff here
if (strpos($data, 'invalid'))
throw new Exception("Data is invalid");
}
function callingFunction()
{
while (true) {
try {
test();
break; // only reached if test() didn't throw
}
catch(Exception $e) {} // if we fall into this, the loop repeats
}
}
You could still apply goto quite cleanly with this approach:
function test()
{
//curl here
//other stuff here
if (strpos($data, 'invalid'))
throw new Exception("Data is invalid");
}
function callingFunction()
{
startTest:
try {
test();
}
catch(Exception $e) {
goto startTest;
}
}
Remove continue; and instead add test();. It's called recursive functions (calling itself).
There are a few ways you can do it, the way my teacher normally suggests is to actually call the function again.
function test(){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove continue ;
test();
return;
}
}
My answer might not be the best, hope this helps.
Assuming you change the parameters beforehand, you can recursively call the function again with new parameters. Just make sure there will be an edge case where the function will stop recursing. As for that, I'd need to see the real code to tell you.
function test($data){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
test($NEW_DATA);
}
}
If you want to break out of the function you're currently in, you should use 'return' instead of 'continue'.
Or if you would like to start the processing over, you should put your logic into a loop.

PHP Always run function

I am trying to get some errors returned in JSON format. So, I made a class level var:
public $errors = Array();
So, lower down in the script, different functions might return an error, and add their error to the $errors array. But, I have to use return; in some places to stop the script after an error occurs.
So, when I do that, how can I still run my last error function that will return all the gathered errors? How can I get around the issue of having to stop the script, but still wanting to return the errors for why I needed to stop the script?!
Really bare bones skeleton:
$errors = array();
function add_error($message, $die = false) {
global $errors;
$errors[] = $message;
if ($die) {
die(implode("\n", $errors));
}
}
If you are using PHP5+ your class can have a destructor method:
public function __destruct() {
die(var_dump($this->errors));
}
You can register a shutdown function.
Add the errors to the current $_SESSION
Add the latest errors to any kind of cache, XML or some storage
If the code 'stops':
// code occurs error
die(print_r($errors));
You can use a trick involving do{}.
do {
if(something) {
// add error
}
if(something_else) {
// add error
break;
}
if(something) {
// add error
}
}while(0);
// check/print errors
Notice break, you can use it to break out of the do scope at any time, after which you have the final error returning logic.
Or you could just what's inside do{} inside a function, and use return instead of break, which would be even better. Or yes, even better, a class with a destructor.

Is it possible to make an object return false by default?

I tried to ask this before, and messed up the question, so I'll try again. Is it possible to make an object return false by default when put in an if statement? What I want:
$dog = new DogObject();
if($dog)
{
return "This is bad;"
}
else
{
return "Excellent! $dog was false!"
}
Is there a way this is possible? It's not completely necessary, but would save me some lines of code. thanks!
No, PHP has no support for operator overloading. Maybe they'll add it in a future version.
Use the instanceof keyword.
For example
$result = Users->insertNewUser();
if($result instanceof MyErrorClass){
(CHECK WHAT WENT WRONG AND SAY WHY)
} else {
//Go on about our business because everything worked.
}
Info is here.
Use this? Not a real neat solution, but does what you want:
<?php
class Foo
{
private $valid = false;
public function Bar ( )
{
// Do stuff
}
public function __toString ( )
{
return ( $this -> valid ) ? '1' : '0';
}
}
?>
Zero is considered false, one is considered true by PHP
I was attempting to do this myself and found a solution that appears to work.
In response to the others who were trying to answer the question by telling the asker to use a different solution, I will also try to explain the reason for the question. Neither the original poster or I want to use an exception, because the point is not to use exception handling features and put that burden on any code we use this class in. The point, at least for me, was to be able to use this class seamlessly in other PHP code that may be written in a non-object-oriented or non-exception-based style. Many built-in PHP functions are written in such a way that a result of false for unsuccessful processes is desirable. At the same time, we might want to be able to handle this object in a special way in our own code.
For example, we might want to do something like:
if ( !($goodObject = ObjectFactory::getObject($objectType)) ) {
// if $objectType was not something ObjectFactory could handle, it
// might return a Special Case object such as FalseObject below
// (see Patterns of Enterprise Application Architecture)
// in order to indicate something went wrong.
// (Because it is easy to do it this way.)
//
// FalseObject could have methods for displaying error information.
}
Here's a very simple implementation.
class FalseObject {
public function __toString() {
// return an empty string that in PHP evaluates to false
return '';
}
}
$false = new FalseObject();
if ( $false ) {
print $false . ' is false.';
} else {
print $false . ' is true.';
}
print '<br />';
if ( !$false ) {
print $false . ' is really true.';
} else {
print $false . ' is really false.';
}
// I am printing $false just to make sure nothing unexpected is happening.
The output is:
is false.
is really false.
I've tested this and it works even if you have some declared variables inside the class, such as:
class FalseObject {
const flag = true;
public $message = 'a message';
public function __toString() {
return '';
}
}
A slightly more interesting implementation might be:
class FalseException extends Exception {
final public function __toString() {
return '';
}
}
class CustomException extends FalseException { }
$false = new CustomException('Something went wrong.');
Using the same test code as before, $false evaluates to false.
I recently had to do something similar, using the null object pattern. Unfortunately, the null object was returning true and the variable in question was sometimes an actual null value (from the function's default parameter). The best way I came up with was if((string)$var) { although this wouldn't work for empty arrays.
Putting something in "an if statement" is simply evaluating the variable there as a boolean.
In your example, $dog would need to be always false for that to work. There is no way to tell when your variable is about to be evaluated in a boolean expression.
What is your ultimate purpose here? What lines of code are you trying to save?
I'm not sure about the object itself. Possible. You could try something like, add a public property to the DogObject class and then have that set by default to false. Such as.
class DogObject
{
var $isValid = false;
public function IsValid()
{
return $isValid;
}
}
And then when you would instantiate it, it would be false by default.
$dog = new DogObject();
if($dog->IsValid())
{
return "This is bad;"
}
else
{
return "Excellent! $dog was false!"
}
Just a thought.
If I understand what your asking, I think you want to do this:
if (!$dog){
return "$dog was false";
}
The ! means not. SO you could read that, "If not dog, or if dog is NOT true"
Under what conditions do you want if($dog) to evaluate to false? You can't do what you've literally asked for, but perhaps the conditioned could be replaced by something that does what you want.
class UserController
{
public function newuserAction()
{
$userModel = new UserModel();
if ($userModel->insertUser()) {
// Success!
} else {
die($userModel->getError());
}
}
}
Or
class UserController
{
public function newuserAction()
{
$userModel = new UserModel();
try {
$userModel->insertUser()
}
catch (Exception $e) {
die($e);
}
}
}
There are a million ways to handle errors. It all depends on the complexity of the error and the amount of recovery options.
How about using an Implicit Cast Operator like the following C# ?
like so:
class DogObject
{
public static implicit operator bool(DogObject a)
{
return false;
}
}
Then you can go...
var dog = new DogObject();
if(!dog)
{
Console.WriteLine("dog was false");
}

Categories