* Revert "Revert multi-profile (#4812)"
This reverts commit efe8089b08
.
* fix poor 1000ms wait UX
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest-8-cores)
* trigger CI
* Add Rust side artifacts for startSketchOn face or plane (#4834)
* Add Rust side artifacts for startSketchOn face or plane
* move ast digging
---------
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
* lint
* lint
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-macos-8-cores)
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)
* trigger CI
* chore: disabled file watcher which prevents faster file write (#4835)
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* partial fixes
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* Trigger CI
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* Trigger CI
* Fix up all the tests
* Fix partial execution
* wip
* WIP
* wip
* rust changes to make three point confrom to same as others since we're not ready with name params yet
* most of the fix for 3 point circle
* get overlays working for circle three point
* fmt
* fix types
* cargo fmt
* add face codef ref for walls and caps
* fix sketch on face after updates to rust side artifact graph
* some things needed for multi-profile tests
* bad attempts at fixing rust
* more
* more
* fix rust
* more rust fixes
* overlay fix
* remove duplicate test
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* lint and typing
* maybe fix a unit test
* small thing
* fix circ dep
* fix unit test
* fix some tests
* fix sweep point-and-click test
* fix more tests and add a fix me
* fix more tests
* fix electron specific test
* tsc
* more test tweaks
* update docs
* commint snaps?
* is clippy happy now?
* clippy again
* test works now without me changing anything big-fixed-itself
* small bug
* make three point have cross hair to make it consistent with othe rtools
* fix up state diagram
* fmt
* add draft point for first click of three point circ
* 1 test for three point circle
* 2 test for three point circle
* clean up
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* remove bad doc comment
* remove test skip
* remove onboarding test changes
* Update src/lang/modifyAst.ts
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
* Update output from simulation tests
* Fix to use correct source ranges
This also reduces cloning.
* Change back to skipping face cap none and both
* Update output after changing back to skipping none and both
* Fix clippy warning
* fix profile start snap bug
* add path ids to cap
* fix going into edit sketch
* make other startSketchOn's work
* fix snapshot test
* explain function name
* Update src/lib/rectangleTool.ts
Co-authored-by: Frank Noirot <frank@zoo.dev>
* rename error
* remove file tree from diff
* Update src/clientSideScene/segments.ts
Co-authored-by: Frank Noirot <frank@zoo.dev>
* nit
* Prevent double write to KCL code on revolve
* Update output after adding cap-to-path graph edge
* Fix edit/select sketch-on-cap via feature tree
* clean up for face codeRef
* fix changing tools part way through circle/rect tools
* fix delete of circle profile
* fix close profiles
* fix closing profile bug (tangentArcTo being ignored)
* remove stale comment
* Delete paths associated with sketch when the sketch plane is deleted
* Add support for deleting sketches on caps (not walls)
* get delet working for walls
* make delet of extrusions work for multi profile
* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)
* Delete the sketch statement too on the cap and wall cases
* Don't write to file in `split-sketch-pipe-if-needed` unless necessary
* Don't wait for file write to complete within `updateEditorWithAstAndWriteToFile`
It is already debounced internally. If we await it, we will have to wait for a debounced timeout
* docs
* fix circ dep
* tsc
* fix selection enter sketch weirdness
* test fixes
* comment out and fixme for delete related tests
* add skip wins
* try and get last test to pass
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Kevin Nadro <nadr0@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
Co-authored-by: 49lf <ircsurfer33@gmail.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
293 lines
8.4 KiB
TypeScript
293 lines
8.4 KiB
TypeScript
import type { Page, Locator } from '@playwright/test'
|
|
import { expect } from '@playwright/test'
|
|
import { isArray, uuidv4 } from 'lib/utils'
|
|
import {
|
|
closeDebugPanel,
|
|
doAndWaitForImageDiff,
|
|
getPixelRGBs,
|
|
openAndClearDebugPanel,
|
|
sendCustomCmd,
|
|
} from '../test-utils'
|
|
|
|
type MouseParams = {
|
|
pixelDiff?: number
|
|
shouldDbClick?: boolean
|
|
delay?: number
|
|
}
|
|
type MouseDragToParams = MouseParams & {
|
|
fromPoint: { x: number; y: number }
|
|
}
|
|
type MouseDragFromParams = MouseParams & {
|
|
toPoint: { x: number; y: number }
|
|
}
|
|
|
|
type SceneSerialised = {
|
|
camera: {
|
|
position: [number, number, number]
|
|
target: [number, number, number]
|
|
}
|
|
}
|
|
|
|
type ClickHandler = (clickParams?: MouseParams) => Promise<void | boolean>
|
|
type MoveHandler = (moveParams?: MouseParams) => Promise<void | boolean>
|
|
type DblClickHandler = (clickParams?: MouseParams) => Promise<void | boolean>
|
|
type DragToHandler = (dragParams: MouseDragToParams) => Promise<void | boolean>
|
|
type DragFromHandler = (
|
|
dragParams: MouseDragFromParams
|
|
) => Promise<void | boolean>
|
|
|
|
export class SceneFixture {
|
|
public page: Page
|
|
public streamWrapper!: Locator
|
|
public loadingIndicator!: Locator
|
|
|
|
get exeIndicator() {
|
|
return this.page.getByTestId('model-state-indicator-execution-done')
|
|
}
|
|
|
|
constructor(page: Page) {
|
|
this.page = page
|
|
this.reConstruct(page)
|
|
}
|
|
private _serialiseScene = async (): Promise<SceneSerialised> => {
|
|
const camera = await this.getCameraInfo()
|
|
|
|
return {
|
|
camera,
|
|
}
|
|
}
|
|
|
|
expectState = async (expected: SceneSerialised) => {
|
|
return expect
|
|
.poll(async () => await this._serialiseScene(), {
|
|
intervals: [1_000, 2_000, 10_000],
|
|
timeout: 60000,
|
|
})
|
|
.toEqual(expected)
|
|
}
|
|
|
|
reConstruct = (page: Page) => {
|
|
this.page = page
|
|
|
|
this.streamWrapper = page.getByTestId('stream')
|
|
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
|
|
}
|
|
|
|
makeMouseHelpers = (
|
|
x: number,
|
|
y: number,
|
|
{ steps }: { steps: number } = { steps: 20 }
|
|
): [ClickHandler, MoveHandler, DblClickHandler] =>
|
|
[
|
|
(clickParams?: MouseParams) => {
|
|
if (clickParams?.pixelDiff) {
|
|
return doAndWaitForImageDiff(
|
|
this.page,
|
|
() =>
|
|
clickParams?.shouldDbClick
|
|
? this.page.mouse.dblclick(x, y, {
|
|
delay: clickParams?.delay || 0,
|
|
})
|
|
: this.page.mouse.click(x, y, {
|
|
delay: clickParams?.delay || 0,
|
|
}),
|
|
clickParams.pixelDiff
|
|
)
|
|
}
|
|
return clickParams?.shouldDbClick
|
|
? this.page.mouse.dblclick(x, y, { delay: clickParams?.delay || 0 })
|
|
: this.page.mouse.click(x, y, { delay: clickParams?.delay || 0 })
|
|
},
|
|
(moveParams?: MouseParams) => {
|
|
if (moveParams?.pixelDiff) {
|
|
return doAndWaitForImageDiff(
|
|
this.page,
|
|
() => this.page.mouse.move(x, y, { steps }),
|
|
moveParams.pixelDiff
|
|
)
|
|
}
|
|
return this.page.mouse.move(x, y, { steps })
|
|
},
|
|
(clickParams?: MouseParams) => {
|
|
if (clickParams?.pixelDiff) {
|
|
return doAndWaitForImageDiff(
|
|
this.page,
|
|
() => this.page.mouse.dblclick(x, y),
|
|
clickParams.pixelDiff
|
|
)
|
|
}
|
|
return this.page.mouse.dblclick(x, y)
|
|
},
|
|
] as const
|
|
makeDragHelpers = (
|
|
x: number,
|
|
y: number,
|
|
{ steps }: { steps: number } = { steps: 20 }
|
|
): [DragToHandler, DragFromHandler] =>
|
|
[
|
|
(dragToParams: MouseDragToParams) => {
|
|
if (dragToParams?.pixelDiff) {
|
|
return doAndWaitForImageDiff(
|
|
this.page,
|
|
() =>
|
|
this.page.dragAndDrop('#stream', '#stream', {
|
|
sourcePosition: dragToParams.fromPoint,
|
|
targetPosition: { x, y },
|
|
}),
|
|
dragToParams.pixelDiff
|
|
)
|
|
}
|
|
return this.page.dragAndDrop('#stream', '#stream', {
|
|
sourcePosition: dragToParams.fromPoint,
|
|
targetPosition: { x, y },
|
|
})
|
|
},
|
|
(dragFromParams: MouseDragFromParams) => {
|
|
if (dragFromParams?.pixelDiff) {
|
|
return doAndWaitForImageDiff(
|
|
this.page,
|
|
() =>
|
|
this.page.dragAndDrop('#stream', '#stream', {
|
|
sourcePosition: { x, y },
|
|
targetPosition: dragFromParams.toPoint,
|
|
}),
|
|
dragFromParams.pixelDiff
|
|
)
|
|
}
|
|
return this.page.dragAndDrop('#stream', '#stream', {
|
|
sourcePosition: { x, y },
|
|
targetPosition: dragFromParams.toPoint,
|
|
})
|
|
},
|
|
] as const
|
|
|
|
/** Likely no where, there's a chance it will click something in the scene, depending what you have in the scene.
|
|
*
|
|
* Expects the viewPort to be 1000x500 */
|
|
clickNoWhere = () => this.page.mouse.click(998, 60)
|
|
/** Likely no where, there's a chance it will click something in the scene, depending what you have in the scene.
|
|
*
|
|
* Expects the viewPort to be 1000x500 */
|
|
moveNoWhere = (steps?: number) => this.page.mouse.move(998, 60, { steps })
|
|
|
|
moveCameraTo = async (
|
|
pos: { x: number; y: number; z: number },
|
|
target: { x: number; y: number; z: number } = { x: 0, y: 0, z: 0 }
|
|
) => {
|
|
await openAndClearDebugPanel(this.page)
|
|
await doAndWaitForImageDiff(
|
|
this.page,
|
|
() =>
|
|
sendCustomCmd(this.page, {
|
|
type: 'modeling_cmd_req',
|
|
cmd_id: uuidv4(),
|
|
cmd: {
|
|
type: 'default_camera_look_at',
|
|
vantage: pos,
|
|
center: target,
|
|
up: { x: 0, y: 0, z: 1 },
|
|
},
|
|
}),
|
|
300
|
|
)
|
|
await closeDebugPanel(this.page)
|
|
}
|
|
/** Forces a refresh of the camera position and target displayed
|
|
* in the debug panel and then returns the values of the fields
|
|
*/
|
|
async getCameraInfo() {
|
|
await openAndClearDebugPanel(this.page)
|
|
await sendCustomCmd(this.page, {
|
|
type: 'modeling_cmd_req',
|
|
cmd_id: uuidv4(),
|
|
cmd: {
|
|
type: 'default_camera_get_settings',
|
|
},
|
|
})
|
|
await this.page
|
|
.locator(`[data-receive-command-type="default_camera_get_settings"]`)
|
|
.first()
|
|
.waitFor()
|
|
const position = await Promise.all([
|
|
this.page.getByTestId('cam-x-position').inputValue().then(Number),
|
|
this.page.getByTestId('cam-y-position').inputValue().then(Number),
|
|
this.page.getByTestId('cam-z-position').inputValue().then(Number),
|
|
])
|
|
const target = await Promise.all([
|
|
this.page.getByTestId('cam-x-target').inputValue().then(Number),
|
|
this.page.getByTestId('cam-y-target').inputValue().then(Number),
|
|
this.page.getByTestId('cam-z-target').inputValue().then(Number),
|
|
])
|
|
await closeDebugPanel(this.page)
|
|
return {
|
|
position,
|
|
target,
|
|
}
|
|
}
|
|
|
|
waitForExecutionDone = async () => {
|
|
await expect(this.exeIndicator).toBeVisible({ timeout: 30000 })
|
|
}
|
|
|
|
expectPixelColor = async (
|
|
colour: [number, number, number] | [number, number, number][],
|
|
coords: { x: number; y: number },
|
|
diff: number
|
|
) => {
|
|
await expectPixelColor(this.page, colour, coords, diff)
|
|
}
|
|
|
|
get gizmo() {
|
|
return this.page.locator('[aria-label*=gizmo]')
|
|
}
|
|
|
|
async clickGizmoMenuItem(name: string) {
|
|
await this.gizmo.hover()
|
|
await this.gizmo.click({ button: 'right' })
|
|
const buttonToTest = this.page.getByRole('button', {
|
|
name: name,
|
|
})
|
|
await expect(buttonToTest).toBeVisible()
|
|
await buttonToTest.click()
|
|
}
|
|
}
|
|
|
|
function isColourArray(
|
|
colour: [number, number, number] | [number, number, number][]
|
|
): colour is [number, number, number][] {
|
|
return isArray(colour[0])
|
|
}
|
|
|
|
export async function expectPixelColor(
|
|
page: Page,
|
|
colour: [number, number, number] | [number, number, number][],
|
|
coords: { x: number; y: number },
|
|
diff: number
|
|
) {
|
|
let finalValue = colour
|
|
await expect
|
|
.poll(
|
|
async () => {
|
|
const pixel = (await getPixelRGBs(page)(coords, 1))[0]
|
|
if (!pixel) return null
|
|
finalValue = pixel
|
|
if (!isColourArray(colour)) {
|
|
return pixel.every(
|
|
(channel, index) => Math.abs(channel - colour[index]) < diff
|
|
)
|
|
}
|
|
return colour.some((c) =>
|
|
c.every((channel, index) => Math.abs(pixel[index] - channel) < diff)
|
|
)
|
|
},
|
|
{ timeout: 10_000 }
|
|
)
|
|
.toBeTruthy()
|
|
.catch((cause) => {
|
|
throw new Error(
|
|
`ExpectPixelColor: expecting ${colour} got ${finalValue}`,
|
|
{ cause }
|
|
)
|
|
})
|
|
}
|