Hey there,
there is no official, documented way to switch frames with Dusk but facebook's webdriver (used by Dusk) supports it, so it's possible.
Fortunately, the Browser class used in Dusk tests is Macroable (as mentioned in https://medium.com/@splatEric/writing-tests-with-laravel-dusk-bb755c0dcb1f#.47d4xdb5e) which means we can easily extend Dusk's functionality without making too much of a mess or messing with vendor files.
Following the directions in the linked article, we can first create a new ServiceProvider:
$ php artisan make:provider DuskBrowserServiceProvider
And add the following in its boot method:
Browser::macro('switchFrame', function($frame) {
$this->driver->switchTo()->defaultContent()->switchTo()->frame($frame);
return $this;
});
(Make sure to use Laravel\Dusk\Browser; in the ServiceProvider.)
Then, we add this new provider in the register method of AppServiceProvider. Right after the initial DuskServiceProvider:
public function register()
{
if ($this->app->environment('local', 'testing')) {
$this->app->register(DuskServiceProvider::class);
$this->app->register(DuskBrowserServiceProvider::class);
}
}
Now, we can call the switchFrame method in any Dusk test.
Here's how I did it while trying to test Paypal's sandbox login and payment:
$browser->loginAs($user)
->visit('/user')
->assertSee('Some Event')
->clickLink('Register Now')
->assertSee('Some Event')
->check('accept_terms')
->press('Submit Application')
->assertSee('Your application has been submitted.')
->press('.paypal-button')
->waitFor('#injectedUnifiedLogin', 30)
->switchFrame('injectedUl') // <---------------- here's where we switch frames
->type('#email', env('PAYPAL_TEST_BUYER_USERNAME')) // to access this nasty field
->type('#password', env('PAYPAL_TEST_BUYER_PASSWORD')) // and this one..
->press('#btnLogin') // apparently, it remembers the frame switch
->waitFor('#confirmButtonTop', 30)
->waitUntilMissing('#spinner')
->press('#confirmButtonTop')
->waitForText('You paid', 30)
->waitUntilMissing('#spinner')
->press('#merchantReturnBtn')
->waitForText('Events Registration', 30)
->pause(10000) // waiting for IPN callback from paypal
->refresh()
->assertSee('Payment verified')
;
Not sure if it's the best way to do this but it definitely works. Hope it helps!