Skip to content

React.js #272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gregory-claeyssens opened this issue May 15, 2017 · 8 comments
Closed

React.js #272

gregory-claeyssens opened this issue May 15, 2017 · 8 comments

Comments

@gregory-claeyssens
Copy link

gregory-claeyssens commented May 15, 2017

Hi there,

I'm trying to fill in a react form with dusk but it seems it does not trigger any onchange event.
Has anyone been able to make react and dusk work together in harmony?

Doing something like this does not work on a React component...
$browser->type('card_number', '4242 4242 4242 4242');
Nor this

$browser->keys('[name=card_number]', '4242 4242 4242 4242');
$browser->pause(1000);
$browser->click('[name=card_exp]');
$browser->pause(1000);

The input just stays empty, I can see that it's focussing on the correct element though...

Thank you in advance.

Seems I was a bit hasty, the onchange event is fired correctly, it seems more like a synthentic event that is not fired. This will probably not be a dusk issue/question

@gregory-claeyssens
Copy link
Author

gregory-claeyssens commented May 16, 2017

So after some searching around i found out that synthetic events are not supported in Chrome, but they are in the Firefox driver. Spend some numerous hours figuring out how to get this working with firefox. This included the following (mac os x):

  1. Have Firefox installed
  2. Install the geckodriver,
  3. Install the selenium stand alone jar
  4. Update my java version
  5. Change DuskTestCase class as found below
  6. Run the selenium stand alone jar
  7. Run php artisan dusk
<?php namespace Tests;

use Facebook\WebDriver\Chrome\ChromeOptions;
use Laravel\Dusk\TestCase as BaseTestCase;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;

abstract class DuskTestCase extends BaseTestCase {
    use CreatesApplication;

    /**
     * Prepare for Dusk test execution.
     *
     * @beforeClass
     * @return void
     */
    public static function prepare() {
        // static::startChromeDriver();
    }

    /**
     * Create the RemoteWebDriver instance.
     *
     * @return \Facebook\WebDriver\Remote\RemoteWebDriver
     */
    protected function driver() {
        return RemoteWebDriver::create(
            'http://localhost:4444/wd/hub', DesiredCapabilities::firefox()
        );
    }
}

I think this might help people if the section 'running different browsers' was explained better in the docs

@deleugpn
Copy link
Contributor

deleugpn commented May 16, 2017

@sweet-greg I would recommend you to write a Medium blog post and submit it to https://laravel-news.com/links to get featured in the weekly newsletter. It's a good community contribution, imo.

@wirelessed
Copy link

I tried to use firefox too but I'm getting a
Facebook\WebDriver\Exception\NoSuchElementException: Unable to locate element:

@DerJacques
Copy link

This may be a very long shot, but [name=card_number] looks like an input field in the Stripe checkout form. If that's not the case, don't read any of the following:

Dusk has a hard time testing the iframe that Stripe automatically creates for the form.
Here's a description on how to to test Stripe using Dusk: https://medium.com/@phpTechnocrat/how-to-use-laravel-dusk-to-test-stripe-cashier-c27471c0383

Again, if that's not what you're doing, you may forget all about this :)

@ryanwild
Copy link

React synthetic events have a known issue in Selenium and jQuery that seem to dispatch events differently, I solved interacting with React elements by dispatching actual DOM Events:

on my Page object I added this method:

public static function triggerDOMEvent(Browser $browser, $event, $elementSelector)
    {
        $script = "var event = document.createEvent('HTMLEvents'); event.initEvent('$event', true, true); var target = $elementSelector; target.dispatchEvent(event);";
        return $browser->driver->executeScript($script);
    }

usage:

SomePage::triggerDOMEvent($browser, 'click', 'document.getElementsByClassName("react-element-class-name")[0]');

See this thread: facebook/react#3249 (comment)

@ryanwild
Copy link

@sweet-greg you could use my function to dispatch a change event like this:

YourPage::triggerDOMEvent($browser, 'change', 'document.getElementsByClassName("your-select-box")[0]');

This would probably need some tweaking to trigger the change and select the specific value but I hope this helps anyone who comes across the same problem

The change event:
https://developer.mozilla.org/en-US/docs/Web/Events/change

@ryanwild
Copy link

ryanwild commented Feb 15, 2018

After further testing I have narrowed down the issue to a React15 behavior.

React 15.x strips out any custom attributes so the dusk="my-element" is lost and and using the standard Dusk API will not work.

The best advice is to simply upgrade to React 16 and everything will work as expected.

Alternatively you could work around the problem by using a different non-standard approach I would not recommend doing so because the Dusk API might change in the future and cause your test case to break.

Here is an example of the alternative workaround to make elements clickable:

<?php

namespace Tests\Browser;

use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Facebook\WebDriver\WebDriverBy;

class ReactTest extends DuskTestCase
{
    /**
     * Tests that the element is clickable and works on React 15
     * 
     * Because React 15 does not allow custom attributes such as the custom `dusk="test-button"`
     * (see here: https://laravel.com/docs/5.5/dusk#dusk-selectors) we have to break the Dusk API
     * convention and reach for the lower level WebDriver API.
     * 
     * This does not allow us to chain our test case commands but is indeed at least a working example
     *
     * @return void
     */
    public function testReactFifteenExample()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/')
                    ->assertSee('Laravel')
                    ->driver->findElement(WebDriverBy::id('test-button'))
                    ->click();
            $browser->assertSee('Hello Computer :P');
        });
    }
}

@driesvints
Copy link
Member

Closing this issue because it's already solved, old or not relevant anymore. Feel free to reply if you're still experiencing this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants