LibWeb: Update add_libweb_test.py to support Screenshot, Ref, and Layout

Changed the usage from `add_libweb_test.py test_name.html` to
`add_libweb_test.py test_name.html test_type` with no default,
and supports automatically generating input/output files in the
right directories for test types Screenshot, Text, Ref, and Layout.

Co-authored-by: Sam Atkins <sam@ladybird.org>
This commit is contained in:
Noah Bright 2024-10-09 16:33:35 -04:00 committed by Sam Atkins
parent bb5d1ac4a3
commit 18b4dc2153
Notes: github-actions[bot] 2025-01-13 14:27:16 +00:00
2 changed files with 88 additions and 24 deletions

View file

@ -123,16 +123,19 @@ That is, you give `./Meta/WPT.sh import` the path part of any `http://wpt.live/`
## Writing tests ## Writing tests
Running `Tests/LibWeb/add_libweb_test.py your-new-test-name` will create a new test HTML file in Running `Tests/LibWeb/add_libweb_test.py your-new-test-name test_type` will create a new test HTML file in
`Tests/LibWeb/Text/input/your-new-test-name.html` with the correct boilerplate code for a Text test — along with `Tests/LibWeb/test_type(/input)` (`/input` is appended for Text and Layout tests) with the correct boilerplate
a corresponding expectations file in `Tests/LibWeb/Text/expected/your-new-test-name.txt`. code for a `test_type` test — along with a corresponding expectations file in the appropriate directory, e.g.,
`Tests/LibWeb/Text/expected/your-new-test-name.txt`, for a Text test, or
`Tests/LibWeb/Ref/reference/your-new-test-name.txt` for a Ref test. The accepted `test_types` are "Text",
"Ref", "Screenshot", and "Layout".
After you update/replace the generated boilerplate in your `your-new-test-name.html` test file with your actual test, If you make a new Text or Layout test, after you update/replace the generated boilerplate in your
running `./Meta/ladybird.sh run headless-browser --run-tests "${LADYBIRD_SOURCE_DIR}/Tests/LibWeb" --rebaseline -f Text/input/foobar.html` will `your-new-test-name.html` test file with your actual test, running
regenerate the corresponding expectations file — to match the actual output from your updated test (where `./Meta/ladybird.sh run headless-browser --run-tests "./Tests/LibWeb" --rebaseline -f Text/input/foobar.html`
`/opt/ladybird` should be replaced with the absolute path your ladybird clone in your local environment). will regenerate the corresponding expectations file to match the actual output from your updated test.
Future versions of the `add_libweb_test.py` script will support other test types. If you add a new Ref or Screenshot test, you'll need to supply the equivalently rendering HTML manually.
### Text tests ### Text tests

View file

