Skip to content

Commit

Permalink
TST: enable exact_match config in playwright notebook test (#2027)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
fangchenli and pre-commit-ci[bot] authored Oct 18, 2023
1 parent 6846643 commit 20bc7d4
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 17 deletions.
84 changes: 67 additions & 17 deletions tests/common/run_notebook.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self, navigator: Navigator):
def run(
self,
path,
expected_outputs: List[Union[re.Pattern, str]],
expected_outputs: List[str],
conda_env: str,
timeout: float = 1000,
complition_wait_time: float = 2,
Expand All @@ -37,7 +37,7 @@ def run(
----------
path: str
Path to notebook relative to the root of the jupyterlab instance.
expected_outputs: List[Union[re.Pattern, str]]
expected_outputs: List[str]
Text to look for in the output of the notebook. This can be a
substring of the actual output if exact_match is False.
conda_env: str
Expand Down Expand Up @@ -79,7 +79,7 @@ def run(
time.sleep(retry_wait_time)
self._wait_for_commands_completion(timeout, complition_wait_time)
all_outputs = self._get_outputs()
self.assert_match_all_outputs(expected_outputs, all_outputs)
assert_match_all_outputs(expected_outputs, all_outputs, exact_match)

def create_notebook(self, conda_env=None):
file_locator = self.nav.page.get_by_text("File", exact=True)
Expand Down Expand Up @@ -124,9 +124,10 @@ def open_notebook(self, path):
def assert_code_output(
self,
code: str,
expected_output: List[Union[re.Pattern, str]],
expected_output: str,
timeout: float = 1000,
complition_wait_time: float = 2,
exact_match: bool = True,
):
"""
Run code in last cell and check for expected output text anywhere on
Expand All @@ -148,7 +149,8 @@ def assert_code_output(
self.run_in_last_cell(code)
self._wait_for_commands_completion(timeout, complition_wait_time)
outputs = self._get_outputs()
self.assert_match_output(expected_output, outputs[-1])
actual_output = outputs[-1] if outputs else ""
assert_match_output(expected_output, actual_output, exact_match)

def run_in_last_cell(self, code):
self._create_new_cell()
Expand Down Expand Up @@ -187,7 +189,7 @@ def _wait_for_commands_completion(
complition_wait_time: float
Time in seconds to wait between checking for expected output text.
"""
elapsed_time = 0
elapsed_time = 0.0
still_visible = True
start_time = time.time()
while elapsed_time < timeout:
Expand All @@ -203,21 +205,11 @@ def _wait_for_commands_completion(
f"but couldn't finish in {timeout} sec"
)

def _get_outputs(self):
def _get_outputs(self) -> List[str]:
output_elements = self.nav.page.query_selector_all(".jp-OutputArea-output")
text_content = [element.text_content().strip() for element in output_elements]
return text_content

def assert_match_all_outputs(self, expected_outputs, actual_outputs):
for ex, act in zip(expected_outputs, actual_outputs):
self.assert_match_output(ex, act)

def assert_match_output(self, expected_output, actual_output):
if isinstance(expected_output, re.Pattern):
assert re.match(expected_output, actual_output)
else:
assert expected_output == actual_output

def _restart_run_all(self):
# restart run all cells
self.nav.page.get_by_text("Kernel", exact=True).click()
Expand All @@ -232,3 +224,61 @@ def _restart_run_all(self):
)
if restart_dialog_button.is_visible():
restart_dialog_button.click()


def assert_match_output(
expected_output: str, actual_output: str, exact_match: bool
) -> None:
"""Assert that the expected_output is found in the actual_output.
----------
Parameters
expected_output: str
The expected output text or regular expression to find in the
actual output.
actual_output: str
The actual output text to search for the expected output.
exact_match: bool
If True, then the expected_output must match the actual_output
exactly. Otherwise, the expected_output must be found somewhere in
the actual_output.
"""
regex = re.compile(rf"{expected_output}")
match = (
regex.fullmatch(actual_output) if exact_match else regex.search(actual_output)
)
assert (
match is not None
), f"Expected output: {expected_output} not found in actual output: {actual_output}"


def assert_match_all_outputs(
expected_outputs: List[str],
actual_outputs: List[str],
exact_matches: Union[bool, List[bool]],
) -> None:
"""Assert that the expected_outputs are found in the actual_outputs.
The expected_outputs and actual_outputs must be the same length.
----------
Parameters
expected_outputs: List[str]
A list of expected output text or regular expression to find in
the actual output.
actual_outputs: List[str]
A list of actual output text to search for the expected output.
exact_matches: Union[bool, List[bool]]
If True, then the expected_output must match the actual_output
exactly. Otherwise, the expected_output must be found somewhere in
the actual_output. If a list is provided, then it must be the same
length as expected_outputs and actual_outputs.
"""
if isinstance(exact_matches, bool):
exact_matches = [exact_matches] * len(expected_outputs)

for exact_output, actual_output, exact in zip(
expected_outputs, actual_outputs, exact_matches
):
assert_match_output(exact_output, actual_output, exact)
35 changes: 35 additions & 0 deletions tests/common/tests/test_notebook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import pytest

from tests.common.run_notebook import assert_match_output


@pytest.mark.parametrize(
"expected, actual, exact",
[
("success: 6", "success: 6", True),
("success", "success: 6", False),
("6", "6", True),
("cde", "abcde", False),
("12.*5", "12345", True),
(".*5", "12345", True),
("ab.*ef", "123abcdef123", False),
],
)
def test_output_match(expected, actual, exact):
assert_match_output(expected, actual, exact_match=exact)


@pytest.mark.parametrize(
"expected, actual, exact",
[
("True", "False", True),
("success: 6", "success", True),
("60", "6", True),
("abcde", "cde", True),
("ab.*ef", "123abcdef123", True),
],
)
def test_output_not_match(expected, actual, exact):
msg = f"Expected output: {expected} not found in actual output: {actual}"
with pytest.raises(AssertionError, match=msg):
assert_match_output(expected, actual, exact_match=exact)

0 comments on commit 20bc7d4

Please sign in to comment.