Fix existing: file renaming (and more things that spin out of settings file path parsing) (#3584)
* Fix the behavior so that we navigate to the new file path * This change is done in other PRs but is also necessary here * Add an Electron Playwright test for renaming a file * Add tests for renaming dir, one is failing * Don't need that console.warn * Add DeepPartial utility type * Fix settings parsing so that project path parsing is fixed * Move URL check after DOM checks * Revert this fallback behavior from https://github.com/KittyCAD/modeling-app/pull/3564 as we don't need it now that config parsing is fixed * Make new bad prompt each run * Fix onboarding asset path in web * Remove double parsing of settings config * Remove unused imports * More unused imports * Fix broken rename test * Update src/lib/desktop.ts Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch> * Add test for renaming file we do not have open * fmt --------- Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
This commit is contained in:
		@ -10,6 +10,7 @@ import {
 | 
			
		||||
import fsp from 'fs/promises'
 | 
			
		||||
import fs from 'fs'
 | 
			
		||||
import { join } from 'path'
 | 
			
		||||
import { FILE_EXT } from 'lib/constants'
 | 
			
		||||
 | 
			
		||||
test.afterEach(async ({ page }, testInfo) => {
 | 
			
		||||
  await tearDown(page, testInfo)
 | 
			
		||||
@ -1337,3 +1338,369 @@ test(
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
test.describe('Renaming in the file tree', () => {
 | 
			
		||||
  test(
 | 
			
		||||
    'A file you have open',
 | 
			
		||||
    { tag: '@electron' },
 | 
			
		||||
    async ({ browser: _ }, testInfo) => {
 | 
			
		||||
      test.skip(
 | 
			
		||||
        process.platform === 'win32',
 | 
			
		||||
        'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
 | 
			
		||||
      )
 | 
			
		||||
      const { electronApp, page } = await setupElectron({
 | 
			
		||||
        testInfo,
 | 
			
		||||
        folderSetupFn: async (dir) => {
 | 
			
		||||
          await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
 | 
			
		||||
          const exampleDir = join(
 | 
			
		||||
            'src',
 | 
			
		||||
            'wasm-lib',
 | 
			
		||||
            'tests',
 | 
			
		||||
            'executor',
 | 
			
		||||
            'inputs'
 | 
			
		||||
          )
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'basic_fillet_cube_end.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'main.kcl')
 | 
			
		||||
          )
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'cylinder.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'fileToRename.kcl')
 | 
			
		||||
          )
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
      const u = await getUtils(page)
 | 
			
		||||
      await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
      page.on('console', console.log)
 | 
			
		||||
 | 
			
		||||
      // Constants and locators
 | 
			
		||||
      const projectLink = page.getByText('Test Project')
 | 
			
		||||
      const projectMenuButton = page.getByTestId('project-sidebar-toggle')
 | 
			
		||||
      const fileToRename = page
 | 
			
		||||
        .getByRole('listitem')
 | 
			
		||||
        .filter({ has: page.getByRole('button', { name: 'fileToRename.kcl' }) })
 | 
			
		||||
      const renamedFile = page
 | 
			
		||||
        .getByRole('listitem')
 | 
			
		||||
        .filter({ has: page.getByRole('button', { name: 'newFileName.kcl' }) })
 | 
			
		||||
      const renameMenuItem = page.getByRole('button', { name: 'Rename' })
 | 
			
		||||
      const renameInput = page.getByPlaceholder('fileToRename.kcl')
 | 
			
		||||
      const newFileName = 'newFileName'
 | 
			
		||||
      const codeLocator = page.locator('.cm-content')
 | 
			
		||||
 | 
			
		||||
      await test.step('Open project and file pane', async () => {
 | 
			
		||||
        await expect(projectLink).toBeVisible()
 | 
			
		||||
        await projectLink.click()
 | 
			
		||||
        await expect(projectMenuButton).toBeVisible()
 | 
			
		||||
        await expect(projectMenuButton).toContainText('main.kcl')
 | 
			
		||||
 | 
			
		||||
        await u.openFilePanel()
 | 
			
		||||
        await expect(fileToRename).toBeVisible()
 | 
			
		||||
        await fileToRename.click()
 | 
			
		||||
        await expect(projectMenuButton).toContainText('fileToRename.kcl')
 | 
			
		||||
        await u.openKclCodePanel()
 | 
			
		||||
        await expect(codeLocator).toContainText('circle(')
 | 
			
		||||
        await u.closeKclCodePanel()
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Rename the file', async () => {
 | 
			
		||||
        await fileToRename.click({ button: 'right' })
 | 
			
		||||
        await renameMenuItem.click()
 | 
			
		||||
        await expect(renameInput).toBeVisible()
 | 
			
		||||
        await renameInput.fill(newFileName)
 | 
			
		||||
        await page.keyboard.press('Enter')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Verify the file is renamed', async () => {
 | 
			
		||||
        await expect(fileToRename).not.toBeAttached()
 | 
			
		||||
        await expect(renamedFile).toBeVisible()
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Verify we navigated', async () => {
 | 
			
		||||
        await expect(projectMenuButton).toContainText(newFileName + FILE_EXT)
 | 
			
		||||
        const url = page.url()
 | 
			
		||||
        expect(url).toContain(newFileName)
 | 
			
		||||
        await expect(projectMenuButton).not.toContainText('fileToRename.kcl')
 | 
			
		||||
        await expect(projectMenuButton).not.toContainText('main.kcl')
 | 
			
		||||
        expect(url).not.toContain('fileToRename.kcl')
 | 
			
		||||
        expect(url).not.toContain('main.kcl')
 | 
			
		||||
 | 
			
		||||
        await u.openKclCodePanel()
 | 
			
		||||
        await expect(codeLocator).toContainText('circle(')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await electronApp.close()
 | 
			
		||||
    }
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  test(
 | 
			
		||||
    'A file you do not have open',
 | 
			
		||||
    { tag: '@electron' },
 | 
			
		||||
    async ({ browser: _ }, testInfo) => {
 | 
			
		||||
      test.skip(
 | 
			
		||||
        process.platform === 'win32',
 | 
			
		||||
        'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
 | 
			
		||||
      )
 | 
			
		||||
      const { electronApp, page } = await setupElectron({
 | 
			
		||||
        testInfo,
 | 
			
		||||
        folderSetupFn: async (dir) => {
 | 
			
		||||
          await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
 | 
			
		||||
          const exampleDir = join(
 | 
			
		||||
            'src',
 | 
			
		||||
            'wasm-lib',
 | 
			
		||||
            'tests',
 | 
			
		||||
            'executor',
 | 
			
		||||
            'inputs'
 | 
			
		||||
          )
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'basic_fillet_cube_end.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'main.kcl')
 | 
			
		||||
          )
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'cylinder.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'fileToRename.kcl')
 | 
			
		||||
          )
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
      const u = await getUtils(page)
 | 
			
		||||
      await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
      page.on('console', console.log)
 | 
			
		||||
 | 
			
		||||
      // Constants and locators
 | 
			
		||||
      const newFileName = 'newFileName'
 | 
			
		||||
      const projectLink = page.getByText('Test Project')
 | 
			
		||||
      const projectMenuButton = page.getByTestId('project-sidebar-toggle')
 | 
			
		||||
      const fileToRename = page
 | 
			
		||||
        .getByRole('listitem')
 | 
			
		||||
        .filter({ has: page.getByRole('button', { name: 'fileToRename.kcl' }) })
 | 
			
		||||
      const renamedFile = page.getByRole('listitem').filter({
 | 
			
		||||
        has: page.getByRole('button', { name: newFileName + FILE_EXT }),
 | 
			
		||||
      })
 | 
			
		||||
      const renameMenuItem = page.getByRole('button', { name: 'Rename' })
 | 
			
		||||
      const renameInput = page.getByPlaceholder('fileToRename.kcl')
 | 
			
		||||
      const codeLocator = page.locator('.cm-content')
 | 
			
		||||
 | 
			
		||||
      await test.step('Open project and file pane', async () => {
 | 
			
		||||
        await expect(projectLink).toBeVisible()
 | 
			
		||||
        await projectLink.click()
 | 
			
		||||
        await expect(projectMenuButton).toBeVisible()
 | 
			
		||||
        await expect(projectMenuButton).toContainText('main.kcl')
 | 
			
		||||
 | 
			
		||||
        await u.openFilePanel()
 | 
			
		||||
        await expect(fileToRename).toBeVisible()
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Rename the file', async () => {
 | 
			
		||||
        await fileToRename.click({ button: 'right' })
 | 
			
		||||
        await renameMenuItem.click()
 | 
			
		||||
        await expect(renameInput).toBeVisible()
 | 
			
		||||
        await renameInput.fill(newFileName)
 | 
			
		||||
        await page.keyboard.press('Enter')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Verify the file is renamed', async () => {
 | 
			
		||||
        await expect(fileToRename).not.toBeAttached()
 | 
			
		||||
        await expect(renamedFile).toBeVisible()
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Verify we have not navigated', async () => {
 | 
			
		||||
        await expect(projectMenuButton).toContainText('main.kcl')
 | 
			
		||||
        await expect(projectMenuButton).not.toContainText(
 | 
			
		||||
          newFileName + FILE_EXT
 | 
			
		||||
        )
 | 
			
		||||
        await expect(projectMenuButton).not.toContainText('fileToRename.kcl')
 | 
			
		||||
 | 
			
		||||
        const url = page.url()
 | 
			
		||||
        expect(url).toContain('main.kcl')
 | 
			
		||||
        expect(url).not.toContain(newFileName)
 | 
			
		||||
        expect(url).not.toContain('fileToRename.kcl')
 | 
			
		||||
 | 
			
		||||
        await u.openKclCodePanel()
 | 
			
		||||
        await expect(codeLocator).toContainText('fillet(')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await electronApp.close()
 | 
			
		||||
    }
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  test(
 | 
			
		||||
    `A folder you're not inside`,
 | 
			
		||||
    { tag: '@electron' },
 | 
			
		||||
    async ({ browser: _ }, testInfo) => {
 | 
			
		||||
      test.skip(
 | 
			
		||||
        process.platform === 'win32',
 | 
			
		||||
        'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
 | 
			
		||||
      )
 | 
			
		||||
      const { electronApp, page } = await setupElectron({
 | 
			
		||||
        testInfo,
 | 
			
		||||
        folderSetupFn: async (dir) => {
 | 
			
		||||
          await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
 | 
			
		||||
          await fsp.mkdir(join(dir, 'Test Project', 'folderToRename'), {
 | 
			
		||||
            recursive: true,
 | 
			
		||||
          })
 | 
			
		||||
          const exampleDir = join(
 | 
			
		||||
            'src',
 | 
			
		||||
            'wasm-lib',
 | 
			
		||||
            'tests',
 | 
			
		||||
            'executor',
 | 
			
		||||
            'inputs'
 | 
			
		||||
          )
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'basic_fillet_cube_end.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'main.kcl')
 | 
			
		||||
          )
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'cylinder.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'folderToRename', 'someFileWithin.kcl')
 | 
			
		||||
          )
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      const u = await getUtils(page)
 | 
			
		||||
      await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
      page.on('console', console.log)
 | 
			
		||||
 | 
			
		||||
      // Constants and locators
 | 
			
		||||
      const projectLink = page.getByText('Test Project')
 | 
			
		||||
      const projectMenuButton = page.getByTestId('project-sidebar-toggle')
 | 
			
		||||
      const folderToRename = page.getByRole('button', {
 | 
			
		||||
        name: 'folderToRename',
 | 
			
		||||
      })
 | 
			
		||||
      const renamedFolder = page.getByRole('button', { name: 'newFolderName' })
 | 
			
		||||
      const renameMenuItem = page.getByRole('button', { name: 'Rename' })
 | 
			
		||||
      const renameInput = page.getByPlaceholder('folderToRename')
 | 
			
		||||
      const newFolderName = 'newFolderName'
 | 
			
		||||
 | 
			
		||||
      await test.step('Open project and file pane', async () => {
 | 
			
		||||
        await expect(projectLink).toBeVisible()
 | 
			
		||||
        await projectLink.click()
 | 
			
		||||
        await expect(projectMenuButton).toBeVisible()
 | 
			
		||||
        await expect(projectMenuButton).toContainText('main.kcl')
 | 
			
		||||
 | 
			
		||||
        const url = page.url()
 | 
			
		||||
        expect(url).toContain('main.kcl')
 | 
			
		||||
        expect(url).not.toContain('folderToRename')
 | 
			
		||||
 | 
			
		||||
        await u.openFilePanel()
 | 
			
		||||
        await expect(folderToRename).toBeVisible()
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Rename the folder', async () => {
 | 
			
		||||
        await folderToRename.click({ button: 'right' })
 | 
			
		||||
        await expect(renameMenuItem).toBeVisible()
 | 
			
		||||
        await renameMenuItem.click()
 | 
			
		||||
        await expect(renameInput).toBeVisible()
 | 
			
		||||
        await renameInput.fill(newFolderName)
 | 
			
		||||
        await page.keyboard.press('Enter')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Verify the folder is renamed, and no navigation occurred', async () => {
 | 
			
		||||
        const url = page.url()
 | 
			
		||||
        expect(url).toContain('main.kcl')
 | 
			
		||||
        expect(url).not.toContain('folderToRename')
 | 
			
		||||
 | 
			
		||||
        await expect(projectMenuButton).toContainText('main.kcl')
 | 
			
		||||
        await expect(renamedFolder).toBeVisible()
 | 
			
		||||
        await expect(folderToRename).not.toBeAttached()
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await electronApp.close()
 | 
			
		||||
    }
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  test(
 | 
			
		||||
    `A folder you are inside`,
 | 
			
		||||
    { tag: '@electron' },
 | 
			
		||||
    async ({ browser: _ }, testInfo) => {
 | 
			
		||||
      test.skip(
 | 
			
		||||
        process.platform === 'win32',
 | 
			
		||||
        'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
 | 
			
		||||
      )
 | 
			
		||||
      const exampleDir = join('src', 'wasm-lib', 'tests', 'executor', 'inputs')
 | 
			
		||||
      const { electronApp, page } = await setupElectron({
 | 
			
		||||
        testInfo,
 | 
			
		||||
        folderSetupFn: async (dir) => {
 | 
			
		||||
          await fsp.mkdir(join(dir, 'Test Project'), { recursive: true })
 | 
			
		||||
          await fsp.mkdir(join(dir, 'Test Project', 'folderToRename'), {
 | 
			
		||||
            recursive: true,
 | 
			
		||||
          })
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'basic_fillet_cube_end.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'main.kcl')
 | 
			
		||||
          )
 | 
			
		||||
          await fsp.copyFile(
 | 
			
		||||
            join(exampleDir, 'cylinder.kcl'),
 | 
			
		||||
            join(dir, 'Test Project', 'folderToRename', 'someFileWithin.kcl')
 | 
			
		||||
          )
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      const u = await getUtils(page)
 | 
			
		||||
      await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
      page.on('console', console.log)
 | 
			
		||||
 | 
			
		||||
      // Constants and locators
 | 
			
		||||
      const projectLink = page.getByText('Test Project')
 | 
			
		||||
      const projectMenuButton = page.getByTestId('project-sidebar-toggle')
 | 
			
		||||
      const folderToRename = page.getByRole('button', {
 | 
			
		||||
        name: 'folderToRename',
 | 
			
		||||
      })
 | 
			
		||||
      const renamedFolder = page.getByRole('button', { name: 'newFolderName' })
 | 
			
		||||
      const fileWithinFolder = page.getByRole('listitem').filter({
 | 
			
		||||
        has: page.getByRole('button', { name: 'someFileWithin.kcl' }),
 | 
			
		||||
      })
 | 
			
		||||
      const renameMenuItem = page.getByRole('button', { name: 'Rename' })
 | 
			
		||||
      const renameInput = page.getByPlaceholder('folderToRename')
 | 
			
		||||
      const newFolderName = 'newFolderName'
 | 
			
		||||
 | 
			
		||||
      await test.step('Open project and navigate into folder', async () => {
 | 
			
		||||
        await expect(projectLink).toBeVisible()
 | 
			
		||||
        await projectLink.click()
 | 
			
		||||
        await expect(projectMenuButton).toBeVisible()
 | 
			
		||||
        await expect(projectMenuButton).toContainText('main.kcl')
 | 
			
		||||
 | 
			
		||||
        const url = page.url()
 | 
			
		||||
        expect(url).toContain('main.kcl')
 | 
			
		||||
        expect(url).not.toContain('folderToRename')
 | 
			
		||||
 | 
			
		||||
        await u.openFilePanel()
 | 
			
		||||
        await expect(folderToRename).toBeVisible()
 | 
			
		||||
        await folderToRename.click()
 | 
			
		||||
        await expect(fileWithinFolder).toBeVisible()
 | 
			
		||||
        await fileWithinFolder.click()
 | 
			
		||||
 | 
			
		||||
        await expect(projectMenuButton).toContainText('someFileWithin.kcl')
 | 
			
		||||
        const newUrl = page.url()
 | 
			
		||||
        expect(newUrl).toContain('folderToRename')
 | 
			
		||||
        expect(newUrl).toContain('someFileWithin.kcl')
 | 
			
		||||
        expect(newUrl).not.toContain('main.kcl')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Rename the folder', async () => {
 | 
			
		||||
        await folderToRename.click({ button: 'right' })
 | 
			
		||||
        await expect(renameMenuItem).toBeVisible()
 | 
			
		||||
        await renameMenuItem.click()
 | 
			
		||||
        await expect(renameInput).toBeVisible()
 | 
			
		||||
        await renameInput.fill(newFolderName)
 | 
			
		||||
        await page.keyboard.press('Enter')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await test.step('Verify the folder is renamed, and navigated to new path', async () => {
 | 
			
		||||
        const urlSnippet = encodeURIComponent(
 | 
			
		||||
          join(newFolderName, 'someFileWithin.kcl')
 | 
			
		||||
        )
 | 
			
		||||
        await page.waitForURL(new RegExp(urlSnippet))
 | 
			
		||||
        await expect(projectMenuButton).toContainText('someFileWithin.kcl')
 | 
			
		||||
        await expect(renamedFolder).toBeVisible()
 | 
			
		||||
        await expect(folderToRename).not.toBeAttached()
 | 
			
		||||
 | 
			
		||||
        // URL is synchronous, so we check the other stuff first
 | 
			
		||||
        const url = page.url()
 | 
			
		||||
        expect(url).not.toContain('main.kcl')
 | 
			
		||||
        expect(url).toContain(newFolderName)
 | 
			
		||||
        expect(url).toContain('someFileWithin.kcl')
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await electronApp.close()
 | 
			
		||||
    }
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user