Skip to content
This repository has been archived by the owner on Jun 3, 2024. It is now read-only.

Fix clearable #599

Merged
merged 11 commits into from
Aug 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
environment:
PYTHON_VERSION: py27
PERCY_PARALLEL_TOTAL: '-1'
- image: percyio/agent

steps:
- checkout
Expand Down Expand Up @@ -53,6 +54,11 @@ jobs:
python --version
npm run test

- run:
name: Percy TearDown
Copy link
Contributor Author

@byronz byronz Aug 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are numerous requests on circleci community about conditional Jobs upon previous failure. right now, the behavior is when the previous job fails, the percy finalize job cannot be executed.

a compromise for now as a percy clean up when failed

command: percy --finalize -all
when: on_fail

'python-3.6':
<<: *test-template
docker:
Expand All @@ -73,7 +79,7 @@ workflows:
version: 2
build:
jobs:
- 'python-2.7'
- python-2.7
- "percy-finalize":
requires:
- 'python-2.7'
Expand Down
12 changes: 11 additions & 1 deletion src/components/DatePickerRange.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default class DatePickerRange extends Component {
}

onDatesChange({startDate: start_date, endDate: end_date}) {
const {setProps, updatemode} = this.props;
const {setProps, updatemode, clearable} = this.props;

const oldMomentDates = convertToMoment(this.state, [
'start_date',
Expand All @@ -71,6 +71,16 @@ export default class DatePickerRange extends Component {
});
}
}

if (
clearable &&
!start_date &&
!end_date &&
(oldMomentDates.start_date !== start_date ||
oldMomentDates.end_date !== end_date)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Marc-Andre-Rivet when you click the x, both start and end will be set to null, the condition can be either one date changed .

) {
setProps({start_date: null, end_date: null});
}
Copy link
Contributor

@Marc-Andre-Rivet Marc-Andre-Rivet Aug 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the previous code was not optimal in terms of setProps, it would have updated the values in all cases. Now this won't update if one is unset, whether updatemode is single or both. Rather than preventing the update if one of start/end was not previously set, could instead check and add each individually if the "global" condition is met.

e.g.

if (clearable && (!start_date || !end_date)) {
    const props = { };
    if (!start_date && oldMomentDates.start_date) {
        props.start_date = null;
    }
    // idem for end_date

    setProps(props);
}

}

isOutsideRange(date) {
Expand Down
110 changes: 110 additions & 0 deletions tests/integration/calendar/test_calendar_props.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import itertools
import pytest

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

DAY_SELECTOR = 'div[data-visible="true"] td.CalendarDay'


@pytest.mark.DCC594
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an idea I have in mind to associate the test case with issue number, could be helpful for test selection by associating the test case with the issue

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@byronz we can keep this if it's useful, but we should do something to clear the warning it currently gives:

/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/_pytest/mark/structures.py:324: PytestUnknownMarkWarning:
Unknown pytest.mark.DCC594 - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html

def test_cdpr001_date_clearable_true_works(dash_duo):

app = dash.Dash(__name__)
app.layout = html.Div([dcc.DatePickerRange(id="dpr", clearable=True)])

dash_duo.start_server(app)

start_date = dash_duo.find_element('input[aria-label="Start Date"]')
end_date = dash_duo.find_element('input[aria-label="End Date"]')

start_date.click()

dash_duo.find_elements(DAY_SELECTOR)[0].click()
dash_duo.find_elements(DAY_SELECTOR)[-1].click()

close_btn = dash_duo.wait_for_element('button[aria-label="Clear Dates"]')

assert start_date.get_attribute("value") and end_date.get_attribute(
"value"
), "both start date and end date should get values"

close_btn.click()
assert not start_date.get_attribute(
"value"
) and not end_date.get_attribute(
"value"
), "both start and end dates should be cleared"


def test_cdpr002_updatemodes(dash_duo):
app = dash.Dash(__name__)

app.layout = html.Div(
[
dcc.DatePickerRange(
id="date-picker-range",
start_date_id="startDate",
end_date_id="endDate",
start_date_placeholder_text="Select a start date!",
end_date_placeholder_text="Select an end date!",
updatemode="bothdates",
),
html.Div(id="date-picker-range-output"),
]
)

@app.callback(
Output("date-picker-range-output", "children"),
[
Input("date-picker-range", "start_date"),
Input("date-picker-range", "end_date"),
],
)
def update_output(start_date, end_date):
return "{} - {}".format(start_date, end_date)

dash_duo.start_server(app=app)

start_date = dash_duo.find_element("#startDate")
start_date.click()

end_date = dash_duo.find_element("#endDate")
end_date.click()

assert (
dash_duo.find_element("#date-picker-range-output").text
== "None - None"
), "the output should not update when both clicked but no selection happen"

start_date.click()

dash_duo.find_elements(DAY_SELECTOR)[4].click()
assert (
dash_duo.find_element("#date-picker-range-output").text
== "None - None"
), "the output should not update when only one is selected"

eday = dash_duo.find_elements(DAY_SELECTOR)[-4]
wait.until(lambda: eday.is_displayed() and eday.is_enabled(), timeout=2)
eday.click()

date_tokens = set(start_date.get_attribute("value").split("/"))
date_tokens.update(end_date.get_attribute("value").split("/"))

assert (
set(
itertools.chain(
*[
_.split("-")
for _ in dash_duo.find_element(
"#date-picker-range-output"
).text.split(" - ")
]
)
)
== date_tokens
), "date should match the callback output"
54 changes: 0 additions & 54 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -1186,60 +1186,6 @@ def test_graphs_without_ids(self):

self.assertNotEqual(graph_1.get_attribute('id'), graph_2.get_attribute('id'))

def test_datepickerrange_updatemodes(self):
app = dash.Dash(__name__)

app.layout = html.Div([
dcc.DatePickerRange(
id='date-picker-range',
start_date_id='startDate',
end_date_id='endDate',
start_date_placeholder_text='Select a start date!',
end_date_placeholder_text='Select an end date!',
updatemode='bothdates'
),
html.Div(id='date-picker-range-output')
])

@app.callback(
dash.dependencies.Output('date-picker-range-output', 'children'),
[dash.dependencies.Input('date-picker-range', 'start_date'),
dash.dependencies.Input('date-picker-range', 'end_date')])
def update_output(start_date, end_date):
return '{} - {}'.format(start_date, end_date)

self.startServer(app=app)

start_date = self.wait_for_element_by_css_selector('#startDate')
start_date.click()

end_date = self.wait_for_element_by_css_selector('#endDate')
end_date.click()

self.wait_for_text_to_equal('#date-picker-range-output', 'None - None')

# using mouse click with fixed day range, this can be improved
# once we start refactoring the test structure
start_date.click()

sday = self.driver.find_element_by_xpath("//td[text()='1' and @tabindex='0']")
sday.click()
self.wait_for_text_to_equal('#date-picker-range-output', 'None - None')

eday = self.driver.find_elements_by_xpath("//td[text()='28']")[1]
eday.click()

date_tokens = set(start_date.get_attribute('value').split('/'))
date_tokens.update(end_date.get_attribute('value').split('/'))

self.assertEqual(
set(itertools.chain(*[
_.split('-')
for _ in self.driver.find_element_by_css_selector(
'#date-picker-range-output').text.split(' - ')])),
date_tokens,
"date should match the callback output")

def test_interval(self):
app = dash.Dash(__name__)
app.layout = html.Div([
Expand Down