/**
* WebdriverIO + tauri-driver で TelosDB の E2E テストを実行する設定。
*
* 前提:
* - cargo install tauri-driver --locked
* - Windows: Edge Driver (msedgedriver) を PATH に通す。バージョンは Edge と一致させる。
* - Linux: WebKitWebDriver (例: webkit2gtk-driver) をインストール。
*
* 実行: npm run test:e2e
* 初回はビルドに時間がかかります。事前に npm run build:e2e でビルドしても可。
*/
import fs from 'fs';
import os from 'os';
import path from 'path';
import { spawn, spawnSync } from 'child_process';
import { fileURLToPath } from 'url';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const root = path.resolve(__dirname);
const isWin = process.platform === 'win32';
const binaryName = isWin ? 'app.exe' : 'app';
// Windows で tauri-driver が使う Edge Driver のパス(環境変数 or edgedriver パッケージで取得)
let nativeDriverPath = process.env.TELOS_EDGE_DRIVER || null;
// 環境変数で上書き可。未指定ならビルド出力の候補を順に試す(ルート target または src/backend/target)
const candidates = [
process.env.TELOS_E2E_APP,
path.join(root, 'target', 'debug', binaryName),
path.join(root, 'src', 'backend', 'target', 'debug', binaryName),
].filter(Boolean);
const applicationPath = candidates.find((p) => fs.existsSync(p)) || candidates[candidates.length - 1];
const E2E_PORTS = [4444, 3001];
function killProcessesOnPort(port) {
try {
if (isWin) {
const out = spawnSync('netstat', ['-ano'], { encoding: 'utf8', shell: true });
const lines = (out.stdout || '').split(/\r?\n/);
const pids = new Set();
for (const line of lines) {
if (!line.includes(`:${port}`)) continue;
const parts = line.trim().split(/\s+/);
const last = parts[parts.length - 1];
if (/^\d+$/.test(last)) pids.add(last);
}
for (const pid of pids) {
spawnSync('taskkill', ['/PID', pid, '/F'], { stdio: 'ignore', shell: true });
}
} else {
spawnSync('fuser', ['-k', `${port}/tcp`], { stdio: 'ignore' });
}
} catch (_) {}
}
function killE2ePorts() {
for (const port of E2E_PORTS) {
killProcessesOnPort(port);
}
}
let tauriDriver;
let exit = false;
export const config = {
host: '127.0.0.1',
port: 4444,
specs: ['./tests/e2e/specs/**/*.spec.js'],
maxInstances: 1,
capabilities: [
{
maxInstances: 1,
'tauri:options': {
application: applicationPath,
},
},
],
reporters: ['spec'],
framework: 'mocha',
mochaOpts: {
ui: 'bdd',
timeout: 60000,
},
onPrepare: () => {
killE2ePorts();
if (!process.env.TELOS_E2E_PRO) {
spawnSync('npm', ['run', 'build:e2e'], {
cwd: root,
stdio: 'inherit',
shell: true,
});
}
},
onComplete: () => {
closeTauriDriver();
killE2ePorts();
},
beforeSession: async () => {
let edgeDriverPath = nativeDriverPath;
if (isWin && !edgeDriverPath) {
try {
const { download } = await import('edgedriver');
edgeDriverPath = await download();
} catch (e) {
console.error('edgedriver download/resolve failed:', e.message || e);
}
}
const driverPath = path.join(os.homedir(), '.cargo', 'bin', isWin ? 'tauri-driver.exe' : 'tauri-driver');
const usePath = fs.existsSync(driverPath) ? driverPath : 'tauri-driver';
const args = [];
if (edgeDriverPath) {
args.push('--native-driver', edgeDriverPath);
}
tauriDriver = spawn(usePath, args, {
stdio: [null, process.stdout, process.stderr],
shell: true,
env: { ...process.env, PATH: process.env.PATH || '' },
});
tauriDriver.on('error', (err) => {
console.error('tauri-driver error:', err);
process.exit(1);
});
tauriDriver.on('exit', (code) => {
if (!exit) {
console.error('tauri-driver exited with code:', code);
process.exit(1);
}
});
},
afterSession: () => {
closeTauriDriver();
},
};
function closeTauriDriver() {
exit = true;
if (tauriDriver) {
tauriDriver.kill();
tauriDriver = null;
}
}
function onShutdown(fn) {
const cleanup = () => {
try {
fn();
} finally {
process.exit();
}
};
process.on('exit', cleanup);
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
process.on('SIGHUP', cleanup);
if (process.platform === 'win32') {
process.on('SIGBREAK', cleanup);
}
}
onShutdown(() => {
closeTauriDriver();
killE2ePorts();
});