-
Notifications
You must be signed in to change notification settings - Fork 635
LayoutControl and Control tests, update Expanding Controls doc #6262
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
Merged
Merged
Changes from all commits
Commits
Show all changes
32 commits
Select commit
Hold shift + click to select a range
e5d930b
Consolidate align and margin tests into layout
InesaFitsner 269e45f
Add layout control tests and clarify aspect_ratio
InesaFitsner 72a73b1
Update layout_control macOS goldens, add tests
InesaFitsner b8bcdf9
Update scale value in layout test and golden image
InesaFitsner 67d217f
Add animate_position test and update goldens
InesaFitsner 6fdd40f
Add control visibility tests and golden images
InesaFitsner 1cdda1f
Add expanding-controls images, docs and tests
InesaFitsner 6b3caa6
Add test for expand_loose behavior in Row
InesaFitsner d9a3c02
Add expand examples and reference them in docs
InesaFitsner 669e9ee
Use ft.Border and ft.BorderRadius in example
InesaFitsner 72529e5
Wrap expand examples in styled containers
InesaFitsner d03cbeb
Add expand examples, docs images and tests
InesaFitsner a2d4304
Add expand_loose example, test, and image
InesaFitsner ebf5402
Add test for disabled propagation to children
InesaFitsner 67be638
Add tooltip tests and golden screenshot
InesaFitsner 6d79352
Add tooltip custom properties screenshot test
InesaFitsner 898bb36
Add badge integration test and golden image
InesaFitsner b790c9d
Add opacity control test and golden image
InesaFitsner b324026
Add RTL layout screenshot test and golden
InesaFitsner 60dfecf
Add ResponsiveRow col integration test
InesaFitsner f88afa7
Rename expand examples and update tests/docs
InesaFitsner 3aa7965
Merge branch 'main' into layout-control-tests
InesaFitsner a392e8f
Move tooltip tests to test_tooltip.py
InesaFitsner 640e9a7
Add create-flet-control-integration-tests skill
InesaFitsner 6efeb92
Add scope-split rule and test file naming
InesaFitsner aab3b9c
Rename tooltip files to control_isolated
InesaFitsner c5eb74f
Move expand examples to controls/control
InesaFitsner 8723991
Move expand golden images and test to core
InesaFitsner e814db3
Rename tooltip tests and golden images
InesaFitsner 3f3d76c
Fix example_images path in expanding-controls doc
InesaFitsner effbb49
Merge branch 'main' into layout-control-tests
InesaFitsner 0025ad5
Update SKILL.md examples paths & file list
InesaFitsner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
167 changes: 167 additions & 0 deletions
167
.codex/skills/create-flet-control-integration-tests/SKILL.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,167 @@ | ||
| --- | ||
| name: create-flet-control-integration-tests | ||
| description: Use when asked to create or update integration tests for any Flet control in sdk/python/packages/flet/integration_tests, including visual goldens and interactive behavior tests. | ||
| --- | ||
|
|
||
| ## When to use | ||
|
|
||
| Use this skill when adding, updating, or reviewing integration tests for a Flet control (core, material, cupertino, theme, services, types, or examples). | ||
|
|
||
| Use it for: | ||
|
|
||
| - visual rendering checks with golden screenshots | ||
| - interaction checks (hover, click, input, keyboard) | ||
| - control property behavior checks | ||
| - regression tests for control bugs | ||
|
|
||
| ## Test placement | ||
|
|
||
| Pick the closest existing suite first: | ||
|
|
||
| - Core controls: `sdk/python/packages/flet/integration_tests/controls/core` | ||
| - Material controls: `sdk/python/packages/flet/integration_tests/controls/material` | ||
| - Cupertino controls: `sdk/python/packages/flet/integration_tests/controls/cupertino` | ||
| - Theme tests: `sdk/python/packages/flet/integration_tests/controls/theme` | ||
| - Type helpers: `sdk/python/packages/flet/integration_tests/controls/types` | ||
| - Services: `sdk/python/packages/flet/integration_tests/controls/services` | ||
| - Examples: `sdk/python/packages/flet/integration_tests/examples` | ||
|
|
||
| Prefer adding tests to an existing file for the same control. Create a new test file only when no suitable file exists. | ||
|
|
||
| ### Scope split rule (required) | ||
|
|
||
| Do not mix `loop_scope="module"` and `loop_scope="function"` tests in the same file. | ||
|
|
||
| Naming convention: | ||
|
|
||
| - `test_<control>.py` for module-scoped visual/stable tests (uses `flet_app`) | ||
| - `test_<control>_isolated.py` for function-scoped tests that require a fresh app per test (uses `flet_app_function`) | ||
|
|
||
| ## Fixture choice | ||
|
|
||
| Use fixtures from `integration_tests/conftest.py`: | ||
|
|
||
| - `flet_app` (`loop_scope="module"`): best for stable visual tests and bulk screenshot tests. | ||
| - `flet_app_function` (`loop_scope="function"`): best for tests that mutate state and must run in a separate app each. | ||
|
|
||
| ## Authoring workflow | ||
|
|
||
| 1. Identify behavior to verify. | ||
| 2. Build deterministic layout/state: | ||
| - set `theme_mode` explicitly when visuals matter | ||
| - set fixed sizes/padding/spacing | ||
| - avoid random or time-varying content | ||
| 3. Choose file by scope rule before writing tests. | ||
| 4. Write test using async pytest. | ||
| 5. Use screenshot assertion for UI behavior, functional assertion for non-visual behavior. | ||
| 6. Name test so `request.node.name` can be used as screenshot key. | ||
| 7. Run target test file. | ||
| 8. If expected visuals changed, regenerate goldens with `FLET_TEST_GOLDEN=1` and re-run without golden mode. | ||
|
|
||
| ## Assertion patterns | ||
|
|
||
| ### Visual control assertion | ||
|
|
||
| ```python | ||
| await flet_app.assert_control_screenshot( | ||
| request.node.name, | ||
| control, | ||
| ) | ||
| ``` | ||
|
|
||
| ### Visual full-page assertion | ||
|
|
||
| ```python | ||
| flet_app_function.assert_screenshot( | ||
| request.node.name, | ||
| await flet_app_function.page.take_screenshot( | ||
| pixel_ratio=flet_app_function.screenshots_pixel_ratio | ||
| ), | ||
| ) | ||
| ``` | ||
|
|
||
| ### Functional assertion | ||
|
|
||
| ```python | ||
| finder = await flet_app_function.tester.find_by_tooltip("Info tooltip") | ||
| assert finder.count == 1 | ||
| ``` | ||
|
|
||
| ## Minimal templates | ||
|
|
||
| ### Template: module-scope file (`test_<control>.py`) | ||
|
|
||
| ```python | ||
| import pytest | ||
|
|
||
| import flet as ft | ||
| import flet.testing as ftt | ||
|
|
||
|
|
||
| @pytest.mark.asyncio(loop_scope="module") | ||
| async def test_<behavior>(flet_app: ftt.FletTestApp, request): | ||
| flet_app.page.theme_mode = ft.ThemeMode.LIGHT | ||
| await flet_app.assert_control_screenshot( | ||
| request.node.name, | ||
| ft.Container(width=240, height=80, alignment=ft.Alignment.CENTER), | ||
| ) | ||
| ``` | ||
|
|
||
| ### Template: function-scope file (`test_<control>_isolated.py`) | ||
|
|
||
| ```python | ||
| import pytest | ||
|
|
||
| import flet as ft | ||
| import flet.testing as ftt | ||
|
|
||
|
|
||
| @pytest.mark.asyncio(loop_scope="function") | ||
| async def test_<behavior>(flet_app_function: ftt.FletTestApp): | ||
| flet_app_function.page.add(ft.IconButton(icon=ft.Icons.INFO, tooltip="Info")) | ||
| await flet_app_function.tester.pump_and_settle() | ||
|
|
||
| finder = await flet_app_function.tester.find_by_tooltip("Info") | ||
| assert finder.count == 1 | ||
| ``` | ||
|
|
||
| ## Run commands | ||
|
|
||
| Run one test file: | ||
|
|
||
| ```bash | ||
| uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/controls/core/test_control.py | ||
| ``` | ||
|
|
||
| Run a subset: | ||
|
|
||
| ```bash | ||
| uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/controls/core/test_control.py -k test_visible | ||
| ``` | ||
|
|
||
| Generate or update goldens: | ||
|
|
||
| ```bash | ||
| FLET_TEST_GOLDEN=1 uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/controls/core/test_control.py | ||
| ``` | ||
|
|
||
| ## Quality checklist | ||
|
|
||
| - Test file location matches control area. | ||
| - `module` and `function` scope tests are in separate files. | ||
| - Function-scoped files use the `test_<control>_isolated.py` naming convention. | ||
| - Fixture scope matches test intent. | ||
| - Screenshot keys are stable (`request.node.name` preferred). | ||
| - Visual tests are deterministic (theme/size/content). | ||
| - Goldens are updated only for intentional visual changes. | ||
| - No unrelated formatting or refactors in the same change. | ||
|
|
||
| ## References | ||
|
|
||
| - `sdk/python/packages/flet/integration_tests/README.md` | ||
| - `sdk/python/packages/flet/integration_tests/conftest.py` | ||
| - `sdk/python/packages/flet/integration_tests/controls/core/test_control.py` | ||
| - `sdk/python/packages/flet/integration_tests/controls/core/test_control_isolated.py` | ||
| - `sdk/python/packages/flet/integration_tests/controls/core/test_layout_control.py` | ||
| - `sdk/python/packages/flet/integration_tests/examples/core/test_control.py` | ||
| - `sdk/python/examples/controls/control` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
88 changes: 88 additions & 0 deletions
88
sdk/python/examples/controls/control/expand_loose_chat_messages.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| from dataclasses import field | ||
|
|
||
| import flet as ft | ||
|
|
||
|
|
||
| @ft.control | ||
| class Message(ft.Container): | ||
| author: str = "" | ||
| body: str = "" | ||
| border: ft.Border = field(default_factory=lambda: ft.Border.all(1, ft.Colors.BLACK)) | ||
| border_radius: ft.BorderRadius = field( | ||
| default_factory=lambda: ft.BorderRadius.all(10) | ||
| ) | ||
| bgcolor: ft.Colors = ft.Colors.GREEN_200 | ||
| padding: ft.PaddingValue = 10 | ||
| expand: bool = True | ||
| expand_loose: bool = True | ||
|
|
||
| def init(self): | ||
| self.content = ft.Column( | ||
| controls=[ | ||
| ft.Text(self.author, weight=ft.FontWeight.BOLD), | ||
| ft.Text(self.body), | ||
| ], | ||
| ) | ||
|
|
||
|
|
||
| def main(page: ft.Page): | ||
| chat = ft.ListView( | ||
| padding=10, | ||
| spacing=10, | ||
| controls=[ | ||
| ft.Row( | ||
| alignment=ft.MainAxisAlignment.START, | ||
| controls=[ | ||
| Message( | ||
| author="John", | ||
| body="Hi, how are you?", | ||
| ), | ||
| ], | ||
| ), | ||
| ft.Row( | ||
| alignment=ft.MainAxisAlignment.END, | ||
| controls=[ | ||
| Message( | ||
| author="Jake", | ||
| body="Hi I am good thanks, how about you?", | ||
| ), | ||
| ], | ||
| ), | ||
| ft.Row( | ||
| alignment=ft.MainAxisAlignment.START, | ||
| controls=[ | ||
| Message( | ||
| author="John", | ||
| body=( | ||
| "Lorem Ipsum is simply dummy text of the printing and " | ||
| "typesetting industry. Lorem Ipsum has been the industry's " | ||
| "standard dummy text ever since the 1500s, when an unknown " | ||
| "printer took a galley of type and scrambled it to make a " | ||
| "type specimen book." | ||
| ), | ||
| ), | ||
| ], | ||
| ), | ||
| ft.Row( | ||
| alignment=ft.MainAxisAlignment.END, | ||
| controls=[ | ||
| Message( | ||
| author="Jake", | ||
| body="Thank you!", | ||
| ), | ||
| ], | ||
| ), | ||
| ], | ||
| ) | ||
|
|
||
| page.add( | ||
| ft.Container( | ||
| content=chat, | ||
| width=300, | ||
| height=500, | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| ft.run(main) |
36 changes: 36 additions & 0 deletions
36
sdk/python/examples/controls/control/expand_row_equal_split.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import flet as ft | ||
|
|
||
|
|
||
| def main(page: ft.Page): | ||
| page.add( | ||
| ft.Container( | ||
| width=500, | ||
| height=180, | ||
| padding=10, | ||
| border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), | ||
| border_radius=10, | ||
| content=ft.Row( | ||
| spacing=8, | ||
| controls=[ | ||
| ft.Container( | ||
| expand=True, | ||
| bgcolor=ft.Colors.ORANGE_300, | ||
| border_radius=8, | ||
| alignment=ft.Alignment.CENTER, | ||
| content=ft.Text("Card 1"), | ||
| ), | ||
| ft.Container( | ||
| expand=True, | ||
| bgcolor=ft.Colors.GREEN_200, | ||
| border_radius=8, | ||
| alignment=ft.Alignment.CENTER, | ||
| content=ft.Text("Card 2"), | ||
| ), | ||
| ], | ||
| ), | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| ft.run(main) |
45 changes: 45 additions & 0 deletions
45
sdk/python/examples/controls/control/expand_row_proportional_1_3_1.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import flet as ft | ||
|
|
||
|
|
||
| def main(page: ft.Page): | ||
| page.add( | ||
| ft.Container( | ||
| width=500, | ||
| padding=10, | ||
| border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), | ||
| border_radius=10, | ||
| content=ft.Row( | ||
| spacing=8, | ||
| controls=[ | ||
| ft.Container( | ||
| expand=1, | ||
| height=60, | ||
| bgcolor=ft.Colors.CYAN_300, | ||
| alignment=ft.Alignment.CENTER, | ||
| border_radius=8, | ||
| content=ft.Text("1"), | ||
| ), | ||
| ft.Container( | ||
| expand=3, | ||
| height=60, | ||
| bgcolor=ft.Colors.AMBER_300, | ||
| alignment=ft.Alignment.CENTER, | ||
| border_radius=8, | ||
| content=ft.Text("3"), | ||
| ), | ||
| ft.Container( | ||
| expand=1, | ||
| height=60, | ||
| bgcolor=ft.Colors.PINK_200, | ||
| alignment=ft.Alignment.CENTER, | ||
| border_radius=8, | ||
| content=ft.Text("1"), | ||
| ), | ||
| ], | ||
| ), | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| ft.run(main) |
22 changes: 22 additions & 0 deletions
22
sdk/python/examples/controls/control/expand_textfield_in_row.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import flet as ft | ||
|
|
||
|
|
||
| def main(page: ft.Page): | ||
| page.add( | ||
| ft.Container( | ||
| width=480, | ||
| padding=10, | ||
| border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), | ||
| border_radius=10, | ||
| content=ft.Row( | ||
| controls=[ | ||
| ft.TextField(hint_text="Enter your name", expand=True), | ||
| ft.Button("Join chat"), | ||
| ] | ||
| ), | ||
| ) | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| ft.run(main) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.