Files
auto_news_upload/test/browser.test.cjs
T

94 lines
7.2 KiB
JavaScript

'use strict';
const {chromium}=require('playwright');
const fs=require('node:fs');
const path=require('node:path');
const assert=require('node:assert/strict');
const ROOT=path.resolve(__dirname,'..');
const output=path.join(__dirname,'artifacts');fs.mkdirSync(output,{recursive:true});
(async()=>{
const browser=await chromium.launch({headless:true,executablePath:process.env.CHROME_PATH||'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'});
try{
const page=await browser.newPage({viewport:{width:1440,height:1100}}),errors=[];
page.on('pageerror',error=>errors.push(error.message));
await page.route('**/*',route=>new URL(route.request().url()).hostname==='127.0.0.1'?route.continue():route.abort());
await page.goto('http://127.0.0.1:8771/');
await page.getByText('原创导入测试稿',{exact:true}).waitFor();
await page.screenshot({path:path.join(output,'desktop.png'),fullPage:true});
await page.locator('#fid').fill('125');await page.locator('#minimum').fill('1');await page.locator('#maximum').fill('2');await page.locator('#interval').fill('10');await page.locator('#history-checked').check();
await page.getByRole('button',{name:'保存处理规则'}).click();await page.getByText('处理规则已保存',{exact:true}).waitFor();
await page.locator('#start').click();await page.getByText('流程运行中',{exact:true}).waitFor();
await page.locator('#stop').click();await page.getByText('流程已暂停',{exact:true}).waitFor();
await page.setViewportSize({width:390,height:844});await page.screenshot({path:path.join(output,'mobile.png'),fullPage:true});
assert.equal(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth),false,'mobile overflow');
assert.deepEqual(errors,[]);console.log('PASS local UI: configuration, start/stop, desktop/mobile layout');
await page.close();
const mock=await browser.newPage();
await mock.route('**/*',route=>route.fulfill({contentType:'text/html; charset=utf-8',body:'<!doctype html><a id="mumucms_username" href="/home.php?mod=space&uid=123">测试账号</a><input id="subject"><iframe id="e_iframe"></iframe><button id="postsubmit">发表帖子</button>'}));
await mock.goto('https://www.dww11.com/forum.php?mod=post&action=newthread&fid=125');
await mock.evaluate(()=>{
window.wysiwyg=1;window.events=[];window.clicks=0;window.formats=0;
window.job={id:'fixture',state:'preparing',title:'测试标题',source:'测试来源',fid:125,account:{uid:'123',name:'测试账号'}};
window.flow={running:true,epoch:1,active:'fixture',config:{fid:125}};
document.querySelector('#postsubmit').addEventListener('click',()=>window.clicks++);
window.DWW11Importer={stagePackage:async()=>({warnings:[]}),importPrepared:async()=>{
document.querySelector('#subject').value='测试标题';
document.querySelector('#e_iframe').contentDocument.body.innerHTML='<p>正文第一段</p><img aid="attachimg_1" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"><p>正文第二段</p><p>来源:测试来源,如有侵权,请联系删除。</p>';
return {images:{'a.gif':'1'},attachmentOrder:['1']};
}};
document.addEventListener('dww11:local-request',event=>{
const {id,route,body}=JSON.parse(event.detail);let value={};
window.events.push({route,body});
if(route==='heartbeat'){window.flow.owner=body.owner;value=window.flow;}
if(route==='next')value={action:window.job.state==='preparing'?'prepare':'resume',job:window.job,run:window.flow};
if(route==='current')value={job:window.job,run:window.flow};
if(route==='event'){window.job.state=body.state;value={ok:true};}
if(route==='stop'){window.flow.running=false;value=window.flow;}
document.dispatchEvent(new CustomEvent('dww11:local-response',{detail:JSON.stringify({id,value})}));
});
});
const importerCore=require('../browser/importer.js');
await mock.addScriptTag({content:'(()=>{'+importerCore.attachmentId.toString()+';'+importerCore.verifyEditorImages.toString()+';Object.assign(window.DWW11Importer,{attachmentId,verifyEditorImages});})();'});
await mock.addScriptTag({path:path.join(ROOT,'browser/formatter.js')});
await mock.addScriptTag({path:path.join(ROOT,'browser/runner.js')});
await mock.waitForFunction(()=>window.job.state==='awaiting_user_review');
await mock.waitForTimeout(2400);
assert.equal(await mock.evaluate(()=>window.clicks),0,'runner must never publish');
assert.equal(await mock.evaluate(()=>document.querySelector('#e_iframe').contentDocument.body.querySelectorAll('[data-dww11-wx-source]').length),1);
const before=await mock.evaluate(()=>document.querySelector('#e_iframe').contentDocument.body.innerHTML);
await mock.evaluate(()=>window.DWW11Formatter.format('测试来源'));
const after=await mock.evaluate(()=>document.querySelector('#e_iframe').contentDocument.body.innerHTML);
assert.equal(after,before,'repeated formatting should be idempotent');
await mock.locator('#postsubmit').click();
await mock.waitForFunction(()=>window.job.state==='user_submitting');
await mock.evaluate(()=>history.pushState({},'', '/thread/999.html'));
await mock.waitForFunction(()=>window.job.state==='submit_unknown');
assert.equal(await mock.evaluate(()=>window.flow.running),false);
assert.equal(await mock.evaluate(()=>window.events.some(e=>e.route==='accept')),false,'unknown page must not count accepted');
assert.equal(await mock.evaluate(()=>window.clicks),1);
console.log('PASS browser fixture: import/format, source uniqueness, repeated formatting, manual-only publish, unknown result stops');
await mock.close();
const ext=await browser.newPage();
await ext.route('**/*',route=>route.fulfill({contentType:'text/html; charset=utf-8',body:'<!doctype html><div class="topwp"><a href="#">立即登录</a></div>'}));
await ext.goto('https://www.dww11.com/');
await ext.evaluate(()=>{
window.routes=[];window.chrome.runtime={sendMessage:async message=>{
window.routes.push(message.route);
if(message.route==='/hello')return {ok:true,data:{total:1,active:1,round:1,remaining:1,flow:null}};
if(message.route==='/start')return new Promise(resolve=>window.finishStart=()=>resolve({ok:true,data:{flow:{id:'test-run',phase:'logout',paused:false}}}));
if(message.route==='/suspend')return {ok:true,data:{}};
throw new Error('Unexpected extension operation: '+message.route);
}};
});
await ext.addScriptTag({path:path.join(ROOT,'../dww11-account-switch-browser-extension/content.js')});
await ext.waitForFunction(()=>JSON.parse(document.querySelector('#dww11-extension-panel').dataset.autoNewsState).idle);
await ext.locator('#dww11-extension-next').click();
await ext.waitForFunction(()=>!!window.finishStart);
await ext.evaluate(()=>{document.dispatchEvent(new CustomEvent('dww11:auto-stop'));window.finishStart();});
await ext.waitForFunction(()=>window.routes.includes('/suspend'));
assert.equal(await ext.evaluate(()=>JSON.parse(document.querySelector('#dww11-extension-panel').dataset.autoNewsState).paused),true);
assert.deepEqual(await ext.evaluate(()=>window.routes),['/hello','/start','/suspend']);
console.log('PASS extension bridge: stop during pending start prevents login and persists pause');
await ext.close();
}finally{await browser.close();}
})().catch(error=>{console.error(error);process.exitCode=1;});