initial playwright setup and test (#1039)
* initial playwright setup and test * try verbose logging * double check resolution * double check token * remove logs * try running on ubuntu and macos * move e2e tests * vitest ignores playwright tests * add a series of tests * tweak yarn setup * typo * update fmt * action typo * rust toolchain? * remove .only from playwright test * A snapshot a day keeps the bugs away! 📷🐛 * A snapshot a day keeps the bugs away! 📷🐛 * add pan and zoom back * try puting os in commit message * A snapshot a day keeps the bugs away! 📷🐛 .os * A snapshot a day keeps the bugs away! 📷🐛 .os * fix commit message * A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-latest) * add command logs to UI for axis tests * typo * fmt * remove .only * add auto complete test * remove .only * update queries to be more playwright recommended * move test utils * remove waits from first test * remove old snapshots * re-arrange files and tests * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * trigger CI * refactor plane test * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * remove .only * try longer wait * try snap shoting * fmt * better CI names * fix * fix linux * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * try make executes on load a bit more robust * fix * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * stabilise snapshots * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-latest) * make tests run linearly * update naming * tidy * .only * update readme * trigger CI * add set tool * util clean up * update readme * readme tweaks * self-review clean up * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * tweak * update readme * Ensure Vite preview server is running before running any Playwright tests (#1114) * Ensure that Vite is serving before tests run * Don't break secrets if developer has extra blank line in env file * @mxschmitt's suggestions * fix * add wait-on types * tsconfig fix * update readme * code template for sktech on each plane test --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Frank Noirot <frank@kittycad.io>
This commit is contained in:
		
							
								
								
									
										394
									
								
								e2e/playwright/flow-tests.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								e2e/playwright/flow-tests.spec.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,394 @@
 | 
			
		||||
import { test, expect } from '@playwright/test'
 | 
			
		||||
import { secrets } from './secrets'
 | 
			
		||||
import { EngineCommand } from '../../src/lang/std/engineConnection'
 | 
			
		||||
import { v4 as uuidv4 } from 'uuid'
 | 
			
		||||
import { getUtils } from './test-utils'
 | 
			
		||||
import waitOn from 'wait-on'
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
 | 
			
		||||
just from the nature of the stream, running the test with debugger and pasting the below
 | 
			
		||||
into the console can be useful to get coords
 | 
			
		||||
 | 
			
		||||
document.addEventListener('mousemove', (e) =>
 | 
			
		||||
  console.log(`await page.mouse.click(${e.clientX}, ${e.clientY})`)
 | 
			
		||||
)
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
test.beforeEach(async ({ context, page }) => {
 | 
			
		||||
  // wait for Vite preview server to be up
 | 
			
		||||
  await waitOn({
 | 
			
		||||
    resources: ['tcp:3000'],
 | 
			
		||||
    timeout: 5000,
 | 
			
		||||
  })
 | 
			
		||||
  await context.addInitScript(async (token) => {
 | 
			
		||||
    localStorage.setItem('TOKEN_PERSIST_KEY', token)
 | 
			
		||||
    localStorage.setItem('persistCode', ``)
 | 
			
		||||
    localStorage.setItem(
 | 
			
		||||
      'SETTINGS_PERSIST_KEY',
 | 
			
		||||
      JSON.stringify({
 | 
			
		||||
        baseUnit: 'in',
 | 
			
		||||
        cameraControls: 'KittyCAD',
 | 
			
		||||
        defaultDirectory: '',
 | 
			
		||||
        defaultProjectName: 'project-$nnn',
 | 
			
		||||
        onboardingStatus: 'dismissed',
 | 
			
		||||
        showDebugPanel: true,
 | 
			
		||||
        textWrapping: 'On',
 | 
			
		||||
        theme: 'system',
 | 
			
		||||
        unitSystem: 'imperial',
 | 
			
		||||
      })
 | 
			
		||||
    )
 | 
			
		||||
  }, secrets.token)
 | 
			
		||||
  // kill animations, speeds up tests and reduced flakiness
 | 
			
		||||
  await page.emulateMedia({ reducedMotion: 'reduce' })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test.setTimeout(60000)
 | 
			
		||||
 | 
			
		||||
test('Basic sketch', async ({ page }) => {
 | 
			
		||||
  const u = getUtils(page)
 | 
			
		||||
  await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
  const PUR = 400 / 37.5 //pixeltoUnitRatio
 | 
			
		||||
  await page.goto('localhost:3000')
 | 
			
		||||
  await u.waitForAuthSkipAppStart()
 | 
			
		||||
  await u.openDebugPanel()
 | 
			
		||||
  await u.waitForDefaultPlanesVisibilityChange()
 | 
			
		||||
 | 
			
		||||
  await expect(page.getByRole('button', { name: 'Start Sketch' })).toBeVisible()
 | 
			
		||||
 | 
			
		||||
  // click on "Start Sketch" button
 | 
			
		||||
  await u.clearCommandLogs()
 | 
			
		||||
  await page.getByRole('button', { name: 'Start Sketch' }).click()
 | 
			
		||||
  await u.waitForDefaultPlanesVisibilityChange()
 | 
			
		||||
 | 
			
		||||
  // select a plane
 | 
			
		||||
  await u.doAndWaitForCmd(() => page.mouse.click(700, 200), 'edit_mode_enter')
 | 
			
		||||
  await u.waitForCmdReceive('set_tool')
 | 
			
		||||
 | 
			
		||||
  await u.doAndWaitForCmd(
 | 
			
		||||
    () => page.getByRole('button', { name: 'Line' }).click(),
 | 
			
		||||
    'set_tool'
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const startXPx = 600
 | 
			
		||||
  await u.doAndWaitForCmd(
 | 
			
		||||
    () => page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10),
 | 
			
		||||
    'mouse_click',
 | 
			
		||||
    false
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
 | 
			
		||||
 | 
			
		||||
  const startAt = '[9.94, -13.41]'
 | 
			
		||||
  const tenish = '10.03'
 | 
			
		||||
  await expect(page.locator('.cm-content'))
 | 
			
		||||
    .toHaveText(`const part001 = startSketchOn('-XZ')
 | 
			
		||||
  |> startProfileAt(${startAt}, %)
 | 
			
		||||
  |> line([${tenish}, 0], %)`)
 | 
			
		||||
 | 
			
		||||
  await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
 | 
			
		||||
  await expect(page.locator('.cm-content'))
 | 
			
		||||
    .toHaveText(`const part001 = startSketchOn('-XZ')
 | 
			
		||||
  |> startProfileAt(${startAt}, %)
 | 
			
		||||
  |> line([${tenish}, 0], %)
 | 
			
		||||
  |> line([0, ${tenish}], %)`)
 | 
			
		||||
  await page.mouse.click(startXPx, 500 - PUR * 20)
 | 
			
		||||
  await expect(page.locator('.cm-content'))
 | 
			
		||||
    .toHaveText(`const part001 = startSketchOn('-XZ')
 | 
			
		||||
  |> startProfileAt(${startAt}, %)
 | 
			
		||||
  |> line([${tenish}, 0], %)
 | 
			
		||||
  |> line([0, ${tenish}], %)
 | 
			
		||||
  |> line([-19.97, 0], %)`)
 | 
			
		||||
 | 
			
		||||
  // deselect line tool
 | 
			
		||||
  await u.doAndWaitForCmd(
 | 
			
		||||
    () => page.getByRole('button', { name: 'Line' }).click(),
 | 
			
		||||
    'set_tool'
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  // click between first two clicks to get center of the line
 | 
			
		||||
  await u.doAndWaitForCmd(
 | 
			
		||||
    () => page.mouse.click(startXPx + PUR * 15, 500 - PUR * 10),
 | 
			
		||||
    'select_with_point'
 | 
			
		||||
  )
 | 
			
		||||
  await u.closeDebugPanel()
 | 
			
		||||
 | 
			
		||||
  // hold down shift
 | 
			
		||||
  await page.keyboard.down('Shift')
 | 
			
		||||
  // click between the latest two clicks to get center of the line
 | 
			
		||||
  await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 20)
 | 
			
		||||
 | 
			
		||||
  // selected two lines therefore there should be two cursors
 | 
			
		||||
  await expect(page.locator('.cm-cursor')).toHaveCount(2)
 | 
			
		||||
 | 
			
		||||
  await page.getByRole('button', { name: 'Equal Length' }).click()
 | 
			
		||||
 | 
			
		||||
  await expect(page.locator('.cm-content'))
 | 
			
		||||
    .toHaveText(`const part001 = startSketchOn('-XZ')
 | 
			
		||||
  |> startProfileAt(${startAt}, %)
 | 
			
		||||
  |> line({ to: [10.03, 0], tag: 'seg01' }, %)
 | 
			
		||||
  |> line([0, ${tenish}], %)
 | 
			
		||||
  |> angledLine([180, segLen('seg01', %)], %)`)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('if you write invalid kcl you get inlined errors', async ({ page }) => {
 | 
			
		||||
  const u = getUtils(page)
 | 
			
		||||
  await page.setViewportSize({ width: 1000, height: 500 })
 | 
			
		||||
  await page.goto('localhost:3000')
 | 
			
		||||
 | 
			
		||||
  await u.waitForAuthSkipAppStart()
 | 
			
		||||
 | 
			
		||||
  // check no error to begin with
 | 
			
		||||
  await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
 | 
			
		||||
 | 
			
		||||
  /* add the following code to the editor (# error is not a valid line)
 | 
			
		||||
    # error
 | 
			
		||||
    const topAng = 30
 | 
			
		||||
    const bottomAng = 25
 | 
			
		||||
   */
 | 
			
		||||
  await page.click('.cm-content')
 | 
			
		||||
  await page.keyboard.type('# error')
 | 
			
		||||
  await page.keyboard.press('Enter')
 | 
			
		||||
  await page.keyboard.type('const topAng = 30')
 | 
			
		||||
  await page.keyboard.press('Enter')
 | 
			
		||||
  await page.keyboard.type('const bottomAng = 25')
 | 
			
		||||
  await page.keyboard.press('Enter')
 | 
			
		||||
 | 
			
		||||
  // error in guter
 | 
			
		||||
  await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
 | 
			
		||||
 | 
			
		||||
  // error text on hover
 | 
			
		||||
  await page.hover('.cm-lint-marker-error')
 | 
			
		||||
  await expect(page.getByText("found unknown token '#'")).toBeVisible()
 | 
			
		||||
 | 
			
		||||
  // select the line that's causing the error and delete it
 | 
			
		||||
  await page.getByText('# error').click()
 | 
			
		||||
  await page.keyboard.press('End')
 | 
			
		||||
  await page.keyboard.down('Shift')
 | 
			
		||||
  await page.keyboard.press('Home')
 | 
			
		||||
  await page.keyboard.up('Shift')
 | 
			
		||||
  await page.keyboard.press('Backspace')
 | 
			
		||||
 | 
			
		||||
  // wait for .cm-lint-marker-error not to be visible
 | 
			
		||||
  await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('executes on load', async ({ page, context }) => {
 | 
			
		||||
  const u = getUtils(page)
 | 
			
		||||
  await context.addInitScript(async (token) => {
 | 
			
		||||
    localStorage.setItem(
 | 
			
		||||
      'persistCode',
 | 
			
		||||
      `const part001 = startSketchOn('-XZ')
 | 
			
		||||
  |> startProfileAt([-6.95, 4.98], %)
 | 
			
		||||
  |> line([25.1, 0.41], %)
 | 
			
		||||
  |> line([0.73, -14.93], %)
 | 
			
		||||
  |> line([-23.44, 0.52], %)`
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
  await page.setViewportSize({ width: 1000, height: 500 })
 | 
			
		||||
  await page.goto('localhost:3000')
 | 
			
		||||
  await u.waitForAuthSkipAppStart()
 | 
			
		||||
 | 
			
		||||
  // expand variables section
 | 
			
		||||
  await page.getByText('Variables').click()
 | 
			
		||||
 | 
			
		||||
  // can find part001 in the variables summary (pretty-json-container, makes sure we're not looking in the code editor)
 | 
			
		||||
  // part001 only shows up in the variables summary if it's been executed
 | 
			
		||||
  await page.waitForFunction(() => {
 | 
			
		||||
    const variablesElement = document.querySelector(
 | 
			
		||||
      '.pretty-json-container'
 | 
			
		||||
    ) as HTMLDivElement
 | 
			
		||||
    return variablesElement.innerHTML.includes('part001')
 | 
			
		||||
  })
 | 
			
		||||
  await expect(
 | 
			
		||||
    page.locator('.pretty-json-container >> text=part001')
 | 
			
		||||
  ).toBeVisible()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('re-executes', async ({ page, context }) => {
 | 
			
		||||
  const u = getUtils(page)
 | 
			
		||||
  await context.addInitScript(async (token) => {
 | 
			
		||||
    localStorage.setItem('persistCode', `const myVar = 5`)
 | 
			
		||||
  })
 | 
			
		||||
  await page.setViewportSize({ width: 1000, height: 500 })
 | 
			
		||||
  await page.goto('localhost:3000')
 | 
			
		||||
  await u.waitForAuthSkipAppStart()
 | 
			
		||||
 | 
			
		||||
  await page.getByText('Variables').click()
 | 
			
		||||
  // expect to see "myVar:5"
 | 
			
		||||
  await expect(
 | 
			
		||||
    page.locator('.pretty-json-container >> text=myVar:5')
 | 
			
		||||
  ).toBeVisible()
 | 
			
		||||
 | 
			
		||||
  // change 5 to 67
 | 
			
		||||
  await page.getByText('const myVar').click()
 | 
			
		||||
  await page.keyboard.press('End')
 | 
			
		||||
  await page.keyboard.press('Backspace')
 | 
			
		||||
  await page.keyboard.type('67')
 | 
			
		||||
 | 
			
		||||
  await expect(
 | 
			
		||||
    page.locator('.pretty-json-container >> text=myVar:67')
 | 
			
		||||
  ).toBeVisible()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('Can create sketches on all planes and their back sides', async ({
 | 
			
		||||
  page,
 | 
			
		||||
}) => {
 | 
			
		||||
  const u = getUtils(page)
 | 
			
		||||
  const PUR = 400 / 37.5 //pixeltoUnitRatio
 | 
			
		||||
  await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
  await page.goto('localhost:3000')
 | 
			
		||||
  await u.waitForAuthSkipAppStart()
 | 
			
		||||
  await u.openDebugPanel()
 | 
			
		||||
  await u.waitForDefaultPlanesVisibilityChange()
 | 
			
		||||
 | 
			
		||||
  const camCmd: EngineCommand = {
 | 
			
		||||
    type: 'modeling_cmd_req',
 | 
			
		||||
    cmd_id: uuidv4(),
 | 
			
		||||
    cmd: {
 | 
			
		||||
      type: 'default_camera_look_at',
 | 
			
		||||
      center: { x: 15, y: 0, z: 0 },
 | 
			
		||||
      up: { x: 0, y: 0, z: 1 },
 | 
			
		||||
      vantage: { x: 30, y: 30, z: 30 },
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const TestSinglePlane = async ({
 | 
			
		||||
    viewCmd,
 | 
			
		||||
    expectedCode,
 | 
			
		||||
    clickCoords,
 | 
			
		||||
  }: {
 | 
			
		||||
    viewCmd: EngineCommand
 | 
			
		||||
    expectedCode: string
 | 
			
		||||
    clickCoords: { x: number; y: number }
 | 
			
		||||
  }) => {
 | 
			
		||||
    await u.openDebugPanel()
 | 
			
		||||
    await u.sendCustomCmd(viewCmd)
 | 
			
		||||
    await u.clearCommandLogs()
 | 
			
		||||
    // await page.waitForTimeout(200)
 | 
			
		||||
    await page.getByRole('button', { name: 'Start Sketch' }).click()
 | 
			
		||||
    await u.waitForDefaultPlanesVisibilityChange()
 | 
			
		||||
 | 
			
		||||
    await u.closeDebugPanel()
 | 
			
		||||
    await page.mouse.click(clickCoords.x, clickCoords.y)
 | 
			
		||||
    await u.openDebugPanel()
 | 
			
		||||
 | 
			
		||||
    await expect(page.getByRole('button', { name: 'Line' })).toBeVisible()
 | 
			
		||||
 | 
			
		||||
    // draw a line
 | 
			
		||||
    const startXPx = 600
 | 
			
		||||
    await u.clearCommandLogs()
 | 
			
		||||
    await page.getByRole('button', { name: 'Line' }).click()
 | 
			
		||||
    await u.waitForCmdReceive('set_tool')
 | 
			
		||||
    await u.clearCommandLogs()
 | 
			
		||||
    await u.closeDebugPanel()
 | 
			
		||||
    await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
 | 
			
		||||
    await u.openDebugPanel()
 | 
			
		||||
    await u.waitForCmdReceive('mouse_click')
 | 
			
		||||
    await u.closeDebugPanel()
 | 
			
		||||
    await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
 | 
			
		||||
    await u.openDebugPanel()
 | 
			
		||||
 | 
			
		||||
    await expect(page.locator('.cm-content')).toHaveText(expectedCode)
 | 
			
		||||
 | 
			
		||||
    await page.getByRole('button', { name: 'Line' }).click()
 | 
			
		||||
    await u.clearCommandLogs()
 | 
			
		||||
    await page.getByRole('button', { name: 'Exit Sketch' }).click()
 | 
			
		||||
    await u.expectCmdLog('[data-message-type="execution-done"]')
 | 
			
		||||
 | 
			
		||||
    await u.clearCommandLogs()
 | 
			
		||||
    await u.removeCurrentCode()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const codeTemplate = (
 | 
			
		||||
    plane = 'XY',
 | 
			
		||||
    sign = ''
 | 
			
		||||
  ) => `const part001 = startSketchOn('${plane}')
 | 
			
		||||
  |> startProfileAt([${sign}3.97, -5.36], %)
 | 
			
		||||
  |> line([${sign}4.01, 0], %)`
 | 
			
		||||
  await TestSinglePlane({
 | 
			
		||||
    viewCmd: camCmd,
 | 
			
		||||
    expectedCode: codeTemplate('XY'),
 | 
			
		||||
    clickCoords: { x: 700, y: 350 }, // red plane
 | 
			
		||||
  })
 | 
			
		||||
  await TestSinglePlane({
 | 
			
		||||
    viewCmd: camCmd,
 | 
			
		||||
    expectedCode: codeTemplate('YZ'),
 | 
			
		||||
    clickCoords: { x: 1000, y: 200 }, // green plane
 | 
			
		||||
  })
 | 
			
		||||
  await TestSinglePlane({
 | 
			
		||||
    viewCmd: camCmd,
 | 
			
		||||
    expectedCode: codeTemplate('XZ', '-'),
 | 
			
		||||
    clickCoords: { x: 630, y: 130 }, // blue plane
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // new camera angle to click the back side of all three planes
 | 
			
		||||
  const camCmdBackSide: EngineCommand = {
 | 
			
		||||
    type: 'modeling_cmd_req',
 | 
			
		||||
    cmd_id: uuidv4(),
 | 
			
		||||
    cmd: {
 | 
			
		||||
      type: 'default_camera_look_at',
 | 
			
		||||
      center: { x: -15, y: 0, z: 0 },
 | 
			
		||||
      up: { x: 0, y: 0, z: 1 },
 | 
			
		||||
      vantage: { x: -30, y: -30, z: -30 },
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
  await TestSinglePlane({
 | 
			
		||||
    viewCmd: camCmdBackSide,
 | 
			
		||||
    expectedCode: codeTemplate('-XY', '-'),
 | 
			
		||||
    clickCoords: { x: 705, y: 136 }, // back of red plane
 | 
			
		||||
  })
 | 
			
		||||
  await TestSinglePlane({
 | 
			
		||||
    viewCmd: camCmdBackSide,
 | 
			
		||||
    expectedCode: codeTemplate('-YZ', '-'),
 | 
			
		||||
    clickCoords: { x: 1000, y: 350 }, // back of green plane
 | 
			
		||||
  })
 | 
			
		||||
  await TestSinglePlane({
 | 
			
		||||
    viewCmd: camCmdBackSide,
 | 
			
		||||
    expectedCode: codeTemplate('-XZ'),
 | 
			
		||||
    clickCoords: { x: 600, y: 400 }, // back of blue plane
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test('Auto complete works', async ({ page }) => {
 | 
			
		||||
  const u = getUtils(page)
 | 
			
		||||
  // const PUR = 400 / 37.5 //pixeltoUnitRatio
 | 
			
		||||
  await page.setViewportSize({ width: 1200, height: 500 })
 | 
			
		||||
  await page.goto('localhost:3000')
 | 
			
		||||
  await u.waitForAuthSkipAppStart()
 | 
			
		||||
  await u.waitForDefaultPlanesVisibilityChange()
 | 
			
		||||
 | 
			
		||||
  // this test might be brittle as we add and remove functions
 | 
			
		||||
  // but should also be easy to update.
 | 
			
		||||
  // tests clicking on an option, selection the first option
 | 
			
		||||
  // and arrowing down to an option
 | 
			
		||||
 | 
			
		||||
  await page.click('.cm-content')
 | 
			
		||||
  await page.keyboard.type('const part001 = start')
 | 
			
		||||
 | 
			
		||||
  // expect there to be three auto complete options
 | 
			
		||||
  await expect(page.locator('.cm-completionLabel')).toHaveCount(3)
 | 
			
		||||
  await page.getByText('startSketchOn').click()
 | 
			
		||||
  await page.keyboard.type("('XY')")
 | 
			
		||||
  await page.keyboard.press('Enter')
 | 
			
		||||
  await page.keyboard.type('  |> startProfi')
 | 
			
		||||
  // expect there be a single auto complete option that we can just hit enter on
 | 
			
		||||
  await expect(page.locator('.cm-completionLabel')).toBeVisible()
 | 
			
		||||
  await page.keyboard.press('Enter') // accepting the auto complete, not a new line
 | 
			
		||||
 | 
			
		||||
  await page.keyboard.type('([0,0], %)')
 | 
			
		||||
  await page.keyboard.press('Enter')
 | 
			
		||||
  await page.keyboard.type('  |> lin')
 | 
			
		||||
 | 
			
		||||
  await expect(page.locator('.cm-tooltip-autocomplete')).toBeVisible()
 | 
			
		||||
  // press arrow down twice then enter to accept xLine
 | 
			
		||||
  await page.keyboard.press('ArrowDown')
 | 
			
		||||
  await page.keyboard.press('ArrowDown')
 | 
			
		||||
  await page.keyboard.press('Enter')
 | 
			
		||||
  await page.keyboard.type('(5, %)')
 | 
			
		||||
 | 
			
		||||
  await expect(page.locator('.cm-content'))
 | 
			
		||||
    .toHaveText(`const part001 = startSketchOn('XY')
 | 
			
		||||
  |> startProfileAt([0,0], %)
 | 
			
		||||
  |> xLine(5, %)`)
 | 
			
		||||
})
 | 
			
		||||
		Reference in New Issue
	
	Block a user