-
Notifications
You must be signed in to change notification settings - Fork 32
Refactoring the reftests. #126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the reftests plugin from a monolithic single-file structure into a well-organized modular architecture, improving code maintainability and separation of concerns.
Key Changes:
- Extracts a 523-line monolithic
reftest.pyinto separate modules with clear responsibilities - Separates HTML/CSS/JavaScript from Python code into dedicated static asset files
- Introduces a
WebReportclass to encapsulate report generation logic - Creates utility functions for file fetching and message retrieval
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
meta/plugins/reftest.py |
Deleted - replaced by modular structure in reftests/ directory |
meta/plugins/__init__.py |
Updated import to use new reftests module instead of old reftest |
meta/plugins/reftests/__init__.py |
New module initialization file |
meta/plugins/reftests/reftest.py |
Main reftest logic extracted and cleaned up from original file |
meta/plugins/reftests/utils.py |
Utility functions for file/message fetching extracted from main module |
meta/plugins/reftests/WebReport.py |
Web report generation logic encapsulated in dedicated class |
meta/plugins/reftests/report.js |
JavaScript code extracted from inline HTML string to separate file |
meta/plugins/reftests/report.css |
CSS styles extracted from inline HTML string to separate file |
meta/plugins/reftests/reftest.py
Outdated
| print(f"Running {file.relative_to(TESTS_DIR)}...") | ||
|
|
||
| def getContainer(test_content: str) -> str | None: | ||
| searchContainer = re.search(r"""<container>([\w\W]+?)</container>""", test) |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable test_content used instead of test in function call. The function parameter is named test_content, but the function body references a variable test on line 239 that doesn't exist in this scope, which will cause a runtime error.
| searchContainer = re.search(r"""<container>([\w\W]+?)</container>""", test) | |
| searchContainer = re.search(r"""<container>([\w\W]+?)</container>""", test_content) |
50ae2b2 to
88f8081
Compare
sleepy-monax
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going in a good direction
| def __init__(self, SOURCE_DIR: Path, TEST_REPORT: Path): | ||
| self.TEST_REPORT: Path = TEST_REPORT | ||
| self.html = f""" | ||
| <!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <title>Reftest</title> | ||
| <script src="{SOURCE_DIR}/report.js"></script> | ||
| <link rel="stylesheet" href="{SOURCE_DIR}/report.css" /> | ||
| </head> | ||
| <body> | ||
| <header> | ||
| Reftest report | ||
| </header> | ||
| """ | ||
| self.testHtml = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SOURCE_DIR and TEST_REPORT should not be constant case
| print() | ||
| print("Failed tests details:") | ||
| print(context.testFailed) | ||
| raise RuntimeError("Some tests failed") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be the responsability of the test runner
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(raising the error I mean)
| """ | ||
| self.testHtml = "" | ||
|
|
||
| def addTestCase(self, testId: int, passed: bool, test: TestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TestId should be a member of TestCase
| def addSkippedCase(self): | ||
| pass | ||
|
|
||
| def addTestCategory(self, testId: int, props, file: Path, passCount: int, failCount: int, skippedCount: int): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should pass TestResults instead of a bunch of primitives
| def addSkipped(self) -> None: | ||
| self.skipped += 1 | ||
|
|
||
| def merge(self, other: 'TestResults') -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"merge" is a bit too generic, maybe something like "sumWith"
| def shouldRunSkipped(self) -> bool: | ||
| """Check if skipped tests should be run.""" | ||
| return self.args.runSkipped | ||
|
|
||
| def shouldStopOnFailure(self) -> bool: | ||
| """Check if execution should stop on first failure.""" | ||
| return self.args.fast |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
technically these could be marked as @Property, but fine as is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol pinged a random guy
| class ReportManager: | ||
| """Manages all test reporting operations.""" | ||
|
|
||
| def __init__(self, reporters: list[Reporter]) -> None: | ||
| self._reporters: list[Reporter] = reporters | ||
|
|
||
| def reportTestCase(self, testId: int, passed: bool, test: TestCase) -> None: | ||
| """Report a single test case result.""" | ||
| for reporter in self._reporters: | ||
| reporter.addTestCase(testId, passed, test) | ||
|
|
||
| def reportSkippedCase(self) -> None: | ||
| """Report a skipped test case.""" | ||
| for reporter in self._reporters: | ||
| reporter.addSkippedCase() | ||
|
|
||
| def reportSkippedFile(self, testId: int, props: dict[str, str]) -> None: | ||
| """Report a skipped test file.""" | ||
| for reporter in self._reporters: | ||
| reporter.addSkippedFile(testId, props) | ||
|
|
||
| def reportTestCategory(self, testId: int, props: dict[str, str], file: Path, | ||
| passCount: int, failCount: int, skippedCount: int) -> None: | ||
| """Report results for a test category.""" | ||
| for reporter in self._reporters: | ||
| reporter.addTestCategory(testId, props, file, passCount, failCount, skippedCount) | ||
|
|
||
| def finish(self, manifests: model.Registry, results: TestResults, context: TestRunnerContext) -> None: | ||
| """Finish reporting and display final results.""" | ||
| for reporter in self._reporters: | ||
| reporter.finish(manifests, results.failed, results.passed, results.skipped, context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it doesn't really manage anything but instead dispatches to other reporter implementations, I think a better name would be ReportRouter, ReportDispatcher, ReportMux, ReportMultiplexer, etc.
Also, since it has the same interface as Reporter, let's be honest and have it implement the Reporter abstract base class.
| def __init__(self, context: TestRunnerContext, reportManager: ReportManager) -> None: | ||
| self._context: TestRunnerContext = context | ||
| self._reportManager: ReportManager = reportManager | ||
| self._parser: TestParser = TestParser() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here, take the reporter ABC, instead of the dispatch specialisation
No description provided.