* Rename `homeMachine` and accessories to `projectsMachine` * Separate out `/home` route from `projectsMachine` * Add logic to navigate out from deleted or renamed project * Show a warning in the command palette for deleting a project * Make it navigate when you create a project * Update "New project" button to use command bar flow Closes #2585 * More explicit warning message text * Make projects watching code not run in web * Tests first version: nested loops * Tests second version: flattened * Remove console logs * Fix tsc * @jtran feedback, use the type guard util * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * Fix tests that relied on one-click, no-navigation project creation * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)" This reverts commit7545b61b49. * Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)" This reverts commit3d2e48732c. * Add a mask to the state indicator to client-side scale test * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * Fix lint * Fix tsc * Add menu item to share link to file * Forward query params while redirecting to /home or /file * Add (broken) event logic and command triggering logic * Fix a couple stray tests that still relied on the old way of creating projects * De-flake another text that could be thrown off by toast-based selectors * FMT * Dumb test error because I was rushing * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * Ahhh more flaky toasts, they're everywhere! * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * Side quest: Only register commands once, power their disabled status while selecting commands via optional actor * Get query-triggered command working in browser too * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * Tests always run on localhost, don't expect the prod origin * rerun CI * wip * wip * Everything's pretty much done but url.zoo.dev has been broken and we need to think about how to test reliably * Merge branch 'main' into franknoirot/4088/create-file-url * Add useCreateFileLinkQuery on Home page * Get primary user flow working on desktop * Rework to open browser app first, then send along to the desktop app if asked * Styling updates to OpenInDesktopAppHandler * Clean up unecessary file * Merge branch 'main' into franknoirot/4088/create-file-url * Separate creating `createFileUrl` and shortlink so it is unit testable * Add E2E test for importing file from URL * Add a couple component tests for OpenInDesktopAppHandler * Fix the "existing project" user flow * Add E2E test for "add to existing project" user flow * Undo mistaken or unecessary changes * Lints, fmt, tsc * Fix unit test * Fix broken rename and delete project commands Something about the `optionsFromContext` config no longer works with file I/O-related commands. I suspect this has to do with our read/write loop patching * Fix unit test, use kebab-case for url query param * Use dev urls everywhere when configured that way I think we were just using some constants that ended up returning bad values for dev, it seemed to return a working shortlink when I went through the flow. * Clean up unneeded PROD_TOKEN * Fix browser command flow, because we had made the projectMachine desktop-only on main * Make the test executor a bit more patient (#5004) * Fix so that all artifact commands are returned regardless of caching (#5005) * Fix so that all artifact commands are returned regardless of caching * Add some more docs and fix up old ones * Add new lint to disallow use of confusing isNaN (#4999) * Point-and-click Sweep (first PR) (#4989) * Refactor 'Delete selection' as actor Will fix #4662 * WIP logging * WIP: working Solid3dGetExtrusionFaceInfo for loft * Working wall deletion of loft * Add offset plane deletion * Add feature tree deletion of shell * Clean up * Revert "Clean up" This reverts commit214763cc2b. * Clean up rust changes, taking the sketch with the most paths * Working cap selection and deletion * Clean up * Add test for loft and offset plane deletion via selection * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores) * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-macos-8-cores) * Set reenter: false as it was originally * Passing test * Add shell deletion via feature tree test * Revert the migration to promise actor * 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 * 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 * Use cmd.id as solid_id after latest engine merge * Add feature tree deletion of offset plane and fix lint * Add feature tree deletion of loft * Clean up * Better comment * Lint fix * Remove sketch sorting * WIP: sweep point-and-click * Working sweep * Add test * Make sweep a development command * Fix tsc error * Clean up for review --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Upgrade typescript-eslint from 5.62.0 to 8.19.1 and remove eslint-config-react-app (#5006) * Fix lost lints and add new ones (#5011) * Add eslint-plugin-jsx-a11y dependency * Add jsx-a11y lint * Add eslint-plugin-react-hooks dependency * Add react hooks lints * Ignore new react hooks lint in tests * Add eslint-plugin-testing-library dependency * Add testing-library lint * Fix yarn lint to use all files recursively * Developer workflow: added auto generated workspace file from vitest extension in vscode (#4997) * chore: added auto generated workspace file from vitest extension in vscode * fix: auto fmt fixes * Change Dependabot PRs to always be made on Mondays (#5025) * Add packages to Dependabot updates (#5024) * Bump @lezer/generator from 1.7.1 to 1.7.2 (#5018) Bumps [@lezer/generator](https://github.com/lezer-parser/generator) from 1.7.1 to 1.7.2. - [Changelog](https://github.com/lezer-parser/generator/blob/main/CHANGELOG.md) - [Commits](https://github.com/lezer-parser/generator/compare/1.7.1...1.7.2) --- updated-dependencies: - dependency-name: "@lezer/generator" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump handlebars from 6.2.0 to 6.3.0 in /src/wasm-lib (#5012) Bumps [handlebars](https://github.com/sunng87/handlebars-rust) from 6.2.0 to 6.3.0. - [Release notes](https://github.com/sunng87/handlebars-rust/releases) - [Changelog](https://github.com/sunng87/handlebars-rust/blob/master/CHANGELOG.md) - [Commits](https://github.com/sunng87/handlebars-rust/compare/v6.2.0...v6.3.0) --- updated-dependencies: - dependency-name: handlebars dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump syn from 2.0.95 to 2.0.96 in /src/wasm-lib (#5015) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.95 to 2.0.96. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.95...2.0.96) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Fix artifact types to be more accurate (#5022) * Fix Cargo.lock to not have changes (#5034) * Upgrade all wasm-bindgen dependencies together (#5037) * Disable auto-updater on non-versioned builds (#5042) * turns on helix from edge (#5036) * updates for new lib Signed-off-by: Jess Frazelle <github@jessfraz.com> * autocomplete Signed-off-by: Jess Frazelle <github@jessfraz.com> * bump version Signed-off-by: Jess Frazelle <github@jessfraz.com> * bump all the things Signed-off-by: Jess Frazelle <github@jessfraz.com> * new samples Signed-off-by: Jess Frazelle <github@jessfraz.com> * docs Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> * ci: Add yarn test of packages/codemirror-lang-kcl (#5035) * ci: Add yarn test of packages/codemirror-lang-kcl * Fix CI error running tests * Fix postcss config error * Bump xstate from 5.17.4 to 5.19.2 (#5027) * Hook up chamfer UI with AST-mod (#4694) * button * config * hook up with ast * cmd bar test * button states fix and test * little naming fix * xState action to actor * remove button state test updates * fixture-based approach * nightly Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com> * Update src/lib/toolbar.ts Co-authored-by: Frank Noirot <frank@zoo.dev> --------- Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com> Co-authored-by: Frank Noirot <frank@zoo.dev> * Remove Redundant Fillet Button State Test (#5009) delete obsolete test * Bump @types/node from 20.14.9 to 22.10.6 in /packages/codemirror-lsp-client (#5041) * custom axis and origin example for helix (#5057) * custom axis and origin for helix Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores) * empty --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * Bump typescript from 5.7.2 to 5.7.3 (#5021) Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.7.2 to 5.7.3. - [Release notes](https://github.com/microsoft/TypeScript/releases) - [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml) - [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.2...v5.7.3) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Refactor: break out `copyFileShareLink` into standalone function * Add "Share file" to command palette * Update dumb use of site URL instead of prod app URL * fmt * @lf94 nit * @pierremtb spinner feedback * Hide share link command and disable menu item for now * Just comment out the command config for now --------- Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: 49lf <ircsurfer33@gmail.com> Co-authored-by: Adam Sunderland <iterion@gmail.com> Co-authored-by: Adam Sunderland <adam@kittycad.io> Co-authored-by: Jonathan Tran <jonnytran@gmail.com> Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com> Co-authored-by: Kevin Nadro <nadr0@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com> Co-authored-by: max <margorskyi@gmail.com>
		
			
				
	
	
		
			438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { test, expect } from './zoo-test'
 | 
						|
