| 1 | // Uses TestBrowserMenuFixture's rendered page with synthetic cells and size API. |
| 2 | import assert from 'node:assert/strict'; |
| 3 | import fs from 'node:fs'; |
| 4 | const pw=await import(process.env.PLAYWRIGHT||'playwright'); |
| 5 | const fixture=JSON.parse(fs.readFileSync(process.env.SHEETS_MENU_FIXTURE)); |
| 6 | for(const name of ['chromium','webkit']) { |
| 7 | const browser=await pw[name].launch(name==='webkit'&&process.env.WEBKIT_EXECUTABLE_PATH?{executablePath:process.env.WEBKIT_EXECUTABLE_PATH}:{}); |
| 8 | try { |
| 9 | const page=await browser.newPage({viewport:{width:1400,height:900}}); |
| 10 | let requests=[],sizes={cols:{}},reject=false; |
| 11 | const errors=[];page.on('pageerror',e=>errors.push(e.message)); |
| 12 | const cells=[{r:0,c:0,raw:'=SUM(B1:B80)',display:'5'}, |
| 13 | {r:80,c:0,raw:'The widest value is below the viewport',display:'The widest value is below the viewport',f:'bold'}, |
| 14 | {r:1,c:1,raw:'Medium length',display:'Medium length'}, |
| 15 | {r:0,c:2,raw:'=A_VERY_LONG_FORMULA_WITH_A_SHORT_RESULT()',display:'1'}, |
| 16 | {r:0,c:3,raw:'W'.repeat(1000),display:'W'.repeat(1000)}]; |
| 17 | await page.route('https://sheets.test/**',async route=>{ |
| 18 | const req=route.request(),path=new URL(req.url()).pathname; |
| 19 | if(fixture.assets[path])return route.fulfill({body:fixture.assets[path],contentType:path.endsWith('.js')?'application/javascript':path.endsWith('.css')?'text/css':'image/svg+xml'}); |
| 20 | if(path.endsWith('/stream'))return route.fulfill({body:'',contentType:'text/event-stream'}); |
| 21 | if(path.endsWith('/size')&&req.method()==='POST') { |
| 22 | const value=req.postDataJSON();requests.push(value); |
| 23 | if(reject)return route.fulfill({status:400,body:'refused'}); |
| 24 | sizes.cols[value.col]=value.size; |
| 25 | } |
| 26 | if(path.startsWith('/api/'))return route.fulfill({json:{version:1,cells,formats:{bold:{b:true,i:true}},sizes}}); |
| 27 | return route.fulfill({body:fixture.html,contentType:'text/html'}); |
| 28 | }); |
| 29 | async function load() { |
| 30 | requests=[];sizes={cols:{}};reject=false; |
| 31 | await page.goto('https://sheets.test/sheets/1');await page.waitForFunction(()=>SheetsGrid?.worksheet()); |
| 32 | await page.evaluate(()=>new Promise(resolve=>requestAnimationFrame(()=>requestAnimationFrame(resolve)))); |
| 33 | } |
| 34 | const header=c=>page.locator(`.jss_worksheet > thead > tr:first-child > td[data-x="${c}"]`); |
| 35 | async function divider(c) { |
| 36 | const rect=await header(c).boundingBox(); |
| 37 | await page.mouse.dblclick(rect.x+rect.width-2,rect.y+rect.height/2); |
| 38 | } |
| 39 | async function resized(c) { |
| 40 | await page.waitForFunction(c=>Number(SheetsGrid.worksheet().getWidth(c))!==100,c); |
| 41 | } |
| 42 | await load();await divider(0);await resized(0); |
| 43 | assert.equal(requests.length,1);assert.equal(requests[0].col,0); |
| 44 | assert.ok(requests[0].size>200,'must measure content below viewport'); |
| 45 | const first=requests[0].size; |
| 46 | await page.reload();await page.waitForFunction(()=>SheetsGrid?.worksheet()); |
| 47 | assert.equal(Number(await page.evaluate(()=>SheetsGrid.worksheet().getWidth(0))),first,'width survives reload'); |
| 48 | console.log(name+': single-column divider fits offscreen formatted content and persists'); |
| 49 | await load();await header(0).click();await header(1).click({modifiers:['Shift']}); |
| 50 | const selected=await page.evaluate(()=>SheetsGrid.selection()); |
| 51 | assert.equal(Math.min(selected.c,selected.c2),0);assert.equal(Math.max(selected.c,selected.c2),1); |
| 52 | await divider(0);await page.waitForFunction(()=>Number(SheetsGrid.worksheet().getWidth(1))!==100); |
| 53 | assert.deepEqual(requests.map(r=>r.col),[0,1]);assert.ok(sizes.cols[0]>sizes.cols[1]); |
| 54 | assert.equal(sizes.cols[0],first); |
| 55 | console.log(name+': selected columns fit individually without first equalizing widths'); |
| 56 | // The existing manual group resize must persist both columns too. |
| 57 | requests=[];const rect=await header(0).boundingBox(); |
| 58 | await page.mouse.move(rect.x+rect.width-2,rect.y+rect.height/2);await page.mouse.down(); |
| 59 | await page.mouse.move(rect.x+rect.width+30,rect.y+rect.height/2);await page.mouse.up(); |
| 60 | await page.evaluate(()=>SheetsSizes.settled()); |
| 61 | assert.deepEqual(requests.map(r=>r.col),[0,1]);assert.equal(sizes.cols[0],sizes.cols[1]); |
| 62 | console.log(name+': manual group resize persists all columns'); |
| 63 | await load();await header(2).click();await page.evaluate(()=>SheetsAutoFit()); |
| 64 | assert.ok(sizes.cols[2]<100,'measure formula result, not raw expression'); |
| 65 | await header(3).click();await page.evaluate(()=>SheetsAutoFit());assert.equal(sizes.cols[3],2000); |
| 66 | await header(4).click();await page.evaluate(()=>SheetsAutoFit());assert.ok(sizes.cols[4]>=16&&sizes.cols[4]<100); |
| 67 | console.log(name+': formula display, empty columns, and maximum width'); |
| 68 | await load();await header(0).click();await header(1).click({modifiers:['Shift']});reject=true; |
| 69 | await page.evaluate(()=>SheetsAutoFit());assert.equal(requests.length,1);assert.deepEqual(sizes.cols,{}); |
| 70 | reject=false;await page.evaluate(()=>SheetsAutoFit());assert.equal(requests.length,3); |
| 71 | assert.deepEqual(errors,[]);console.log(name+': failed resize stops and can retry'); |
| 72 | } finally {await browser.close();} |
| 73 | } |
| 74 | |