@ -9,31 +9,52 @@ from pathlib import Path
TEST_DIR = Path(__file__).resolve().parent TEST_DIR = Path(__file__).resolve().parent
def create_text_test(test_name: str, is_async: bool = False) -> None: def create_test(test_name: str, test_type: str, is_async: bool = False) -> None:
""" """
Create a new Text type test file with the given test name. Create a test of a given type with the given test name
Args: Args:
test_name (str): Name of the test. test_name (str): Name of the test.
test_type (str): Type of the test. Currently supports
"Text", "Layout", "Screenshot" and "Ref""
is_async (bool, optional): Whether it is an async test. Defaults to False. is_async (bool, optional): Whether it is an async test. Defaults to False.
""" """
input_prefix = TEST_DIR / "Text" / "input" / test_name
input_dir = input_prefix.parent
input_file = input_prefix.with_suffix(".html")
expected_prefix = TEST_DIR / "Text" / "expected" / test_name input_prefix = TEST_DIR / test_type / "input" / test_name
expected_dir = expected_prefix.parent input_file = input_prefix.with_suffix(".html")
expected_file = expected_prefix.with_suffix(".txt") input_dir = input_prefix.parent
output_prefix = TEST_DIR / test_type / "expected" / test_name
if test_type in ["Layout", "Text"]:
output_file = output_prefix.with_suffix(".txt")
else:
output_file = output_prefix.with_name(Path(test_name).stem + "-ref.html")
output_dir = output_prefix.parent
# Create directories if they don't exist # Create directories if they don't exist
input_dir.mkdir(parents=True, exist_ok=True) input_dir.mkdir(parents=True, exist_ok=True)
expected_dir.mkdir(parents=True, exist_ok=True) output_dir.mkdir(parents=True, exist_ok=True)
num_sub_levels = len(Path(test_name).parents) - 1 num_sub_levels = len(Path(test_name).parents) - 1
path_to_include_js = "../" * num_sub_levels + "include.js" path_to_include_js = "../" * num_sub_levels + "include.js"
# Create input and expected files def generate_boilerplate():
input_file.write_text(fR"""<!DOCTYPE html> """
return a tuple of strings with the input and
output boilerplate for a given test type
"""
generic_boilerplate = R"""<!DOCTYPE html>
<head>
<style>
</style>
</head>
<body>
</body>
"""
if test_type == "Text":
input_boilerplate = fR"""<!DOCTYPE html>
<script src="{path_to_include_js}"></script> <script src="{path_to_include_js}"></script>
<script> <script>
{f"asyncTest(async (done)" if is_async else "test(()"} => {{ {f"asyncTest(async (done)" if is_async else "test(()"} => {{
@ -41,20 +62,60 @@ def create_text_test(test_name: str, is_async: bool = False) -> None:
{f" done();" if is_async else ""} {f" done();" if is_async else ""}
}}); }});
</script> </script>
""") """
expected_file.write_text("Expected println() output\n") expected_boilerplate = "Expected println() output\n"
print(f"Text test '{Path(test_name).with_suffix('.html')}' created successfully.") elif test_type == "Ref":
input_boilerplate = fR"""<!DOCTYPE html>
<head>
<link rel="match" href="{"../" * num_sub_levels}../expected/{Path(test_name).with_suffix("")}-ref.html" />
<style>
</style>
</head>
<body>
</body>
"""
expected_boilerplate = f"Put equivalently rendering HTML for {test_name} here."
elif test_type == "Screenshot":
input_boilerplate = generic_boilerplate
expected_boilerplate = f"Put equivalently rendering HTML for {test_name} here."
# layout tests are async agnostic
elif test_type == "Layout":
input_boilerplate = generic_boilerplate
expected_boilerplate = f"""run
./Meta/ladybird.sh run headless-browser --run-tests
"${{LADYBIRD_SOURCE_DIR}}/Tests/LibWeb" --rebaseline -f {input_file}
to produce the expected output for this test
"""
print("Delete <!DOCTYPE html> and replace it with <!--Quirks mode--> if test should run in quirks mode")
else:
# should be unreachable
raise ValueError(f"UNREACHABLE Invalid test type: {test_type}")
return (input_boilerplate, expected_boilerplate)
# Create input and expected files
input_boilerplate, expected_boilerplate = generate_boilerplate()
input_file.write_text(input_boilerplate)
output_file.write_text(expected_boilerplate)
print(f"{test_type} test '{Path(test_name).with_suffix('.html')}' created successfully.")
def main(): def main():
supported_test_types = ["Ref", "Text", "Screenshot", "Layout"]
parser = argparse.ArgumentParser(description="Create a new LibWeb Text test file.") parser = argparse.ArgumentParser(description="Create a new LibWeb Text test file.")
parser.add_argument("test_name", type=str, help="Name of the test") parser.add_argument("test_name", type=str, help="Name of the test")
parser.add_argument("test_type", type=str, help="Type of the test", choices=supported_test_types)
parser.add_argument("--async", action="store_true", help="Flag to indicate if it's an async test", dest="is_async") parser.add_argument("--async", action="store_true", help="Flag to indicate if it's an async test", dest="is_async")
args = parser.parse_args() args = parser.parse_args()
# TODO: Add support for other test types: Layout and Ref create_test(args.test_name, args.test_type, args.is_async)
create_text_test(args.test_name, args.is_async)
if __name__ == "__main__": if __name__ == "__main__":