{"id":47784969,"url":"https://github.com/firefly-zero/firefly-test","last_synced_at":"2026-04-18T19:01:24.819Z","repository":{"id":324540506,"uuid":"831346099","full_name":"firefly-zero/firefly-test","owner":"firefly-zero","description":"☑️ Framework for testing Firefly Zero apps","archived":false,"fork":false,"pushed_at":"2026-04-18T17:12:49.000Z","size":256,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-04-18T18:33:19.244Z","etag":null,"topics":["firefly-zero","gamedev","pytest","python","rust","test","testing","testing-framework"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/firefly-zero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-07-20T09:33:03.000Z","updated_at":"2026-04-18T17:12:51.000Z","dependencies_parsed_at":null,"dependency_job_id":"859bd588-f6bd-4ee4-82d7-0aa85280ca4a","html_url":"https://github.com/firefly-zero/firefly-test","commit_stats":null,"previous_names":["firefly-zero/firefly-test"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/firefly-zero/firefly-test","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firefly-zero%2Ffirefly-test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firefly-zero%2Ffirefly-test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firefly-zero%2Ffirefly-test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firefly-zero%2Ffirefly-test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/firefly-zero","download_url":"https://codeload.github.com/firefly-zero/firefly-test/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firefly-zero%2Ffirefly-test/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31980783,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T17:30:12.329Z","status":"ssl_error","status_checked_at":"2026-04-18T17:29:59.069Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["firefly-zero","gamedev","pytest","python","rust","test","testing","testing-framework"],"created_at":"2026-04-03T14:22:27.044Z","updated_at":"2026-04-18T19:01:24.806Z","avatar_url":"https://github.com/firefly-zero.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# firefly-test\n\nFramework for writing tests for Firefly Zero apps. This is a Python library, so the tests using it are writtten in Pytohn as well. However, you can test a Firefly Zero app or game written in any language, not just Python.\n\nIf you don't know Python, don't panic: it's a simple language for simple tasks, and you can learn it good enoug to write your first tests in a matter of minutes. And this documentation will help you.\n\n## Installation\n\n```bash\npython3 -m pip install firefly-test\n```\n\nInstallation from the source is currently not possible: the project depends on `firefly-runtime` which is not open-sourced yet (but will be soon). The wheel distributions on PyPI contain the compiled binaries for the runtime.\n\n## Writing tests in Python\n\nThe most popular and simple tool for running Python tests is [pytest](https://docs.pytest.org/en/). Make sure you have it installed:\n\n```bash\npython3 -m pip install --break-system-packages pytest\n```\n\nTests should be placed in the `tests` directory in the root of the project. Each file with tests should start with `test_`. And each test function also should start with `test_`. For example, create `tests/test_math.py`:\n\n```python\nimport math\n\ndef test_cos():\n    assert math.cos(0.0) == 1.0\n```\n\nNow, run the tests:\n\n```bash\npytest\n```\n\nYou can read more in the pytest documentation: [docs.pytest.org](https://docs.pytest.org/en/).\n\n## Installing your app\n\nThe framework tests not your source code but a compiled and installed app. So, make sure to build and install your project:\n\n```bash\nfirefly_cli build\n```\n\nIn the examples below, we'll be using [sys.input-test](https://catalog.fireflyzero.com/sys.input-test) as our test target. If you want to follow along, make sure you have it installed:\n\n```bash\nfirefly_cli import sys.input-test\n```\n\n## Using firefly-test\n\nThe `App` class accepts the ID of the app you want to test and provides methods and attributes for interacting with the app:\n\n```python\nfrom firefly_test import App\napp = App('sys.input-test')\n```\n\nThe first thing you should do is `start` your app. It will initialize the app memory, call the `boot` callback, etc.\n\n```python\napp.start()\n```\n\nNow each time you call `update`, it will run one update cycle: call the `update` and `render` app callbacks, read inputs, flash the image from the frame buffer on the fake screen, etc.\n\n```python\napp.update()\n```\n\nAfter the update, you can access the frame buffer using the `frame` attribute. The frame has a lot of helpful methods for checking the image it contains. For example, you can use the `at` method to get the color value of the pixel at the given coordinates:\n\n```python\nfrom firefly_test import Color\nassert app.frame.at(x=0, y=0) == Color.WHITE\n```\n\nwe can iterate over all pixels and, for example, check that every pixel is one of the 3 expected colors:\n\n```python\nallowed_colors = {Color.WHITE, Color.LIGHT_GRAY, Color.GRAY}\nfor color in app.frame:\n    assert color in allowed_colors\n```\n\nThe `update` method may also accept `Input`. This is the input value that this and all subsequent colors will receive (until overwritten). For example, check that pressing the `S` button changes the color fo the pixel (x=185, y=100) from white to light blue:\n\n```python\nassert app.frame.at(185, 100) == Color.WHITE\napp.update(Input(s=True))\nassert app.frame.at(185, 100) == Color.LIGHT_BLUE\n```\n\nYou can find this test (and the others covered below) in the [tests/test_integration.py](./tests/test_integration.py) file.\n\n## Pattern testing\n\nYou can assert that a subregion of a frame matches a pattern. A pattern is an ASCII where each symbols represent an expected color:\n\n* `.`: any color.\n* `K`: black.\n* `P`: purple.\n* `R`: red.\n* `O`: orange.\n* `Y`: yellow.\n* `G`: green.\n* `g`: light green.\n* `D`: dark green.\n* `B`: blue.\n* `d`: dark blue.\n* `b`: light blue.\n* `C`: cyan.\n* `W`: white.\n* `◔`: light gray.\n* `◑`: gray.\n* `◕`: dark gray.\n\nTake a frame subregion:\n\n```python\ncircle = app.frame.get_sub(\n    x=160, y=100, width=20, height=5,\n)\n```\n\nAssert that it matches a pattern:\n\n```python\ncircle.assert_match(\"\"\"\n    WWWW◑◑◑◑◑◑◑◑◑◑◑◑WWWW\n    WWW◑◑◑◑WWWWWW◑◑◑◑WWW\n    WW◑◑◑WWWWWWWWWW◑◑◑WW\n    W◑◑◑WWWWWWWWWWWW◑◑◑W\n    ◑◑◑WWWWWWWWWWWWWW◑◑◑\n\"\"\")\n```\n\nIn this example, we checked that the selected region is a gray circle's top on a white background.\n\n## Snapshot testing\n\nYou can compare a frame or frame region to a snapshot:\n\n```python\nfrom pathlib import Path\nsnapshots = Path(__file__).parent / '.snapshots'\napp.update()\napp.frame.assert_match(snapshots / 'default')\n```\n\nOn the first run, the test will save the frame in the `.snapshots/default` file. When you run it the next time, it will read the old frame from the file and compare it to the current one. If they mismatch, even by one pixel, the test will fail. You can use `to_png` method of the frame to save it into a PNG file and see how it looks like. If the change is desirable, you can remove the old snapshot and the next run will save the new snapshot.\n\n## License\n\n[MIT License](./LICENSE). You can freely use it for testing any apps and games, free or commercial, open-source or proprietary. Happy hacking!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirefly-zero%2Ffirefly-test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffirefly-zero%2Ffirefly-test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffirefly-zero%2Ffirefly-test/lists"}