You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/scripts/probe-toast-dismiss.ts

106 lines
3.8 KiB

/**
* One-shot Playwright probe to verify the Toast dismiss flow emits
* `data-event*` perceptual signals on the item element.
*
* Usage:
* 1. `npm run dev` in another terminal (defaults to port 5173)
* 2. `node --import tsx/esm scripts/probe-toast-dismiss.ts`
*
* Output: list of mutations seen during the dismiss interaction. If the
* runtime + semantic engine are wired correctly, you should see at minimum:
* - data-event="dismiss" added
* - data-event-id="sig-N" added
* - data-event-phase="active" added
* - data-event-family="emerge" added
* …followed shortly after by their removal as the cleanup tick runs.
*/
import { chromium } from 'playwright'
const URL = process.env.PROBE_URL ?? 'http://localhost:5173/test/soma/toast'
async function main() {
const browser = await chromium.launch()
const page = await browser.newPage()
const consoleLines: string[] = []
page.on('console', (msg) => consoleLines.push(`[${msg.type()}] ${msg.text()}`))
await page.goto(URL, { waitUntil: 'networkidle' })
// 1. Trigger a default toast (the demo page has an "Add default" button).
const triggerBtn = page.getByRole('button', { name: /^default$/i }).first()
await triggerBtn.click()
// 2. Wait for the item to mount.
const item = page.locator('[data-toast-item]').first()
await item.waitFor({ state: 'attached', timeout: 5000 })
// 3. Install a MutationObserver in the page context that watches the item.
await page.evaluate(() => {
const item = document.querySelector('[data-toast-item]') as HTMLElement | null
if (!item) {
;(window as unknown as Record<string, unknown>).__probeResult = {
error: 'item not found'
}
return
}
const captured: Array<{ time: number; attr: string; oldValue: string | null; newValue: string | null }> = []
const start = performance.now()
const observer = new MutationObserver((mutations) => {
for (const m of mutations) {
if (m.type !== 'attributes' || !m.attributeName) continue
captured.push({
time: Math.round(performance.now() - start),
attr: m.attributeName,
oldValue: m.oldValue,
newValue: (m.target as HTMLElement).getAttribute(m.attributeName)
})
}
})
observer.observe(item, { attributes: true, attributeOldValue: true })
;(window as unknown as Record<string, unknown>).__probeStop = () => {
observer.disconnect()
return captured
}
})
// 4. Click the close button (× inside the toast item).
const closeBtn = item.locator('[data-toast-close]').first()
await closeBtn.click()
// 5. Wait long enough for the dismiss + cleanup to complete (~5 frames).
await page.waitForTimeout(200)
// 6. Pull the captured mutations out.
const result = (await page.evaluate(() => {
const stop = (window as unknown as { __probeStop?: () => unknown; __probeResult?: unknown })
.__probeStop
const errResult = (window as unknown as { __probeResult?: unknown }).__probeResult
if (errResult) return errResult
return stop ? stop() : { error: 'observer not installed' }
})) as Array<{ time: number; attr: string; oldValue: string | null; newValue: string | null }>
console.log('\n=== Console messages ===')
for (const line of consoleLines) console.log(line)
console.log('\n=== Mutations on the toast item during dismiss ===')
if (Array.isArray(result) && result.length === 0) {
console.log('(none)')
} else if (Array.isArray(result)) {
for (const m of result) {
console.log(`+${m.time}ms ${m.attr}: ${JSON.stringify(m.oldValue)} → ${JSON.stringify(m.newValue)}`)
}
const sawSignal = result.some((m) => m.attr === 'data-event' && m.newValue === 'dismiss')
console.log(`\nSignal observed: ${sawSignal ? '✅ YES' : '❌ NO'}`)
} else {
console.log('error result:', result)
}
await browser.close()
}
main().catch((err) => {
console.error(err)
process.exit(1)
})

Powered by TurnKey Linux.