Completed
Push — master ( d8a4a6...a1059c )
by Marcel
14s queued 10s
created

StartDashboardCommand::tryToOpenInBrowser()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
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);
0 ignored issues
show
Security Bug introduced by
It seems like $url defined by parse_url(config('app.url')) on line 35 can also be of type false; however, BeyondCode\DuskDashboard...ardCommand::createApp() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

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 returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
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());
0 ignored issues
show
Documentation introduced by
'php artisan dusk' is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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