laravel / dusk

Laravel Dusk provides simple end-to-end testing and browser automation.
https://laravel.com/docs/dusk
MIT License
1.88k stars 323 forks source link

TTY mode requires /dev/tty to be writable when running Dusk as cron from Forge #202

Closed swissmant closed 7 years ago

swissmant commented 7 years ago

I have some tests built using Dusk and they run fine from command line using php artisan dusk. However, if I try to run them as a cron (from Laravel Forge), I get an error saying TTY mode requires /dev/tty to be writable

Here's the full output:

Symfony\Component\Process\Exception\RuntimeException: TTY mode requires /dev/tty to be read/writable. in /home/forge/crawlers.plaidfox.com/vendor/symfony/process/Process.php:1006
Stack trace:
#0 /home/forge/crawlers.plaidfox.com/vendor/laravel/dusk/src/Console/DuskCommand.php(63): Symfony\Component\Process\Process->setTty(true)
#1 /home/forge/crawlers.plaidfox.com/vendor/laravel/dusk/src/Console/DuskCommand.php(124): Laravel\Dusk\Console\DuskCommand->Laravel\Dusk\Console\{closure}()
#2 /home/forge/crawlers.plaidfox.com/vendor/laravel/dusk/src/Console/DuskCommand.php(67): Laravel\Dusk\Console\DuskCommand->withDuskEnvironment(Object(Closure))
#3 [internal function]: Laravel\Dusk\Console\DuskCommand->handle()
#4 /home/forge/crawlers.plaidfox.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(29): call_user_func_array(Array, Array)
#5 /home/forge/crawlers.plaidfox.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(87): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#6 /home/forge/crawlers.plaidfox.com/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(31): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#7 /home/forge/crawlers.plaidfox.com/vendor/laravel/framework/src/Illuminate/Container/Container.php(524): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#8 /home/forge/crawlers.plaidfox.com/vendor/laravel/framework/src/Illuminate/Console/Command.php(182): Illuminate\Container\Container->call(Array)
#9 /home/forge/crawlers.plaidfox.com/vendor/symfony/console/Command/Command.php(265): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#10 /home/forge/crawlers.plaidfox.com/vendor/laravel/framework/src/Illuminate/Console/Command.php(167): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#11 /home/forge/crawlers.plaidfox.com/vendor/symfony/console/Application.php(826): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#12 /home/forge/crawlers.plaidfox.com/vendor/symfony/console/Application.php(189): Symfony\Component\Console\Application->doRunCommand(Object(Laravel\Dusk\Console\DuskCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#13 /home/forge/crawlers.plaidfox.com/vendor/symfony/console/Application.php(120): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#14 /home/forge/crawlers.plaidfox.com/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(123): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 /home/forge/crawlers.plaidfox.com/artisan(35): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 {main}  

I tried to force TTY mode to be false in Process.php mentioned above, and the test ran to a limited extent. What happened is that the test method before the $this->browse closure function, but anything within the closure or following it were not output to the logs. Here is my test class (excluding a couple of extra methods not necessary for de-bugging purposes):

<?php

namespace Tests\Browser;

use App\Product;
use Carbon\Carbon;
use Tests\DuskTestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

use Facades\Plaidfox\Houzz\HouzzAPI;

