1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace BeyondCode\DuskDashboard\Console; |
4
|
|
|
|
5
|
|
|
use Clue\React\Buzz\Browser; |
6
|
|
|
use Illuminate\Console\Command; |
7
|
|
|
use Ratchet\WebSocket\WsServer; |
8
|
|
|
use React\EventLoop\LoopInterface; |
9
|
|
|
use Symfony\Component\Finder\Finder; |
10
|
|
|
use Symfony\Component\Routing\Route; |
11
|
|
|
use BeyondCode\DuskDashboard\Watcher; |
12
|
|
|
use Symfony\Component\Process\Process; |
13
|
|
|
use React\EventLoop\Factory as LoopFactory; |
14
|
|
|
use BeyondCode\DuskDashboard\Ratchet\Socket; |
15
|
|
|
use BeyondCode\DuskDashboard\Ratchet\Server\App; |
16
|
|
|
use BeyondCode\DuskDashboard\Ratchet\Http\EventController; |
17
|
|
|
use BeyondCode\DuskDashboard\Ratchet\Http\DashboardController; |
18
|
|
|
|
19
|
|
|
class StartDashboardCommand extends Command |
20
|
|
|
{ |
21
|
|
|
const PORT = 9773; |
22
|
|
|
|
23
|
|
|
protected $signature = 'dusk:dashboard'; |
24
|
|
|
|
25
|
|
|
protected $description = 'Start the Laravel Dusk Dashboard'; |
26
|
|
|
|
27
|
|
|
/** @var App */ |
28
|
|
|
protected $app; |
29
|
|
|
|
30
|
|
|
/** @var LoopInterface */ |
31
|
|
|
protected $loop; |
32
|
|
|
|
33
|
|
|
public function handle() |
34
|
|
|
{ |
35
|
|
|
$url = parse_url(config('app.url')); |
36
|
|
|
|
37
|
|
|
$this->loop = LoopFactory::create(); |
38
|
|
|
|
39
|
|
|
$this->loop->futureTick(function () use ($url) { |
40
|
|
|
$dashboardUrl = 'http://'.$url['host'].':'.self::PORT.'/dashboard'; |
41
|
|
|
|
42
|
|
|
$this->info('Started Dusk Dashboard on port '.self::PORT); |
43
|
|
|
|
44
|
|
|
$this->info('Your Dusk tests are now being watched.'); |
45
|
|
|
|
46
|
|
|
$this->info('If the dashboard does not automatically open, visit: '.$dashboardUrl); |
47
|
|
|
|
48
|
|
|
$this->tryToOpenInBrowser($dashboardUrl); |
49
|
|
|
}); |
50
|
|
|
|
51
|
|
|
$this->createTestWatcher(); |
52
|
|
|
|
53
|
|
|
$this->createApp($url); |
|
|
|
|
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
protected function addRoutes() |
57
|
|
|
{ |
58
|
|
|
$eventRoute = new Route('/events', ['_controller' => new EventController()], [], [], null, [], ['POST']); |
59
|
|
|
|
60
|
|
|
$this->app->routes->add('events', $eventRoute); |
61
|
|
|
|
62
|
|
|
$dashboardRoute = new Route('/dashboard', ['_controller' => new DashboardController()], [], [], null, [], ['GET']); |
63
|
|
|
|
64
|
|
|
$this->app->routes->add('dashboard', $dashboardRoute); |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
protected function createTestWatcher() |
68
|
|
|
{ |
69
|
|
|
$finder = (new Finder) |
70
|
|
|
->name('*.php') |
71
|
|
|
->files() |
72
|
|
|
->in($this->getTestSuitePath()); |
73
|
|
|
|
74
|
|
|
(new Watcher($finder, $this->loop))->startWatching(function () { |
75
|
|
|
$client = new Browser($this->loop); |
76
|
|
|
|
77
|
|
|
$client->post('http://127.0.0.1:'.StartDashboardCommand::PORT.'/events', [ |
78
|
|
|
'Content-Type' => 'application/json', |
79
|
|
|
], json_encode([ |
80
|
|
|
'channel' => 'dusk-dashboard', |
81
|
|
|
'name' => 'dusk-reset', |
82
|
|
|
'data' => [], |
83
|
|
|
]) |
84
|
|
|
); |
85
|
|
|
|
86
|
|
|
$process = new Process('php artisan dusk', base_path()); |
|
|
|
|
87
|
|
|
|
88
|
|
|
$process->start(); |
89
|
|
|
}); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
protected function getTestSuitePath() |
93
|
|
|
{ |
94
|
|
|
$directories = []; |
95
|
|
|
|
96
|
|
|
if (file_exists(base_path('phpunit.dusk.xml'))) { |
97
|
|
|
$xml = simplexml_load_file(base_path('phpunit.dusk.xml')); |
98
|
|
|
|
99
|
|
|
foreach ($xml->testsuites->testsuite as $testsuite) { |
100
|
|
|
$directories[] = (string) $testsuite->directory; |
101
|
|
|
} |
102
|
|
|
} else { |
103
|
|
|
$directories[] = base_path('tests/Browser'); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
return $directories; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
protected function createApp(array $url) |
110
|
|
|
{ |
111
|
|
|
$socket = new Socket(); |
112
|
|
|
|
113
|
|
|
$this->app = new App($url['host'], self::PORT, '0.0.0.0', $this->loop); |
114
|
|
|
|
115
|
|
|
$this->app->route('/socket', new WsServer($socket), ['*']); |
116
|
|
|
|
117
|
|
|
$this->addRoutes(); |
118
|
|
|
|
119
|
|
|
$this->app->run(); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
protected function tryToOpenInBrowser($url) |
123
|
|
|
{ |
124
|
|
|
if (PHP_OS === 'Darwin') { |
125
|
|
|
exec('open '.$url); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
|
This check looks for type mismatches where the missing type is
false
. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTime
object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalse
before passing on the value to another function or method that may not be able to handle afalse
.