const {chromium}=require('playwright'); const assert=require('node:assert/strict'); const path=require('node:path'); const fs=require('node:fs/promises'); (async()=>{ const browser=await chromium.launch({executablePath:process.env.HCR_TEST_CHROME||'C:/Program Files/Google/Chrome/Application/chrome.exe',headless:true}); const page=await browser.newPage({viewport:{width:1440,height:1000}}); const errors=[],checks=[];page.on('pageerror',error=>errors.push(error.message)); await page.exposeFunction('recordCspViolation',message=>errors.push(message));await page.addInitScript(()=>document.addEventListener('securitypolicyviolation',event=>window.recordCspViolation('CSP: '+event.violatedDirective+' '+event.blockedURI))); const pass=message=>{checks.push(message);console.log('PASS: '+message);}; const openClubModal=async step=>{await page.locator('[data-club-step="'+step+'"]').first().click();await page.locator('.club-action-modal.show').waitFor();}; const submit=async data=>{await Promise.all([page.waitForNavigation({waitUntil:'load'}),page.evaluate(data=>formSubmit(data),data)]);await page.waitForFunction(()=>typeof formSubmit==='function');await page.waitForLoadState('networkidle');}; try{ await page.goto(process.env.HCR_TEST_URL+'/main.php'); await page.locator('#user_email').fill('admin@example.test');await page.locator('#user_password').fill('Admin test password 123!');await Promise.all([page.waitForNavigation({waitUntil:'load'}),page.locator('#login button[type="submit"]').click()]);await require('./browser_mfa')(page,'Admin test password 123!');await page.waitForFunction(()=>typeof formSubmit==='function'); pass('Browser login loads the application shell without script errors'); const safe=await page.evaluate(()=>{ const original=HTMLFormElement.prototype.submit;HTMLFormElement.prototype.submit=function(){}; try{const value='">';formSubmit({action:'Users.setupUsers',find_user:value});return !document.querySelector('#injected-hidden-value')&&document.querySelector('#formSubmit input[name="find_user"]').value===value;}finally{HTMLFormElement.prototype.submit=original;} });assert(safe);pass('Hidden form values remain text rather than injected HTML'); await submit({action:'Users.setupUsers'});await page.locator('.setupUsers').waitFor(); await page.locator('.btnAdd').click();await page.locator('#addUser').waitFor(); await page.locator('#user_name').fill('browser_tester');await page.locator('#user_first_name').fill('Browser');await page.locator('#user_last_name').fill('Tester');await page.locator('#user_email').fill('browser@example.test');await page.locator('#user_role').selectOption('User'); await page.locator('.btnSave').click();await page.locator('.setupUsers').waitFor(); await page.getByText('Browser',{exact:true}).waitFor();pass('Administrative account form saves through asynchronous validation'); assert((await page.locator('.toast-body').innerText()).includes('invitation'));pass('Failed invitation is visible after returning to the user list'); const row=page.locator('tr.user-row').filter({hasText:'browser_tester'});await row.click();await page.locator('.userSummary').waitFor();pass('Clicking a user opens the repaired summary'); await page.locator('.summary-edit').click();await page.locator('#editUser').waitFor(); const failUsage=async route=>{ const data=route.request().postData()||''; if(data.includes('Users.userActive'))await route.fulfill({status:500,contentType:'application/json',body:JSON.stringify({ok:false,error:'Deliberate usage-check failure'})});else await route.continue(); }; await page.route('**/*',failUsage);await page.locator('.btnDelete').click();await page.getByText('Deliberate usage-check failure',{exact:true}).waitFor();assert(!await page.locator('#confirm-dialog').isVisible());pass('A failed deletion check shows an error and does not open confirmation');await page.unroute('**/*',failUsage); await page.locator('.btnDelete').click();await page.locator('#confirm-dialog').waitFor({state:'visible'});await page.locator('#confirm-dialog .btnConfirmDialogConfirm').click();await page.locator('.setupUsers').waitFor();assert(await page.locator('tr.user-row').filter({hasText:'browser_tester'}).count()===0);pass('Deleting an unused account succeeds through the browser'); await submit({action:'Dropdowns.setupDropdowntypes'});await page.locator('.setupDropdowntypes').waitFor();await page.locator('.btnAdd').click();await page.locator('#addDropdowntype').waitFor();await page.locator('#dropdowntype_name').fill('browser_type');await page.locator('#dropdowntype_title').fill('Browser type');await page.locator('.btnSave').click();await page.locator('.setupDropdowntypes').waitFor();pass('Dropdown type form works with restricted usage metadata'); const richHtml='
Legacy bold italic underline link font
| Cell |
Safelink
');return editor.$.html.get();}); assert(!/