class AllHandsTest extends DuskTestCase
{
    /**
     * Crawl All Hands website.
     * Logs in to All Hands website and searches for stock information. This then updates the Product table.
     *
     * @group crawlers
     * @return void
     */
    public function testCrawl()
    {
        \Log::info('Begin crawling All Hands site.');
        $products = Product::where([
                ['vendor_id', '=', 67]
            ])
            ->get();
        \Log::info('Products found: '.count($products));

        $this->browse(function ($browser) use ($products) {
            \Log::info('within browse function');
            $browser->visit('http://allhands.com')
                    ->assertSee('All Hands');
            $browser->type('username', '12345')
                ->type('password', 'useful1')
                ->press('save');

            $products->each(function($product) use ($browser) {
                \Log::info('Product sku: '.$product->vendor_sku);
                try {
                    $url = 'http://allhands.com/product/' . $product->vendor_sku;
                    $browser->visit($url);
                    if($browser->driver->getCurrentURL() != $url) {
                        throw new \Exception("Product not found: ".$url);
                    } 
                    // Confirm that preceding element on page is correct
                    $precedingElement = $browser->element('#sectionOverview>p:nth-child(2)>span>strong')->getText();
                    if($precedingElement === "Available for Immediate Shipment:") {
                        $stockValue = $browser->element('#sectionOverview>p:nth-child(2)>span>span')->getText();
                        $availabilityText = $browser->element('#sectionOverview>p:nth-child(2)>span>span:last-child')->getText();
                        list($status, $back_order) = $this->calculateStatusAndBackOrder($stockValue, $availabilityText);
                        $product->stock = $stockValue;
                        $product->status = $status;
                        $product->back_order = $back_order;
                        $product->save();
                        $houzzResponse = HouzzAPI::updateInventoryQty($product);
                    } else {
                        \Log::info('Stock value for product: ' . $product->vendor_sku . ' could not be determined.');
                    }
                } catch (\Exception $ex) {
                    \Log::info($ex->getMessage());
                }
            });
        });
        \Log::info('Finished crawling All Hands site.');
    }

So the logged messages were:

Begin crawling All Hands site.
Products found: 802

but I get nothing else.

We're running on Ubuntu 16.04 on a Digital Ocean droplet.

Not sure if it's relevant, but here's the Forge command: Every Minute * * * * * forge php /home/forge/crawlers.mysite.com/artisan schedule:run

Also, if it's relevant, here is the schedule() method in app/Consol/Kernel.php:

    protected function schedule(Schedule $schedule)
    {
        $schedule->exec('php /home/forge/crawlers.mysite.com/artisan dusk')->dailyAt('22:00');
    }

I tried running it like this, and I also tried: $schedule->command('dusk')->dailyAt('22:00');

calebporzio commented 7 years ago

I'm dealing with the exact same thing. I've tried quite a few things to no avail. Is this a symfony Process thing? Or a Scheduler thing? Or a Dusk thing? - hard to tell.

Basically it seems the problem is solely with the running the dusk command from a cron job. Running it any other way works fine (I'm using phantomjs)

matrunchyk commented 7 years ago

Same here. I run the test in a docker container within Bitbucket Pipeline and it's unable to run Dusk.

$ php artisan dusk

[Symfony\Component\Process\Exception\RuntimeException]
TTY mode requires /dev/tty to be read/writable.

I can't use PhantomJS here.

johanvanhelden commented 7 years ago

Also a Bitbucket Pipeline user here and of course I am having the same issue. I am ensure if this is something Dusk should be fixing, or if this is something Atlassian should fix in the Pipeline system.

calebporzio commented 7 years ago

I mean, I'm just trying to get these things running via Laravel's Scheduler - I think it's something that should be addressed - ya?

deleugpn commented 7 years ago

Can you guys try to pull #223 and see if it solves the problem?

@calebporzio @swissmant

calebporzio commented 7 years ago

@deleugpn - Awesome! Works like a charm :)

Oxicode commented 3 years ago

Also a Bitbucket Pipeline user here and of course I am having the same issue. I am ensure if this is something Dusk should be fixing, or if this is something Atlassian should fix in the Pipeline system.

me too

ALTELMA commented 2 years ago

Also a Bitbucket Pipeline user here and of course I am having the same issue. I am ensure if this is something Dusk should be fixing, or if this is something Atlassian should fix in the Pipeline system.

me too

me too. I was trying to set up a test with dusk with alpine, But not working in the Bitbucket pipelines.

In the local, It works fine. I can run the test without a selenium driver. But unfortunately on Bitbucket.