return function()
	describe("Druid Instance", function()
		local druid
		local druid_instance ---@type druid.instance
		local context
		local mock_input = require("test.helper.mock_input")

		before(function()
			context = vmath.vector3()
			druid = require("druid.druid")
			druid_instance = druid.new(context)
		end)

		after(function()
			-- Clean up druid instance
			if druid_instance then
				druid_instance:final()
				druid_instance = nil
			end
		end)

		it("Should create button component", function()
			local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))

			local on_click_calls = 0
			local function on_click()
				on_click_calls = on_click_calls + 1
			end

			local button = druid_instance:new_button(button_node, on_click)

			assert(button ~= nil)
			assert(button.node == button_node)

			-- Test that button click works
			druid_instance:on_input(mock_input.click_pressed(50, 25))
			druid_instance:on_input(mock_input.click_released(50, 25))

			assert(on_click_calls == 1)

			-- Clean up component
			druid_instance:remove(button)
			gui.delete_node(button_node)
		end)

		it("Should create blocker component", function()
			local blocker_node = gui.new_box_node(vmath.vector3(100, 50, 0), vmath.vector3(200, 100, 0))

			local blocker = druid_instance:new_blocker(blocker_node)

			assert(blocker ~= nil)
			assert(blocker.node == blocker_node)

			-- Test that blocker blocks input
			local is_blocked = druid_instance:on_input(mock_input.click_pressed(100, 50))

			assert(is_blocked)

			-- Clean up component
			druid_instance:remove(blocker)
			gui.delete_node(blocker_node)
		end)

		it("Should create back_handler component", function()
			local on_back_calls = 0
			local function on_back()
				on_back_calls = on_back_calls + 1
			end

			local back_handler = druid_instance:new_back_handler(on_back)

			assert(back_handler ~= nil)

			-- Test that back handler works
			druid_instance:on_input(mock_input.key_pressed("key_back"))
			druid_instance:on_input(mock_input.key_released("key_back"))

			assert(on_back_calls == 1)

			-- Clean up component
			druid_instance:remove(back_handler)
		end)

		it("Should create hover component", function()
			local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))

			local on_hover_calls = 0
			local function on_hover()
				on_hover_calls = on_hover_calls + 1
			end

			local hover = druid_instance:new_hover(button_node, on_hover)

			assert(hover ~= nil)
			assert(hover.node == button_node)

			-- Test that hover works
			druid_instance:on_input(mock_input.input_empty(50, 25))

			assert(on_hover_calls == 1)

			-- Clean up component
			druid_instance:remove(hover)
			gui.delete_node(button_node)
		end)

		it("Should create text component", function()
			local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Test Text")
			gui.set_font(text_node, "druid_text_bold")

			local text = druid_instance:new_text(text_node, "New Text")

			assert(text ~= nil)
			assert(text.node == text_node)
			assert(gui.get_text(text_node) == "New Text")

			-- Test that text setter works
			text:set_text("Updated Text")
			assert(gui.get_text(text_node) == "Updated Text")

			-- Clean up component
			druid_instance:remove(text)
			gui.delete_node(text_node)
		end)

		it("Should create grid component", function()
			local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0))
			local template = gui.new_box_node(vmath.vector3(10, 10, 0), vmath.vector3(20, 20, 0))

			local grid = druid_instance:new_grid(parent_node, template, 3)

			assert(grid ~= nil)
			assert(grid.parent == parent_node)
			assert(grid.in_row == 3)

			-- Add an item to the grid
			local item = gui.clone(template)
			grid:add(item)
			assert(#grid.nodes == 1)

			-- Clean up component
			druid_instance:remove(grid)
			gui.delete_node(parent_node)
			gui.delete_node(template)
		end)

		it("Should create scroll component", function()
			local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0))
			local content_node = gui.new_box_node(vmath.vector3(250, 200, 0), vmath.vector3(500, 400, 0))

			-- Setup node hierarchy for scroll
			gui.set_parent(content_node, parent_node)

			local scroll = druid_instance:new_scroll(parent_node, content_node)

			assert(scroll ~= nil)
			assert(scroll.view_node == parent_node)
			assert(scroll.content_node == content_node)

			-- Test that scroll setters work
			scroll:set_horizontal_scroll(true)

			-- Clean up component
			druid_instance:remove(scroll)
			gui.delete_node(parent_node) -- This will also delete content_node as it's a child
		end)

		it("Should create drag component", function()
			local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))

			local on_drag_calls = 0
			local drag_dx, drag_dy

			local function on_drag(_, dx, dy)
				on_drag_calls = on_drag_calls + 1
				drag_dx, drag_dy = dx, dy
			end

			local drag = druid_instance:new_drag(button_node, on_drag)
			drag.style.DRAG_DEADZONE = 0
			drag.style.NO_USE_SCREEN_KOEF = true

			assert(drag ~= nil)
			assert(drag.node == button_node)

			-- Test that drag callback works
			druid_instance:on_input(mock_input.click_pressed(50, 25))
			druid_instance:on_input(mock_input.input_empty(60, 35))
			druid_instance:on_input(mock_input.click_released(60, 35))

			assert(on_drag_calls == 1)
			assert(math.floor(drag_dx) == 10)
			assert(math.floor(drag_dy) == 10)

			-- Clean up component
			druid_instance:remove(drag)
			gui.delete_node(button_node)
		end)

		it("Should create swipe component", function()
			local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))

			local on_swipe_calls = 0
			local function on_swipe()
				on_swipe_calls = on_swipe_calls + 1
			end

			local swipe = druid_instance:new_swipe(button_node, on_swipe)

			assert(swipe ~= nil)
			assert(swipe.node == button_node)

			-- Clean up component
			druid_instance:remove(swipe)
			gui.delete_node(button_node)
		end)

		it("Should create timer component", function()
			local text_node = gui.new_text_node(vmath.vector3(50, 25, 0), "Test Text")
			gui.set_font(text_node, "druid_text_bold")

			local on_timer_end_calls = 0
			local function on_timer_end()
				on_timer_end_calls = on_timer_end_calls + 1
			end

			local timer = druid_instance:new_timer(text_node, 10, 0, on_timer_end)

			assert(timer ~= nil)
			assert(timer.node == text_node)

			-- Clean up component
			druid_instance:remove(timer)
			gui.delete_node(text_node)
		end)

		it("Should create progress component", function()
			local button_node = gui.new_box_node(vmath.vector3(50, 25, 0), vmath.vector3(100, 50, 0))

			local progress = druid_instance:new_progress(button_node, "x", 0.5)

			assert(progress ~= nil)
			assert(progress.node == button_node)
			assert(progress:get() == 0.5)

			-- Test that progress setter works
			progress:set_to(0.75)
			assert(progress:get() == 0.75)

			-- Clean up component
			druid_instance:remove(progress)
			gui.delete_node(button_node)
		end)

		it("Should create layout component", function()
			local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0))

			local layout = druid_instance:new_layout(parent_node)

			assert(layout ~= nil)
			assert(layout.node == parent_node)

			-- Clean up component
			druid_instance:remove(layout)
			gui.delete_node(parent_node)
		end)

		it("Should create hotkey component", function()
			local on_hotkey_calls = 0
			local function on_hotkey()
				on_hotkey_calls = on_hotkey_calls + 1
			end

			local hotkey = druid_instance:new_hotkey("key_f", on_hotkey)

			assert(hotkey ~= nil)

			-- Test that hotkey works
			druid_instance:on_input(mock_input.key_pressed("key_f"))
			druid_instance:on_input(mock_input.key_released("key_f"))

			assert(on_hotkey_calls == 1)

			-- Clean up component
			druid_instance:remove(hotkey)
		end)

		it("Should create container component", function()
			local parent_node = gui.new_box_node(vmath.vector3(150, 100, 0), vmath.vector3(300, 200, 0))

			local layout_changed_calls = 0
			local function layout_changed()
				layout_changed_calls = layout_changed_calls + 1
			end

			-- The container component requires a node with size
			local container = druid_instance:new_container(parent_node, "fit")

			assert(container ~= nil)

			-- Clean up component
			druid_instance:remove(container)
			gui.delete_node(parent_node)
		end)
	end)
end
