Skip to content

Commit

Permalink
chore: roll Playwright to ToT
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelfeldman committed Oct 6, 2022
1 parent 4fda29c commit 24dd032
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 31 deletions.
28 changes: 13 additions & 15 deletions playwright/_impl/_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
escape_for_attribute_selector,
escape_for_text_selector,
escape_regex_flags,
escape_with_quotes,
)

if sys.version_info >= (3, 8): # pragma: no cover
Expand Down Expand Up @@ -79,19 +78,17 @@ def __init__(
self._dispatcher_fiber = frame._connection._dispatcher_fiber

if has_text:
if isinstance(has_text, Pattern):
js_regex = f"/{has_text.pattern}/{escape_regex_flags(has_text)}"
self._selector += (
f' >> has={json.dumps("text=" + js_regex, ensure_ascii=False)}'
)
else:
escaped = escape_with_quotes(has_text, '"')
self._selector += f" >> :scope:has-text({escaped})"
text_selector = "text=" + escape_for_text_selector(has_text, exact=False)
self._selector += (
f" >> internal:has={json.dumps(text_selector, ensure_ascii=False)}"
)

if has:
if has._frame != frame:
raise Error('Inner "has" locator must belong to the same frame.')
self._selector += " >> has=" + json.dumps(has._selector, ensure_ascii=False)
self._selector += " >> internal:has=" + json.dumps(
has._selector, ensure_ascii=False
)

def __repr__(self) -> str:
return f"<Locator frame={self._frame!r} selector={self._selector!r}>"
Expand Down Expand Up @@ -645,7 +642,7 @@ def locator(
) -> Locator:
return Locator(
self._frame,
f"{self._frame_selector} >> control=enter-frame >> {selector}",
f"{self._frame_selector} >> internal:control=enter-frame >> {selector}",
has_text=has_text,
has=has,
)
Expand Down Expand Up @@ -706,7 +703,8 @@ def get_by_title(

def frame_locator(self, selector: str) -> "FrameLocator":
return FrameLocator(
self._frame, f"{self._frame_selector} >> control=enter-frame >> {selector}"
self._frame,
f"{self._frame_selector} >> internal:control=enter-frame >> {selector}",
)

@property
Expand Down Expand Up @@ -740,13 +738,13 @@ def get_by_attribute_text_selector(
attr_name: str, text: Union[str, Pattern[str]], exact: bool = None
) -> str:
if isinstance(text, Pattern):
return f"attr=[{attr_name}=/{text.pattern}/{escape_regex_flags(text)}]"
return f"internal:attr=[{attr_name}=/{text.pattern}/{escape_regex_flags(text)}]"
suffix = "s" if exact else "i"
return f"attr=[{attr_name}={escape_for_attribute_selector(text)}{suffix}]"
return f"internal:attr=[{attr_name}={escape_for_attribute_selector(text)}{suffix}]"


def get_by_label_selector(text: Union[str, Pattern[str]], exact: bool = None) -> str:
return get_by_text_selector(text, exact=exact) + " >> control=resolve-label"
return "internal:label=" + escape_for_text_selector(text, exact=exact)


def get_by_alt_text_selector(text: Union[str, Pattern[str]], exact: bool = None) -> str:
Expand Down
15 changes: 1 addition & 14 deletions playwright/_impl/_str_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import re
from typing import Pattern, Union


def escape_with_quotes(text: str, char: str = "'") -> str:
stringified = json.dumps(text, ensure_ascii=False)
escaped_text = stringified[1:-1].replace('\\"', '"')
if char == "'":
return char + escaped_text.replace("'", "\\'") + char
if char == '"':
return char + escaped_text.replace('"', '\\"') + char
if char == "`":
return char + escaped_text.replace("`", "\\`") + char
raise ValueError("Invalid escape char")


def escape_regex_flags(pattern: Pattern) -> str:
flags = ""
if pattern.flags != 0:
Expand Down Expand Up @@ -60,7 +47,7 @@ def escape_for_text_selector(
return '"' + text.replace('"', '\\"') + '"'
if '"' in text or ">>" in text or text[0] == "/":
suffix = "" if case_sensitive else "i"
return re.sub(r"\s+", "\\s+", escape_for_regex(text)) + suffix
return "/" + re.sub(r"\s+", "\\\\s+", escape_for_regex(text)) + "/" + suffix
return text


Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
InWheel = None
from wheel.bdist_wheel import bdist_wheel as BDistWheelCommand

driver_version = "1.27.0-alpha-1664914898000"
driver_version = "1.28.0-alpha-oct-6-2022"


def extractall(zip: zipfile.ZipFile, path: str) -> None:
Expand Down
83 changes: 82 additions & 1 deletion tests/sync/test_locator_get_by.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ def test_get_by_test_id_escape_id(page: Page) -> None:


def test_get_by_text(page: Page) -> None:
page.set_content("<div>yo</div><div>ya</div><div>\nye </div>")
page.set_content("<div><div>yo</div><div>ya</div><div>\nye </div></div>")

expect(page.get_by_text("yo")).to_have_count(1)
expect(page.main_frame.get_by_text("yo")).to_have_count(1)
expect(page.locator("div").get_by_text("yo")).to_have_count(1)

assert ">\nye </div>" in page.get_by_text("ye").evaluate("e => e.outerHTML")
assert ">\nye </div>" in page.get_by_text(r"ye").evaluate("e => e.outerHTML")

Expand All @@ -50,6 +55,11 @@ def test_get_by_label(page: Page) -> None:
page.set_content(
"<div><label for=target>Name</label><input id=target type=text></div>"
)

expect(page.get_by_label("Name")).to_have_count(1)
expect(page.main_frame.get_by_label("Name")).to_have_count(1)
expect(page.locator("div").get_by_label("Name")).to_have_count(1)

assert page.get_by_text("Name").evaluate("e => e.nodeName") == "LABEL"
assert page.get_by_label("Name").evaluate("e => e.nodeName") == "INPUT"
assert page.main_frame.get_by_label("Name").evaluate("e => e.nodeName") == "INPUT"
Expand All @@ -58,13 +68,38 @@ def test_get_by_label(page: Page) -> None:
)


def test_get_by_label_with_nested_elements(page: Page) -> None:
page.set_content(
"<label for=target>Last <span>Name</span></label><input id=target type=text>"
)

expect(page.get_by_label("last name")).to_have_attribute("id", "target")
expect(page.get_by_label("st na")).to_have_attribute("id", "target")
expect(page.get_by_label("Name")).to_have_attribute("id", "target")
expect(page.get_by_label("Last Name", exact=True)).to_have_attribute("id", "target")
expect(
page.get_by_label(re.compile(r"Last\s+name", re.IGNORECASE))
).to_have_attribute("id", "target")

expect(page.get_by_label("Last", exact=True)).to_have_count(0)
expect(page.get_by_label("last name", exact=True)).to_have_count(0)
expect(page.get_by_label("Name", exact=True)).to_have_count(0)
expect(page.get_by_label("what?")).to_have_count(0)
expect(page.get_by_label(re.compile(r"last name"))).to_have_count(0)


def test_get_by_placeholder(page: Page) -> None:
page.set_content(
"""<div>
<input placeholder="Hello">
<input placeholder="Hello World">
</div>"""
)

expect(page.get_by_placeholder("hello")).to_have_count(2)
expect(page.main_frame.get_by_placeholder("hello")).to_have_count(2)
expect(page.locator("div").get_by_placeholder("hello")).to_have_count(2)

expect(page.get_by_placeholder("hello")).to_have_count(2)
expect(page.get_by_placeholder("Hello", exact=True)).to_have_count(1)
expect(page.get_by_placeholder(re.compile(r"wor", re.IGNORECASE))).to_have_count(1)
Expand All @@ -81,6 +116,11 @@ def test_get_by_alt_text(page: Page) -> None:
<input alt="Hello World">
</div>"""
)

expect(page.get_by_alt_text("hello")).to_have_count(2)
expect(page.main_frame.get_by_alt_text("hello")).to_have_count(2)
expect(page.locator("div").get_by_alt_text("hello")).to_have_count(2)

expect(page.get_by_alt_text("hello")).to_have_count(2)
expect(page.get_by_alt_text("Hello", exact=True)).to_have_count(1)
expect(page.get_by_alt_text(re.compile(r"wor", re.IGNORECASE))).to_have_count(1)
Expand All @@ -97,10 +137,51 @@ def test_get_by_title(page: Page) -> None:
<input title="Hello World">
</div>"""
)

expect(page.get_by_title("hello")).to_have_count(2)
expect(page.main_frame.get_by_title("hello")).to_have_count(2)
expect(page.locator("div").get_by_title("hello")).to_have_count(2)

expect(page.get_by_title("hello")).to_have_count(2)
expect(page.get_by_title("Hello", exact=True)).to_have_count(1)
expect(page.get_by_title(re.compile(r"wor", re.IGNORECASE))).to_have_count(1)

# Coverage
expect(page.main_frame.get_by_title("hello")).to_have_count(2)
expect(page.locator("div").get_by_title("hello")).to_have_count(2)


def test_get_by_escaping(page: Page) -> None:
page.set_content(
"""<label id=label for=control>Hello
wo"rld</label><input id=control />"""
)
page.locator("input").evaluate(
"""input => {
input.setAttribute('placeholder', 'hello\\nwo"rld');
input.setAttribute('title', 'hello\\nwo"rld');
input.setAttribute('alt', 'hello\\nwo"rld');
}"""
)
expect(page.get_by_text('hello\nwo"rld')).to_have_attribute("id", "label")
expect(page.get_by_label('hello\nwo"rld')).to_have_attribute("id", "control")
expect(page.get_by_placeholder('hello\nwo"rld')).to_have_attribute("id", "control")
expect(page.get_by_alt_text('hello\nwo"rld')).to_have_attribute("id", "control")
expect(page.get_by_title('hello\nwo"rld')).to_have_attribute("id", "control")

page.set_content(
"""<label id=label for=control>Hello
world</label><input id=control />"""
)
page.locator("input").evaluate(
"""input => {
input.setAttribute('placeholder', 'hello\\nworld');
input.setAttribute('title', 'hello\\nworld');
input.setAttribute('alt', 'hello\\nworld');
}"""
)
expect(page.get_by_text("hello\nworld")).to_have_attribute("id", "label")
expect(page.get_by_label("hello\nworld")).to_have_attribute("id", "control")
expect(page.get_by_placeholder("hello\nworld")).to_have_attribute("id", "control")
expect(page.get_by_alt_text("hello\nworld")).to_have_attribute("id", "control")
expect(page.get_by_title("hello\nworld")).to_have_attribute("id", "control")

0 comments on commit 24dd032

Please sign in to comment.