@@ -183,6 +183,49 @@ struct NavigationTests {
183183 #expect( entry2 [ 0 ] == . string( " abc " ) ) // binding round-tripped
184184 }
185185
186+ @Test ( " toolbar rides as placed hidden children whose buttons stay live " )
187+ func toolbar( ) {
188+ struct Screen : View {
189+ @State var saved = 0
190+ var body : some View {
191+ Text ( " Body " )
192+ . toolbar {
193+ ToolbarItem ( placement: . navigationBarTrailing) {
194+ Button ( " Save " ) { saved += 1 }
195+ }
196+ ToolbarItem ( placement: . navigationBarLeading) {
197+ Text ( " Leading " )
198+ }
199+ // a bare view is placed automatically
200+ Text ( " Bare " )
201+ }
202+ }
203+ }
204+ let host = ViewHost ( Screen ( ) )
205+ var node = host. evaluate ( )
206+ #expect( node. props [ " hasToolbar " ] == . bool( true ) )
207+ let items = node. children. filter { $0. type == " ToolbarItem " }
208+ #expect( items. count == 3 )
209+ let placements = items. compactMap { item -> String ? in
210+ guard case . string( let p) ? = item. props [ " placement " ] else { return nil }
211+ return p
212+ }
213+ #expect( placements == [ " navigationBarTrailing " , " navigationBarLeading " , " automatic " ] )
214+
215+ // the trailing item's button still dispatches into the screen's state
216+ guard let tap = findOnTap ( items [ 0 ] ) else {
217+ Issue . record ( " toolbar button lost its callback " ) ; return
218+ }
219+ host. callbacks. invokeVoid ( tap)
220+ node = host. evaluate ( )
221+ let label = node. children
222+ . filter { $0. type == " ToolbarItem " }
223+ . compactMap { firstTextString ( $0) }
224+ . first
225+ #expect( label == " Save " ) // still rendered after the state change
226+ #expect( host. callbacks. callback ( for: tap) != nil )
227+ }
228+
186229 @Test ( " TabView emits tabs with their item labels and selection " )
187230 func tabs( ) {
188231 struct Screen : View {
0 commit comments