import * as fsp from 'fs/promises'
 | 
						|
import { executorInputPath, getUtils } from './test-utils'
 | 
						|
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
 | 
						|
import path from 'path'
 | 
						|
 | 
						|
test.describe('Command bar tests', () => {
 | 
						|
  test('Extrude from command bar selects extrude line after', async ({
 | 
						|
    page,
 | 
						|
    homePage,
 | 
						|
  }) => {
 | 
						|
    await page.addInitScript(async () => {
 | 
						|
      localStorage.setItem(
 | 
						|
        'persistCode',
 | 
						|
        `sketch001 = startSketchOn('XY')
 | 
						|
  |> startProfileAt([-10, -10], %)
 | 
						|
  |> line([20, 0], %)
 | 
						|
  |> line([0, 20], %)
 | 
						|
  |> xLine(-20, %)
 | 
						|
  |> close(%)
 | 
						|
    `
 | 
						|
      )
 | 
						|
    })
 | 
						|
 | 
						|
    const u = await getUtils(page)
 | 
						|
    await page.setBodyDimensions({ width: 1200, height: 500 })
 | 
						|
 | 
						|
    await homePage.goToModelingScene()
 | 
						|
 | 
						|
    await u.openDebugPanel()
 | 
						|
    await u.expectCmdLog('[data-message-type="execution-done"]')
 | 
						|
    await u.closeDebugPanel()
 | 
						|
 | 
						|
    // Click the line of code for xLine.
 | 
						|
    await page.getByText(`close(%)`).click() // TODO remove this and reinstate // await topHorzSegmentClick()
 | 
						|
    await page.waitForTimeout(100)
 | 
						|
 | 
						|
    await page.getByRole('button', { name: 'Extrude' }).click()
 | 
						|
    await page.waitForTimeout(200)
 | 
						|
    await page.keyboard.press('Enter')
 | 
						|
    await page.waitForTimeout(200)
 | 
						|
    await page.keyboard.press('Enter')
 | 
						|
    await page.waitForTimeout(200)
 | 
						|
    await expect(page.locator('.cm-activeLine')).toHaveText(
 | 
						|
      `extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
 | 
						|
    )
 | 
						|
  })
 | 
						|
 | 
						|
  test('Command bar can change a setting, and switch back and forth between arguments', async ({
 | 
						|
    page,
 | 
						|
    homePage,
 | 
						|
  }) => {
 | 
						|
    await page.setBodyDimensions({ width: 1200, height: 500 })
 | 
						|
    await homePage.goToModelingScene()
 | 
						|
 | 
						|
    const commandBarButton = page.getByRole('button', { name: 'Commands' })
 | 
						|
    const cmdSearchBar = page.getByPlaceholder('Search commands')
 | 
						|
    const commandName = 'debug panel'
 | 
						|
    const commandOption = page.getByRole('option', {
 | 
						|
      name: commandName,
 | 
						|
      exact: false,
 | 
						|
    })
 | 
						|
    const commandLevelArgButton = page.getByRole('button', { name: 'level' })
 | 
						|
    const commandThemeArgButton = page.getByRole('button', { name: 'value' })
 | 
						|
    const paneSelector = page.getByRole('button', { name: 'debug panel' })
 | 
						|
    // This selector changes after we set the setting
 | 
						|
    let commandOptionInput = page.getByPlaceholder('On')
 | 
						|
 | 
						|
    await expect(
 | 
						|
      page.getByRole('button', { name: 'Start Sketch' })
 | 
						|
    ).not.toBeDisabled()
 | 
						|
 | 
						|
    // First try opening the command bar and closing it
 | 
						|
    await page
 | 
						|
      .getByRole('button', { name: 'Commands', exact: false })
 | 
						|
      .or(page.getByRole('button', { name: '⌘K' }))
 | 
						|
      .click()
 | 
						|
 | 
						|
    await expect(cmdSearchBar).toBeVisible()
 | 
						|
    await page.keyboard.press('Escape')
 | 
						|
    await expect(cmdSearchBar).not.toBeVisible()
 | 
						|
 | 
						|
    // Now try the same, but with the keyboard shortcut, check focus
 | 
						|
    await page.keyboard.press('ControlOrMeta+K')
 | 
						|
    await expect(cmdSearchBar).toBeVisible()
 | 
						|
    await expect(cmdSearchBar).toBeFocused()
 | 
						|
 | 
						|
    // Try typing in the command bar
 | 
						|
    await cmdSearchBar.fill(commandName)
 | 
						|
    await expect(commandOption).toBeVisible()
 | 
						|
    await commandOption.click()
 | 
						|
    const toggleInput = page.getByPlaceholder('On')
 | 
						|
    await expect(toggleInput).toBeVisible()
 | 
						|
    await expect(toggleInput).toBeFocused()
 | 
						|
    // Select On
 | 
						|
    await page.keyboard.press('ArrowDown')
 | 
						|
    await page.keyboard.press('ArrowDown')
 | 
						|
    await expect(page.getByRole('option', { name: 'Off' })).toHaveAttribute(
 | 
						|
      'data-headlessui-state',
 | 
						|
      'active'
 | 
						|
    )
 | 
						|
    await page.keyboard.press('Enter')
 | 
						|
 | 
						|
    // Check the toast appeared
 | 
						|
    await expect(
 | 
						|
      page.getByText(`Set show debug panel to "false" for this project`)
 | 
						|
    ).toBeVisible()
 | 
						|
    // Check that the visibility changed
 | 
						|
    await expect(paneSelector).not.toBeVisible()
 | 
						|
 | 
						|
    commandOptionInput = page.locator('[id="option-input"]')
 | 
						|
 | 
						|
    // Test case for https://github.com/KittyCAD/modeling-app/issues/2882
 | 
						|
    await commandBarButton.click()
 | 
						|
    await cmdSearchBar.focus()
 | 
						|
    await cmdSearchBar.fill(commandName)
 | 
						|
    await commandOption.click()
 | 
						|
    await expect(commandThemeArgButton).toBeDisabled()
 | 
						|
    await commandOptionInput.focus()
 | 
						|
    await commandOptionInput.fill('on')
 | 
						|
    await commandLevelArgButton.click()
 | 
						|
    await expect(commandLevelArgButton).toBeDisabled()
 | 
						|
 | 
						|
    // Test case for https://github.com/KittyCAD/modeling-app/issues/2881
 | 
						|
    await commandThemeArgButton.click()
 | 
						|
    await expect(commandThemeArgButton).toBeDisabled()
 | 
						|
    await expect(commandLevelArgButton).toHaveText('level: project')
 | 
						|
  })
 | 
						|
 | 
						|
  test('Command bar keybinding works from code editor and can change a setting', async ({
 | 
						|
    page,
 | 
						|
    homePage,
 | 
						|
  }) => {
 | 
						|
    await page.setBodyDimensions({ width: 1200, height: 500 })
 | 
						|
    await homePage.goToModelingScene()
 | 
						|
 | 
						|
    await expect(
 | 
						|
      page.getByRole('button', { name: 'Start Sketch' })
 | 
						|
    ).not.toBeDisabled()
 | 
						|
 | 
						|
    // Put the cursor in the code editor
 | 
						|
    await page.locator('.cm-content').click()
 | 
						|
 | 
						|
    // Now try the same, but with the keyboard shortcut, check focus
 | 
						|
    await page.keyboard.press('ControlOrMeta+K')
 | 
						|
 | 
						|
    let cmdSearchBar = page.getByPlaceholder('Search commands')
 | 
						|
    await expect(cmdSearchBar).toBeVisible()
 | 
						|
    await expect(cmdSearchBar).toBeFocused()
 | 
						|
 | 
						|
    // Try typing in the command bar
 | 
						|
    await cmdSearchBar.fill('theme')
 | 
						|
    const themeOption = page.getByRole('option', {
 | 
						|
      name: 'Settings · app · theme',
 | 
						|
    })
 | 
						|
    await expect(themeOption).toBeVisible()
 | 
						|
    await themeOption.click()
 | 
						|
    const themeInput = page.getByPlaceholder('dark')
 | 
						|
    await expect(themeInput).toBeVisible()
 | 
						|
    await expect(themeInput).toBeFocused()
 | 
						|
    // Select dark theme
 | 
						|
    await page.keyboard.press('ArrowDown')
 | 
						|
    await page.keyboard.press('ArrowDown')
 | 
						|
    await page.keyboard.press('ArrowDown')
 | 
						|
    await expect(page.getByRole('option', { name: 'system' })).toHaveAttribute(
 | 
						|
      'data-headlessui-state',
 | 
						|
      'active'
 | 
						|
    )
 | 
						|
    await page.keyboard.press('Enter')
 | 
						|
 | 
						|
    // Check the toast appeared
 | 
						|
    await expect(
 | 
						|
      page.getByText(`Set theme to "system" as a user default`)
 | 
						|
    ).toBeVisible()
 | 
						|
    // Check that the theme changed
 | 
						|
    await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
 | 
						|
  })
 | 
						|
 | 
						|
  test('Can extrude from the command bar', async ({ page, homePage }) => {
 | 
						|
    await page.addInitScript(async () => {
 | 
						|
      localStorage.setItem(
 | 
						|
        'persistCode',
 | 
						|
        `distance = sqrt(20)
 | 
						|
    sketch001 = startSketchOn('XZ')
 | 
						|
    |> startProfileAt([-6.95, 10.98], %)
 | 
						|
    |> line([25.1, 0.41], %)
 | 
						|
    |> line([0.73, -20.93], %)
 | 
						|
    |> line([-23.44, 0.52], %)
 | 
						|
    |> close(%)
 | 
						|
        `
 | 
						|
      )
 | 
						|
    })
 | 
						|
 | 
						|
    const u = await getUtils(page)
 | 
						|
    await page.setBodyDimensions({ width: 1200, height: 500 })
 | 
						|
 | 
						|
    await homePage.goToModelingScene()
 | 
						|
 | 
						|
    // Make sure the stream is up
 | 
						|
    await u.openDebugPanel()
 | 
						|
    await u.expectCmdLog('[data-message-type="execution-done"]')
 | 
						|
 | 
						|
    await expect(
 | 
						|
      page.getByRole('button', { name: 'Start Sketch' })
 | 
						|
    ).not.toBeDisabled()
 | 
						|
    await u.clearCommandLogs()
 | 
						|
    await page.getByRole('button', { name: 'Extrude' }).isEnabled()
 | 
						|
 | 
						|
    let cmdSearchBar = page.getByPlaceholder('Search commands')
 | 
						|
    await page.keyboard.press('ControlOrMeta+K')
 | 
						|
    await expect(cmdSearchBar).toBeVisible()
 | 
						|
 | 
						|
    // Search for extrude command and choose it
 | 
						|
    await page.getByRole('option', { name: 'Extrude' }).click()
 | 
						|
 | 
						|
    // Assert that we're on the selection step
 | 
						|
    await expect(page.getByRole('button', { name: 'selection' })).toBeDisabled()
 | 
						|
    // Select a face
 | 
						|
    await page.mouse.move(700, 200)
 | 
						|
    await page.mouse.click(700, 200)
 | 
						|
 | 
						|
    // Assert that we're on the distance step
 | 
						|
    await expect(
 | 
						|
      page.getByRole('button', { name: 'distance', exact: false })
 | 
						|
    ).toBeDisabled()
 | 
						|
 | 
						|
    // Assert that the an alternative variable name is chosen,
 | 
						|
    // since the default variable name is already in use (distance)
 | 
						|
    await page.getByRole('button', { name: 'Create new variable' }).click()
 | 
						|
    await expect(page.getByPlaceholder('Variable name')).toHaveValue(
 | 
						|
      'distance001'
 | 
						|
    )
 | 
						|
 | 
						|
    const continueButton = page.getByRole('button', { name: 'Continue' })
 | 
						|
    const submitButton = page.getByRole('button', { name: 'Submit command' })
 | 
						|
    await continueButton.click()
 | 
						|
 | 
						|
    // Review step and argument hotkeys
 | 
						|
    await expect(submitButton).toBeEnabled()
 | 
						|
    await expect(submitButton).toBeFocused()
 | 
						|
    await submitButton.press('Backspace')
 | 
						|
 | 
						|
    // Assert we're back on the distance step
 | 
						|
    await expect(
 | 
						|
      page.getByRole('button', { name: 'distance', exact: false })
 | 
						|
    ).toBeDisabled()
 | 
						|
 | 
						|
    await continueButton.click()
 | 
						|
    await submitButton.click()
 | 
						|
 | 
						|
    await u.waitForCmdReceive('extrude')
 | 
						|
 | 
						|
    await expect(page.locator('.cm-content')).toContainText(
 | 
						|
      'extrude001 = extrude(distance001, sketch001)'
 | 
						|
    )
 | 
						|
  })
 | 
						|
 | 
						|
  test('Can switch between sketch tools via command bar', async ({
 | 
						|
    page,
 | 
						|
    homePage,
 | 
						|
  }) => {
 | 
						|
    await page.setBodyDimensions({ width: 1200, height: 500 })
 | 
						|
    await homePage.goToModelingScene()
 | 
						|
 | 
						|
    const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
 | 
						|
    const cmdBarButton = page.getByRole('button', { name: 'Commands' })
 | 
						|
    const rectangleToolCommand = page.getByRole('option', {
 | 
						|
      name: 'rectangle',
 | 
						|
    })
 | 
						|
    const rectangleToolButton = page.getByRole('button', {
 | 
						|
      name: 'rectangle Corner rectangle',
 | 
						|
    })
 | 
						|
    const lineToolCommand = page.getByRole('option', {
 | 
						|
      name: 'Line',
 | 
						|
    })
 | 
						|
    const lineToolButton = page.getByRole('button', {
 | 
						|
      name: 'line Line',
 | 
						|
      exact: true,
 | 
						|
    })
 | 
						|
    const arcToolCommand = page.getByRole('option', { name: 'Tangential Arc' })
 | 
						|
    const arcToolButton = page.getByRole('button', {
 | 
						|
      name: 'arc Tangential Arc',
 | 
						|
    })
 | 
						|
 | 
						|
    // Start a sketch
 | 
						|
    await sketchButton.click()
 | 
						|
    await page.mouse.click(700, 200)
 | 
						|
 | 
						|
    // Switch between sketch tools via the command bar
 | 
						|
    await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
 | 
						|
    await cmdBarButton.click()
 | 
						|
    await rectangleToolCommand.click()
 | 
						|
    await expect(rectangleToolButton).toHaveAttribute('aria-pressed', 'true')
 | 
						|
    await cmdBarButton.click()
 | 
						|
    await lineToolCommand.click()
 | 
						|
    await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
 | 
						|
 | 
						|
    // Click in the scene a couple times to draw a line
 | 
						|
    // so tangential arc is valid
 | 
						|
    await page.mouse.click(700, 200)
 | 
						|
    await page.mouse.move(700, 300, { steps: 5 })
 | 
						|
    await page.mouse.click(700, 300)
 | 
						|
 | 
						|
    // switch to tangential arc via command bar
 | 
						|
    await cmdBarButton.click()
 | 
						|
    await arcToolCommand.click()
 | 
						|
    await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true')
 | 
						|
  })
 | 
						|
 | 
						|
  test(`Reacts to query param to open "import from URL" command`, async ({
 | 
						|
    page,
 | 
						|
    cmdBar,
 | 
						|
    editor,
 | 
						|
    homePage,
 | 
						|
  }) => {
 | 
						|
    await test.step(`Prepare and navigate to home page with query params`, async () => {
 | 
						|
      const targetURL = `?create-file&name=test&units=mm&code=ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D&ask-open-desktop`
 | 
						|
      await homePage.expectState({
 | 
						|
        projectCards: [],
 | 
						|
        sortBy: 'last-modified-desc',
 | 
						|
      })
 | 
						|
      await page.goto(page.url() + targetURL)
 | 
						|
      expect(page.url()).toContain(targetURL)
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step(`Submit the command`, async () => {
 | 
						|
      await cmdBar.expectState({
 | 
						|
        stage: 'arguments',
 | 
						|
        commandName: 'Import file from URL',
 | 
						|
        currentArgKey: 'method',
 | 
						|
        currentArgValue: '',
 | 
						|
        headerArguments: {
 | 
						|
          Method: '',
 | 
						|
          Name: 'test',
 | 
						|
          Code: '1 line',
 | 
						|
        },
 | 
						|
        highlightedHeaderArg: 'method',
 | 
						|
      })
 | 
						|
      await cmdBar.selectOption({ name: 'New Project' }).click()
 | 
						|
      await cmdBar.expectState({
 | 
						|
        stage: 'review',
 | 
						|
        commandName: 'Import file from URL',
 | 
						|
        headerArguments: {
 | 
						|
          Method: 'New project',
 | 
						|
          Name: 'test',
 | 
						|
          Code: '1 line',
 | 
						|
        },
 | 
						|
      })
 | 
						|
      await cmdBar.progressCmdBar()
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
 | 
						|
      await editor.expectEditor.toContain('extrusionDistance = 12')
 | 
						|
    })
 | 
						|
  })
 | 
						|
 | 
						|
  test(`"import from URL" can add to existing project`, async ({
 | 
						|
    page,
 | 
						|
    cmdBar,
 | 
						|
    editor,
 | 
						|
    homePage,
 | 
						|
    toolbar,
 | 
						|
    context,
 | 
						|
  }) => {
 | 
						|
    await context.folderSetupFn(async (dir) => {
 | 
						|
      const testProjectDir = path.join(dir, 'testProjectDir')
 | 
						|
      await Promise.all([fsp.mkdir(testProjectDir, { recursive: true })])
 | 
						|
      await Promise.all([
 | 
						|
        fsp.copyFile(
 | 
						|
          executorInputPath('cylinder.kcl'),
 | 
						|
          path.join(testProjectDir, 'main.kcl')
 | 
						|
        ),
 | 
						|
      ])
 | 
						|
    })
 | 
						|
    await test.step(`Prepare and navigate to home page with query params`, async () => {
 | 
						|
      const targetURL = `?create-file&name=test&units=mm&code=ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D&ask-open-desktop`
 | 
						|
      await homePage.expectState({
 | 
						|
        projectCards: [
 | 
						|
          {
 | 
						|
            fileCount: 1,
 | 
						|
            title: 'testProjectDir',
 | 
						|
          },
 | 
						|
        ],
 | 
						|
        sortBy: 'last-modified-desc',
 | 
						|
      })
 | 
						|
      await page.goto(page.url() + targetURL)
 | 
						|
      expect(page.url()).toContain(targetURL)
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step(`Submit the command`, async () => {
 | 
						|
      await cmdBar.expectState({
 | 
						|
        stage: 'arguments',
 | 
						|
        commandName: 'Import file from URL',
 | 
						|
        currentArgKey: 'method',
 | 
						|
        currentArgValue: '',
 | 
						|
        headerArguments: {
 | 
						|
          Method: '',
 | 
						|
          Name: 'test',
 | 
						|
          Code: '1 line',
 | 
						|
        },
 | 
						|
        highlightedHeaderArg: 'method',
 | 
						|
      })
 | 
						|
      await cmdBar.selectOption({ name: 'Existing Project' }).click()
 | 
						|
      await cmdBar.expectState({
 | 
						|
        stage: 'arguments',
 | 
						|
        commandName: 'Import file from URL',
 | 
						|
        currentArgKey: 'projectName',
 | 
						|
        currentArgValue: '',
 | 
						|
        headerArguments: {
 | 
						|
          Method: 'Existing project',
 | 
						|
          Name: 'test',
 | 
						|
          ProjectName: '',
 | 
						|
          Code: '1 line',
 | 
						|
        },
 | 
						|
        highlightedHeaderArg: 'projectName',
 | 
						|
      })
 | 
						|
      await cmdBar.selectOption({ name: 'testProjectDir' }).click()
 | 
						|
      await cmdBar.expectState({
 | 
						|
        stage: 'review',
 | 
						|
        commandName: 'Import file from URL',
 | 
						|
        headerArguments: {
 | 
						|
          Method: 'Existing project',
 | 
						|
          ProjectName: 'testProjectDir',
 | 
						|
          Name: 'test',
 | 
						|
          Code: '1 line',
 | 
						|
        },
 | 
						|
      })
 | 
						|
      await cmdBar.progressCmdBar()
 | 
						|
    })
 | 
						|
 | 
						|
    await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
 | 
						|
      await editor.expectEditor.toContain('extrusionDistance = 12')
 | 
						|
      await toolbar.openPane('files')
 | 
						|
      await toolbar.expectFileTreeState(['main.kcl', 'test.kcl'])
 | 
						|
    })
 | 
						|
  })
 | 
						|
})
 |