import assert from 'node:assert/strict'; import { test } from 'node:test'; import { existsSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'; import { join, resolve } from 'node:path'; import { tmpdir } from 'node:os'; import { fixture } from './host.mjs'; export function browserSuite(tool, plugin) { if (!['playwright','cypress'].includes(tool.name)) return; const tools=process.env.FLUENTCI_BROWSER_TOOLS; const required=process.env.FLUENTCI_REQUIRE_BROWSER_TESTS==='1'; test('native '+tool.name+' runs browser assertions and propagates test failures', {skip:!tools&&!required,timeout:300000},()=>{ assert.ok(tools,'Set FLUENTCI_BROWSER_TOOLS to the npm installation prefix'); const packageName=tool.name==='playwright'?'@playwright/test':'cypress'; const version=JSON.parse(readFileSync(resolve(tools,'node_modules',packageName,'package.json'),'utf8')).version; const project=realpathSync(mkdtempSync(join(tmpdir(),'fluentci-browser-'))); let counter=0; try { writeFileSync(join(project,'package.json'),JSON.stringify({name:'browser-fixture',private:true})); const setup=fixture({native:true,input:{project,runDir:join(project,'setup-run'),version,timeoutMs:120000}}); try {plugin.setup();} catch(error) { const log=join(project,'setup-run',tool.name+'.stderr'); const logs=existsSync(log)?readFileSync(log,'utf8'):''; throw Error(error.message+'\n'+logs); } assert.equal(JSON.parse(setup.output[0]).outcome,'succeeded'); assert.equal(JSON.parse(readFileSync(join(project,'package.json'),'utf8')).devDependencies[packageName],version); const executable=join(project,'node_modules','.bin',tool.program); assert.ok(existsSync(executable)); function invoke(command,fields={},failure=false) { const runDir=join(project,'run-'+counter++); const f=fixture({native:true,input:{project,executable,runDir,timeoutMs:120000,...fields}}); if(failure) { assert.throws(plugin[command],/failed/); assert.equal(f.output.length,0); } else { try {plugin[command]();} catch(error) { const logs=['stdout','stderr'].map(suffix=>{ const path=join(runDir,tool.name+'.'+suffix); return existsSync(path)?readFileSync(path,'utf8'):''; }).join('\n'); throw Error(error.message+'\n'+logs); } assert.equal(JSON.parse(f.output[0]).outcome,'succeeded'); } return runDir; } invoke('version'); if(tool.name==='playwright') { writeFileSync(join(project,'playwright.config.cjs'),'module.exports = {testDir: ".", testMatch: "*.spec.cjs", use: {browserName: "chromium", headless: true}};\n'); const spec=join(project,'smoke.spec.cjs'); writeFileSync(spec,'const {test,expect}=require("@playwright/test"); test("local browser",async({page})=>{await page.setContent("