feat(FN-4077): fix mobile switcher trigger sizing in ChatView
Fixes the mobile switcher trigger sizing in ChatView by updating CSS dimensions and adjusting the component's conditional rendering logic, with corresponding test coverage added. Fusion-Task-Id: FN-4077 Fusion-Task-Lineage: 966eafb9-35fd-4ac6-ab4a-42c0e96a2584
This commit is contained in:
@@ -2,6 +2,7 @@ import { mkdtempSync } from "node:fs";
|
||||
import { rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { setTimeout as delay } from "node:timers/promises";
|
||||
import { vi } from "vitest";
|
||||
|
||||
vi.mock("node:child_process", async (importOriginal) => {
|
||||
@@ -52,9 +53,10 @@ export function createTaskStoreTestHarness() {
|
||||
afterEach: async () => {
|
||||
vi.useRealTimers();
|
||||
store.stopWatching();
|
||||
// Yield one microtask tick without relying on process.nextTick,
|
||||
// which can be faked in timer-heavy suites and hang teardown.
|
||||
await Promise.resolve();
|
||||
// Yield one real event-loop turn so fs.watch cleanup settles before
|
||||
// close()/rm() run. Promise.resolve() is only a microtask and has proven
|
||||
// too weak for some full-suite watcher teardowns.
|
||||
await delay(0);
|
||||
store.close();
|
||||
await rm(rootDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
||||
await rm(globalDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
||||
|
||||
@@ -396,8 +396,10 @@
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
padding: var(--space-xs) var(--space-sm);
|
||||
min-height: calc(var(--space-lg) * 2);
|
||||
min-height: calc(var(--space-lg) * 2 + var(--space-xs));
|
||||
font: inherit;
|
||||
line-height: normal;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.chat-mobile-session-trigger .chat-thread-header-title {
|
||||
@@ -421,6 +423,11 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.chat-mobile-session-trigger > svg {
|
||||
width: var(--icon-size-md);
|
||||
height: var(--icon-size-md);
|
||||
}
|
||||
|
||||
.chat-mobile-session-trigger svg:last-child {
|
||||
margin-left: auto;
|
||||
color: var(--text-muted);
|
||||
|
||||
@@ -2286,7 +2286,7 @@ export function ChatView({ projectId, addToast, experimentalFeatures }: ChatView
|
||||
<div className="chat-mobile-session-menu" ref={mobileSessionMenuRef}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-icon chat-mobile-session-trigger"
|
||||
className="btn chat-mobile-session-trigger"
|
||||
data-testid="chat-mobile-session-trigger"
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={mobileSessionMenuOpen}
|
||||
@@ -2295,7 +2295,7 @@ export function ChatView({ projectId, addToast, experimentalFeatures }: ChatView
|
||||
{activeModelProvider ? <ProviderIcon provider={activeModelProvider} size="md" /> : <Bot size={16} />}
|
||||
<span className="chat-thread-header-title">{threadHeaderTitle}</span>
|
||||
{showThreadHeaderModelTag && <span className="chat-model-tag">{activeModelTag}</span>}
|
||||
<ChevronDown aria-hidden="true" />
|
||||
<ChevronDown size={16} aria-hidden="true" />
|
||||
</button>
|
||||
{mobileSessionMenuOpen && (
|
||||
<div className="chat-mobile-session-dropdown" role="menu" data-testid="chat-mobile-session-dropdown">
|
||||
|
||||
@@ -2489,16 +2489,23 @@ describe("ChatView CSS — mobile thread switcher", () => {
|
||||
|
||||
it("includes mobile session switcher trigger and dropdown tokenized contracts", () => {
|
||||
const triggerMatch = css.match(/\.chat-mobile-session-trigger\s*\{([^}]*)\}/);
|
||||
const triggerIconMatch = css.match(/\.chat-mobile-session-trigger\s*>\s*svg\s*\{([^}]*)\}/);
|
||||
const dropdownMatch = css.match(/\.chat-mobile-session-dropdown\s*\{([^}]*)\}/);
|
||||
const optionMatch = css.match(/\.chat-mobile-session-option\s*\{([^}]*)\}/);
|
||||
const optionTitleMatch = css.match(/\.chat-mobile-session-option-title\s*\{([^}]*)\}/);
|
||||
expect(triggerMatch).toBeTruthy();
|
||||
expect(triggerIconMatch).toBeTruthy();
|
||||
expect(dropdownMatch).toBeTruthy();
|
||||
expect(optionMatch).toBeTruthy();
|
||||
expect(optionTitleMatch).toBeTruthy();
|
||||
expect(triggerMatch?.[1]).toContain("min-height: calc(var(--space-lg) * 2)");
|
||||
expect(triggerMatch?.[1]).toContain("min-height: calc(var(--space-lg) * 2 + var(--space-xs))");
|
||||
expect(triggerMatch?.[1]).toContain("min-width: 0");
|
||||
expect(triggerMatch?.[1]).toContain("padding: var(--space-xs) var(--space-sm)");
|
||||
expect(triggerMatch?.[1]).toContain("font: inherit");
|
||||
expect(triggerMatch?.[1]).toContain("line-height: normal");
|
||||
expect(triggerMatch?.[1]).toContain("text-align: left");
|
||||
expect(triggerIconMatch?.[1]).toContain("width: var(--icon-size-md)");
|
||||
expect(triggerIconMatch?.[1]).toContain("height: var(--icon-size-md)");
|
||||
expect(dropdownMatch?.[1]).toContain("background: var(--surface)");
|
||||
expect(dropdownMatch?.[1]).toContain("border: 1px solid var(--border)");
|
||||
expect(optionMatch?.[1]).toContain("min-height: calc(var(--space-lg) * 2.25)");
|
||||
@@ -3102,7 +3109,12 @@ describe("ChatView mobile behavior", () => {
|
||||
|
||||
render(<ChatView projectId="proj-123" addToast={vi.fn()} />);
|
||||
|
||||
await userEvent.click(screen.getByTestId("chat-mobile-session-trigger"));
|
||||
const trigger = screen.getByTestId("chat-mobile-session-trigger");
|
||||
expect(trigger).toHaveClass("btn", "chat-mobile-session-trigger");
|
||||
expect(trigger).not.toHaveClass("btn-icon");
|
||||
expect(trigger).toHaveTextContent("Test Chat");
|
||||
|
||||
await userEvent.click(trigger);
|
||||
expect(screen.getByTestId("chat-mobile-session-dropdown")).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(screen.getByTestId("chat-mobile-session-option-session-002"));
|
||||
|
||||
Reference in New Issue
Block a user