I need to run one of my Laravel Dusk tests from an artisan command so that it processes daily. I've tried $this->call('dusk'); in my command but that runs all of dusk's tests and doesn't allow me to add a group or a filter. I need to run just 1 test. How can I add a filter?
$this->call('dusk', [ '--group' => 'communication_tests' ]);
or
$this->call('dusk', [ '--filter' => 'tests\Browser\myTestFile::myTestMethod' ]);
doesn't work and it ignores the options passed in. Any ideas on how to accomplish this?
1st create your working Laravel Dusk Test. Test it out with php artisan dusk and make sure it's working.
2nd create your own command in the app\Commands folder called DuskCommand to overwrite laravels native DuskCommand and have it's signature be 'dusk'. Have it extend Laravel\Dusk\Console\DuskCommand and write into its handle method the code below (see https://github.com/laravel/dusk/issues/371 for other version of this code). I edited mine to remove the $this->option('without-tty') ? 3 : 2 ternary statement so it just reads 2 for mine as that option didn't exist or wasn't needed for my version of laravel.
3rd add your new class to the Kernel so that when you call php artisan dusk the class is recognized.
4th create your new command to programmatically run your dusk test using the final line added by #taytus.
5th add that new class to the Kernel also.
Here's my file run down below...
My laravel dusk test (tests\Browser\CommunicationsTest.php) (STEP 1)
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use App\Models\User;
class CommunicationsTest extends DuskTestCase
{
/**
* A Dusk test example.
* #group all_communication_tests
* #return void
*/
public function test_that_all_coms_work()
{
// Test Text
$this->browse(function (Browser $browser) {
$browser->resize(1920, 1080);
$browser->loginAs(7)
->visit('/events/types/appointments')
->assertSee('Automated Messages')
->click('.text_message0')
->pause(1000)
->click('.send-eng-text-btn')
->pause(1000)
->type('phone', env('TESTING_DEVELOPER_PHONE'))
->click('.send-text')
->pause(5000)
->assertSee('Your test text has been sent.');
// Test Email
$browser->visit('/events/types/appointments')
->assertSee('Automated Messages')
->click('.email0')
->assertSee('Automated Messages')
->driver->executeScript('window.scrollTo(595, 1063);');
$browser->click('.send-eng-email-btn')
->pause(2000)
->click('.send-email')
->pause(10000)
->assertSee('Your test email has been sent.');
// Test Call
$browser->visit('/audio/testcall')
->assertSee('Test Call')
->type('phone', env('TESTING_DEVELOPER_PHONE'))
->press('Call')
->pause(3000)
->assertSee('Test Call Queued');
});
}
}
My Overwritting dusk command (app\Console\Commands\DuskCommand.php) (STEP 2)
<?php
namespace App\Console\Commands;
use Laravel\Dusk\Console\DuskCommand as VendorDuskCommand;
use Symfony\Component\Process\ProcessBuilder;
class DuskCommand extends VendorDuskCommand
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'dusk';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Run Tests on our system... by extending the Laravel Vendor DuskCommand.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$this->purgeScreenshots();
$this->purgeConsoleLogs();
$options=array();
// This line checks if it is a direct call or if has been called from Artisan (we assume is Artisan, more checks can be added)
if($_SERVER['argv'][1]!='dusk'){
$filter=$this->input->getParameterOption('--filter');
// $filter returns 0 if has not been set up
if($filter){
$options[]='--filter';
$options[]=$filter;
// note: --path is a custom key, check how I use it in Commands\CommunicationsTest.php
$options[]=$this->input->getParameterOption('--path');
}
}else{
$options = array_slice($_SERVER['argv'], 2);
}
return $this->withDuskEnvironment(function () use ($options) {
$process = (new ProcessBuilder())
->setTimeout(null)
->setPrefix($this->binary())
->setArguments($this->phpunitArguments($options))
->getProcess();
try {
$process->setTty(true);
} catch (RuntimeException $e) {
$this->output->writeln('Warning: '.$e->getMessage());
}
return $process->run(function ($type, $line) {
$this->output->write($line);
});
});
}
}
Now add that new command to the Kernel so it will register when you call it and overwrite the functionality of the native/vendor DuskCommand. (STEP 3)
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
// .... preceding commands....
Commands\DuskCommand::class,
];
Now create your command that will call dusk programmatically - here's mine (STEP 4)
<?php
namespace App\Console\Commands;
use DB;
use Illuminate\Console\Command;
class TestCommunications extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'test:communications';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Test Email, Text, and Phone Calls to make sure they\'re operational.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$response = $this->call('dusk',['--filter'=>'test_that_all_coms_work','--path'=>'tests/Browser/CommunicationsTest.php']);
}
}
and register it in the Kernel (STEP 5)...
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
.... preceding commands....
Commands\DuskCommand::class,
Commands\TestCommunications::class,
];
Now run php artisan dusk and it should hit the extending DuskCommand and work fine. Then call your new php artisan command that replaces my TestCommunications.php file and it should run dusk perfectly... assuming your test works of course. Let me know if you have any question or if I left anything out.
Remember Dusk only works in a local environment ... this is not something you want/should/natively can implement on a production environment
Related
So consider the service provider, yes I know I am registering this command in two places, but just give me a moment to explain:
<?php
namespace App\Modules\Core\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Foundation\AliasLoader;
use App\Modules\Core\Handlers\RedirectHandler;
use App\Modules\Core\Console\Commands\CreateAdminUser;
use App\Modules\Core\Values\IsMedicalRecordEmpty;
class CoreProvider extends ServiceProvider
{
protected $commands = [
CreateAdminUser::class,
];
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(RedirectHandler::class, function($app) {
return new RedirectHandler();
});
$this->app->bind(IsMedicalRecordEmpty::class, function($app) {
return new IsMedicalRecordEmpty();
});
}
public function register() {
$this->commands($this->commands);
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->commands([
CreateAdminUser::class,
]);
}
}
}
So as stated before we can see that I am registering this command in two places, because I am trying to figure out why calling php artisan doesn't show the command, it only shows if I register it in the app\Console\Kernel, but because I am trying to take a modular approach to the code base, I want to register it in my service provider, to which is registered as such:
'providers' => [
...
/**
* Module Related Providers
*/
App\Modules\Core\Providers\CoreProvider::class,
...
],
I register the provider properly, I (yes I know I don't need to register the command twice) register the command in the way that stack has explained it, either way should in theory work.
But alas the command does not show up when I run php artisan. At all.
The command is simple:
<?php
namespace App\Modules\Core\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use Illuminate\Auth\Events\Verified;
use App\Modules\Core\Users\Mail\GeneratedAdmin;
use App\Modules\Core\Users\Models\User;
use App\Modules\Core\Users\Services\RegisterUserService;
class CreateAdminUser extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'create:admin {first_name} {last_name} {email}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Create one admin.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
// do stuff here ...
}
}
Any ideas?
Your code is redeclaring register(), first in the method with the binds, and then again with your method calling $this->command() - are you even referencing your service provider correctly? PHP should have told you this - it did for me when I tried your sample code...
Whoops\Exception\ErrorException : Cannot redeclare App\Modules\Core\Providers\CoreProvider::register()
It's worth noting that removing the first method with the binds caused the command to show for me.
I have written code for cron command as below in lumen (micro framwork of laravel)
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\EmailDump;
use DB;
/**
* dumpEmails Class
*
* This cron is to dump emails with cron use
*
* #author Hetal Gohel <hetal.gohel#brainvire.com>
*
*/
class dumpEmails extends Command {
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'insert:emails';
/**
* The console command description.
*
* #var string
*/
protected $description = 'This cron is to dump emails with cron use';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
echo "1";die;
}
}
in kernel file defined as below,
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands = [
\Laravelista\LumenVendorPublish\VendorPublishCommand::class,
'\App\Console\Commands\dumpEmails',
];
/**
* Define the application's command schedule.
*
* #param \Illuminate\Console\Scheduling\Schedule $schedule
* #return void
*/
// protected function schedule(Schedule $schedule)
// {
// return $schedule;
// }
}
I have fired command from console as below,
php artisan insert:emails
while run this command getting error as below,
[Symfony\Component\Console\Exception\CommandNotFoundException] ←[39;49m
←[37;41m There are no commands defined in the "insert" namespace.
please help me to resolve this issue.thank you.
Please remove __construct and keep just the handle method.
Also, when you are listing under $commands at Kernel you need to specify the class.
So your
`\App\Console\Commands\dumpEmails`
becomes
DumpEmails::class
A few extra tips:
Class names are capitalised; (dumpEmails -> DumpEmails)
Add the { to a new line;
This
class dumpEmails extends Command {
should be
class DumpEmails extends Command
{
I also recommend checking out about PSR-x standards. I left one of the blogs I think might help you kick start with them, but go further! :)
Last, but not least, do not forget Command Parent already lets you use its command line potential. So if you wish to output and debug, you can do so by using:
$this->info('Your message to inform');
$this->error('Your error message');
I am using laravel 5.5 and trying to create a new command. This has worked well in 5.4 but now it won't register at all.
First I create the command:
php artisan make:command heloworl
And I get something like this:
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class heloworl extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'Hello:World';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
echo "hello world";
}
}
Now I try php artisan hello:world and it says that the command does not exist at all.
I also tried just php artisan to get a list of commands and it is not there.
Any ideas?
I had a Laravel 5.2 project that I upgraded to 5.5, and for me it wasn't loading them automatically for some reason, even though I had the command classes in the right place.
Turns out I had to modify app/Console/Kernel.php, adding the following line to the top of the commands method:
$this->load(__DIR__.'/Commands');
After this I was able to use my commands properly, and I didn't have to add each of them to the $commands array.
You need to add it to app\Console\Kernel.php to the protected $commands array.
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* #var array
*/
protected $commands
= [
//fully qualified namespace to class goes here
];
}
As part of my Laravel 5.2 application, I would like to define a custom command for artisan, but my command doesn't appear in artisan list.
1). I created the command skeleton: artisan make:console --command=process:emails
2). I added a bit of test code to the handle() method of the new class:
<?php
namespace App\Console\Commands;
use App\CommunicationsQueue;
use Illuminate\Console\Command;
class ProcessEmailQueueCommand extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'process:email';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Send all currently pending emails in the queue';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
CommunicationsQueue::where('status', 'PENDING')->update(['status'=>'TEST']);
$this->info('The mails queue was successfully processed.');
}
}
3). Then, I registerred the command in app/Console/Kernel.php:
protected $commands = [
'App\Console\Commands\ProcessEmailQueueCommand',
];
What am I missing here? I'm sure it's something incredibly simple, but I'm not seeing it.
in app/Console/Kernel.php try with the following code
protected $commands = [
'App\Console\Commands\ProcessEmailQueueCommand',
];
On Kernel.php, try include the full name, which should be:
protected $commands = [
\App\Console\Commands\ProcessEmailQueueCommand::class,
];
I am new in laravel. I was trying to make a custom artisan command for creating tables in my test project.I followed this link but my command was not on the artisan list.Event I tried same example given in that link but its also not worked. I dont know why its happening.
I DID THIS:
1) Run this command php artisan make:console SendEmails
2) Put complete class code in app/Console/Commands/SendEmails.php file
<?php
namespace App\Console\Commands;
use App\User;
use App\DripEmailer;
use Illuminate\Console\Command;
class SendEmails extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'email:send {user}';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Send drip e-mails to a user';
/**
* The drip e-mail service.
*
* #var DripEmailer
*/
protected $drip;
/**
* Create a new command instance.
*
* #param DripEmailer $drip
* #return void
*/
public function __construct(DripEmailer $drip)
{
parent::__construct();
$this->drip = $drip;
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$this->drip->send(User::find($this->argument('user')));
}
}
Please help me let me know what I am doing wrong.
You just forgot to Register your command.
This part: https://laravel.com/docs/5.1/artisan#registering-commands.
Open app/Console/Kernel.php and add you command class in $commands array.
like this :
protected $commands = [
Commands\SendEmails::class
];
That's it.