Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
commit
03634b1ca3
11340 files changed
+3442369
No files matched your search
@@ -0,0 +1,130 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
$composerPopoutZones,
|
||||
clampPopoutPosition,
|
||||
getComposerPopoutZone,
|
||||
POPOUT_WIDTH_REM,
|
||||
type PopoutBounds,
|
||||
pruneComposerPopoutZones,
|
||||
setComposerPopoutPosition,
|
||||
setComposerPoppedOut
|
||||
} from './composer-popout'
|
||||
|
||||
// jsdom's window is 1024x768; every expectation below is relative to that.
|
||||
const VW = 1024
|
||||
const VH = 768
|
||||
|
||||
const BOX = { height: 56, width: 320 }
|
||||
|
||||
// A split layout: chat on the right half, under a 40px header.
|
||||
const RIGHT_HALF: PopoutBounds = { bottom: VH, left: VW / 2, right: VW, top: 40 }
|
||||
// The same drag intent, viewed from the left half.
|
||||
const LEFT_HALF: PopoutBounds = { bottom: VH, left: 0, right: VW / 2, top: 40 }
|
||||
|
||||
const LEFT_ZONE = 'g-left'
|
||||
const RIGHT_ZONE = 'g-right'
|
||||
|
||||
describe('clampPopoutPosition', () => {
|
||||
it('keeps the whole box inside its surface, not just its corner', () => {
|
||||
const { bottom, right } = clampPopoutPosition({ bottom: 24, right: 24 }, BOX, RIGHT_HALF)
|
||||
|
||||
// Insets are viewport-relative, so convert back to an absolute rect.
|
||||
const boxRight = VW - right
|
||||
const boxLeft = boxRight - BOX.width
|
||||
const boxBottom = VH - bottom
|
||||
const boxTop = boxBottom - BOX.height
|
||||
|
||||
expect(boxLeft).toBeGreaterThanOrEqual(RIGHT_HALF.left)
|
||||
expect(boxRight).toBeLessThanOrEqual(RIGHT_HALF.right)
|
||||
expect(boxTop).toBeGreaterThanOrEqual(RIGHT_HALF.top)
|
||||
expect(boxBottom).toBeLessThanOrEqual(RIGHT_HALF.bottom)
|
||||
})
|
||||
|
||||
it('pulls an out-of-bounds intent back into the surface', () => {
|
||||
// Dragged far left of this surface (a position that belongs to the other
|
||||
// half of the split) — it must land inside, not off the edge.
|
||||
const { right } = clampPopoutPosition({ bottom: 24, right: 900 }, BOX, RIGHT_HALF)
|
||||
|
||||
expect(VW - right - BOX.width).toBeGreaterThanOrEqual(RIGHT_HALF.left)
|
||||
})
|
||||
|
||||
it('is pure — the same intent yields a different placement per surface', () => {
|
||||
const intent = { bottom: 24, right: 24 }
|
||||
|
||||
const onRight = clampPopoutPosition(intent, BOX, RIGHT_HALF)
|
||||
const onLeft = clampPopoutPosition(intent, BOX, LEFT_HALF)
|
||||
|
||||
// Right half honors the intent (it fits); left half has to push the box
|
||||
// inward. Two surfaces, two placements, one unchanged intent — this is what
|
||||
// lets keep-alive tabs share a zone's position without overwriting it.
|
||||
expect(onRight).not.toEqual(onLeft)
|
||||
expect(clampPopoutPosition(intent, BOX, RIGHT_HALF)).toEqual(onRight)
|
||||
})
|
||||
|
||||
it('falls back to the full window when the surface has no measured area', () => {
|
||||
const { bottom, right } = clampPopoutPosition({ bottom: 24, right: 24 }, BOX, undefined)
|
||||
|
||||
expect(bottom).toBe(24)
|
||||
expect(right).toBe(24)
|
||||
})
|
||||
|
||||
it('assumes the compact float width when the box is unmeasured', () => {
|
||||
// Pre-layout (peel-off, restore) there is no rect yet; the fallback must
|
||||
// still leave the box grabbable rather than clamping it to a zero-width slot.
|
||||
const { right } = clampPopoutPosition({ bottom: 24, right: 5000 }, undefined, RIGHT_HALF)
|
||||
|
||||
expect(VW - right - POPOUT_WIDTH_REM * 16).toBeGreaterThanOrEqual(RIGHT_HALF.left)
|
||||
})
|
||||
})
|
||||
|
||||
describe('pop-out state is scoped to a layout zone', () => {
|
||||
beforeEach(() => {
|
||||
$composerPopoutZones.set({})
|
||||
})
|
||||
|
||||
it('floats one zone without touching its neighbor', () => {
|
||||
setComposerPoppedOut(LEFT_ZONE, true)
|
||||
|
||||
// Tabs in the left zone float; the right split stays docked. This is the
|
||||
// whole point of keying by zone: popping out on the left must not fling a
|
||||
// composer out of every other pane.
|
||||
expect(getComposerPopoutZone(LEFT_ZONE).poppedOut).toBe(true)
|
||||
expect(getComposerPopoutZone(RIGHT_ZONE).poppedOut).toBe(false)
|
||||
})
|
||||
|
||||
it('keeps each zone position independent', () => {
|
||||
setComposerPopoutPosition(LEFT_ZONE, { bottom: 100, right: 100 })
|
||||
setComposerPopoutPosition(RIGHT_ZONE, { bottom: 24, right: 24 })
|
||||
|
||||
expect(getComposerPopoutZone(LEFT_ZONE).position).toEqual({ bottom: 100, right: 100 })
|
||||
expect(getComposerPopoutZone(RIGHT_ZONE).position).toEqual({ bottom: 24, right: 24 })
|
||||
})
|
||||
|
||||
it('reports the default for a zone nobody has touched', () => {
|
||||
// Every tab in a fresh zone reads the same default, so a new split starts
|
||||
// docked at the default corner rather than inheriting a neighbor's drag.
|
||||
expect(getComposerPopoutZone('g-unseen')).toEqual({ poppedOut: false, position: { bottom: 24, right: 24 } })
|
||||
})
|
||||
|
||||
it('does not let one zone float seed the zones split after it', () => {
|
||||
setComposerPoppedOut(LEFT_ZONE, true)
|
||||
setComposerPopoutPosition(LEFT_ZONE, { bottom: 200, right: 200 })
|
||||
|
||||
// A zone created later is its own thing — it must not inherit the float
|
||||
// state of whichever zone happened to be touched first.
|
||||
expect(getComposerPopoutZone('g-split-later')).toEqual({
|
||||
poppedOut: false,
|
||||
position: { bottom: 24, right: 24 }
|
||||
})
|
||||
})
|
||||
|
||||
it('drops state for zones that no longer exist', () => {
|
||||
setComposerPoppedOut(LEFT_ZONE, true)
|
||||
setComposerPoppedOut(RIGHT_ZONE, true)
|
||||
|
||||
pruneComposerPopoutZones([LEFT_ZONE])
|
||||
|
||||
expect(Object.keys($composerPopoutZones.get())).toEqual([LEFT_ZONE])
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user