Dash testing -- callback/mock synchronisation issues on Windows (but not on Linux or OSX)

** EDIT **
I’ve done some further investigation of the issue (and verified that it’s not present on Linux OR OSX) and raised an issue on Github here:


See the github issue for an updated example / further details.

Hi,
I’ve started instrumenting some existing code using dash-testing and have run into a strange issue. Developing in my usual environment (Linux), my tests work – use css selectors to read current values, update them and then verify that mocked functions invoked in a callback are called as expected.
Running the same tests on Windows, the callbacks don’t appear to be triggered when I modify values using sendkeys(). I can see the relevant inputs getting changed when the browser window pops up, and callbacks are getting invoked once (the initial invocation on page load). Also selenium wait_for…() methods continue to work to verify the content modified using sendkeys(), but the callbacks don’t appear to run again in response to these UI events.

I’ve written a nonsense self contained example (below) that illustrates the issue. Reproduced on two Windows 10 machines using Python 3.7.4 and latest dash (1.0.2) and selenium (3.141.0). Chromedriver 75.0.3770

Test passes on my Arch Linux dev machine running same versions (chromedriver via chromium package). Also (today) using updated package versoin 76.0.3809

EDIT the 3 invocations of random.randint expected are:

  1. Page load
  2. -2 entered
  3. -20 entered
    On windows, only the first appears to occur.
import re
import random

import pytest

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State

DEFAULT_VALUE = 20
NEW_VALUE = -20

def _build_app_layout():
    app = dash.Dash(__name__)
    app.layout = html.Div(id='top',children=[
      dcc.Input(id='some_input', value=str(DEFAULT_VALUE)),
      html.Div(id='alert_container')
    ])
    @app.callback(Output('alert_container', 'children'),
                  [Input('some_input', 'value')])
    def validate_input(new_value: str):
        valid = new_value == str(random.randint(int(new_value), DEFAULT_VALUE)) if re.match(r'[+-]?\d+',new_value) else False
        return 'Valid' if valid else 'Invalid'
    return app


@pytest.mark.newtest
@pytest.mark.webtest
def test_should_validate_inputs_when_ULL_modified(mocker, dash_duo):
    """This is a self-contained test intended to reproduce a problem we've been
    having, where callbacks are triggered by selenium (dash-testing) on Linux, but
    not on Windows.
    """
    # Given
    mocker.patch('random.randint', return_value=DEFAULT_VALUE)
    dash_duo.start_server(_build_app_layout())
    input_element = dash_duo.find_element('input#some_input')
    initial_value = input_element.get_attribute('value')

    # When
    dash_duo.clear_input(input_element)
    input_element.send_keys(f'{NEW_VALUE}')
    dash_duo.wait_for_contains_text('input#some_input', str(NEW_VALUE), timeout=5)

    # Then
    assert random.randint.call_count == 3
    random.randint.assert_called_with(NEW_VALUE, DEFAULT_VALUE)

I’ll raise an issue on Github Monday, just posting here first as a quick sanity check in case I’m doing something obvious/stupid that I shouldn’t.