* Add back stream idle mode
* Shut up codespell
* Correct serialization; only expose at user level
* cargo fmt
* tsc lint fmt
* Move engineStreamMachine as a global actor; tons of more work
* Fix up everything after bumping kittycad/lib
* Remove camera sync
* Use pause/play iconology
* Add back better ping indicator
* wip
* Fix streamIdleMode checkbox being wonky
* yarn fmt
* Massive extinction event for waitForExecutionDone; try to stop projects view switching from crashing
* Clear diagnostics when unmounting code editor!
* wip
* Rework initial root projects dir + deflake many projects tests
* More e2e fixes
* Deflake revolve some revolve tests
* Fix the rest of the mfing tests
* yarn fmt
* yarn lint
* yarn tsc
* Fix tsc after rebase
* wip
* less flaky point and click
* wip
* Fixup after rebase
* Fix more tests
* Fix 2 more
* Fix up named-views tests
* yarn fmt lint tsc
* Fix up new changes
* Get rid of 1 cyclic dependency
* Fix another cyclic mfer!
* fmt
* fmt tsc
* Fix zoom to fit being frigged
* a new list of circular deps
* Remove NetworkHealthIndicator test that was shit
* Fix the bad reload repeat issue kevin started on
* Fix zoom to fit at the right moments...
* Fix cache count numbers in editor test
* Remove a test race - poll window info.
* Qualify fail function
* Try something
* Use scene.connectionEstablished
* Hopefully fix snapshots at least
* Add app console.log
* Fix native menu tests more
* tsc lint
* Fix camera failure
* Try again
* Test attempt number 15345203, action!
* Add back old window detection heuristic
* Remove firstWindow to complete the work of 2342d04fe2
* Tweak some tests for MacOS
* Tweak "set appearance" test for MacOS
Revert this if it messes up any other platform's color checks!
* Are you serious? This was all that needed formatting?
* More color tweaks
Local MacOS and CI MacOS don't agree
* Fixes on apperance e2e test for stream idle branch (#6168)
pierremtb/stream-idle-revamp-appearance-fixes
* Another apperance fix
* Skip one native menu test to make stream idle green (#6169)
* pierremtb/stream-idle-revamp-more-fixes
* Fix lint
* Update snapshot for test_generate_settings_docs
---------
Co-authored-by: lee-at-zoo-corp <lee@zoo.dev>
Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
		
	
		
			
				
	
	
		
			441 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			441 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import * as fsp from 'fs/promises'
 | 
						|
import { join } from 'path'
 | 
						|
 | 
						|
import { expect, test } from '@e2e/playwright/zoo-test'
 | 
						|
 | 
						|
const FEATURE_TREE_EXAMPLE_CODE = `export fn timesFive(x) {
 | 
						|
  return 5 * x
 | 
						|
}
 | 
						|
export fn triangle() {
 | 
						|
  return startSketchOn(XZ)
 | 
						|
    |> startProfileAt([0, 0], %)
 | 
						|
    |> xLine(length = 10)
 | 
						|
    |> line(end = [-10, -5])
 | 
						|
    |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
						|
    |> close()
 | 
						|
}
 | 
						|
 | 
						|
length001 = timesFive(1) * 5
 | 
						|
sketch001 = startSketchOn(XZ)
 | 
						|
  |> startProfileAt([20, 10], %)
 | 
						|
  |> line(end = [10, 10])
 | 
						|
  |> angledLine([-45, length001], %)
 | 
						|
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
						|
  |> close()
 | 
						|
revolve001 = revolve(sketch001, axis = X)
 | 
						|
triangle()
 | 
						|
  |> extrude(length = 30)
 | 
						|
plane001 = offsetPlane(XY, offset = 10)
 | 
						|
sketch002 = startSketchOn(plane001)
 | 
						|
  |> startProfileAt([-20, 0], %)
 | 
						|
  |> line(end = [5, -15])
 | 
						|
  |> xLine(length = -10)
 | 
						|
  |> line(endAbsolute = [-40, 0])
 | 
						|
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
						|
  |> close()
 | 
						|
extrude001 = extrude(sketch002, length = 10)
 | 
						|
`
 | 
						|
 | 
						|
const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn(XZ)
 | 
						|
  |> startProfileAt([0, 0], %)
 | 
						|
  |> angledLine([0, 4], %, $rectangleSegmentA001)
 | 
						|
  |> angledLine([
 | 
						|
       segAng(rectangleSegmentA001) - 90,
 | 
						|
       2
 | 
						|
     ], %, $rectangleSegmentB001)
 | 
						|
  |> angledLine([
 | 
						|
       segAng(rectangleSegmentA001),
 | 
						|
       -segLen(rectangleSegmentA001)
 | 
						|
     ], %, $rectangleSegmentC001)
 | 
						|
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
 | 
						|
  |> close(%)
 | 
						|
extrude001 = extrude(sketch001, length = 10)
 | 
						|
sketch002 = startSketchOn(extrude001, rectangleSegmentB001)
 | 
						|
  |> circle(
 | 
						|
       center = [-1, 2],
 | 
						|
       radius = .5
 | 
						|
     )
 | 
						|
plane001 = offsetPlane(XZ, offset = -5)
 | 
						|
sketch003 = startSketchOn(plane001)
 | 
						|
  |> circle(center = [0, 0], radius = 5)
 | 
						|
`
 | 
						|
 | 
						|
test.describe('Feature Tree pane', () => {
 | 
						|
  test(
 | 
						|
    'User can go to definition and go to function definition',
 | 
						|
    { tag: '@electron' },
 | 
						|
    async ({ context, homePage, scene, editor, toolbar, cmdBar, page }) => {
 | 
						|
      await context.folderSetupFn(async (dir) => {
 | 
						|
        const bracketDir = join(dir, 'test-sample')
 | 
						|
        await fsp.mkdir(bracketDir, { recursive: true })
 | 
						|
        await fsp.writeFile(
 | 
						|
          join(bracketDir, 'main.kcl'),
 | 
						|
          FEATURE_TREE_EXAMPLE_CODE,
 | 
						|
          'utf-8'
 | 
						|
        )
 | 
						|
      })
 | 
						|
 | 
						|
      await test.step('setup test', async () => {
 | 
						|
        await homePage.expectState({
 | 
						|
          projectCards: [
 | 
						|
            {
 | 
						|
              title: 'test-sample',
 | 
						|
              fileCount: 1,
 | 
						|
            },
 | 
						|
          ],
 | 
						|
          sortBy: 'last-modified-desc',
 | 
						|
        })
 | 
						|
        await homePage.openProject('test-sample')
 | 
						|
        await scene.connectionEstablished()
 | 
						|
        await scene.settled(cmdBar)
 | 
						|
 | 
						|
        await toolbar.openFeatureTreePane()
 | 
						|
        await expect
 | 
						|
          .poll(() => page.getByText('Feature tree').count())
 | 
						|
          .toBeGreaterThan(1)
 | 
						|
      })
 | 
						|
 | 
						|
      async function testViewSource({
 | 
						|
        operationName,
 | 
						|
        operationIndex,
 | 
						|
        expectedActiveLine,
 | 
						|
      }: {
 | 
						|
        operationName: string
 | 
						|
        operationIndex: number
 | 
						|
        expectedActiveLine: string
 | 
						|
      }) {
 | 
						|
        await test.step(`Go to definition of the ${operationName}`, async () => {
 | 
						|
          await toolbar.viewSourceOnOperation(operationName, operationIndex)
 | 
						|
          await editor.expectState({
 | 
						|
            highlightedCode: '',
 | 
						|
            diagnostics: [],
 | 
						|
            activeLines: [expectedActiveLine],
 | 
						|
          })
 | 
						|
          await expect(
 | 
						|
            editor.activeLine.first(),
 | 
						|
            `${operationName} code should be scrolled into view`
 | 
						|
          ).toBeVisible()
 | 
						|
        })
 | 
						|
      }
 | 
						|
 | 
						|
      await testViewSource({
 | 
						|
        operationName: 'Offset Plane',
 | 
						|
        operationIndex: 0,
 | 
						|
        expectedActiveLine: 'plane001 = offsetPlane(XY, offset = 10)',
 | 
						|
      })
 | 
						|
      await testViewSource({
 | 
						|
        operationName: 'Extrude',
 | 
						|
        operationIndex: 1,
 | 
						|
        expectedActiveLine: 'extrude001 = extrude(sketch002, length = 10)',
 | 
						|
      })
 | 
						|
      await testViewSource({
 | 
						|
        operationName: 'Revolve',
 | 
						|
        operationIndex: 0,
 | 
						|
        expectedActiveLine: 'revolve001 = revolve(sketch001, axis = X)',
 | 
						|
      })
 | 
						|
      await testViewSource({
 | 
						|
        operationName: 'Triangle',
 | 
						|
        operationIndex: 0,
 | 
						|
        expectedActiveLine: 'triangle()',
 | 
						|
      })
 | 
						|
 | 
						|
      await test.step('Go to definition on the triangle function', async () => {
 | 
						|
        await toolbar.goToDefinitionOnOperation('Triangle', 0)
 | 
						|
        await editor.expectState({
 | 
						|
          highlightedCode: '',
 | 
						|
          diagnostics: [],
 | 
						|
          activeLines: ['export fn triangle() {'],
 | 
						|
        })
 | 
						|
        await expect(
 | 
						|
          editor.activeLine.first(),
 | 
						|
          'Triangle function definition should be scrolled into view'
 | 
						|
        ).toBeVisible()
 | 
						|
      })
 | 
						|
    }
 | 
						|
  )
 | 
						|
 | 
						|
  test(
 | 
						|
    `User can edit sketch (but not on offset plane yet) from the feature tree`,
 | 
						|
    { tag: '@electron' },
 | 
						|
    async ({ context, homePage, scene, editor, toolbar, page }) => {
 | 
						|
      await context.addInitScript((initialCode) => {
 | 
						|
        localStorage.setItem('persistCode', initialCode)
 | 
						|
      }, FEATURE_TREE_SKETCH_CODE)
 | 
						|
      await page.setBodyDimensions({ width: 1000, height: 500 })
 | 
						|
      await homePage.goToModelingScene()
 | 
						|
 | 
						|
      await test.step('force re-exe', async () => {
 | 
						|
        await page.waitForTimeout(1000)
 | 
						|
        await editor.replaceCode('90', '91')
 | 
						|
        await page.waitForTimeout(1500)
 | 
						|
      })
 | 
						|
 | 
						|
      await test.step('On a default plane should work', async () => {
 | 
						|
        await (await toolbar.getFeatureTreeOperation('Sketch', 0)).dblclick()
 | 
						|
        await expect(
 | 
						|
          toolbar.exitSketchBtn,
 | 
						|
          'We should be in sketch mode now'
 | 
						|
        ).toBeVisible()
 | 
						|
        await editor.expectState({
 | 
						|
          highlightedCode: '',
 | 
						|
          diagnostics: [],
 | 
						|
          activeLines: ['sketch001 = startSketchOn(XZ)'],
 | 
						|
        })
 | 
						|
        await toolbar.exitSketchBtn.click()
 | 
						|
      })
 | 
						|
 | 
						|
      await test.step('On an extrude face should *not* work', async () => {
 | 
						|
        // Tooltip is getting in the way of clicking, so I'm first closing the pane
 | 
						|
        await toolbar.closeFeatureTreePane()
 | 
						|
        await page.waitForTimeout(1000)
 | 
						|
        await editor.replaceCode('91', '90')
 | 
						|
        await page.waitForTimeout(2000)
 | 
						|
        await (await toolbar.getFeatureTreeOperation('Sketch', 1)).dblclick()
 | 
						|
 | 
						|
        await expect(
 | 
						|
          toolbar.exitSketchBtn,
 | 
						|
          'We should be in sketch mode now'
 | 
						|
        ).toBeVisible()
 | 
						|
        await editor.expectState({
 | 
						|
          highlightedCode: '',
 | 
						|
          diagnostics: [],
 | 
						|
          activeLines: [
 | 
						|
            'sketch002=startSketchOn(extrude001,rectangleSegmentB001)',
 | 
						|
          ],
 | 
						|
        })
 | 
						|
        await toolbar.exitSketchBtn.click()
 | 
						|
      })
 | 
						|
 | 
						|
      await test.step('On an offset plane should work', async () => {
 | 
						|
        // Tooltip is getting in the way of clicking, so I'm first closing the pane
 | 
						|
        await toolbar.closeFeatureTreePane()
 | 
						|
        await (await toolbar.getFeatureTreeOperation('Sketch', 2)).dblclick()
 | 
						|
        await editor.expectState({
 | 
						|
          highlightedCode: '',
 | 
						|
          diagnostics: [],
 | 
						|
          activeLines: ['sketch003=startSketchOn(plane001)'],
 | 
						|
        })
 | 
						|
        await expect(
 | 
						|
          toolbar.exitSketchBtn,
 | 
						|
          'We should be in sketch mode now'
 | 
						|
        ).toBeVisible()
 | 
						|
      })
 | 
						|
    }
 | 
						|
  )
 | 
						|
  test(`User can edit an extrude operation from the feature tree`, async ({
 | 
						|
    context,
 | 
						|
    homePage,
 | 
						|
    scene,
 | 
						|
    editor,
 | 
						|
    toolbar,
 | 
						|
    cmdBar,
 | 
						|
    page,
 | 
						|
  }) => {
 | 
						|
    const initialInput = '23'
 | 
						|
    const initialCode = `sketch001 = startSketchOn(XZ)
 | 
						|
      |> circle(center = [0, 0], radius = 5)
 | 
						|
      renamedExtrude = extrude(sketch001, length = ${initialInput})`
 | 
						|
    const newConstantName = 'distance001'
 | 
						|
    const expectedCode = `${newConstantName} = 23
 | 
						|
    sketch001 = startSketchOn(XZ)
 | 
						|
      |> circle(center = [0, 0], radius = 5)
 | 
						|
            renamedExtrude = extrude(sketch001, length = ${newConstantName})`
 | 
						|
 | 
						|
    await context.folderSetupFn(async (dir) => {
 | 
						|
      const testDir = join(dir, 'test-sample')
 | 
						|
      await fsp.mkdir(testDir, { recursive: true })
 | 
						|
      await fsp.writeFile(join(testDir, 'main.kcl'), initialCode, 'utf-8')
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step('setup test', async () => {
 | 
						|
      await homePage.expectState({
 | 
						|
        projectCards: [
 | 
						|
          {
 | 
						|
            title: 'test-sample',
 | 
						|
            fileCount: 1,
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        sortBy: 'last-modified-desc',
 | 
						|
      })
 | 
						|
      await homePage.openProject('test-sample')
 | 
						|
      await scene.settled(cmdBar)
 | 
						|
      await toolbar.openFeatureTreePane()
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step('Double click on the extrude operation', async () => {
 | 
						|
      await (await toolbar.getFeatureTreeOperation('Extrude', 0))
 | 
						|
        .first()
 | 
						|
        .dblclick()
 | 
						|
      await editor.expectState({
 | 
						|
        highlightedCode: '',
 | 
						|
        diagnostics: [],
 | 
						|
        activeLines: [
 | 
						|
          `renamedExtrude = extrude(sketch001, length = ${initialInput})`,
 | 
						|
        ],
 | 
						|
      })
 | 
						|
      await cmdBar.expectState({
 | 
						|
        commandName: 'Extrude',
 | 
						|
        stage: 'arguments',
 | 
						|
        currentArgKey: 'distance',
 | 
						|
        currentArgValue: initialInput,
 | 
						|
        headerArguments: {
 | 
						|
          Distance: initialInput,
 | 
						|
        },
 | 
						|
        highlightedHeaderArg: 'distance',
 | 
						|
      })
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step('Add a named constant for distance argument and submit', async () => {
 | 
						|
      await expect(cmdBar.currentArgumentInput).toBeVisible()
 | 
						|
      const addVariableButton = page.getByRole('button', {
 | 
						|
        name: 'Create new variable',
 | 
						|
      })
 | 
						|
      await addVariableButton.click()
 | 
						|
      await cmdBar.progressCmdBar()
 | 
						|
      await cmdBar.expectState({
 | 
						|
        stage: 'review',
 | 
						|
        headerArguments: {
 | 
						|
          // The calculated value is shown in the argument summary
 | 
						|
          Distance: initialInput,
 | 
						|
        },
 | 
						|
        commandName: 'Extrude',
 | 
						|
      })
 | 
						|
      await cmdBar.progressCmdBar()
 | 
						|
      await editor.expectState({
 | 
						|
        highlightedCode: '',
 | 
						|
        diagnostics: [],
 | 
						|
        activeLines: [
 | 
						|
          `renamedExtrude = extrude(sketch001, length = ${newConstantName})`,
 | 
						|
        ],
 | 
						|
      })
 | 
						|
      await editor.expectEditor.toContain(expectedCode, {
 | 
						|
        shouldNormalise: true,
 | 
						|
      })
 | 
						|
    })
 | 
						|
  })
 | 
						|
  test(`User can edit an offset plane operation from the feature tree`, async ({
 | 
						|
    context,
 | 
						|
    homePage,
 | 
						|
    scene,
 | 
						|
    editor,
 | 
						|
    toolbar,
 | 
						|
    cmdBar,
 | 
						|
  }) => {
 | 
						|
    const testCode = (value: string) => `p = offsetPlane(XY, offset = ${value})`
 | 
						|
    const initialInput = '10'
 | 
						|
    const initialCode = testCode(initialInput)
 | 
						|
    const newInput = '5 + 10'
 | 
						|
    const expectedCode = testCode(newInput)
 | 
						|
    await context.folderSetupFn(async (dir) => {
 | 
						|
      const testDir = join(dir, 'test-sample')
 | 
						|
      await fsp.mkdir(testDir, { recursive: true })
 | 
						|
      await fsp.writeFile(join(testDir, 'main.kcl'), initialCode, 'utf-8')
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step('setup test', async () => {
 | 
						|
      await homePage.expectState({
 | 
						|
        projectCards: [
 | 
						|
          {
 | 
						|
            title: 'test-sample',
 | 
						|
            fileCount: 1,
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        sortBy: 'last-modified-desc',
 | 
						|
      })
 | 
						|
      await homePage.openProject('test-sample')
 | 
						|
      await scene.settled(cmdBar)
 | 
						|
      await toolbar.openFeatureTreePane()
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step('Double click on the offset plane operation', async () => {
 | 
						|
      await (await toolbar.getFeatureTreeOperation('Offset Plane', 0))
 | 
						|
        .first()
 | 
						|
        .dblclick()
 | 
						|
      await editor.expectState({
 | 
						|
        highlightedCode: '',
 | 
						|
        diagnostics: [],
 | 
						|
        activeLines: [initialCode],
 | 
						|
      })
 | 
						|
      await cmdBar.expectState({
 | 
						|
        commandName: 'Offset plane',
 | 
						|
        stage: 'arguments',
 | 
						|
        currentArgKey: 'distance',
 | 
						|
        currentArgValue: initialInput,
 | 
						|
        headerArguments: {
 | 
						|
          Plane: '1 plane',
 | 
						|
          Distance: initialInput,
 | 
						|
        },
 | 
						|
        highlightedHeaderArg: 'distance',
 | 
						|
      })
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step('Edit the distance argument and submit', async () => {
 | 
						|
      await expect(cmdBar.currentArgumentInput).toBeVisible()
 | 
						|
      await cmdBar.currentArgumentInput.locator('.cm-content').fill(newInput)
 | 
						|
      await cmdBar.progressCmdBar()
 | 
						|
      await cmdBar.expectState({
 | 
						|
        stage: 'review',
 | 
						|
        headerArguments: {
 | 
						|
          Plane: '1 plane',
 | 
						|
          // We show the calculated value in the argument summary
 | 
						|
          Distance: '15',
 | 
						|
        },
 | 
						|
        commandName: 'Offset plane',
 | 
						|
      })
 | 
						|
      await cmdBar.progressCmdBar()
 | 
						|
      await editor.expectState({
 | 
						|
        highlightedCode: '',
 | 
						|
        diagnostics: [],
 | 
						|
        activeLines: [expectedCode],
 | 
						|
      })
 | 
						|
    })
 | 
						|
  })
 | 
						|
 | 
						|
  test(`Delete sketch on offset plane and all profiles from feature tree`, async ({
 | 
						|
    context,
 | 
						|
    page,
 | 
						|
    homePage,
 | 
						|
    scene,
 | 
						|
    editor,
 | 
						|
    toolbar,
 | 
						|
    cmdBar,
 | 
						|
  }) => {
 | 
						|
    const beforeKclCode = `plane001 = offsetPlane(XY, offset = 5)
 | 
						|
sketch001 = startSketchOn(plane001)
 | 
						|
profile001 = circle(sketch001, center = [0, 20], radius = 12)
 | 
						|
profile002 = startProfileAt([0, 7.25], sketch001)
 | 
						|
  |> xLine(length = 13.3)
 | 
						|
profile003 = startProfileAt([0, -4.93], sketch001)
 | 
						|
  |> line(endAbsolute = [-5.56, 0])`
 | 
						|
    await context.folderSetupFn(async (dir) => {
 | 
						|
      const testProject = join(dir, 'test-sample')
 | 
						|
      await fsp.mkdir(testProject, { recursive: true })
 | 
						|
      await fsp.writeFile(join(testProject, 'main.kcl'), beforeKclCode, 'utf-8')
 | 
						|
    })
 | 
						|
    // One dumb hardcoded screen pixel value
 | 
						|
    const testPoint = { x: 650, y: 250 }
 | 
						|
    const sketchColor: [number, number, number] = [149, 149, 149]
 | 
						|
    const planeColor: [number, number, number] = [74, 74, 74]
 | 
						|
 | 
						|
    await homePage.openProject('test-sample')
 | 
						|
    await scene.settled(cmdBar)
 | 
						|
 | 
						|
    await test.step(`Verify we see the sketch`, async () => {
 | 
						|
      await scene.expectPixelColor(sketchColor, testPoint, 10)
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step('Delete sketch via feature tree selection', async () => {
 | 
						|
      const operationButton = await toolbar.getFeatureTreeOperation('Sketch', 0)
 | 
						|
      await operationButton.click({ button: 'left' })
 | 
						|
      await page.keyboard.press('Delete')
 | 
						|
      await scene.expectPixelColor(planeColor, testPoint, 10)
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step(`Verify the code changed`, async () => {
 | 
						|
      await editor.expectEditor.toContain('plane001 =')
 | 
						|
      await editor.expectEditor.not.toContain('sketch001 =')
 | 
						|
      await editor.expectEditor.not.toContain('profile002 = ')
 | 
						|
    })
 | 
						|
  })
 | 
						|
})
 |