From 45fa04a94ba910586fd174b3cb115effb0177b35 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Thu, 23 Jul 2026 11:25:03 +0300 Subject: [PATCH] Bonsai tests: stop hardcoding STEP ids in boolean.feature The two boolean.feature scenarios pinned representation item objects by absolute STEP id (Item/IfcHalfSpaceSolid/90, the BBIM_Boolean pset text [91]). Those ids shift every time any earlier entity allocation in an empty project changes (latest instance: #8577 moved 90 to 86), so this cluster re-breaks on unrelated commits. Make the object-name and panel-text BDD steps run their argument through replace_variables, the same substitution 'the variable' and the connection steps already use, and have boolean.feature capture the real ids from the IFC file (by_type(...)[0].id()) into variables at the point the entities are created. The steps stay strict: the substituted name must still resolve to exactly the named object, there is no wildcard matching. Substitution is a no-op for every existing feature string without a {variable} placeholder. This change was made with the assistance of an AI tool. --- src/bonsai/test/bim/feature/boolean.feature | 18 ++++++++++++------ src/bonsai/test/bim/test_feature.py | 5 +++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/bonsai/test/bim/feature/boolean.feature b/src/bonsai/test/bim/feature/boolean.feature index cbf4981dc8..5f79c04e8e 100644 --- a/src/bonsai/test/bim/feature/boolean.feature +++ b/src/bonsai/test/bim/feature/boolean.feature @@ -12,16 +12,19 @@ Scenario: Ensure added booleans are marked as manual And I click "OK" And the object "IfcFurniture/Unnamed" exists And I toggle edit mode - And the object "Item/IfcExtrudedAreaSolid/73" exists + And the variable "extrusion" is "{ifc}.by_type('IfcExtrudedAreaSolid')[0].id()" + And the object "Item/IfcExtrudedAreaSolid/{extrusion}" exists And I open the "Add Item" menu When I click "Half Space Solid" - And the object "Item/IfcHalfSpaceSolid/90" exists + And the variable "half_space" is "{ifc}.by_type('IfcHalfSpaceSolid')[0].id()" + And the variable "boolean" is "{ifc}.by_type('IfcBooleanResult')[0].id()" + And the object "Item/IfcHalfSpaceSolid/{half_space}" exists And I deselect all objects And I toggle edit mode And I select the object "IfcFurniture/Unnamed" And I look at the "Property Sets" panel Then I see "BBIM_Boolean" - And I see "[91]" + And I see "[{boolean}]" Scenario: Ensure removed booleans are unmarked as manual Given an empty IFC project @@ -33,17 +36,20 @@ Scenario: Ensure removed booleans are unmarked as manual And I click "OK" And the object "IfcFurniture/Unnamed" exists And I toggle edit mode - And the object "Item/IfcExtrudedAreaSolid/73" exists + And the variable "extrusion" is "{ifc}.by_type('IfcExtrudedAreaSolid')[0].id()" + And the object "Item/IfcExtrudedAreaSolid/{extrusion}" exists And I open the "Add Item" menu And I click "Half Space Solid" + And the variable "half_space" is "{ifc}.by_type('IfcHalfSpaceSolid')[0].id()" + And the variable "boolean" is "{ifc}.by_type('IfcBooleanResult')[0].id()" And I deselect all objects And I toggle edit mode And I select the object "IfcFurniture/Unnamed" And I toggle edit mode - And I select the object "Item/IfcHalfSpaceSolid/90" + And I select the object "Item/IfcHalfSpaceSolid/{half_space}" When I delete the selected objects And I toggle edit mode And I select the object "IfcFurniture/Unnamed" And I look at the "Property Sets" panel Then I don't see "BBIM_Boolean" - And I don't see "[91]" + And I don't see "[{boolean}]" diff --git a/src/bonsai/test/bim/test_feature.py b/src/bonsai/test/bim/test_feature.py index 9962f6bec2..34150fbe98 100644 --- a/src/bonsai/test/bim/test_feature.py +++ b/src/bonsai/test/bim/test_feature.py @@ -468,6 +468,7 @@ def i_trigger_operator(operator): @then(parsers.parse('I see "{text}"')) def i_see_text(text): assert panel_spy + text = replace_variables(text) panel_spy.refresh_spy() assert [l for l in panel_spy.spied_labels if text in l], f"Text {text} not found in {panel_spy.spied_labels}" @@ -602,6 +603,7 @@ def i_select_the_row_where_i_see_text_in_the_nth_list(text, nth): @then(parsers.parse('I don\'t see "{text}"')) def i_dont_see_text(text): assert panel_spy + text = replace_variables(text) panel_spy.refresh_spy() assert not [l for l in panel_spy.spied_labels if text in l], f"Text {text} found in {panel_spy.spied_labels}" @@ -1092,6 +1094,7 @@ def then_the_object_name_is_placed_in_the_collection_collection(name: str, colle @given(parsers.parse('additionally the object "{name}" is selected')) @when(parsers.parse('additionally the object "{name}" is selected')) def additionally_the_object_name_is_selected(name): + name = replace_variables(name) obj = bpy.context.scene.objects.get(name) if not obj: total = len(bpy.context.scene.objects) @@ -1172,6 +1175,7 @@ def nothing_happens(): @when(parsers.parse('the object "{name}" exists')) @then(parsers.parse('the object "{name}" exists')) def the_object_name_exists(name: str) -> bpy.types.Object: + name = replace_variables(name) # Some objects from linked collections may share the same name. This disambiguates them. if name.startswith("Col:"): _, collection_name, name = name.split(":") @@ -1186,6 +1190,7 @@ def the_object_name_exists(name: str) -> bpy.types.Object: @then(parsers.parse('the object "{name}" does not exist')) def the_object_name_does_not_exist(name) -> None: + name = replace_variables(name) obj = bpy.data.objects.get(name) assert obj is None, f'The object "{name}" exists'