add a regression test for when engine returns a export fail (#3407)
* add a regression test for when engine returns a export fail Signed-off-by: Jess Frazelle <github@jessfraz.com> * better errors Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
import { getUtils, setup, tearDown } from './test-utils'
|
||||
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates'
|
||||
import { bracket } from 'lib/exampleKcl'
|
||||
|
||||
test.beforeEach(async ({ context, page }) => {
|
||||
await setup(context, page)
|
||||
@ -164,7 +166,7 @@ const sketch001 = startSketchAt([-0, -0])
|
||||
|> yLineTo(0, %)
|
||||
|> close(%)
|
||||
|>
|
||||
|
||||
|
||||
const example = extrude(5, exampleSketch)
|
||||
shell({ faces: ['end'], thickness: 0.25 }, exampleSketch)`
|
||||
)
|
||||
@ -223,4 +225,210 @@ const sketch001 = startSketchAt([-0, -0])
|
||||
|
||||
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
||||
})
|
||||
test('when engine fails export we handle the failure and alert the user', async ({
|
||||
page,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async (code) => {
|
||||
localStorage.setItem('persistCode', code)
|
||||
}, TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR)
|
||||
|
||||
await page.setViewportSize({ width: 1000, height: 500 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
// wait for execution done
|
||||
await u.openDebugPanel()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.closeDebugPanel()
|
||||
|
||||
// expect zero errors in guter
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
// export the model
|
||||
const exportButton = page.getByTestId('export-pane-button')
|
||||
await expect(exportButton).toBeVisible()
|
||||
|
||||
// Click the export button
|
||||
exportButton.click()
|
||||
|
||||
// Click the stl.
|
||||
const stlOption = page.getByText('glTF')
|
||||
await expect(stlOption).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
await expect(errorToastMessage).toBeVisible()
|
||||
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
await expect(engineErrorToastMessage).toBeVisible()
|
||||
|
||||
// Make sure the exporting toast is gone
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Click the code editor
|
||||
page.locator('.cm-content').click()
|
||||
|
||||
await page.waitForTimeout(2000)
|
||||
|
||||
// Expect the toast to be gone
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
// Now add in code that works.
|
||||
page.locator('.cm-content').fill(bracket)
|
||||
page.locator('.cm-content').click()
|
||||
await page.keyboard.press('End')
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// wait for execution done
|
||||
await u.openDebugPanel()
|
||||
await u.clearCommandLogs()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.closeDebugPanel()
|
||||
|
||||
// Now try exporting
|
||||
|
||||
// Click the export button
|
||||
exportButton.click()
|
||||
|
||||
// Click the stl.
|
||||
await expect(stlOption).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
|
||||
// Expect it to succeed.
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
const successToastMessage = page.getByText(`Exported successfully`)
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
})
|
||||
test('ensure you can not export while an export is already going', async ({
|
||||
page,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async (code) => {
|
||||
localStorage.setItem('persistCode', code)
|
||||
}, bracket)
|
||||
|
||||
await page.setViewportSize({ width: 1000, height: 500 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
// wait for execution done
|
||||
await u.openDebugPanel()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.closeDebugPanel()
|
||||
|
||||
// expect zero errors in guter
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
// export the model
|
||||
const exportButton = page.getByTestId('export-pane-button')
|
||||
await expect(exportButton).toBeVisible()
|
||||
|
||||
// Click the export button
|
||||
exportButton.click()
|
||||
|
||||
// Click the stl.
|
||||
const stlOption = page.getByText('glTF')
|
||||
await expect(stlOption).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
|
||||
// Try exporting again.
|
||||
// Click the export button
|
||||
exportButton.click()
|
||||
|
||||
// Click the stl.
|
||||
await expect(stlOption).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).toBeVisible()
|
||||
|
||||
// Expect it to succeed.
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
const successToastMessage = page.getByText(`Exported successfully`)
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Try exporting again.
|
||||
// Click the export button
|
||||
exportButton.click()
|
||||
|
||||
// Click the stl.
|
||||
await expect(stlOption).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
|
||||
// Expect it to succeed.
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
@ -368,3 +368,5 @@ startSketchOn(keychain, 'end')
|
||||
height - (keychainHoleSize + 1.5)
|
||||
], keychainHoleSize, %)
|
||||
|> extrude(-thickness, %)`
|
||||
|
||||
export const TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR = `const thing = 1`
|
||||
|
@ -80,7 +80,6 @@ import { modelingMachineEvent } from 'editor/manager'
|
||||
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'
|
||||
import {
|
||||
ExportIntent,
|
||||
EngineConnectionState,
|
||||
EngineConnectionStateType,
|
||||
EngineConnectionEvents,
|
||||
} from 'lang/std/engineConnection'
|
||||
@ -371,7 +370,6 @@ export const ModelingMachineProvider = ({
|
||||
// Set the export intent.
|
||||
engineCommandManager.exportIntent = ExportIntent.Make
|
||||
|
||||
console.log('making', event.data)
|
||||
// Set the current machine.
|
||||
machineManager.currentMachine = event.data.machine
|
||||
|
||||
@ -413,7 +411,6 @@ export const ModelingMachineProvider = ({
|
||||
// Set the export intent.
|
||||
engineCommandManager.exportIntent = ExportIntent.Save
|
||||
|
||||
console.log('exporting', event.data)
|
||||
const format = {
|
||||
...event.data,
|
||||
} as Partial<Models['OutputFormat_type']>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { TEST } from 'env'
|
||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||
import { Themes, getSystemTheme } from 'lib/theme'
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
import { useMemo, useRef } from 'react'
|
||||
import { highlightSelectionMatches, searchKeymap } from '@codemirror/search'
|
||||
import { lineHighlightField } from 'editor/highlightextension'
|
||||
import { roundOff } from 'lib/utils'
|
||||
|
@ -9,7 +9,6 @@ import { useAppState, useAppStream } from 'AppState'
|
||||
import { SettingsViaQueryString } from 'lib/settings/settingsTypes'
|
||||
import {
|
||||
EngineConnectionStateType,
|
||||
EngineConnectionEvents,
|
||||
DisconnectingType,
|
||||
} from 'lang/std/engineConnection'
|
||||
|
||||
|
@ -14,10 +14,6 @@ import {
|
||||
} from './artifactGraph'
|
||||
import { err } from 'lib/trap'
|
||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||
import {
|
||||
EngineCommandManagerEvents,
|
||||
EngineConnectionEvents,
|
||||
} from 'lang/std/engineConnection'
|
||||
import { CI, VITE_KC_DEV_TOKEN } from 'env'
|
||||
import fsp from 'fs/promises'
|
||||
import fs from 'fs'
|
||||
@ -140,7 +136,7 @@ beforeAll(async () => {
|
||||
console.error(ast)
|
||||
return Promise.reject(ast)
|
||||
}
|
||||
const result = await kclManager.executeAst(ast)
|
||||
await kclManager.executeAst(ast)
|
||||
|
||||
cacheToWriteToFileTemp[codeKey] = {
|
||||
orderedCommands: engineCommandManager.orderedCommands,
|
||||
|
@ -952,6 +952,7 @@ class EngineConnection extends EventTarget {
|
||||
) {
|
||||
// Reject the promise with the error.
|
||||
this.engineCommandManager.pendingExport.reject(errorsString)
|
||||
toast.error(errorsString)
|
||||
this.engineCommandManager.pendingExport = undefined
|
||||
}
|
||||
} else {
|
||||
@ -1315,7 +1316,7 @@ export class EngineCommandManager extends EventTarget {
|
||||
commandLogs: CommandLog[] = []
|
||||
pendingExport?: {
|
||||
resolve: (a: null) => void
|
||||
reject: (reason: any) => void
|
||||
reject: (reason: string) => void
|
||||
commandId: string
|
||||
}
|
||||
settings: SettingsViaQueryString
|
||||
@ -1911,8 +1912,9 @@ export class EngineCommandManager extends EventTarget {
|
||||
const promise = new Promise<null>((resolve, reject) => {
|
||||
this.pendingExport = {
|
||||
resolve,
|
||||
reject: () => {
|
||||
reject: (reason: string) => {
|
||||
this.exportIntent = null
|
||||
reject(reason)
|
||||
},
|
||||
commandId: command.cmd_id,
|
||||
}
|
||||
|
Reference in New Issue
Block a user