Add to_html method for TableData#62
Conversation
📝 WalkthroughWalkthroughA new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/test_table_data_to_html.py`:
- Around line 8-69: The tests only exercise TableData.to_html and repeat
TableData setup; add domain model validation tests and consolidate setup into
pytest fixtures: create a fixture (e.g., tabledata_basic) that returns a
TableData instance used by multiple tests, and add tests asserting model
validation behavior on TableData constructors (e.g., invalid headers types,
mismatched row lengths, non-string cell values) expecting the appropriate
exceptions (ValueError/TypeError) instead of calling to_html; reference the
TableData class and its to_html method when adding these tests and use
pytest.fixture to DRY the repeated setup.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 4381762a-ea46-4b5f-b80b-909a7b01a51d
📒 Files selected for processing (3)
gslides_api/agnostic/element.pypyproject.tomltests/test_table_data_to_html.py
| class TestTableDataToHtml: | ||
| def test_basic_table(self): | ||
| td = TableData(headers=["Name", "Value"], rows=[["Alice", "100"], ["Bob", "200"]]) | ||
| result = td.to_html() | ||
| assert "<table>" in result | ||
| assert "<thead>" in result | ||
| assert "<tbody>" in result | ||
| assert "<th>Name</th>" in result | ||
| assert "<th>Value</th>" in result | ||
| assert "<td>Alice</td>" in result | ||
| assert "<td>100</td>" in result | ||
| assert "<td>Bob</td>" in result | ||
| assert "<td>200</td>" in result | ||
|
|
||
| def test_with_css_class(self): | ||
| td = TableData(headers=["A"], rows=[["1"]]) | ||
| result = td.to_html(css_class="dtbl") | ||
| assert '<table class="dtbl">' in result | ||
|
|
||
| def test_without_css_class(self): | ||
| td = TableData(headers=["A"], rows=[["1"]]) | ||
| result = td.to_html() | ||
| assert "<table>" in result | ||
| assert "class=" not in result | ||
|
|
||
| def test_empty_headers(self): | ||
| td = TableData(headers=[], rows=[]) | ||
| assert td.to_html() == "" | ||
|
|
||
| def test_html_escaping(self): | ||
| td = TableData( | ||
| headers=["<script>", "A&B"], | ||
| rows=[["x < y", '"quoted"']], | ||
| ) | ||
| result = td.to_html() | ||
| assert "<script>" in result | ||
| assert "A&B" in result | ||
| assert "x < y" in result | ||
| assert ""quoted"" in result | ||
| assert "<script>" not in result # must be escaped | ||
|
|
||
| def test_css_class_escaping(self): | ||
| td = TableData(headers=["A"], rows=[["1"]]) | ||
| result = td.to_html(css_class='x" onclick="alert(1)') | ||
| # The double quote must be escaped so it can't break out of the attribute | ||
| assert '"' in result | ||
| assert 'class="x" onclick="alert(1)"' in result | ||
|
|
||
| def test_short_row_pads_with_empty(self): | ||
| td = TableData(headers=["A", "B", "C"], rows=[["only_one"]]) | ||
| result = td.to_html() | ||
| assert "<td>only_one</td>" in result | ||
| assert result.count("<td></td>") == 2 | ||
|
|
||
| def test_structure_order(self): | ||
| td = TableData(headers=["H"], rows=[["R"]]) | ||
| result = td.to_html() | ||
| # Verify structural ordering | ||
| assert result.index("<thead>") < result.index("</thead>") | ||
| assert result.index("</thead>") < result.index("<tbody>") | ||
| assert result.index("<tbody>") < result.index("</tbody>") | ||
| assert result.index("</tbody>") < result.index("</table>") |
There was a problem hiding this comment.
Add model-validation coverage and move repeated setup into fixtures.
This file verifies HTML serialization well, but it misses domain model validation tests and repeats common TableData setup inline.
Suggested test refactor/extension
import pytest
+from pydantic import ValidationError
from gslides_api.agnostic.element import TableData
+@pytest.fixture
+def single_cell_table() -> TableData:
+ return TableData(headers=["A"], rows=[["1"]])
+
class TestTableDataToHtml:
@@
- def test_with_css_class(self):
- td = TableData(headers=["A"], rows=[["1"]])
- result = td.to_html(css_class="dtbl")
+ def test_with_css_class(self, single_cell_table: TableData):
+ result = single_cell_table.to_html(css_class="dtbl")
assert '<table class="dtbl">' in result
- def test_without_css_class(self):
- td = TableData(headers=["A"], rows=[["1"]])
- result = td.to_html()
+ def test_without_css_class(self, single_cell_table: TableData):
+ result = single_cell_table.to_html()
assert "<table>" in result
assert "class=" not in result
+
+ `@pytest.mark.parametrize`(
+ "headers,rows",
+ [
+ (None, [["1"]]),
+ (["A"], None),
+ ("A", [["1"]]),
+ ],
+ )
+ def test_domain_model_validation(self, headers, rows):
+ with pytest.raises(ValidationError):
+ TableData(headers=headers, rows=rows)As per coding guidelines tests/**/*.py: "Test both API format serialization and domain model validation in test files" and "Use pytest fixtures for common setup patterns in tests".
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| class TestTableDataToHtml: | |
| def test_basic_table(self): | |
| td = TableData(headers=["Name", "Value"], rows=[["Alice", "100"], ["Bob", "200"]]) | |
| result = td.to_html() | |
| assert "<table>" in result | |
| assert "<thead>" in result | |
| assert "<tbody>" in result | |
| assert "<th>Name</th>" in result | |
| assert "<th>Value</th>" in result | |
| assert "<td>Alice</td>" in result | |
| assert "<td>100</td>" in result | |
| assert "<td>Bob</td>" in result | |
| assert "<td>200</td>" in result | |
| def test_with_css_class(self): | |
| td = TableData(headers=["A"], rows=[["1"]]) | |
| result = td.to_html(css_class="dtbl") | |
| assert '<table class="dtbl">' in result | |
| def test_without_css_class(self): | |
| td = TableData(headers=["A"], rows=[["1"]]) | |
| result = td.to_html() | |
| assert "<table>" in result | |
| assert "class=" not in result | |
| def test_empty_headers(self): | |
| td = TableData(headers=[], rows=[]) | |
| assert td.to_html() == "" | |
| def test_html_escaping(self): | |
| td = TableData( | |
| headers=["<script>", "A&B"], | |
| rows=[["x < y", '"quoted"']], | |
| ) | |
| result = td.to_html() | |
| assert "<script>" in result | |
| assert "A&B" in result | |
| assert "x < y" in result | |
| assert ""quoted"" in result | |
| assert "<script>" not in result # must be escaped | |
| def test_css_class_escaping(self): | |
| td = TableData(headers=["A"], rows=[["1"]]) | |
| result = td.to_html(css_class='x" onclick="alert(1)') | |
| # The double quote must be escaped so it can't break out of the attribute | |
| assert '"' in result | |
| assert 'class="x" onclick="alert(1)"' in result | |
| def test_short_row_pads_with_empty(self): | |
| td = TableData(headers=["A", "B", "C"], rows=[["only_one"]]) | |
| result = td.to_html() | |
| assert "<td>only_one</td>" in result | |
| assert result.count("<td></td>") == 2 | |
| def test_structure_order(self): | |
| td = TableData(headers=["H"], rows=[["R"]]) | |
| result = td.to_html() | |
| # Verify structural ordering | |
| assert result.index("<thead>") < result.index("</thead>") | |
| assert result.index("</thead>") < result.index("<tbody>") | |
| assert result.index("<tbody>") < result.index("</tbody>") | |
| assert result.index("</tbody>") < result.index("</table>") | |
| import pytest | |
| from pydantic import ValidationError | |
| from gslides_api.agnostic.element import TableData | |
| `@pytest.fixture` | |
| def single_cell_table() -> TableData: | |
| return TableData(headers=["A"], rows=[["1"]]) | |
| class TestTableDataToHtml: | |
| def test_basic_table(self): | |
| td = TableData(headers=["Name", "Value"], rows=[["Alice", "100"], ["Bob", "200"]]) | |
| result = td.to_html() | |
| assert "<table>" in result | |
| assert "<thead>" in result | |
| assert "<tbody>" in result | |
| assert "<th>Name</th>" in result | |
| assert "<th>Value</th>" in result | |
| assert "<td>Alice</td>" in result | |
| assert "<td>100</td>" in result | |
| assert "<td>Bob</td>" in result | |
| assert "<td>200</td>" in result | |
| def test_with_css_class(self, single_cell_table: TableData): | |
| result = single_cell_table.to_html(css_class="dtbl") | |
| assert '<table class="dtbl">' in result | |
| def test_without_css_class(self, single_cell_table: TableData): | |
| result = single_cell_table.to_html() | |
| assert "<table>" in result | |
| assert "class=" not in result | |
| def test_empty_headers(self): | |
| td = TableData(headers=[], rows=[]) | |
| assert td.to_html() == "" | |
| def test_html_escaping(self): | |
| td = TableData( | |
| headers=["<script>", "A&B"], | |
| rows=[["x < y", '"quoted"']], | |
| ) | |
| result = td.to_html() | |
| assert "<script>" in result | |
| assert "A&B" in result | |
| assert "x < y" in result | |
| assert ""quoted"" in result | |
| assert "<script>" not in result # must be escaped | |
| def test_css_class_escaping(self): | |
| td = TableData(headers=["A"], rows=[["1"]]) | |
| result = td.to_html(css_class='x" onclick="alert(1)') | |
| # The double quote must be escaped so it can't break out of the attribute | |
| assert '"' in result | |
| assert 'class="x" onclick="alert(1)"' in result | |
| def test_short_row_pads_with_empty(self): | |
| td = TableData(headers=["A", "B", "C"], rows=[["only_one"]]) | |
| result = td.to_html() | |
| assert "<td>only_one</td>" in result | |
| assert result.count("<td></td>") == 2 | |
| def test_structure_order(self): | |
| td = TableData(headers=["H"], rows=[["R"]]) | |
| result = td.to_html() | |
| # Verify structural ordering | |
| assert result.index("<thead>") < result.index("</thead>") | |
| assert result.index("</thead>") < result.index("<tbody>") | |
| assert result.index("<tbody>") < result.index("</tbody>") | |
| assert result.index("</tbody>") < result.index("</table>") | |
| `@pytest.mark.parametrize`( | |
| "headers,rows", | |
| [ | |
| (None, [["1"]]), | |
| (["A"], None), | |
| ("A", [["1"]]), | |
| ], | |
| ) | |
| def test_domain_model_validation(self, headers, rows): | |
| with pytest.raises(ValidationError): | |
| TableData(headers=headers, rows=rows) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/test_table_data_to_html.py` around lines 8 - 69, The tests only
exercise TableData.to_html and repeat TableData setup; add domain model
validation tests and consolidate setup into pytest fixtures: create a fixture
(e.g., tabledata_basic) that returns a TableData instance used by multiple
tests, and add tests asserting model validation behavior on TableData
constructors (e.g., invalid headers types, mismatched row lengths, non-string
cell values) expecting the appropriate exceptions (ValueError/TypeError) instead
of calling to_html; reference the TableData class and its to_html method when
adding these tests and use pytest.fixture to DRY the repeated setup.
Summary by CodeRabbit