67 lines
4.6 KiB
JavaScript
67 lines
4.6 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { fixture } from './fixture.mjs';
|
|
import { browser } from './browser.mjs';
|
|
import { P, stub } from './helpers/projects-review-fixture.mjs';
|
|
|
|
async function setup(t, width, before = '') {
|
|
const f = await fixture(), b = await browser({machine:false});
|
|
t.after(async () => { await b.close(); await f.close(); });
|
|
await b.call('Fetch.enable', {patterns:[{urlPattern:'*'}]});
|
|
b.on('Fetch.requestPaused', p => void b.call(p.request.url.startsWith(f.base+'/') ? 'Fetch.continueRequest' : 'Fetch.failRequest', p.request.url.startsWith(f.base+'/') ? {requestId:p.requestId} : {requestId:p.requestId,errorReason:'BlockedByClient'}).catch(()=>{}));
|
|
await b.call('Page.addScriptToEvaluateOnNewDocument', {source:stub + before});
|
|
await b.viewport(width, width === 390 ? 900 : 1000);
|
|
await b.navigate(f.base+'/#/projects/'+P);
|
|
const wait = expr => b.evaluate(`(async()=>{for(let i=0;i<180;i++){if(${expr})return;await new Promise(r=>setTimeout(r,30))}throw Error('Timed out: '+${JSON.stringify(expr)})})()`);
|
|
await wait(`document.querySelector('[data-project-content] [data-project-room-status]')`);
|
|
return {b,wait};
|
|
}
|
|
|
|
async function accessibleName(b, selector) {
|
|
const {result} = await b.call('Runtime.evaluate', {expression:`document.querySelector(${JSON.stringify(selector)})`});
|
|
const {nodes} = await b.call('Accessibility.getPartialAXTree', {objectId:result.objectId, fetchRelatives:false});
|
|
return nodes[0].name.value;
|
|
}
|
|
|
|
for (const width of [1440,390]) {
|
|
test(`S8 project action icons, accessible names and positions at ${width}`, async t => {
|
|
const {b,wait} = await setup(t,width);
|
|
const expected = width === 1440 ? [[1060,1190],[1202,1290],[1302,1418]] : [[12,132],[140,220],[228,340]];
|
|
const y = width === 1440 ? [130,174] : [198,242];
|
|
for (const route of ['', '/conversations', '/tasks', '/requirements', '/files', '/settings', ...(width === 1440 ? ['/room'] : [])]) {
|
|
if (route) {
|
|
await b.evaluate(`location.hash=${JSON.stringify(route === '/room' ? '#/projects/rooms/'+P : '#/projects/'+P+route)}`);
|
|
await wait(`document.querySelector('.project-header')?.dataset.projectSection===${JSON.stringify(route.slice(1))}`);
|
|
}
|
|
for (const [i,name] of ['North star','PRD','Settings'].entries()) {
|
|
const selector = `.project-header .project-primary-action:nth-of-type(${i+1})`;
|
|
const data = await b.evaluate(`(()=>{const e=document.querySelector(${JSON.stringify(selector)}),r=e.getBoundingClientRect();return {icon:!!e.querySelector('svg[aria-hidden="true"]'),left:r.left,right:r.right,top:r.top,bottom:r.bottom}})()`);
|
|
assert.equal(await accessibleName(b,selector),name,`${route || '/overview'} accessible name`);
|
|
assert.ok(data.icon,`${route || '/overview'} ${name} missing decorative icon`);
|
|
for (const [actual,want] of [[data.left,expected[i][0]],[data.right,expected[i][1]],[data.top,y[0]],[data.bottom,y[1]]]) assert.ok(Math.abs(actual-want)<=4,`${route || '/overview'} ${name}: ${JSON.stringify(data)} expected x=${expected[i]} y=${y}`);
|
|
}
|
|
}
|
|
});
|
|
test(`S8 Overview New conversation has a decorative plus at ${width}`, async t => {
|
|
const {b} = await setup(t,width);
|
|
const selector = '[data-project-content] .project-section-title .btn';
|
|
assert.equal(await accessibleName(b,selector),'New conversation');
|
|
assert.equal(await b.evaluate(`!!document.querySelector('${selector} svg[aria-hidden="true"]')`),true);
|
|
});
|
|
}
|
|
|
|
test('S8 room state and link remain in Project facts, never the Overview header', async t => {
|
|
const {b,wait} = await setup(t,1440);
|
|
const facts = '[data-project-content] aside [data-project-room-status]';
|
|
for (const [state, expected] of [['open','Open'],['closed','Closed'],['unavailable','Unavailable']]) {
|
|
if (state === 'closed') await b.evaluate(`reviewClosed=true;document.querySelector('#refresh').click()`);
|
|
if (state === 'unavailable') await b.evaluate(`reviewFail['/api/chat/rooms/${P}/messages?limit=100']=true;document.querySelector('#refresh').click()`);
|
|
await wait(`document.querySelector('${facts}')?.textContent.includes('${expected}')`);
|
|
const result = await b.evaluate(`(()=>{const h=document.querySelector('.project-header'),f=document.querySelector('${facts}');return {header:h.textContent,headerLink:!![...h.querySelectorAll('a')].find(a=>a.textContent.trim()==='Read room'),facts:f.textContent,link:f.querySelector('a')?.getAttribute('href')}})()`);
|
|
assert.doesNotMatch(result.header,/Room:/);
|
|
assert.equal(result.headerLink,false);
|
|
assert.match(result.facts,new RegExp('Room: '+expected));
|
|
assert.equal(result.link,'#/projects/rooms/'+P);
|
|
}
|
|
});
|