| ... | @@ -71,6 +71,51 @@ describe("ProviderModelPicker", () => { | ... | @@ -71,6 +71,51 @@ describe("ProviderModelPicker", () => { |
| 71 | } | 71 | } |
| 72 | }); | 72 | }); |
| 73 | | 73 | |
| | 74 | it("opens provider submenus with a visible gap from the parent menu", async () => { |
| | 75 | const mounted = await mountPicker({ |
| | 76 | provider: "claudeAgent", |
| | 77 | model: "claude-opus-4-6", |
| | 78 | lockedProvider: null, |
| | 79 | }); |
| | 80 | |
| | 81 | try { |
| | 82 | await page.getByRole("button").click(); |
| | 83 | const providerTrigger = page.getByRole("menuitem", { name: "Codex" }); |
| | 84 | await providerTrigger.hover(); |
| | 85 | |
| | 86 | await vi.waitFor(() => { |
| | 87 | expect(document.body.textContent ?? "").toContain("GPT-5 Codex"); |
| | 88 | }); |
| | 89 | |
| | 90 | const providerTriggerElement = Array.from( |
| | 91 | document.querySelectorAll<HTMLElement>('[role="menuitem"]'), |
| | 92 | ).find((element) => element.textContent?.includes("Codex")); |
| | 93 | if (!providerTriggerElement) { |
| | 94 | throw new Error("Expected the Codex provider trigger to be mounted."); |
| | 95 | } |
| | 96 | |
| | 97 | const providerTriggerRect = providerTriggerElement.getBoundingClientRect(); |
| | 98 | const modelElement = Array.from( |
| | 99 | document.querySelectorAll<HTMLElement>('[role="menuitemradio"]'), |
| | 100 | ).find((element) => element.textContent?.includes("GPT-5 Codex")); |
| | 101 | if (!modelElement) { |
| | 102 | throw new Error("Expected the submenu model option to be mounted."); |
| | 103 | } |
| | 104 | |
| | 105 | const submenuPopup = modelElement.closest('[data-slot="menu-sub-content"]'); |
| | 106 | if (!(submenuPopup instanceof HTMLElement)) { |
| | 107 | throw new Error("Expected submenu popup to be mounted."); |
| | 108 | } |
| | 109 | |
| | 110 | const submenuRect = submenuPopup.getBoundingClientRect(); |
| | 111 | |
| | 112 | expect(submenuRect.left).toBeGreaterThanOrEqual(providerTriggerRect.right); |
| | 113 | expect(submenuRect.left - providerTriggerRect.right).toBeGreaterThanOrEqual(2); |
| | 114 | } finally { |
| | 115 | await mounted.cleanup(); |
| | 116 | } |
| | 117 | }); |
| | 118 | |
| 74 | it("shows models directly when the provider is locked mid-thread", async () => { | 119 | it("shows models directly when the provider is locked mid-thread", async () => { |
| 75 | const mounted = await mountPicker({ | 120 | const mounted = await mountPicker({ |
| 76 | provider: "claudeAgent", | 121 | provider: "claudeAgent", |