From bb3ef29fab64c60050b86bd43dcb2e48f02cf0f6 Mon Sep 17 00:00:00 2001 From: liu weikai Date: Wed, 14 Oct 2026 23:51:53 +0800 Subject: [PATCH] Use retained owners and automatic network startup in browser checks --- tests/site/geocaching-maintenance.browser.mjs | 5 ++++- tests/site/track-multidirectory-network.browser.mjs | 2 +- tests/site/track-refresh-network.browser.mjs | 2 +- tests/site/track-replica-reader.browser.mjs | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/site/geocaching-maintenance.browser.mjs b/tests/site/geocaching-maintenance.browser.mjs index 0e51af7f..2a31f3d4 100644 --- a/tests/site/geocaching-maintenance.browser.mjs +++ b/tests/site/geocaching-maintenance.browser.mjs @@ -174,6 +174,7 @@ try{ await page.locator('.geo-draft-marker').waitFor(); await page.getByRole('button',{name:'保存草稿到设备',exact:true}).click();await page.getByText('草稿已保存到设备。刷新列表可更新发布状态。',{exact:true}).waitFor(); const created=[...records.values()].find(row=>row.value[2][3]==='网页创建草稿');assert.ok(created);assert.notEqual(idText(created.id),idText(draftId));assert.equal(created.value[3],1);assert.equal(created.value[0],null);assert.equal(commits,3); + await page.waitForFunction(()=>Object.keys(localStorage).every(name=>!name.startsWith('trailmate.geo.draft-save.v1.'))); assert.equal(created.value[2][1],Math.round(latitude*1e7));assert.equal(created.value[2][2],Math.round(longitude*1e7)); const maintenanceCalls=calls.length; const maintenanceFields=await page.locator('.geo-draft-editor input,.geo-draft-editor textarea,.geo-draft-editor select').evaluateAll(nodes=>nodes.map(node=>node.value)); @@ -194,7 +195,9 @@ try{ // New publication uses browser IP. Keep the real-page legacy recovery checks // by loading an existing task, rather than resurrecting its removed RF entry. assert.equal(publicationCommits,0);assert.equal(directoryReads,0); - const operation=new Uint8Array(16).fill(6),legacyOwner=new Uint8Array(16).fill(9); + // An existing task uses the owner's actual retained USB session. A + // fabricated different owner would correctly conflict with its saved account. + const operation=new Uint8Array(16).fill(6),legacyOwner=uploadOwner.slice(); const priorGeneration=created.value[3],contentHash=await Identity.fullHash(encode(created.value)); publicationPrepared={id:created.id,generation:BigInt(priorGeneration),directory:directoryDelivery,operation,owner:legacyOwner,hash:contentHash}; created.value[0]=key;created.value[3]++;publicationCommits=1;catalogEpoch++; diff --git a/tests/site/track-multidirectory-network.browser.mjs b/tests/site/track-multidirectory-network.browser.mjs index 237f0159..b5e6754c 100644 --- a/tests/site/track-multidirectory-network.browser.mjs +++ b/tests/site/track-multidirectory-network.browser.mjs @@ -23,7 +23,7 @@ await new Promise(resolve=>server.listen(Number(process.env.TRAIL_MATE_MULTI_PAG try{ const page=await browser.newPage(),errors=[];page.on('pageerror',error=>errors.push(String(error)));await page.goto(origin);await page.waitForFunction(()=>typeof window.verifyMultipleDirectories==='function');const result=await page.evaluate(value=>window.verifyMultipleDirectories(value),{endpoint,seeds:[replicaSeed,sourceSeed]});assert.deepEqual(result.providers,[2,2]); const ui=await browser.newPage({viewport:{width:1440,height:1400}});ui.on('pageerror',error=>errors.push(String(error)));await ui.goto(origin+'/trail-mate/tracks/?lang=zh-Hans');const ip=trackIPText('zh-Hans'),multi=trackMultidirectoryText('zh-Hans'),browse=trackBrowseText('zh-Hans'); - await ui.waitForFunction(value=>document.querySelector('input[type=url]')?.value===value,endpoint);await ui.getByRole('button',{name:ip.connect,exact:true}).click();await ui.getByLabel(ip.directory,{exact:true}).waitFor();await ui.waitForFunction(label=>[...document.querySelectorAll('select')].find(value=>value.getAttribute('aria-label')===label)?.options.length===3,ip.directory);await ui.getByLabel(ip.directory,{exact:true}).selectOption(replicaDelivery); + await ui.waitForFunction(value=>document.querySelector('input[type=url]')?.value===value,endpoint);await ui.getByLabel(ip.directory,{exact:true}).waitFor();await ui.waitForFunction(label=>[...document.querySelectorAll('select')].find(value=>value.getAttribute('aria-label')===label)?.options.length===3,ip.directory);await ui.getByLabel(ip.directory,{exact:true}).selectOption(replicaDelivery); const panel=ui.locator('.shared-track-browser');await panel.getByLabel(multi.toggle,{exact:false}).check();await panel.getByLabel(trackFilterText('zh-Hans').archived,{exact:true}).check();await panel.locator('.leaflet-control-zoom-out').click();await panel.locator('.leaflet-control-zoom-out').click();await ui.waitForTimeout(400); await panel.getByRole('button',{name:browse.search,exact:true}).click();for(let i=0;i<6;i++){await ui.waitForFunction(label=>[...document.querySelectorAll('.shared-track-browser button')].find(value=>value.textContent===label)?.disabled===false,browse.search);const next=panel.getByRole('button',{name:trackQueryContinuationText('zh-Hans').next,exact:true});if(!await next.count())break;await next.click();}await ui.waitForFunction(()=>document.querySelectorAll('.shared-track-results > li').length===2);assert.equal(await panel.locator('.track-query-variant').count(),2);assert.equal(await panel.locator('.track-query-variant button').count(),4); await ui.evaluate(()=>scrollTo(0,0));await ui.screenshot({path:'docs/locales/zh-Hans/web-outdoor-management/images/track-multidirectory-production-page-zh-Hans.png',fullPage:true}); diff --git a/tests/site/track-refresh-network.browser.mjs b/tests/site/track-refresh-network.browser.mjs index 0b71b8f8..e5abc29f 100644 --- a/tests/site/track-refresh-network.browser.mjs +++ b/tests/site/track-refresh-network.browser.mjs @@ -35,7 +35,7 @@ try{ browser=await chromium.launch({channel:process.env.TRAIL_MATE_TEST_BROWSER_CHANNEL,headless:true});const context=await browser.newContext();await context.exposeFunction('refreshDeviceReply',deviceReply);await context.addInitScript(()=>{let input;const port={async open(){this.readable=new ReadableStream({start(controller){input=controller;}});this.writable=new WritableStream({async write(bytes){const response=await window.refreshDeviceReply([...bytes]);try{input.enqueue(Uint8Array.from(response));}catch{}}});},async setSignals(){},async close(){}};Object.defineProperty(navigator,'serial',{configurable:true,value:{requestPort:async()=>port}});});await context.route('https://tile.openstreetmap.org/**',route=>route.fulfill({contentType:'image/svg+xml',body:''}));const page=await context.newPage(),errors=[];page.on('pageerror',error=>errors.push(String(error)));await page.goto(origin+'/trail-mate/tracks/?lang=zh-Hans');await page.addScriptTag({content:inspector.outputFiles[0].text}); const workspace=kmlWorkspaceText('zh-Hans'),device=deviceRecordText('zh-Hans'),network=trackIPText('zh-Hans'),prep=trackPreparationText('zh-Hans'),ip=geocachingIpPublicationText('zh-Hans'),transfer=trackTransferText('zh-Hans');const publication=page.locator('.track-preparation').filter({has:page.getByRole('button',{name:prep.prepare,exact:true})}); const chooser=page.waitForEvent('filechooser');await page.getByRole('button',{name:workspace.import,exact:true}).click();await(await chooser).setFiles({name:'refresh.kml',mimeType:'application/vnd.google-earth.kml+xml',buffer:Buffer.from(bytes)});await page.locator('.tracks-row.selected').waitFor(); - async function connect(){await page.getByRole('button',{name:device.connect,exact:true}).click();await page.getByRole('button',{name:network.connect,exact:true}).click();await page.waitForFunction(()=>document.querySelector('.track-directories select')?.options.length===2,{},{timeout:60000});await page.locator('.track-directories select').selectOption({index:1});await page.getByRole('button',{name:prep.prepare,exact:true}).waitFor();} + async function connect(){await page.getByRole('button',{name:device.connect,exact:true}).click();await page.waitForFunction(()=>document.querySelector('.track-directories select')?.options.length===2,{},{timeout:60000});await page.locator('.track-directories select').selectOption({index:1});await page.getByRole('button',{name:prep.prepare,exact:true}).waitFor();} await connect();const beforeTransport=await page.evaluate(endpoint=>refreshInspector.transport(endpoint),endpoint);assert.notDeepEqual(beforeTransport.publicKey,[...publicKey]);await page.getByRole('button',{name:prep.prepare,exact:true}).click();await page.locator('dialog[open]').getByRole('button',{name:ip.publish,exact:true}).click();await page.waitForFunction(()=>{const value=document.querySelector('[data-track-ip-progress="uploading"]');return value&&document.querySelector('.track-preparation progress')?.value>=65536;},{},{timeout:90000});await publication.scrollIntoViewIfNeeded();await page.screenshot({path:'docs/locales/zh-Hans/web-outdoor-management/images/track-network-progress-zh-Hans.png'});await page.getByRole('button',{name:transfer.pause,exact:true}).click();await page.getByText(transfer.paused,{exact:true}).waitFor();await publication.getByText(ip.unconfirmed,{exact:true}).waitFor();assert.equal(signCount,1);assert.equal(await page.locator('.track-preparation [role=alert]').count(),0);const checkpoint=await page.evaluate(pub=>refreshInspector.checkpoints(pub),[...publicKey]);assert.equal(checkpoint[0].stage,'unconfirmed'); const offsetMatch=service.output.split('\n').filter(line=>line.startsWith('{')).map(line=>{try{return JSON.parse(line);}catch{return null;}}).filter(row=>row?.event==='file_begin'&&row.hash===digest);assert.equal(offsetMatch.length,1);assert.equal(offsetMatch[0].owner,beforeTransport.hash); await page.reload();await page.addScriptTag({content:inspector.outputFiles[0].text});await page.getByRole('button',{name:/刷新续传验收/}).click();await connect();const afterTransport=await page.evaluate(endpoint=>refreshInspector.transport(endpoint),endpoint);assert.deepEqual(afterTransport,beforeTransport);await page.getByRole('button',{name:prep.prepare,exact:true}).click();await publication.getByText(ip.unconfirmed,{exact:true}).waitFor();await page.getByRole('button',{name:ip.resume,exact:true}).click();await publication.getByText(ip.confirmed,{exact:true}).waitFor({timeout:90000});assert.equal(signCount,1); diff --git a/tests/site/track-replica-reader.browser.mjs b/tests/site/track-replica-reader.browser.mjs index ad2e5469..b03263d4 100644 --- a/tests/site/track-replica-reader.browser.mjs +++ b/tests/site/track-replica-reader.browser.mjs @@ -64,8 +64,8 @@ try{ await ui.goto(origin+'/trail-mate/tracks/?lang=zh-Hans'); const ip=trackIPText('zh-Hans'),conflict=trackConflictText('zh-Hans'),shared=trackSharedText('zh-Hans'),pack=trackPackageText('zh-Hans'),historyText=trackVersionHistoryText('zh-Hans'); await ui.waitForFunction(value=>document.querySelector('input[type=url]')?.value===value,endpoint); - await ui.getByRole('button',{name:ip.connect,exact:true}).click(); const directory=ui.getByLabel(ip.directory,{exact:true});await directory.waitFor(); + await ui.waitForFunction(label=>[...document.querySelectorAll('select')].find(node=>node.getAttribute('aria-label')===label)?.options.length===2,ip.directory); const key=await directory.locator('option').nth(1).getAttribute('value');assert.ok(key);await directory.selectOption(key); const binary=text=>Uint8Array.from(text.match(/../g),part=>parseInt(part,16)); const {trackId}=await import('../../site/tracks/src/shared-id.js');