updates from chat
Security and workflow regressions / regression (push) Has been cancelled

This commit is contained in:
2026-10-21 20:41:57 -04:00
parent acc8cb70f5
commit b851712968
19 changed files with 435 additions and 22 deletions
+10 -1
View File
@@ -31,7 +31,16 @@ const assert=require('node:assert/strict');
if(process.env.HCR_UI_SCREENSHOT)await admin.screenshot({path:process.env.HCR_UI_SCREENSHOT.replace('.png','-member.png')});await admin.setViewportSize({width:390,height:844});assert(await admin.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth));pass('Member summary totals and history fit phone-width screens');await admin.setViewportSize({width:1280,height:720});
await admin.locator('nav[aria-label="Member actions"] [data-club-step=member]').click();await admin.locator('.club-action-modal.show').getByLabel('Joined on',{exact:true}).fill('2026-02-01');await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Save membership',exact:true}).click()]);assert((await admin.locator('.memberSummary header').textContent()).includes('2026-02-01'));assert(new URL(admin.url()).searchParams.get('membership_serial')===String(ids.clubA_membera));pass('Administrator edits membership in a modal and remains on the same member summary');
await admin.locator('[data-club-step=charge]').click();await admin.locator('.club-action-modal.show').getByLabel('Season',{exact:true}).selectOption({label:'Available new season'});await admin.locator('.club-action-modal.show').getByLabel('Dues (USD)',{exact:true}).fill('20.00');await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Save dues',exact:true}).click()]);assert((await admin.locator('.memberSummary').textContent()).includes('$3,170.00'));pass('Administrator adds dues for the preselected member without returning to the club');
await admin.getByRole('row').filter({hasText:'Available new season'}).locator('[data-club-step=payment]').click();await admin.locator('.club-action-modal.show').getByLabel('Payment (USD)',{exact:true}).fill('10.00');await admin.locator('.club-action-modal.show').getByLabel('Reference (optional)',{exact:true}).fill('Summary modal payment');await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Record payment',exact:true}).click()]);assert((await admin.locator('.memberSummary').textContent()).includes('$3,129.00'));await admin.getByText('Summary modal payment',{exact:false}).waitFor();pass('Administrator records a selected season payment and sees updated totals on the member summary');
await admin.getByRole('row').filter({hasText:'Available new season'}).locator('[data-club-step=payment]').click();await admin.locator('.club-action-modal.show').getByLabel('Payment (USD)',{exact:true}).fill('10.00');await admin.locator('.club-action-modal.show').getByLabel('Reference (optional)',{exact:true}).fill('Summary modal payment');await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Record payment',exact:true}).click()]);assert((await admin.locator('.memberSummary').textContent()).includes('$3,129.00'));await admin.getByRole('cell',{name:'unspecified / Summary modal payment',exact:true}).waitFor();pass('Administrator records a selected season payment and sees updated totals on the member summary');
await admin.getByRole('row').filter({hasText:'Available new season'}).locator('[data-club-step=adjust]').click();assert.equal(await admin.locator('.club-action-modal.show').getByLabel('Corrected total (USD)',{exact:true}).inputValue(),'20.00');await admin.locator('.club-action-modal.show').getByLabel('Corrected total (USD)',{exact:true}).fill('15.00');await admin.locator('.club-action-modal.show').getByLabel('Reason',{exact:true}).fill('Summary dues correction');await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Save correction',exact:true}).click()]);assert((await admin.locator('.memberSummary').textContent()).includes('$3,124.00'));pass('Member-summary correction modal prefills dues and refreshes totals without leaving the member');
const receipt=admin.getByRole('row').filter({hasText:'Summary modal payment'});await receipt.locator('[data-club-step=reverse]').click();await admin.locator('.club-action-modal.show').getByRole('button',{name:'Cancel',exact:true}).click();await admin.locator('.club-action-modal.show').waitFor({state:'hidden'});assert((await admin.locator('.memberSummary').textContent()).includes('$3,124.00'));await receipt.locator('[data-club-step=reverse]').click();await admin.locator('.club-action-modal.show').getByLabel('Reversal reason',{exact:true}).fill('Summary wrong receipt');await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Confirm reversal',exact:true}).click()]);assert((await admin.locator('.memberSummary').textContent()).includes('$3,134.00'));const reversed=admin.getByRole('row').filter({hasText:'Summary modal payment'});assert((await reversed.textContent()).includes('Summary wrong receipt'));assert.equal(await reversed.locator('[data-club-step=reverse]').count(),0);pass('Member-summary reversal supports Cancel, preserves the receipt and removes its reversal button');
const privateText='Private browser member note\nSecond line';await admin.locator('.member-admin-notes [data-club-step=note_add]').click();await admin.locator('.club-action-modal.show').getByLabel('Note',{exact:true}).fill('Unsaved private draft');await admin.locator('.club-action-modal.show').getByRole('button',{name:'Cancel',exact:true}).click();await admin.locator('.club-action-modal.show').waitFor({state:'hidden'});assert.equal(await admin.locator('.member-admin-notes').getByRole('cell',{name:'Unsaved private draft',exact:true}).count(),0);await admin.locator('.member-admin-notes [data-club-step=note_add]').click();await admin.locator('.club-action-modal.show').getByLabel('Note',{exact:true}).fill(privateText);await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Save note',exact:true}).click()]);await admin.locator('.member-admin-notes').getByRole('cell',{name:'Private browser member note Second line',exact:true}).waitFor();assert(new URL(admin.url()).hash==='#admin-notes');pass('Administrative note add modal supports Cancel and saves back to the member notes section');
await admin.locator('.member-admin-notes [data-club-step=note_edit]').click();assert.equal(await admin.locator('.club-action-modal.show').getByLabel('Note',{exact:true}).inputValue(),privateText);await admin.locator('.club-action-modal.show').getByLabel('Note',{exact:true}).fill('Updated private browser note');await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Save note',exact:true}).click()]);await admin.locator('.member-admin-notes').getByRole('cell',{name:'Updated private browser note',exact:true}).waitFor();pass('Administrative note edit modal prefills and saves the selected note');
const privacyContext=await browser.newContext(),privacyPage=await privacyContext.newPage();await login(privacyPage,'membera@example.test');await privacyPage.getByRole('link',{name:'Tenant Membera',exact:true}).click();assert.equal(await privacyPage.locator('.member-admin-notes').count(),0);assert(!(await privacyPage.content()).includes('Updated private browser note'));assert.equal(await privacyPage.locator('.memberSummary [name=note_text]').count(),0);await privacyContext.close();pass('Member browser receives no administrative note section, text or hidden note fields');
await admin.locator('.member-admin-notes [data-club-step=note_delete]').click();await admin.locator('.club-action-modal.show').getByRole('button',{name:'Confirm deletion',exact:true}).waitFor();assert((await admin.locator('.club-action-modal.show').innerText()).includes('Updated private browser note'));await admin.locator('.club-action-modal.show').getByRole('button',{name:'Cancel',exact:true}).click();await admin.locator('.club-action-modal.show').waitFor({state:'hidden'});assert.equal(await admin.locator('.member-admin-notes').getByRole('cell',{name:'Updated private browser note',exact:true}).count(),1);pass('Note deletion confirmation shows selected note and Cancel preserves it');
await admin.locator('.member-admin-notes [data-club-step=note_delete]').click();await Promise.all([admin.waitForNavigation(),admin.locator('.club-action-modal.show').getByRole('button',{name:'Confirm deletion',exact:true}).click()]);assert.equal(await admin.locator('.member-admin-notes [data-club-step=note_delete]').count(),0);assert(!(await admin.content()).includes('Updated private browser note'));assert(new URL(admin.url()).hash==='#admin-notes');pass('Confirmed note deletion refreshes summary and removes note and hidden dialogs');
await admin.getByRole('link',{name:'Back to club roster',exact:true}).click();await admin.getByRole('heading',{name:'Tenant Alpha',exact:true}).waitFor();
await admin.locator('header [data-club-step=invite]').click();const invite=admin.locator('form').filter({has:admin.getByRole('button',{name:'Send club invitation',exact:true})});await invite.getByLabel('Invitation email').fill('invitee@example.test');await invite.getByRole('button',{name:'Send club invitation',exact:true}).click();await admin.getByText('The invitation email could not be sent.',{exact:false}).waitFor();pass('Administrator sends a club invitation and sees delivery failure clearly');
await login(member,'invitee@example.test');assert(await member.getByText('You are not assigned to an active club yet.',{exact:false}).count());pass('Accounts without a club retain the empty workspace and invitation access');await member.goto(base+'/main.php?Xaction=Roster.invitations');await member.getByRole('heading',{name:'Tenant Alpha',exact:true}).waitFor();await member.getByRole('button',{name:'Accept invitation',exact:true}).click();await member.getByRole('heading',{name:'Tenant Alpha',exact:true}).waitFor();assert.equal(await member.getByRole('button',{name:'Send club invitation',exact:true}).count(),0);pass('Invited member accepts the club invitation and receives a read-only workspace');