Origem: D:/Documents/Github/PiAgentUI/PiAgentUi Arquivos omitidos (segredos, bancos de dados, logs, >50 MB): 4
240 lines
7.1 KiB
JavaScript
240 lines
7.1 KiB
JavaScript
import fs from 'node:fs'
|
|
import os from 'node:os'
|
|
import path from 'node:path'
|
|
import { spawn, spawnSync } from 'node:child_process'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
const projectRoot = path.resolve(__dirname, '..')
|
|
const fakePiScript = path.join(__dirname, 'fixtures', 'fake-pi.mjs')
|
|
const hostHome = os.homedir()
|
|
const tempRoot = process.env.PIAGENTUI_E2E_TEMP_ROOT
|
|
? path.resolve(process.env.PIAGENTUI_E2E_TEMP_ROOT)
|
|
: fs.mkdtempSync(path.join(os.tmpdir(), 'piagentui-e2e-'))
|
|
process.env.PIAGENTUI_E2E_TEMP_ROOT = tempRoot
|
|
const markerDir = path.join(tempRoot, 'markers')
|
|
const appHome = path.join(tempRoot, 'home')
|
|
const appData = path.join(appHome, 'AppData', 'Roaming')
|
|
const localAppData = path.join(appHome, 'AppData', 'Local')
|
|
const xdgDataHome = path.join(appHome, '.local', 'share')
|
|
const xdgConfigHome = path.join(appHome, '.config')
|
|
const xdgCacheHome = path.join(appHome, '.cache')
|
|
const e2eAgentDir = path.join(tempRoot, 'pi-runtime', 'agent')
|
|
const e2eSessionDir = path.join(tempRoot, 'pi-runtime', 'agent', 'sessions')
|
|
|
|
for (const dir of [
|
|
markerDir,
|
|
appHome,
|
|
appData,
|
|
localAppData,
|
|
xdgDataHome,
|
|
xdgConfigHome,
|
|
xdgCacheHome,
|
|
e2eAgentDir,
|
|
e2eSessionDir,
|
|
]) {
|
|
fs.mkdirSync(dir, { recursive: true })
|
|
}
|
|
|
|
process.env.PIAGENTUI_E2E_MARKER_DIR = markerDir
|
|
|
|
const appEnv = {
|
|
...process.env,
|
|
HOME: appHome,
|
|
USERPROFILE: appHome,
|
|
APPDATA: appData,
|
|
LOCALAPPDATA: localAppData,
|
|
XDG_DATA_HOME: xdgDataHome,
|
|
XDG_CONFIG_HOME: xdgConfigHome,
|
|
XDG_CACHE_HOME: xdgCacheHome,
|
|
PIAGENTUI_E2E_NODE: process.execPath,
|
|
PIAGENTUI_E2E_PI_SCRIPT: fakePiScript,
|
|
PIAGENTUI_E2E_MARKER_DIR: markerDir,
|
|
PI_CODING_AGENT_DIR: e2eAgentDir,
|
|
PI_CODING_AGENT_SESSION_DIR: e2eSessionDir,
|
|
}
|
|
|
|
let tauriDriver
|
|
let driverExitExpected = false
|
|
|
|
function appBinaryPath() {
|
|
if (process.env.PIAGENTUI_E2E_APP) return path.resolve(projectRoot, process.env.PIAGENTUI_E2E_APP)
|
|
|
|
const exe = process.platform === 'win32' ? 'piagentui.exe' : 'piagentui'
|
|
return path.join(projectRoot, 'src-tauri', 'target', 'debug', exe)
|
|
}
|
|
|
|
function e2eConfigPath() {
|
|
return path.join(path.dirname(appBinaryPath()), 'piagentui-e2e.json')
|
|
}
|
|
|
|
function tauriDriverPath() {
|
|
if (process.env.TAURI_DRIVER) return process.env.TAURI_DRIVER
|
|
const exe = process.platform === 'win32' ? 'tauri-driver.exe' : 'tauri-driver'
|
|
const cargoPath = path.join(hostHome, '.cargo', 'bin', exe)
|
|
return fs.existsSync(cargoPath) ? cargoPath : exe
|
|
}
|
|
|
|
function nativeDriverArgs() {
|
|
const explicit = process.env.TAURI_NATIVE_DRIVER
|
|
if (explicit) return ['--native-driver', explicit]
|
|
|
|
if (process.platform !== 'win32') return []
|
|
const candidates = [
|
|
path.join(projectRoot, 'msedgedriver.exe'),
|
|
path.join(projectRoot, '..', 'msedgedriver.exe'),
|
|
path.join(process.cwd(), 'msedgedriver.exe'),
|
|
]
|
|
const driver = candidates.find(candidate => fs.existsSync(candidate))
|
|
if (driver) console.info(`Using native WebDriver: ${driver}`)
|
|
return driver ? ['--native-driver', driver] : []
|
|
}
|
|
|
|
function run(command, args, options = {}) {
|
|
const result = spawnSync(command, args, {
|
|
cwd: projectRoot,
|
|
stdio: 'inherit',
|
|
shell: process.platform === 'win32',
|
|
...options,
|
|
})
|
|
if (result.status !== 0) {
|
|
throw new Error(`${command} ${args.join(' ')} failed with status ${result.status}`)
|
|
}
|
|
}
|
|
|
|
function cleanup() {
|
|
driverExitExpected = true
|
|
tauriDriver?.kill()
|
|
fs.rmSync(e2eConfigPath(), { force: true })
|
|
if (!process.env.PIAGENTUI_E2E_KEEP_TMP) {
|
|
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
}
|
|
}
|
|
|
|
export const config = {
|
|
runner: 'local',
|
|
hostname: '127.0.0.1',
|
|
port: 4444,
|
|
specs: [path.join(projectRoot, 'e2e', 'specs', '**', '*.mjs')],
|
|
maxInstances: 1,
|
|
capabilities: [
|
|
{
|
|
browserName: 'wry',
|
|
maxInstances: 1,
|
|
'tauri:options': {
|
|
application: appBinaryPath(),
|
|
},
|
|
},
|
|
],
|
|
logLevel: process.env.PIAGENTUI_E2E_LOG_LEVEL ?? 'warn',
|
|
reporters: ['spec'],
|
|
framework: 'mocha',
|
|
mochaOpts: {
|
|
ui: 'bdd',
|
|
timeout: 120000,
|
|
},
|
|
waitforTimeout: 15000,
|
|
connectionRetryTimeout: 120000,
|
|
connectionRetryCount: 1,
|
|
|
|
onPrepare() {
|
|
if (!process.env.PIAGENTUI_E2E_SKIP_BUILD) {
|
|
run('pnpm', ['tauri', 'build', '--debug', '--no-bundle'])
|
|
}
|
|
|
|
const application = appBinaryPath()
|
|
if (!fs.existsSync(application)) {
|
|
throw new Error(`Tauri debug binary not found: ${application}`)
|
|
}
|
|
|
|
fs.writeFileSync(
|
|
e2eConfigPath(),
|
|
JSON.stringify(
|
|
{
|
|
node: process.execPath,
|
|
script: fakePiScript,
|
|
markerDir,
|
|
agentDir: e2eAgentDir,
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
'utf8',
|
|
)
|
|
|
|
const driver = tauriDriverPath()
|
|
tauriDriver = spawn(driver, nativeDriverArgs(), {
|
|
stdio: ['ignore', process.stdout, process.stderr],
|
|
env: appEnv,
|
|
shell: process.platform === 'win32',
|
|
})
|
|
|
|
tauriDriver.on('error', error => {
|
|
console.error('tauri-driver error:', error)
|
|
process.exit(1)
|
|
})
|
|
tauriDriver.on('exit', code => {
|
|
if (!driverExitExpected) {
|
|
console.error('tauri-driver exited unexpectedly with code:', code)
|
|
process.exit(1)
|
|
}
|
|
})
|
|
},
|
|
|
|
async afterTest(_test, _context, result) {
|
|
if (result.passed) return
|
|
|
|
const artifactsDir = path.join(tempRoot, 'artifacts')
|
|
fs.mkdirSync(artifactsDir, { recursive: true })
|
|
|
|
try {
|
|
const handles = await browser.getWindowHandles()
|
|
const details = []
|
|
for (const handle of handles) {
|
|
await browser.switchToWindow(handle)
|
|
details.push({ handle, url: await browser.getUrl(), title: await browser.getTitle() })
|
|
}
|
|
fs.writeFileSync(path.join(artifactsDir, 'windows.json'), JSON.stringify(details, null, 2), 'utf8')
|
|
fs.writeFileSync(path.join(artifactsDir, 'source.html'), await browser.getPageSource(), 'utf8')
|
|
const diagnostics = await browser.execute(() => ({
|
|
href: window.location.href,
|
|
webdriver: navigator.webdriver,
|
|
hasPiBootData: 'PI_BOOT_DATA' in window,
|
|
piBootData: window.PI_BOOT_DATA ?? null,
|
|
hasTauriInternals: '__TAURI_INTERNALS__' in window,
|
|
serviceConfig: window.localStorage.getItem('piagentui-service-config'),
|
|
}))
|
|
fs.writeFileSync(path.join(artifactsDir, 'diagnostics.json'), JSON.stringify(diagnostics, null, 2), 'utf8')
|
|
try {
|
|
fs.writeFileSync(
|
|
path.join(artifactsDir, 'browser-logs.json'),
|
|
JSON.stringify(await browser.getLogs('browser'), null, 2),
|
|
'utf8',
|
|
)
|
|
} catch {}
|
|
await browser.saveScreenshot(path.join(artifactsDir, 'failure.png'))
|
|
console.error(`E2E failure artifacts: ${artifactsDir}`)
|
|
} catch (error) {
|
|
console.error('Failed to write E2E failure artifacts:', error)
|
|
}
|
|
},
|
|
|
|
after() {
|
|
const marker = path.join(markerDir, 'fake-pi-state.json')
|
|
if (!fs.existsSync(marker)) {
|
|
throw new Error(`Fake Pi marker was not written: ${marker}`)
|
|
}
|
|
},
|
|
|
|
onComplete() {
|
|
cleanup()
|
|
},
|
|
}
|
|
|
|
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGBREAK']) {
|
|
process.once(signal, () => {
|
|
cleanup()
|
|
process.exit(1)
|
|
})
|
|
}
|