oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1// Uses TestBrowserMenuFixture's rendered page with synthetic cells and size API.
2import assert from 'node:assert/strict';
3import fs from 'node:fs';
4const pw=await import(process.env.PLAYWRIGHT||'playwright');
5const fixture=JSON.parse(fs.readFileSync(process.env.SHEETS_MENU_FIXTURE));
6for(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