Repository: microsoft/playwright-python
Pull request #2661 (2024-11-21 14:04:04)

fix(select): handle empty values and labels in select options
Fixes https://github.com/microsoft/playwright-python/issues/2659


Patch:
diff --git a/playwright/_impl/_element_handle.py b/playwright/_impl/_element_handle.py
index 07d055e..cb3d672 100644
--- a/playwright/_impl/_element_handle.py
+++ b/playwright/_impl/_element_handle.py
@@ -392,15 +392,15 @@ def convert_select_option_values(
 
     options: Any = None
     elements: Any = None
-    if value:
+    if value is not None:
         if isinstance(value, str):
             value = [value]
         options = (options or []) + list(map(lambda e: dict(valueOrLabel=e), value))
-    if index:
+    if index is not None:
         if isinstance(index, int):
             index = [index]
         options = (options or []) + list(map(lambda e: dict(index=e), index))
-    if label:
+    if label is not None:
         if isinstance(label, str):
             label = [label]
         options = (options or []) + list(map(lambda e: dict(label=e), label))


Test patch:
diff --git a/tests/async/test_page_select_option.py b/tests/async/test_page_select_option.py
index e59c6a4..c5edf54 100644
--- a/tests/async/test_page_select_option.py
+++ b/tests/async/test_page_select_option.py
@@ -45,6 +45,22 @@ async def test_select_option_should_select_single_option_by_label(
     assert await page.evaluate("result.onChange") == ["indigo"]
 
 
+async def test_select_option_should_select_single_option_by_empty_label(
+    page: Page, server: Server
+) -> None:
+    await page.set_content(
+        """
+        <select>
+            <option value="indigo">Indigo</option>
+            <option value="violet"></option>
+        </select>
+    """
+    )
+    assert await page.locator("select").input_value() == "indigo"
+    await page.select_option("select", label="")
+    assert await page.locator("select").input_value() == "violet"
+
+
 async def test_select_option_should_select_single_option_by_handle(
     page: Page, server: Server
 ) -> None:
@@ -65,6 +81,14 @@ async def test_select_option_should_select_single_option_by_index(
     assert await page.evaluate("result.onChange") == ["brown"]
 
 
+async def test_select_option_should_select_single_option_by_index_0(
+    page: Page, server: Server
+) -> None:
+    await page.goto(server.PREFIX + "/input/select.html")
+    await page.select_option("select", index=0)
+    assert await page.evaluate("result.onInput") == ["black"]
+
+
 async def test_select_option_should_select_only_first_option(
     page: Page, server: Server
 ) -> None:
@@ -112,6 +136,23 @@ async def test_select_option_should_select_multiple_options_with_attributes(
     assert await page.evaluate("result.onChange") == ["blue", "gray", "green"]
 
 
+async def test_select_option_should_select_option_with_empty_value(
+    page: Page, server: Server
+) -> None:
+    await page.goto(server.EMPTY_PAGE)
+    await page.set_content(
+        """
+        <select>
+            <option value="first">First</option>
+            <option value="">Second</option>
+        </select>
+    """
+    )
+    assert await page.locator("select").input_value() == "first"
+    await page.select_option("select", value="")
+    assert await page.locator("select").input_value() == ""
+
+
 async def test_select_option_should_respect_event_bubbling(
     page: Page, server: Server
 ) -> None:
diff --git a/tests/sync/test_page_select_option.py b/tests/sync/test_page_select_option.py
index 3c746dc..7bb6ade 100644
--- a/tests/sync/test_page_select_option.py
+++ b/tests/sync/test_page_select_option.py
@@ -43,6 +43,22 @@ def test_select_option_should_select_single_option_by_label(
     assert page.evaluate("result.onChange") == ["indigo"]
 
 
+def test_select_option_should_select_single_option_by_empty_label(
+    page: Page, server: Server
+) -> None:
+    page.set_content(
+        """
+        <select>
+            <option value="indigo">Indigo</option>
+            <option value="violet"></option>
+        </select>
+    """
+    )
+    assert page.locator("select").input_value() == "indigo"
+    page.select_option("select", label="")
+    assert page.locator("select").input_value() == "violet"
+
+
 def test_select_option_should_select_single_option_by_handle(
     server: Server, page: Page
 ) -> None:
@@ -61,6 +77,14 @@ def test_select_option_should_select_single_option_by_index(
     assert page.evaluate("result.onChange") == ["brown"]
 
 
+def test_select_option_should_select_single_option_by_index_0(
+    page: Page, server: Server
+) -> None:
+    page.goto(server.PREFIX + "/input/select.html")
+    page.select_option("select", index=0)
+    assert page.evaluate("result.onInput") == ["black"]
+
+
 def test_select_option_should_select_only_first_option(
     server: Server, page: Page
 ) -> None:
@@ -108,6 +132,23 @@ def test_select_option_should_select_multiple_options_with_attributes(
     assert page.evaluate("result.onChange") == ["blue", "gray", "green"]
 
 
+def test_select_option_should_select_option_with_empty_value(
+    page: Page, server: Server
+) -> None:
+    page.goto(server.EMPTY_PAGE)
+    page.set_content(
+        """
+        <select>
+            <option value="first">First</option>
+            <option value="">Second</option>
+        </select>
+    """
+    )
+    assert page.locator("select").input_value() == "first"
+    page.select_option("select", value="")
+    assert page.locator("select").input_value() == ""
+
+
 def test_select_option_should_respect_event_bubbling(
     server: Server, page: Page
 ) -> None: