captcha icon indicating copy to clipboard operation
captcha copied to clipboard

How to get captcha code in test ?

Open FzSalehi opened this issue 3 years ago • 7 comments

Hi , im using this captcha in a form and i want to do some tests .. how to get correct code and insert it in form to submit the form?

FzSalehi avatar Feb 28 '22 09:02 FzSalehi

same question

sinamiandashti avatar May 01 '22 21:05 sinamiandashti

@FzSalehi , @sinamiandashti I had the same problem today. Here my solution for it. Not pretty, but does the work. :stuck_out_tongue_winking_eye:

Some explanation:

You can not get the captcha value, because it is hashed after the creation and only the hash is obtained. See: https://github.com/mewebstudio/captcha/blob/master/src/Captcha.php#L343

The comparison is done via hashing and comparing the provided value with existing hash. See: https://github.com/mewebstudio/captcha/blob/master/src/Captcha.php#L478

The good thing is, that the author used dependency injection and all the properties and methods are public or protected, so you can easily override necessary parts and replace the base class. :thumbsup:

Here my simple Fake Class solution:

<?php

namespace Tests;

use Mews\Captcha\Captcha;

class CaptchaFake extends Captcha
{
    public static string $expectedValue = '';

    public static function fake(string $value = ''): void
    {
        self::$expectedValue = $value;

        app()->bind('captcha', function ($app) {
            return new CaptchaFake(
                $app['Illuminate\Filesystem\Filesystem'],
                $app['Illuminate\Contracts\Config\Repository'],
                $app['Intervention\Image\ImageManager'],
                $app['Illuminate\Session\Store'],
                $app['Illuminate\Hashing\BcryptHasher'],
                $app['Illuminate\Support\Str']
            );
        });
    }

    public function check(string $value): bool
    {
        return self::$expectedValue === $value;
    }
}

I have added a static expected value property, so I can easily simulate success and failure. Just call the fake method at the beginning of your test method:

CaptchaFake::fake('123456');

I did not wanted to mock a lot so I just copied the creation of the original Captcha Class from the provider. See: https://github.com/mewebstudio/captcha/blob/master/src/CaptchaServiceProvider.php#L73

If you use the check_api method, you can fake it as well. https://github.com/mewebstudio/captcha/blob/master/src/Captcha.php#L505

Hope it helps you as well. Enjoy :wink:

Sergej-Tihonov avatar May 03 '22 09:05 Sergej-Tihonov

Oohh man, @Sergej-Tihonov. Thank so much. It's work!

ronaldaraujo avatar Aug 11 '22 00:08 ronaldaraujo

@sinamiandashti thank you for your help .. I have also a solution which is not so pretty too 😜 but it is simpler

you can modify laravel request validations .. right ?

so just put a simple condition like so:

// in some controller
public function store(Request $request)
{
    //here we decide which inputs required
    $requiredInputs = $this->getInputRequired(); 


    //then do the validation ...
    $validatedData = $request->validate($requiredInputs );


    // The blog post is valid...
}

private function getInputRequired(){
    // this is golden condition
    if(env('debug')){

       return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];

    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
        'captcha' => 'required',
    ];
    }

}

in this way .. you will never need to pass captcha input from your test requests.

But anyways I suggest to @mewebstudio to do something about the testing environment.

I think @Sergej-Tihonov 's solution could be implemented in this package.

FzSalehi avatar Aug 11 '22 04:08 FzSalehi

expectedValue

it's a very bad practice, never mix test and production code.

m3di avatar Sep 05 '22 19:09 m3di

Hi You can use it like below

If used API

Captcha::shouldReceive('check_api')->andReturn(true);

If did not use API

Captcha::shouldReceive('check')->andReturn(true);

@sinamiandashti @FzSalehi

rezasrk avatar Sep 22 '22 12:09 rezasrk

Hi You can use it like below

If used API

Captcha::shouldReceive('check_api')->andReturn(true);

If did not use API

Captcha::shouldReceive('check')->andReturn(true);

@sinamiandashti @FzSalehi

thank you, this work for me, I use FormRequest validation and it's working

githubcodehome avatar Nov 22 '22 21:11 githubcodehome