학생 회기 모바일 사용성 보정

This commit is contained in:
Yun Chan 2026-08-09 22:00:32 +09:00
parent aaebe4450e
commit c743e9ccb9
7 changed files with 395 additions and 31 deletions

View file

@ -806,9 +806,14 @@ async function expectMobileActiveVisualIntegrity(page: Page) {
const avatar = visibleRect(".sx-orb-wrap");
const client = visibleRect(".sx-stage__client");
const now = visibleRect(".sx-stage__now");
const sessionbar = visibleRect(".sx-sessionbar");
const timebar = visibleRect(".sx-timebar");
const mobileContext = visibleRect(".sx-mobile-context");
const transcript = visibleRect(".sx-transcript");
const transcriptHead = visibleRect(".sx-transcript__head");
const scroll = visibleRect(".sx-transcript__scroll");
const compose = visibleRect(".sx-compose");
const controlbar = visibleRect(".sx-controlbar");
const replies = Array.from(
document.querySelectorAll<HTMLElement>(".sx-transcript__scroll .sx-utt"),
).filter((element) => getComputedStyle(element).display !== "none");
@ -820,6 +825,44 @@ async function expectMobileActiveVisualIntegrity(page: Page) {
return {
viewport: `${innerWidth}x${innerHeight}`,
compactStage: innerWidth <= 420 && innerHeight <= 620,
avatarHidden: avatar == null,
geometry: {
scroll: scroll
? { top: scroll.top, bottom: scroll.bottom, height: scroll.height }
: null,
scrollClientHeight:
document.querySelector<HTMLElement>(".sx-transcript__scroll")?.clientHeight ?? null,
scrollHeight:
document.querySelector<HTMLElement>(".sx-transcript__scroll")?.scrollHeight ?? null,
scrollTop:
document.querySelector<HTMLElement>(".sx-transcript__scroll")?.scrollTop ?? null,
latestReply: latestReply
? { top: latestReply.top, bottom: latestReply.bottom, height: latestReply.height }
: null,
sessionbar: sessionbar
? { top: sessionbar.top, bottom: sessionbar.bottom, height: sessionbar.height }
: null,
timebar: timebar
? { top: timebar.top, bottom: timebar.bottom, height: timebar.height }
: null,
mobileContext: mobileContext
? { top: mobileContext.top, bottom: mobileContext.bottom, height: mobileContext.height }
: null,
transcript: transcript
? { top: transcript.top, bottom: transcript.bottom, height: transcript.height }
: null,
transcriptHead: transcriptHead
? { top: transcriptHead.top, bottom: transcriptHead.bottom, height: transcriptHead.height }
: null,
compose: compose
? { top: compose.top, bottom: compose.bottom, height: compose.height }
: null,
stage: stage ? { top: stage.top, bottom: stage.bottom, height: stage.height } : null,
controlbar: controlbar
? { top: controlbar.top, bottom: controlbar.bottom, height: controlbar.height }
: null,
},
overlaps,
stageContainsAvatar: Boolean(stage && avatar && contained(stage, avatar)),
stageContainsClient: Boolean(stage && client && contained(stage, client)),
@ -836,13 +879,18 @@ async function expectMobileActiveVisualIntegrity(page: Page) {
};
});
expect(result.overlaps, result.viewport).toEqual([]);
expect(result.stageContainsAvatar, result.viewport).toBe(true);
expect(result.stageContainsClient, result.viewport).toBe(true);
expect(result.statusHidden, result.viewport).toBe(true);
expect(result.transcriptContained, result.viewport).toBe(true);
expect(result.composeContained, result.viewport).toBe(true);
expect(result.latestReplyVisible, result.viewport).toBe(true);
const diagnostic = `${result.viewport} ${JSON.stringify(result.geometry)}`;
expect(result.overlaps, diagnostic).toEqual([]);
if (result.compactStage) {
expect(result.avatarHidden, diagnostic).toBe(true);
} else {
expect(result.stageContainsAvatar, diagnostic).toBe(true);
}
expect(result.stageContainsClient, diagnostic).toBe(true);
expect(result.statusHidden, diagnostic).toBe(true);
expect(result.transcriptContained, diagnostic).toBe(true);
expect(result.composeContained, diagnostic).toBe(true);
expect(result.latestReplyVisible, diagnostic).toBe(true);
}
async function capture(page: Page, projectName: string, stage: string) {