{"id":14490926,"url":"https://github.com/kunitoki/straw","last_synced_at":"2026-06-16T00:32:07.934Z","repository":{"id":255440931,"uuid":"687173181","full_name":"kunitoki/straw","owner":"kunitoki","description":"Straw is a juce automation framework for integration testing","archived":false,"fork":false,"pushed_at":"2024-06-14T07:34:13.000Z","size":1493,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-13T18:34:52.702Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","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/kunitoki.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}},"created_at":"2023-09-04T19:39:37.000Z","updated_at":"2025-05-07T02:44:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"35ff35e3-80fe-443c-91d5-e9576bdd7228","html_url":"https://github.com/kunitoki/straw","commit_stats":null,"previous_names":["kunitoki/straw"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kunitoki/straw","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunitoki%2Fstraw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunitoki%2Fstraw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunitoki%2Fstraw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunitoki%2Fstraw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kunitoki","download_url":"https://codeload.github.com/kunitoki/straw/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kunitoki%2Fstraw/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34386320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-09-03T05:00:38.983Z","updated_at":"2026-06-16T00:32:07.911Z","avatar_url":"https://github.com/kunitoki.png","language":"C++","funding_links":[],"categories":["Testing"],"sub_categories":[],"readme":"![Straw Banner](https://github.com/kunitoki/straw/blob/main/banner.png?raw=true)\n\n# straw\nStraw is a juce automation framework for integration testing.\n\n## Download and install the python framework\n\nGo to https://www.python.org/downloads/ and download a python install. The version *3.11 is reccommended*. After installing it, make sure you write down the location of the install. For example on macOS, typically it is installed in `/Library/Frameworks/Python.framework/Versions/3.11` but you could use the `/Library/Frameworks/Python.framework/Versions/Current` symbolic link for simplicity.\n\n## Setup the dependency using cmake\n\nIn order to configure straw in the juce project, is necessary to fetch the code for it together with specifying and finding the Python install. Once both are setup they need to be passed to the list of libraries to link. \n\n```cmake\n# Fetch the dependency using FetchContent\nInclude (FetchContent)\nFetchContent_Declare (straw\n  GIT_REPOSITORY https://github.com/kunitoki/straw.git\n  GIT_TAG origin/main\n  SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/straw)\nFetchContent_MakeAvailable (straw)\n\n# Setup the Python_ROOT_DIR where python has been installed and python options\nset(Python_ROOT_DIR \"/Library/Frameworks/Python.framework/Versions/Current\")\nset(Python_USE_STATIC_LIBS TRUE) # Optional for static builds\nfind_package(Python REQUIRED Development.Embed)\n\n# Add libraries to the linking libraries of your target\ntarget_link_libraries(${TARGET_NAME} PRIVATE\n    ...\n    straw::juce_straw_recommended_warning_flags\n    straw::juce_straw\n    Python::Python)\n```\n\n## Declare and instantiate the server\n\nIn your application, add a new dependency to `straw::AutomationServer` which will start listening on port 8001.\n\n```cpp\nclass Application : public juce::JUCEApplication\n{\npublic:\n    Application() = default;\n\n    void initialise (const String\u0026) override\n    {\n        // Initialise your windows and components here...\n\n        // Create the animation server instance\n        automationServer = std::make_unique\u003cstraw::AutomationServer\u003e();\n\n        // Register default endpoints (optional)\n        automationServer-\u003eregisterDefaultEndpoints();\n\n        // Start the HTTP server\n        auto result = automationServer-\u003estart();\n        if (result.failed())\n            DBG(result.getErrorMessage());\n    }\n\n    void shutdown() override\n    {\n        // Server is stopped together with background connections\n        automationServer.reset();\n    }\n\nprivate:\n    std::unique_ptr\u003cstraw::AutomationServer\u003e automationServer;\n};\n```\n\nAt this point when the app has started, it is able to respond to requests from the same machine:\n\n```sh\ncurl -X GET http://localhost:8001/straw/component/exists -H 'Content-Type: application/json' -d '{\"id\":\"MyComponentID\"}'\n# Will return a json with the result of the query { \"result\": true }\n```\n\n## Registering custom endpoints\n\nIt is possible to register custom endpoints:\n\n```cpp\n// Initialise your windows and components here...\nmainComponent = std::make_unique\u003cMainComponent\u003e();\n\n// Create the animation server instance\nautomationServer = std::make_unique\u003cstraw::AutomationServer\u003e();\n\n// Register a custom endpoint\nauto weakMainComponent = juce::Component::SafePointer\u003cMainComponent\u003e(mainComponent.get());\nautomationServer.registerEndpoint (\"/change_background_colour\", [weakMainComponent](straw::Request request)\n{\n    // Parse the data from the request\n    auto colour = juce::Colour::fromString (request.data.getProperty (\"colour\", \"FF00FF00\").toString());\n\n    juce::MessageManager::callAsync ([weakMainComponent, colour, connection = std::move (request.connection)]\n    {\n        if (auto mainComponent = weakMainComponent.getComponent())\n        {\n            mainComponent-\u003esetColour (juce::DocumentWindow::backgroundColourId, colour);\n            mainComponent-\u003erepaint();\n\n            // Return a 200 OK HTTP response with a JSON payload of { \"result\": true }\n            straw::sendHttpResultResponse (true, 200, *connection);\n        }\n        else\n        {\n            // Return a 404 Not Found HTTP response with a JSON payload of { \"error\": \"...\" }\n            straw::sendHttpErrorMessage(\"Unable to find the component!\", 404, *connection);\n        }\n    });\n});\n\n// Start the HTTP server\nauto result = automationServer-\u003estart();\n```\n\nThis way your application can execute a remote JSON RPC callback:\n\n```sh\n# Execute custom defined callback\ncurl -X GET http://localhost:8001/change_background_colour -H 'Content-Type: application/json' -d '{\"colour\":\"FFFF0000\"}\n```\n\n## Setting up and executing python test suites\n\nTo execute a test suite defined as a remote python script, all is necessary to do is to first register the default `juce` and `straw` python bindings.\n\n```cpp\n\n// Create the animation server instance\nautomationServer = std::make_unique\u003cstraw::AutomationServer\u003e();\n\n// Register default endpoints (needed for the remote test suite script execution)\nautomationServer-\u003eregisterDefaultEndpoints();\n\n// Register default bindings (juce classes and straw helper methods)\nautomationServer-\u003eregisterDefaultComponents();\n\n// Start the HTTP server\nauto result = automationServer-\u003estart();\n```\n\nThen it's possible to send a `text/x-python` script to the automation server and it will be executed, content of `MyTestSuite.py`:\n\n```python\nimport straw\n\nstraw.log (\"Testing findComponent ====================\")\n\ncomp = straw.findComponentById (\"non-existing\")\nstraw.assertTrue (comp is None)\n\ncomp = straw.findComponentById (\"button\")\nstraw.assertEqual (comp.typeName(), \"juce::TextButton\")\nstraw.assertEqual (comp.getComponentID(), \"button\")\nstraw.assertTrue (comp is not None)\nstraw.assertTrue (comp.isVisible())\nstraw.assertTrue (comp.isShowing())\n\nproperties = comp.getProperties()\nstraw.assertEqual (len (properties), 1)\nstraw.assertTrue (\"example\" in properties)\nstraw.assertEqual (properties[\"example\"], 1337)\n\ncomp = straw.findComponentById (\"slider\")\nstraw.assertEqual (comp.typeName(), \"juce::Slider\")\nstraw.assertGreaterThan (comp.getValue(), 0.0)\n\ncomp = straw.findComponentById (\"animation\")\nchildren = comp.getChildren()\nstraw.assertEqual (len (children), 2)\nstraw.assertTrue ([x for x in children if x.getComponentID() == \"button\"])\nstraw.assertTrue ([x for x in children if x.getComponentID() == \"slider\"])\n```\n\nAnd send it to the automation server for evaluation:\n\n```sh\ncurl --data-binary '@MyTestSuite.py' http://localhost:8001 -H 'Content-Type: text/x-python'\n```\n\nIf all is good, a result JSON object is returned `{ \"result\": true }`\n\n## Expose custom components and custom methods to the python scripts\n\nTODO\n\n\n## Example of REST API\n\n```sh\n# Test if a component exists\ncurl -X GET http://localhost:8001/straw/component/exists -H 'Content-Type: application/json' -d '{\"id\":\"animation\"}'\n\n# Return the informations from a component (recursive as well)\ncurl -X GET http://localhost:8001/straw/component/info -H 'Content-Type: application/json' -d '{\"id\":\"animation\", \"recursive\": true}'\n\n# Click a component\ncurl -X GET http://localhost:8001/straw/component/click -H 'Content-Type: application/json' -d '{\"id\":\"button\"}'\n\n# Render a component (with or without children and return a png)\ncurl -X GET http://localhost:8001/straw/component/render -H 'Content-Type: application/json' -d '{\"id\":\"animation\", \"withChildren\":true}' \u003e test.png\n\n# Execute custom defined callback\ncurl -X GET http://localhost:8001/change_background_colour -H 'Content-Type: application/json' -d '{\"colour\":\"FFFF0000\"}'\n```\n\n## Example of Python API\n\n```sh\ncurl --data-binary '@./Demo/Scripts/clickComponent.py' http://localhost:8001 -H 'Content-Type: text/x-python'\ncurl --data-binary '@./Demo/Scripts/findComponent.py' http://localhost:8001 -H 'Content-Type: text/x-python'\ncurl --data-binary '@./Demo/Scripts/log.py' http://localhost:8001 -H 'Content-Type: text/x-python'\ncurl --data-binary '@./Demo/Scripts/raise.py' http://localhost:8001 -H 'Content-Type: text/x-python'\ncurl --data-binary '@./Demo/Scripts/test.py' http://localhost:8001 -H 'Content-Type: text/x-python'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkunitoki%2Fstraw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkunitoki%2Fstraw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkunitoki%2Fstraw/lists"}