Compare commits

...

6 Commits

View File

@ -49,8 +49,15 @@ const commonPoints = {
num1: 7.25,
num2: 14.44,
}
let log: { index: number; timestamp: number; payload: string | Buffer }[] = []
test.afterEach(async ({ context, page }, testInfo) => {
// attach the websocket logs to the html report
if (log?.length > 0)
await testInfo.attach(`WebSocket log`, {
body: String(
log.map((l) => `(${l.index})_${l.timestamp}_${l.payload}\n`).join('')
),
})
if (testInfo.status === 'skipped') return
if (testInfo.status === 'failed') return
@ -91,6 +98,32 @@ test.beforeEach(async ({ context, page }) => {
)
// kill animations, speeds up tests and reduced flakiness
await page.emulateMedia({ reducedMotion: 'reduce' })
// get playwright to listen for websocket messages
page.on('websocket', (ws) => {
console.log(`WebSocket opened: ${ws.url()}>`)
ws.on('framesent', (event) =>
log.push({
index: log.length,
timestamp: new Date().valueOf(),
payload: event.payload,
})
)
ws.on('framereceived', (event) =>
log.push({
index: log.length,
timestamp: new Date().valueOf(),
payload: event.payload,
})
)
ws.on('close', () =>
log.push({
index: log.length,
timestamp: new Date().valueOf(),
payload: 'Websocket closed',
})
)
})
await page.goto('/')
})
test.setTimeout(120000)
@ -7173,7 +7206,90 @@ test.describe('Test network and connection issues', () => {
await expect(networkToggle).toContainText('Connected')
})
test('Engine disconnect & reconnect in sketch mode', async ({
async function waitForWSMessage(
action: Promise<void>,
waitForCommand:
| 'select_with_point'
| 'set_selection_filter'
| 'default_camera_set_orthographic'
| 'select_add',
timeout = 5_000
) {
const actionTimestamp = new Date().valueOf()
const logCursor = log.length
await action
const delay = 10
const attempts = timeout / delay
for (let i = 0; i < attempts; i += 1) {
const cmdFound = findMatchingWsEvent(actionTimestamp, waitForCommand)
if (cmdFound) {
// command found, now wait for the success message
// by waiting on the matching success response corresponding to the request_id
const cmdId = safeParseJson(String(cmdFound.payload)).cmd_id
const successMessage = findSuccessResponse(actionTimestamp, cmdId)
if (successMessage) {
console.log(`✅ "${waitForCommand}" was found in the websocket logs`)
return true
}
}
await new Promise((resolve) => setTimeout(resolve, delay))
}
console.log(`⚠️ "${waitForCommand}" was not found in the websocket logs`)
console.log(
`\t inspect the websocket logs between (${logCursor})th and (${log.length})th event`
)
return false
function findSuccessResponse(timestamp: number, cmdId: string) {
// filter the logs to only show entries with timestamp greater than the timestamp of the command
const relevantLogEntries = log.filter((wsEvent) => {
try {
return wsEvent && wsEvent.timestamp > timestamp
} catch (error) {
return undefined
}
})
return relevantLogEntries?.find((wsEvent) => {
try {
const jsonObj = safeParseJson(String(wsEvent.payload))
return jsonObj && jsonObj.request_id === cmdId && jsonObj.success
} catch (error) {
return undefined
}
})
}
function findMatchingWsEvent(timestamp: number, cmdType: string) {
// filter the logs to only show entries with timestamp greater
// than the timestamp of when the playwright action was performed
const relevantLogEntries = log.filter((wsEvent) => {
try {
return wsEvent && wsEvent.timestamp > timestamp
} catch (error) {
return undefined
}
})
return relevantLogEntries.find((wsEvent) => {
try {
const wsMessage = safeParseJson(String(wsEvent.payload))
return wsMessage && wsMessage.cmd && wsMessage.cmd.type === cmdType
} catch (error) {
return undefined
}
})
}
function safeParseJson(jsonString: string) {
try {
return JSON.parse(jsonString)
} catch (error) {
return undefined
}
}
}
test.only('Engine disconnect & reconnect in sketch mode', async ({
page,
browserName,
}) => {
@ -7197,20 +7313,33 @@ test.describe('Test network and connection issues', () => {
// click on "Start Sketch" button
await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click()
await page.waitForTimeout(100)
await waitForWSMessage(
page.getByRole('button', { name: 'Start Sketch' }).click(),
'set_selection_filter'
)
// ^ this is similar to ⤵️
// await u.doAndWaitForCmd(
// () => page.getByRole('button', { name: 'Start Sketch' }).click(),
// 'set_selection_filter'
// )
// select a plane
await page.mouse.click(700, 200)
await waitForWSMessage(
page.mouse.click(700, 200),
'default_camera_set_orthographic'
)
// ^ this is similar to ⤵️
// await u.doAndWaitForCmd(
// () => page.mouse.click(700, 200),
// 'default_camera_set_orthographic'
// )
await expect(page.locator('.cm-content')).toHaveText(
`const sketch001 = startSketchOn('XZ')`
)
await u.closeDebugPanel()
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
const startXPx = 600
// The issue is that these types of interactions do not trigger any WebSocket messages for synchronization. :( ⤵️
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
@ -7218,8 +7347,6 @@ test.describe('Test network and connection issues', () => {
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt(${commonPoints.startAt}, %)