chore: stabilizing named views e2e tests (#6246)

* fix: moving toast application state:

* fix: forgot the await on the expect calls, ts didn't yell at me?

* fix: cleaning up the camera move e2e code

* fix: lint,tsc,fmt

* Unblock on macOS for now

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>
Co-authored-by: Jace Browning <jacebrowning@gmail.com>
This commit is contained in:
Kevin Nadro
2025-04-11 09:32:44 -05:00
committed by GitHub
parent 7d3294ff78
commit a07dbc3aac
6 changed files with 71 additions and 42 deletions

View File

@ -6,7 +6,9 @@ import type { NamedView } from '@rust/kcl-lib/bindings/NamedView'
import {
createProject,
perProjectsettingsToToml,
orRunWhenFullSuiteEnabled,
perProjectSettingsToToml,
runningOnMac,
tomlToPerProjectSettings,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
@ -57,11 +59,13 @@ function tomlStringOverWriteNamedViewUuids(toml: string): string {
settings.settings.app.named_views = remappedNamedViews
}
}
return perProjectsettingsToToml(settings)
return perProjectSettingsToToml(settings)
}
test.describe('Named view tests', () => {
test.skip() // TODO: Jace is working on these
if (runningOnMac()) {
test.fixme(orRunWhenFullSuiteEnabled())
}
test('Verify project.toml is not created', async ({ page }, testInfo) => {
// Create project and load it
const projectName = 'named-views'
@ -105,6 +109,9 @@ test.describe('Named view tests', () => {
PROJECT_SETTINGS_FILE_NAME
)
const toastMessage = page.getByText('Named view uuid1 created.')
await expect(toastMessage).toBeInViewport()
// Expect project.toml to be generated on disk since a named view was created
await expect(async () => {
let exists = await fileExists(tempProjectSettingsFilePath)
@ -130,7 +137,6 @@ test.describe('Named view tests', () => {
}, testInfo) => {
const projectName = 'named-views'
const myNamedView1 = 'uuid1'
const myNamedView2 = 'uuid2'
// Create project and go into the project
await createProject({ name: projectName, page })
@ -142,6 +148,9 @@ test.describe('Named view tests', () => {
await cmdBar.argumentInput.fill(myNamedView1)
await cmdBar.progressCmdBar(false)
let toastMessage = page.getByText('Named view uuid1 created.')
await expect(toastMessage).toBeInViewport()
// Generate file paths for project.toml
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
const tempProjectSettingsFilePath = join(
@ -170,17 +179,20 @@ test.describe('Named view tests', () => {
// Delete a named view
await cmdBar.openCmdBar()
await cmdBar.chooseCommand('delete named view')
cmdBar.selectOption({ name: myNamedView2 })
cmdBar.selectOption({ name: myNamedView1 })
await cmdBar.progressCmdBar(false)
toastMessage = page.getByText('Named view uuid1 removed.')
await expect(toastMessage).toBeInViewport()
await expect(async () => {
// Read project.toml into memory again since we deleted a named view
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
// // Write the entire tomlString to a snapshot.
// // There are many key/value pairs to check this is a safer match.
// Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted')
}).toPass()
})
@ -202,6 +214,9 @@ test.describe('Named view tests', () => {
await cmdBar.argumentInput.fill(myNamedView)
await cmdBar.progressCmdBar(false)
let toastMessage = page.getByText('Named view uuid1 created.')
await expect(toastMessage).toBeInViewport()
// Generate file paths for project.toml
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
const tempProjectSettingsFilePath = join(
@ -258,26 +273,19 @@ test.describe('Named view tests', () => {
await cmdBar.argumentInput.fill(myNamedView1)
await cmdBar.progressCmdBar(false)
await page.waitForTimeout(1000)
let toastMessage = page.getByText('Named view uuid1 created.')
await expect(toastMessage).toBeInViewport()
const orbitMouseStart = { x: 800, y: 130 }
const orbitMouseEnd = { x: 0, y: 130 }
await page.mouse.move(orbitMouseStart.x, orbitMouseStart.y)
await page.mouse.down({ button: 'middle' })
await page.mouse.move(orbitMouseEnd.x, orbitMouseEnd.y, {
steps: 3,
})
await page.mouse.up({ button: 'middle' })
await page.waitForTimeout(1000)
await scene.moveCameraTo({ x: 608, y: 0, z: 0 }, { x: 0, y: 0, z: 0 })
await page.waitForTimeout(2500)
await cmdBar.openCmdBar()
await cmdBar.chooseCommand('create named view')
await cmdBar.argumentInput.fill(myNamedView2)
await cmdBar.progressCmdBar(false)
// Wait a moment for the project.toml to get written to disk with the new view point
await page.waitForTimeout(1000)
toastMessage = page.getByText('Named view uuid2 created.')
await expect(toastMessage).toBeInViewport()
// Generate paths for the project.toml
const tempProjectSettingsFilePath = join(

View File

@ -1,16 +1,5 @@
[settings]
app = { }
modeling = { }
text_editor = { }
command_bar = { }
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
name = "uuid1"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 0, 0, 0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1

View File

@ -17,12 +17,12 @@ version = 1
[settings.app.named_views.c810cf04-c6cc-4a4a-8b11-17bf445dcab7]
name = "uuid2"
eye_offset = 1_378.0059
eye_offset = 608
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 1_826.5239, 0.0, 0.0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
pivot_position = [ 0, 0, 0 ]
pivot_rotation = [ 0.5, 0.5, 0.5, 0.5 ]
world_coord_system = "right_handed_up_z"
version = 1

View File

@ -1140,7 +1140,7 @@ export function tomlToPerProjectSettings(
return TOML.parse(toml)
}
export function perProjectsettingsToToml(
export function perProjectSettingsToToml(
settings: DeepPartial<ProjectConfiguration>
) {
// eslint-disable-next-line no-restricted-syntax

View File

@ -160,10 +160,11 @@ export function createNamedViewsCommand() {
data: {
level: 'project',
value: requestedNamedViews,
toastCallback: () => {
toast.success(`Named view ${requestedView.name} created.`)
},
},
})
toast.success(`Named view ${requestedView.name} created.`)
}
}
}
@ -210,9 +211,11 @@ export function createNamedViewsCommand() {
data: {
level: 'project',
value: rest,
toastCallback: () => {
toast.success(`Named view ${viewToDelete.name} removed.`)
},
},
})
toast.success(`Named view ${viewToDelete.name} removed.`)
} else {
toast.error(`Unable to delete, could not find the named view`)
}
@ -307,6 +310,8 @@ export function createNamedViewsCommand() {
type: 'default_camera_get_settings',
},
})
// We do not have the promise of the engine command for ensuring the camera projection has been completed.
toast.success(`Named view ${name} loaded.`)
} else {
toast.error(`Unable to load named view, could not find named view`)

View File

@ -76,7 +76,14 @@ export const settingsMachine = setup({
level: SettingsLevel
}
| { type: 'Set all settings'; settings: typeof settings }
| { type: 'set.app.namedViews'; value: NamedView }
| {
type: 'set.app.namedViews'
data: {
value: NamedView
toastCallback: () => void
level: SettingsLevel
}
}
| { type: 'load.project'; project?: Project }
| { type: 'clear.project' }
) & { doNotPersist?: boolean },
@ -84,7 +91,11 @@ export const settingsMachine = setup({
actors: {
persistSettings: fromPromise<
void,
{ doNotPersist: boolean; context: SettingsMachineContext }
{
doNotPersist: boolean
context: SettingsMachineContext
toastCallback?: () => void
}
>(async ({ input }) => {
// Without this, when a user changes the file, it'd
// create a detection loop with the file-system watcher.
@ -93,7 +104,12 @@ export const settingsMachine = setup({
codeManager.writeCausedByAppCheckedInFileTreeFileSystemWatcher = true
const { currentProject, ...settings } = input.context
return saveSettings(settings, currentProject?.path)
const val = await saveSettings(settings, currentProject?.path)
if (input.toastCallback) {
input.toastCallback()
}
return val
}),
loadUserSettings: fromPromise<SettingsMachineContext, void>(async () => {
const { settings } = await loadAndValidateSettings()
@ -517,6 +533,17 @@ export const settingsMachine = setup({
},
},
input: ({ context, event }) => {
if (
event.type === 'set.app.namedViews' &&
'toastCallback' in event.data
) {
return {
doNotPersist: event.doNotPersist ?? false,
context,
toastCallback: event.data.toastCallback,
}
}
return {
doNotPersist: event.doNotPersist ?? false,
context,