xftp-web: fix build and Playwright test failures (#1720)

This commit is contained in:
sh
2026-03-02 16:22:36 +00:00
committed by GitHub
parent f6aca47604
commit 3ecb901e3e
4 changed files with 27 additions and 21 deletions

View File

@@ -8,10 +8,12 @@ export default defineConfig({
ignoreHTTPSErrors: true,
launchOptions: {
// --ignore-certificate-errors makes fetch() accept self-signed certs
// --disable-dev-shm-usage avoids crashes in Docker (default /dev/shm is 64MB)
args: [
'--ignore-certificate-errors',
'--ignore-certificate-errors-spki-list',
'--allow-insecure-localhost',
'--disable-dev-shm-usage',
]
}
},

View File

@@ -13,7 +13,8 @@ test.describe('Upload Flow', () => {
await uploadPage.expectDropZoneVisible()
await uploadPage.selectTextFile('picker-test.txt', 'test content ' + Date.now())
await uploadPage.waitForEncrypting()
// Small files (< 100KB) skip "Encrypting" and go directly to "Uploading"
// await uploadPage.waitForEncrypting()
await uploadPage.waitForUploading()
const link = await uploadPage.waitForShareLink()
@@ -96,14 +97,20 @@ test.describe('Upload Flow', () => {
// ─────────────────────────────────────────────────────────────────────────────
test.describe('Download Flow', () => {
test('download shows error for malformed hash', async ({downloadPage}) => {
await downloadPage.goto('#not-valid-base64!!!')
await downloadPage.expectInitialError(/[Ii]nvalid|corrupted/)
await downloadPage.expectDownloadButtonNotVisible()
test('non-XFTP anchor hash shows upload page', async ({page}) => {
await page.goto('http://localhost:4173#hello-world')
await expect(page.locator('#drop-zone')).toBeVisible()
})
test('download shows error for invalid structure', async ({downloadPage}) => {
await downloadPage.goto('#AAAA')
test('short non-XFTP hash shows upload page', async ({page}) => {
await page.goto('http://localhost:4173#AAAA')
await expect(page.locator('#drop-zone')).toBeVisible()
})
test('corrupted XFTP hash shows error', async ({downloadPage}) => {
// Long base64url string that looks like XFTP but is not valid DEFLATE data
const corrupted = 'A'.repeat(100)
await downloadPage.goto('#' + corrupted)
await downloadPage.expectInitialError(/[Ii]nvalid|corrupted/)
})

View File

@@ -49,19 +49,15 @@ function getFingerprint(): string {
.replace(/\+/g, '-').replace(/\//g, '_')
}
// Plugin to inject __XFTP_SERVERS__ lazily (reads PORT_FILE written by test/runSetup.ts)
// Plugin to inject __XFTP_SERVERS__ via Vite define (reads PORT_FILE written by test/runSetup.ts)
function xftpServersPlugin(): Plugin {
let serverAddr: string | null = null
const fp = getFingerprint()
return {
name: 'xftp-servers-define',
transform(code, _id) {
if (!code.includes('__XFTP_SERVERS__')) return null
if (!serverAddr) {
const port = readFileSync(PORT_FILE, 'utf-8').trim()
serverAddr = `xftp://${fp}@localhost:${port}`
}
return code.replace(/__XFTP_SERVERS__/g, JSON.stringify([serverAddr]))
config() {
const port = readFileSync(PORT_FILE, 'utf-8').trim()
const serverAddr = `xftp://${fp}@localhost:${port}`
return {define: {__XFTP_SERVERS__: JSON.stringify([serverAddr])}}
}
}
}

View File

@@ -1,7 +1,6 @@
import sodium from 'libsodium-wrappers-sumo'
import {initUpload} from './upload.js'
import {initDownload} from './download.js'
import {decodeDescriptionURI} from '../src/agent.js'
import {t} from './i18n.js'
function getAppElement(): HTMLElement | null {
@@ -20,22 +19,24 @@ async function main() {
if (!app?.hasAttribute('data-no-hashchange')) {
window.addEventListener('hashchange', () => {
const hash = window.location.hash.slice(1)
if (!hash || isXFTPHash(hash)) initApp()
if (!hash || looksLikeXFTPHash(hash)) initApp()
})
}
await wasmReady
app?.dispatchEvent(new CustomEvent('xftp:ready', {bubbles: true}))
}
function isXFTPHash(hash: string): boolean {
try { decodeDescriptionURI(hash); return true } catch { return false }
// XFTP hashes are base64url-encoded DEFLATE data, always long.
// Matches the index.html inline script heuristic (length > 50).
function looksLikeXFTPHash(hash: string): boolean {
return hash.length > 50 && /^[A-Za-z0-9_=-]+$/.test(hash)
}
function initApp() {
const app = getAppElement()!
const hash = window.location.hash.slice(1)
if (hash && isXFTPHash(hash)) {
if (hash && looksLikeXFTPHash(hash)) {
initDownload(app, hash)
} else {
initUpload(app)