import { describe, expect, it } from "vite-plus/test"; import { constrainAuxiliaryPaneWidth, deriveCenteredContentHorizontalPadding, deriveFileInspectorPaneLayout, deriveLayout, deriveThreadFeedInitialContentInset, deriveThreadWorkLogSizing, deriveWorkspacePaneLayout, SPLIT_LAYOUT_MIN_HEIGHT, SPLIT_LAYOUT_MIN_WIDTH,} from "./layout"; describe("thread work-log text sizing", () => { it.each([11, 16, 22])( "keeps exact compact rows at base size %i without OS enlargement", (baseFontSize) => { expect(deriveThreadWorkLogSizing({ baseFontSize, fontScale: 1 })).toMatchObject({ estimatedRowHeight: 28, fixedRowHeight: 28, }); }, ); it.each([ { baseFontSize: 16, fontScale: 1.25, estimatedRowHeight: 28 }, { baseFontSize: 16, fontScale: 2, estimatedRowHeight: 38 }, { baseFontSize: 22, fontScale: 2, estimatedRowHeight: 52 }, ])( "measures accessibility text instead of locking it to the estimate: %j", ({ estimatedRowHeight, ...settings }) => { expect(deriveThreadWorkLogSizing(settings)).toMatchObject({ estimatedRowHeight, fixedRowHeight: undefined, }); }, ); it("invalidates native text measurements even when the minimum row height is unchanged", () => { const original = deriveThreadWorkLogSizing({ baseFontSize: 16, fontScale: 1 }); for (const settings of [ { baseFontSize: 16, fontScale: 1.1 }, { baseFontSize: 17, fontScale: 1 }, ]) { const resized = deriveThreadWorkLogSizing(settings); expect(resized.estimatedRowHeight).toBe(original.estimatedRowHeight); expect(resized.textSizeKey).not.toBe(original.textSizeKey); } });}); describe("deriveThreadFeedInitialContentInset", () => { it("seeds Android scroll math with the composer overlay estimate", () => { expect( deriveThreadFeedInitialContentInset({ platform: "android", usesNativeAutomaticInsets: false, bottomContentInset: 174, }), ).toEqual({ bottom: 174 }); }); it("does not double native iOS insets", () => { expect( deriveThreadFeedInitialContentInset({ platform: "ios", usesNativeAutomaticInsets: true, bottomContentInset: 174, }), ).toBeUndefined(); });}); describe("resizable pane constraints", () => { it("preserves a useful main pane while constraining a trailing pane", () => { expect(constrainAuxiliaryPaneWidth({ preferredWidth: 440, availableWidth: 1_100 })).toBe(440); expect(constrainAuxiliaryPaneWidth({ preferredWidth: 440, availableWidth: 900 })).toBe(340); expect(constrainAuxiliaryPaneWidth({ preferredWidth: 100, availableWidth: 1_100 })).toBe(260); });}); describe("deriveCenteredContentHorizontalPadding", () => { it("keeps the minimum padding while the viewport fits the reading width", () => { expect( deriveCenteredContentHorizontalPadding({ viewportWidth: 744, maxContentWidth: 960, minimumPadding: 20, }), ).toBe(20); }); it("centers only the content inside a wider full-width scroll host", () => { expect( deriveCenteredContentHorizontalPadding({ viewportWidth: 1_032, maxContentWidth: 960, minimumPadding: 20, }), ).toBe(56); }); it("supports unconstrained compact content", () => { expect( deriveCenteredContentHorizontalPadding({ viewportWidth: 430, maxContentWidth: null, minimumPadding: 16, }), ).toBe(16); });}); describe("deriveLayout", () => { it.each([ { name: "small iPhone portrait", width: 375, height: 667 }, { name: "large iPhone portrait", width: 430, height: 932 }, { name: "small iPhone landscape", width: 667, height: 375 }, { name: "large iPhone landscape", width: 932, height: 430 }, { name: "short wide window", width: 1_024, height: 599 }, { name: "narrow tall window", width: 719, height: 1_024 }, ])("keeps a $name in the compact shell", ({ width, height }) => { expect(deriveLayout({ width, height })).toEqual({ variant: "compact", usesSplitView: false, listPaneWidth: null, shellPadding: 0, }); }); it.each([ { name: "small tablet portrait", width: 744, height: 1_133 }, { name: "tablet landscape", width: 1_024, height: 768 }, { name: "large resizable window", width: 1_366, height: 1_024 }, { name: "foldable-sized window", width: 800, height: 700 }, ])("uses the split shell for a $name", ({ width, height }) => { expect(deriveLayout({ width, height })).toMatchObject({ variant: "split", usesSplitView: true, }); }); it("switches only after both space requirements are met", () => { expect( deriveLayout({ width: SPLIT_LAYOUT_MIN_WIDTH, height: SPLIT_LAYOUT_MIN_HEIGHT }).variant, ).toBe("split"); expect( deriveLayout({ width: SPLIT_LAYOUT_MIN_WIDTH - 1, height: SPLIT_LAYOUT_MIN_HEIGHT }).variant, ).toBe("compact"); expect( deriveLayout({ width: SPLIT_LAYOUT_MIN_WIDTH, height: SPLIT_LAYOUT_MIN_HEIGHT - 1 }).variant, ).toBe("compact"); }); it("keeps the sidebar within usable native-column bounds", () => { expect(deriveLayout({ width: 720, height: 1_000 }).listPaneWidth).toBe(280); expect(deriveLayout({ width: 1_024, height: 768 }).listPaneWidth).toBe(328); expect(deriveLayout({ width: 1_600, height: 1_000 }).listPaneWidth).toBe(380); });}); describe("deriveWorkspacePaneLayout", () => { it("keeps the auxiliary pane out of a standard iPad detail column", () => { const layout = deriveLayout({ width: 1_194, height: 834 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_194, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, }), ).toEqual({ primarySidebarVisible: true, primarySidebarSuppressedByAuxiliary: false, contentPaneWidth: 814, supportsAuxiliaryPane: false, auxiliaryPaneVisible: false, auxiliaryPaneWidth: null, }); }); it("offers an auxiliary pane when maximizing a standard iPad landscape window", () => { const layout = deriveLayout({ width: 1_194, height: 834 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_194, primarySidebarPreferredVisible: false, auxiliaryPanePreferredVisible: true, }), ).toEqual({ primarySidebarVisible: false, primarySidebarSuppressedByAuxiliary: false, contentPaneWidth: 1_194, supportsAuxiliaryPane: true, auxiliaryPaneVisible: true, auxiliaryPaneWidth: 320, }); }); it("prioritizes a trailing file inspector over the thread sidebar at medium widths", () => { const layout = deriveLayout({ width: 1_024, height: 1_366 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_024, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, auxiliaryPaneRole: "inspector", }), ).toEqual({ primarySidebarVisible: false, primarySidebarSuppressedByAuxiliary: true, contentPaneWidth: 1_024, supportsAuxiliaryPane: true, auxiliaryPaneVisible: true, auxiliaryPaneWidth: 260, }); }); it("keeps threads, content, and the file inspector visible in a large landscape window", () => { const layout = deriveLayout({ width: 1_366, height: 1_024 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_366, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, auxiliaryPaneRole: "inspector", }), ).toEqual({ primarySidebarVisible: true, primarySidebarSuppressedByAuxiliary: false, contentPaneWidth: 986, supportsAuxiliaryPane: true, auxiliaryPaneVisible: true, auxiliaryPaneWidth: 276, }); }); it("keeps an explicitly hidden thread sidebar hidden when the file inspector is visible", () => { const layout = deriveLayout({ width: 1_024, height: 1_366 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_024, primarySidebarPreferredVisible: false, auxiliaryPanePreferredVisible: true, auxiliaryPaneRole: "inspector", }), ).toMatchObject({ primarySidebarVisible: false, primarySidebarSuppressedByAuxiliary: false, auxiliaryPaneVisible: true, }); }); it("restores the thread sidebar when the file inspector is hidden", () => { const layout = deriveLayout({ width: 1_024, height: 1_366 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_024, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: false, auxiliaryPaneRole: "inspector", }), ).toMatchObject({ primarySidebarVisible: true, primarySidebarSuppressedByAuxiliary: false, auxiliaryPaneVisible: false, }); }); it("keeps file navigation on the native stack below the inspector breakpoint", () => { const layout = deriveLayout({ width: 744, height: 1_133 }); expect(deriveFileInspectorPaneLayout({ layout, viewportWidth: 744 })).toEqual({ supported: false, width: null, }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 744, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, auxiliaryPaneRole: "inspector", }), ).toMatchObject({ primarySidebarVisible: true, supportsAuxiliaryPane: false, auxiliaryPaneVisible: false, }); }); it("supports three visible columns in a sufficiently large window", () => { const layout = deriveLayout({ width: 1_366, height: 1_024 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_366, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, }), ).toMatchObject({ primarySidebarVisible: true, contentPaneWidth: 986, supportsAuxiliaryPane: true, auxiliaryPaneVisible: true, auxiliaryPaneWidth: 276, }); }); it("uses a preferred inspector width when all three panes still fit", () => { const layout = deriveLayout({ width: 1_366, height: 1_024 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_366, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, auxiliaryPaneRole: "inspector", auxiliaryPanePreferredWidth: 420, }), ).toMatchObject({ primarySidebarVisible: true, auxiliaryPaneVisible: true, auxiliaryPaneWidth: 420, }); }); it("clamps a preferred supplementary width before squeezing the main pane", () => { const layout = deriveLayout({ width: 1_366, height: 1_024 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_366, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, auxiliaryPanePreferredWidth: 460, }).auxiliaryPaneWidth, ).toBe(426); }); it("respects a hidden auxiliary-pane preference", () => { const layout = deriveLayout({ width: 1_366, height: 1_024 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 1_366, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: false, }).auxiliaryPaneVisible, ).toBe(false); }); it("never exposes workspace panes in compact layouts", () => { const layout = deriveLayout({ width: 430, height: 932 }); expect( deriveWorkspacePaneLayout({ layout, viewportWidth: 430, primarySidebarPreferredVisible: true, auxiliaryPanePreferredVisible: true, }), ).toMatchObject({ primarySidebarVisible: false, supportsAuxiliaryPane: false, auxiliaryPaneVisible: false, auxiliaryPaneWidth: null, }); });});
import { describe, expect, it } from "vite-plus/test";
import {
constrainAuxiliaryPaneWidth,
deriveCenteredContentHorizontalPadding,
deriveFileInspectorPaneLayout,
deriveLayout,
deriveThreadFeedInitialContentInset,
deriveThreadWorkLogSizing,
deriveWorkspacePaneLayout,
SPLIT_LAYOUT_MIN_HEIGHT,
SPLIT_LAYOUT_MIN_WIDTH,
} from "./layout";
describe("thread work-log text sizing", () => {
it.each([11, 16, 22])(
"keeps exact compact rows at base size %i without OS enlargement",
(baseFontSize) => {
expect(deriveThreadWorkLogSizing({ baseFontSize, fontScale: 1 })).toMatchObject({
estimatedRowHeight: 28,
fixedRowHeight: 28,
});
},
);
it.each([
{ baseFontSize: 16, fontScale: 1.25, estimatedRowHeight: 28 },
{ baseFontSize: 16, fontScale: 2, estimatedRowHeight: 38 },
{ baseFontSize: 22, fontScale: 2, estimatedRowHeight: 52 },
])(
"measures accessibility text instead of locking it to the estimate: %j",
({ estimatedRowHeight, ...settings }) => {
expect(deriveThreadWorkLogSizing(settings)).toMatchObject({
estimatedRowHeight,
fixedRowHeight: undefined,
});
},
);
it("invalidates native text measurements even when the minimum row height is unchanged", () => {
const original = deriveThreadWorkLogSizing({ baseFontSize: 16, fontScale: 1 });
for (const settings of [
{ baseFontSize: 16, fontScale: 1.1 },
{ baseFontSize: 17, fontScale: 1 },
]) {
const resized = deriveThreadWorkLogSizing(settings);
expect(resized.estimatedRowHeight).toBe(original.estimatedRowHeight);
expect(resized.textSizeKey).not.toBe(original.textSizeKey);
}
});
});
describe("deriveThreadFeedInitialContentInset", () => {
it("seeds Android scroll math with the composer overlay estimate", () => {
expect(
deriveThreadFeedInitialContentInset({
platform: "android",
usesNativeAutomaticInsets: false,
bottomContentInset: 174,
}),
).toEqual({ bottom: 174 });
});
it("does not double native iOS insets", () => {
expect(
deriveThreadFeedInitialContentInset({
platform: "ios",
usesNativeAutomaticInsets: true,
bottomContentInset: 174,
}),
).toBeUndefined();
});
});
describe("resizable pane constraints", () => {
it("preserves a useful main pane while constraining a trailing pane", () => {
expect(constrainAuxiliaryPaneWidth({ preferredWidth: 440, availableWidth: 1_100 })).toBe(440);
expect(constrainAuxiliaryPaneWidth({ preferredWidth: 440, availableWidth: 900 })).toBe(340);
expect(constrainAuxiliaryPaneWidth({ preferredWidth: 100, availableWidth: 1_100 })).toBe(260);
});
});
describe("deriveCenteredContentHorizontalPadding", () => {
it("keeps the minimum padding while the viewport fits the reading width", () => {
expect(
deriveCenteredContentHorizontalPadding({
viewportWidth: 744,
maxContentWidth: 960,
minimumPadding: 20,
}),
).toBe(20);
});
it("centers only the content inside a wider full-width scroll host", () => {
expect(
deriveCenteredContentHorizontalPadding({
viewportWidth: 1_032,
maxContentWidth: 960,
minimumPadding: 20,
}),
).toBe(56);
});
it("supports unconstrained compact content", () => {
expect(
deriveCenteredContentHorizontalPadding({
viewportWidth: 430,
maxContentWidth: null,
minimumPadding: 16,
}),
).toBe(16);
});
});
describe("deriveLayout", () => {
it.each([
{ name: "small iPhone portrait", width: 375, height: 667 },
{ name: "large iPhone portrait", width: 430, height: 932 },
{ name: "small iPhone landscape", width: 667, height: 375 },
{ name: "large iPhone landscape", width: 932, height: 430 },
{ name: "short wide window", width: 1_024, height: 599 },
{ name: "narrow tall window", width: 719, height: 1_024 },
])("keeps a $name in the compact shell", ({ width, height }) => {
expect(deriveLayout({ width, height })).toEqual({
variant: "compact",
usesSplitView: false,
listPaneWidth: null,
shellPadding: 0,
});
});
it.each([
{ name: "small tablet portrait", width: 744, height: 1_133 },
{ name: "tablet landscape", width: 1_024, height: 768 },
{ name: "large resizable window", width: 1_366, height: 1_024 },
{ name: "foldable-sized window", width: 800, height: 700 },
])("uses the split shell for a $name", ({ width, height }) => {
expect(deriveLayout({ width, height })).toMatchObject({
variant: "split",
usesSplitView: true,
});
});
it("switches only after both space requirements are met", () => {
expect(
deriveLayout({ width: SPLIT_LAYOUT_MIN_WIDTH, height: SPLIT_LAYOUT_MIN_HEIGHT }).variant,
).toBe("split");
expect(
deriveLayout({ width: SPLIT_LAYOUT_MIN_WIDTH - 1, height: SPLIT_LAYOUT_MIN_HEIGHT }).variant,
).toBe("compact");
expect(
deriveLayout({ width: SPLIT_LAYOUT_MIN_WIDTH, height: SPLIT_LAYOUT_MIN_HEIGHT - 1 }).variant,
).toBe("compact");
});
it("keeps the sidebar within usable native-column bounds", () => {
expect(deriveLayout({ width: 720, height: 1_000 }).listPaneWidth).toBe(280);
expect(deriveLayout({ width: 1_024, height: 768 }).listPaneWidth).toBe(328);
expect(deriveLayout({ width: 1_600, height: 1_000 }).listPaneWidth).toBe(380);
});
});
describe("deriveWorkspacePaneLayout", () => {
it("keeps the auxiliary pane out of a standard iPad detail column", () => {
const layout = deriveLayout({ width: 1_194, height: 834 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_194,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
}),
).toEqual({
primarySidebarVisible: true,
primarySidebarSuppressedByAuxiliary: false,
contentPaneWidth: 814,
supportsAuxiliaryPane: false,
auxiliaryPaneVisible: false,
auxiliaryPaneWidth: null,
});
});
it("offers an auxiliary pane when maximizing a standard iPad landscape window", () => {
const layout = deriveLayout({ width: 1_194, height: 834 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_194,
primarySidebarPreferredVisible: false,
auxiliaryPanePreferredVisible: true,
}),
).toEqual({
primarySidebarVisible: false,
primarySidebarSuppressedByAuxiliary: false,
contentPaneWidth: 1_194,
supportsAuxiliaryPane: true,
auxiliaryPaneVisible: true,
auxiliaryPaneWidth: 320,
});
});
it("prioritizes a trailing file inspector over the thread sidebar at medium widths", () => {
const layout = deriveLayout({ width: 1_024, height: 1_366 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_024,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
auxiliaryPaneRole: "inspector",
}),
).toEqual({
primarySidebarVisible: false,
primarySidebarSuppressedByAuxiliary: true,
contentPaneWidth: 1_024,
supportsAuxiliaryPane: true,
auxiliaryPaneVisible: true,
auxiliaryPaneWidth: 260,
});
});
it("keeps threads, content, and the file inspector visible in a large landscape window", () => {
const layout = deriveLayout({ width: 1_366, height: 1_024 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_366,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
auxiliaryPaneRole: "inspector",
}),
).toEqual({
primarySidebarVisible: true,
primarySidebarSuppressedByAuxiliary: false,
contentPaneWidth: 986,
supportsAuxiliaryPane: true,
auxiliaryPaneVisible: true,
auxiliaryPaneWidth: 276,
});
});
it("keeps an explicitly hidden thread sidebar hidden when the file inspector is visible", () => {
const layout = deriveLayout({ width: 1_024, height: 1_366 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_024,
primarySidebarPreferredVisible: false,
auxiliaryPanePreferredVisible: true,
auxiliaryPaneRole: "inspector",
}),
).toMatchObject({
primarySidebarVisible: false,
primarySidebarSuppressedByAuxiliary: false,
auxiliaryPaneVisible: true,
});
});
it("restores the thread sidebar when the file inspector is hidden", () => {
const layout = deriveLayout({ width: 1_024, height: 1_366 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_024,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: false,
auxiliaryPaneRole: "inspector",
}),
).toMatchObject({
primarySidebarVisible: true,
primarySidebarSuppressedByAuxiliary: false,
auxiliaryPaneVisible: false,
});
});
it("keeps file navigation on the native stack below the inspector breakpoint", () => {
const layout = deriveLayout({ width: 744, height: 1_133 });
expect(deriveFileInspectorPaneLayout({ layout, viewportWidth: 744 })).toEqual({
supported: false,
width: null,
});
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 744,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
auxiliaryPaneRole: "inspector",
}),
).toMatchObject({
primarySidebarVisible: true,
supportsAuxiliaryPane: false,
auxiliaryPaneVisible: false,
});
});
it("supports three visible columns in a sufficiently large window", () => {
const layout = deriveLayout({ width: 1_366, height: 1_024 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_366,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
}),
).toMatchObject({
primarySidebarVisible: true,
contentPaneWidth: 986,
supportsAuxiliaryPane: true,
auxiliaryPaneVisible: true,
auxiliaryPaneWidth: 276,
});
});
it("uses a preferred inspector width when all three panes still fit", () => {
const layout = deriveLayout({ width: 1_366, height: 1_024 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_366,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
auxiliaryPaneRole: "inspector",
auxiliaryPanePreferredWidth: 420,
}),
).toMatchObject({
primarySidebarVisible: true,
auxiliaryPaneVisible: true,
auxiliaryPaneWidth: 420,
});
});
it("clamps a preferred supplementary width before squeezing the main pane", () => {
const layout = deriveLayout({ width: 1_366, height: 1_024 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_366,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
auxiliaryPanePreferredWidth: 460,
}).auxiliaryPaneWidth,
).toBe(426);
});
it("respects a hidden auxiliary-pane preference", () => {
const layout = deriveLayout({ width: 1_366, height: 1_024 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 1_366,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: false,
}).auxiliaryPaneVisible,
).toBe(false);
});
it("never exposes workspace panes in compact layouts", () => {
const layout = deriveLayout({ width: 430, height: 932 });
expect(
deriveWorkspacePaneLayout({
layout,
viewportWidth: 430,
primarySidebarPreferredVisible: true,
auxiliaryPanePreferredVisible: true,
}),
).toMatchObject({
primarySidebarVisible: false,
supportsAuxiliaryPane: false,
auxiliaryPaneVisible: false,
auxiliaryPaneWidth: null,
});
});
});