109 lines
8.4 KiB
JavaScript
109 lines
8.4 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { setup, P, T, S, S2 } from './helpers/w15-conversations.mjs';
|
|
|
|
test('canonical project and session routes preserve identity, drafts and optional mounts', async t=>{
|
|
const {b,render,shot,wait}=await setup(t);
|
|
await b.evaluate(`window.MosaicRequests={mount(){},projectSummary(o){window.__mounts.push(['summary',o.requestIds,o.project]);o.container.textContent='Fixture request summary';}}`);
|
|
await render(`/projects/${P}`);
|
|
await wait('document.querySelector("[data-project-content]")?.textContent.includes("Showing requests from recent messages")');
|
|
assert.match(await b.evaluate('document.querySelector(".chat-area").textContent'),/Showing requests from recent messages/);
|
|
for(const w of [1440,390]) await shot('project-overview-unloaded',w);
|
|
await render(`/projects/${P}/settings`);
|
|
assert.deepEqual(await b.evaluate('window.__mounts.at(-1)'),['remote',P,'repo-key']);
|
|
await render(`/projects/threads/${T}/sessions/${S}`);
|
|
assert.equal(await b.evaluate('document.querySelector(".chat-conversation").dataset.session'),S);
|
|
assert.deepEqual(await b.evaluate('window.__contexts.at(-1)'),{projectId:P,repositoryKey:'repo-key',thread:T,session:S});
|
|
assert.ok(await b.evaluate(`!!document.querySelector('.project-tabs a[href$="/files"]') && !document.querySelector('[data-chat-files]')`));
|
|
assert.equal(await b.evaluate(`!!document.querySelector('.project-chat [data-chat-summary]') || window.__mounts.some(x=>x[0]==='summary')`),false);
|
|
await b.evaluate('document.querySelector("#chat-body").value="first draft";document.querySelector("#chat-body").dispatchEvent(new Event("input",{bubbles:true}))');
|
|
for(const w of [1440,390]) await shot('conversation-progress',w);
|
|
await b.evaluate('document.querySelector(".chat-details").open=true');
|
|
for(const w of [1440,390]) await shot('conversation-details',w);
|
|
await render(`/projects/threads/${T}/sessions/${S2}`);
|
|
assert.equal(await b.evaluate('document.querySelector("#chat-body").value'),'');
|
|
await b.evaluate('document.querySelector("#chat-body").value="second draft";document.querySelector("#chat-body").dispatchEvent(new Event("input",{bubbles:true}))');
|
|
for(const w of [1440,390]) await shot('two-named-sessions',w);
|
|
await render(`/projects/threads/${T}/sessions/${S}`);
|
|
assert.equal(await b.evaluate('document.querySelector("#chat-body").value'),'first draft');
|
|
await render(`/projects/${P}`);
|
|
await wait('document.querySelector("[data-project-content]")?.textContent.includes("Showing requests from recent messages")');
|
|
assert.match(await b.evaluate('document.querySelector("[data-project-content]").textContent'),/Showing requests from recent messages/);
|
|
for(const w of [1440,390]) await shot('project-overview-known',w);
|
|
await b.evaluate('delete window.MosaicRequests'); await render(`/projects/${P}`);
|
|
await wait('document.querySelector("[data-project-content]")?.textContent.includes("Not available yet")');
|
|
await render(`/projects/threads/${T}/sessions/${S}`);
|
|
await b.evaluate('window.__failRead=true');await render(`/projects/threads/${T}/sessions/${S}`);
|
|
assert.equal(await b.evaluate('document.querySelector("#chat-body").value'),'first draft');
|
|
for(const w of [1440,390]) await shot('read-failed-draft-kept',w);
|
|
assert.equal(await b.evaluate('window.__writes.length'),0);
|
|
});
|
|
|
|
test('room picker serializes selected instance and retains unresolved drafts', async t=>{
|
|
const {b,render,shot}=await setup(t);await render(`/projects/rooms/${P}`);
|
|
assert.match(await b.evaluate('document.querySelector(".chat-room").textContent'),/Each reply stays in that member/);
|
|
for(const w of [1440,390]) await shot('room-picker',w);
|
|
await b.evaluate('document.querySelector("[data-room-member=bob]").click()');
|
|
assert.match(await b.evaluate('document.querySelector("#chat-room-body").value'),/^@alice /);
|
|
assert.match(await b.evaluate('document.querySelector("#chat-room-tags").textContent'),/To:.*alice/);
|
|
await b.evaluate('document.querySelector("#chat-room-body").value="@alice Please ask @bob too";document.querySelector("#chat-room-body").dispatchEvent(new Event("input",{bubbles:true}))');
|
|
assert.match(await b.evaluate('document.querySelector("#chat-room-tags").textContent'),/To:.*alice/);
|
|
assert.equal(await b.evaluate('document.querySelector("[data-room-offer=bob]") !== null'),true);
|
|
await b.evaluate('document.querySelector("[data-room-offer=bob]").click()');
|
|
assert.match(await b.evaluate('document.querySelector("#chat-room-tags").textContent'),/alice.*bob/);
|
|
await b.evaluate('document.querySelector("#chat-room-body").value="@unknown message";document.querySelector("#chat-room-body").dispatchEvent(new Event("input",{bubbles:true}));document.querySelector("[data-room-member=bob]").click()');
|
|
assert.equal(await b.evaluate('document.querySelector("#chat-room-body").value'),'@unknown message');
|
|
assert.match(await b.evaluate('document.querySelector("#chat-room-receipt").textContent'),/Repair/);
|
|
for(const w of [1440,390]) await shot('room-invalid',w);
|
|
assert.equal(await b.evaluate('window.__writes.length'),0);
|
|
});
|
|
|
|
|
|
test('granted routes do not expose owner room or remote controls', async t=>{
|
|
const {b}=await setup(t);
|
|
await b.evaluate(`MosaicChat.render({path:'/projects/rooms/${P}',container:document.getElementById('bus-view'),canSend:true,user:true})`);
|
|
assert.match(await b.evaluate('document.querySelector(".chat-area").textContent'),/Rooms require the business owner/);
|
|
assert.equal(await b.evaluate('!!document.querySelector("#chat-room-send-form")'),false);
|
|
await b.evaluate(`MosaicChat.render({path:'/projects/${P}/settings',container:document.getElementById('bus-view'),canSend:true,user:true})`);
|
|
assert.equal(await b.evaluate('window.__mounts.some(x=>x[0]==="remote")'),false);
|
|
assert.equal(await b.evaluate('window.__writes.length'),0);
|
|
});
|
|
|
|
|
|
test('pending clear, room receipt and shared history retain truthful state', async t=>{
|
|
const {b,render,wait,shot}=await setup(t);
|
|
await render(`/projects/threads/${T}/sessions/${S}`);
|
|
await b.evaluate('document.querySelector(".chat-details").open=true;window.__holdClear=true;document.querySelector("#chat-clear").click()');
|
|
await wait('window.__writes.some(w=>w.path.endsWith("/clear"))');
|
|
assert.match(await b.evaluate('document.querySelector(".chat-log").textContent'),/fixture message/);
|
|
assert.match(await b.evaluate('document.querySelector("#chat-clear-receipt").textContent'),/requesting clear/);
|
|
for(const w of [1440,390]) await shot('clear-pending',w);
|
|
await b.evaluate('window.__releaseClear()');
|
|
await render(`/projects/rooms/${P}`);
|
|
await b.evaluate('window.__roomAccept=true;document.querySelector("[data-room-member=bob]").click();const e=document.querySelector("#chat-room-body");e.value="@alice hello";e.dispatchEvent(new Event("input",{bubbles:true}));document.querySelector("#chat-room-send-form").dispatchEvent(new Event("submit",{bubbles:true,cancelable:true}))');
|
|
await wait('document.querySelector("#chat-room-receipt").textContent.includes("Accepted")');
|
|
for(const w of [1440,390]) await shot('room-sent',w);
|
|
await b.evaluate('window.__shared=true');
|
|
await render(`/projects/threads/${T}`);
|
|
assert.match(await b.evaluate('document.querySelector(".chat-area").textContent'),/Read-only thread/);
|
|
assert.equal(await b.evaluate('!!document.querySelector("#chat-send-form")'),false);
|
|
for(const w of [1440,390]) await shot('shared-readonly',w);
|
|
});
|
|
|
|
test('room recipient controls accept keyboard and pointer at both widths', async t=>{
|
|
const {b,render}=await setup(t);
|
|
for(const width of [1440,390]) {
|
|
await b.viewport(width,1000); await render(`/projects/rooms/${P}`);
|
|
await b.evaluate('document.querySelector("[data-room-chip=bob]").focus()');
|
|
await b.key(' ');
|
|
assert.match(await b.evaluate('document.querySelector("#chat-room-tags").textContent'),/alice/);
|
|
assert.equal(await b.evaluate('document.activeElement.dataset.roomChip'),'bob');
|
|
await b.key('Tab'); await b.key('Tab','Tab',8); await b.key('Escape');
|
|
assert.notEqual(await b.evaluate('document.activeElement.tagName'),'BODY');
|
|
const box=await b.evaluate('(()=>{const r=document.querySelector("[data-room-chip=bob]").getBoundingClientRect();return {x:r.x+r.width/2,y:r.y+r.height/2}})()');
|
|
await b.call('Input.dispatchMouseEvent',{type:'mousePressed',x:box.x,y:box.y,button:'left',clickCount:1});
|
|
await b.call('Input.dispatchMouseEvent',{type:'mouseReleased',x:box.x,y:box.y,button:'left',clickCount:1});
|
|
assert.match(await b.evaluate('document.querySelector("#chat-room-tags").textContent'),/bob/);
|
|
}
|
|
});
|