diff --git a/integration/test_upload.py b/integration/test_upload.py index 240b4ae47..0e0917fca 100644 --- a/integration/test_upload.py +++ b/integration/test_upload.py @@ -47,6 +47,11 @@ def UploadFile(): ), id="selected_files", ), + rx.button( + "Clear", + on_click=rx.clear_selected_files, + id="clear_button", + ), ) app = rx.App(state=UploadState) @@ -172,3 +177,48 @@ def test_upload_file_multiple(tmp_path, upload_file: AppHarness, driver): time.sleep(0.5) for exp_name, exp_contents in exp_files.items(): assert backend_state._file_data[exp_name] == exp_contents + + +def test_clear_files(tmp_path, upload_file: AppHarness, driver): + """Select then clear several file uploads and check that they are cleared. + + Args: + tmp_path: pytest tmp_path fixture + upload_file: harness for UploadFile app. + driver: WebDriver instance. + """ + assert upload_file.app_instance is not None + token_input = driver.find_element(By.ID, "token") + assert token_input + # wait for the backend connection to send the token + token = upload_file.poll_for_value(token_input) + assert token is not None + + upload_box = driver.find_element(By.XPATH, "//input[@type='file']") + assert upload_box + upload_button = driver.find_element(By.ID, "upload_button") + assert upload_button + + exp_files = { + "test1.txt": "test file contents!", + "test2.txt": "this is test file number 2!", + "reflex.txt": "reflex is awesome!", + } + for exp_name, exp_contents in exp_files.items(): + target_file = tmp_path / exp_name + target_file.write_text(exp_contents) + upload_box.send_keys(str(target_file)) + + time.sleep(0.2) + + # check that the selected files are displayed + selected_files = driver.find_element(By.ID, "selected_files") + assert selected_files.text == "\n".join(exp_files) + + clear_button = driver.find_element(By.ID, "clear_button") + assert clear_button + clear_button.click() + + # check that the selected files are cleared + selected_files = driver.find_element(By.ID, "selected_files") + assert selected_files.text == "" diff --git a/reflex/components/forms/__init__.py b/reflex/components/forms/__init__.py index ad816a46e..40640c1c8 100644 --- a/reflex/components/forms/__init__.py +++ b/reflex/components/forms/__init__.py @@ -46,11 +46,12 @@ from .select import Option, Select from .slider import Slider, SliderFilledTrack, SliderMark, SliderThumb, SliderTrack from .switch import Switch from .textarea import TextArea -from .upload import Upload, selected_files +from .upload import Upload, clear_selected_files, selected_files helpers = [ "color_mode_cond", "selected_files", + "clear_selected_files", ] __all__ = [f for f in dir() if f[0].isupper()] + helpers # type: ignore diff --git a/reflex/components/forms/upload.py b/reflex/components/forms/upload.py index f923a71a1..344596618 100644 --- a/reflex/components/forms/upload.py +++ b/reflex/components/forms/upload.py @@ -15,6 +15,8 @@ upload_file = BaseVar(name="e => setFiles((files) => e)", type_=EventChain) # Use this var along with the Upload component to render the list of selected files. selected_files = BaseVar(name="files.map((f) => f.name)", type_=List[str]) +clear_selected_files = BaseVar(name="_e => setFiles((files) => [])", type_=EventChain) + class Upload(Component): """A file upload component."""