Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel faker email that pass the email validation email:rfc,dns

I get

invalid email address

when using faker to fill the email fields of my app.

'email' => ['required', 'email:rfc,dns']

is there a way to make faker spit out valid email addresses that pass these tests?

I tried safeEmail and some others but they still fail

like image 662
Toskan Avatar asked Oct 15 '25 11:10

Toskan


1 Answers

I have the same problem and it's all related to the Egulias\EmailValidator\Validation\DNSCheckValidation class used by Laravel to validate an email (as you can see here example is a reserved top level domain).

There's no way of avoiding that an email created with faker passes this validation and, IMO, it's just as it should be. But we need to do our tests don't we?

There's a simple way (that can be used also in FormRequest or whatever you're using that implements the validator):

// In your test:
$this->post('my-url', ['email' => $this->faker->unique()->safeEmail])

// In your code
$emailRules = 'email:rfc';

if(!app()->runningUnitTests()) {
    $emailRules .= ',dns';
}

$validator = Validator::make($data, ['email' => ['required', $emailRules]]);
// [...]

Another way is to create a custom email validation rule that encapsulate the runningUnitTests logic (and I think it's much more cleaner)

<?php

namespace App\Rules;

use Egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\Validation\DNSCheckValidation;
use Egulias\EmailValidator\Validation\MultipleValidationWithAnd;
use Egulias\EmailValidator\Validation\NoRFCWarningsValidation;
use Egulias\EmailValidator\Validation\RFCValidation;
use Egulias\EmailValidator\Validation\SpoofCheckValidation;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Validation\Concerns\FilterEmailValidation;

/** @codeCoverageIgnore */
class ValidEmail implements Rule
{
    protected array $parameters;

    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct(array $parameters = [])
    {
        $this->parameters = $parameters;
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        if (! is_string($value) && ! (is_object($value) && method_exists($value, '__toString'))) {
            return false;
        }

        $validations = collect($this->parameters)
            ->unique()
            ->map(function ($validation) {
                if ($validation === 'rfc') {
                    return new RFCValidation();
                } elseif ($validation === 'strict') {
                    return new NoRFCWarningsValidation();
                } elseif ($validation === 'dns' && !app()->runningUnitTests()) {
                    return new DNSCheckValidation();
                } elseif ($validation === 'spoof') {
                    return new SpoofCheckValidation();
                } elseif ($validation === 'filter') {
                    return new FilterEmailValidation();
                }

                return null;
            })
            ->values()
            ->filter()
            ->all() ?: [new RFCValidation()];

        return (new EmailValidator)->isValid($value, new MultipleValidationWithAnd($validations));
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return __('validation.email');
    }
}

Than in your code:


$validator = Validator::make($data, ['email' => ['required', new ValidEmail()]]);

// OR

$validator = Validator::make($data, ['email' => ['required', new ValidEmail(['rfc','filter','dns'])]]);
// [...]
like image 100
IlGala Avatar answered Oct 18 '25 04:10

IlGala



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!