import { expect, test } from '@e2e/playwright/zoo-test' import * as fsp from 'fs/promises' import * as path from 'path' /* eslint-disable jest/no-conditional-expect */ const file = `sketch001 = startSketchOn(XZ) profile001 = startProfile(sketch001, at = [57.81, 250.51]) |> line(end = [121.13, 56.63], tag = $seg02) |> line(end = [83.37, -34.61], tag = $seg01) |> line(end = [19.66, -116.4]) |> line(end = [-221.8, -41.69]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close() extrude001 = extrude(profile001, length = 200) sketch002 = startSketchOn(XZ) |> startProfile(at = [-114, 85.52]) |> xLine(length = 265.36) |> line(end = [33.17, -261.22]) |> xLine(length = -297.25) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close() extrude002 = extrude(sketch002, length = 50) sketch003 = startSketchOn(XY) |> startProfile(at = [52.92, 157.81]) |> angledLine(angle = 0, length = 176.4, tag = $rectangleSegmentA001) |> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 53.4, tag = $rectangleSegmentB001) |> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> close() extrude003 = extrude(sketch003, length = 20) ` test.describe('Prompt-to-edit tests', () => { test.describe('Check the happy path, for basic changing color', () => { const cases = [ { desc: 'User accepts change', shouldReject: false, }, { desc: 'User rejects change', shouldReject: true, }, ] as const for (const { desc, shouldReject } of cases) { test(`${desc}`, async ({ context, homePage, cmdBar, editor, page, scene, }) => { await context.folderSetupFn(async (dir) => { const projectDir = path.join(dir, 'test-project') await fsp.mkdir(projectDir, { recursive: true }) await fsp.writeFile(path.join(projectDir, 'main.kcl'), file) }) await homePage.openProject('test-project') await scene.settled(cmdBar) const body1CapCoords = { x: 571, y: 311 } const [clickBody1Cap] = scene.makeMouseHelpers( body1CapCoords.x, body1CapCoords.y ) const yellow: [number, number, number] = [179, 179, 131] const submittingToast = page.getByText( 'Submitting to Text-to-CAD API...' ) const successToast = page.getByText('Prompt to edit successful') const acceptBtn = page.getByRole('button', { name: 'checkmark Continue', }) const rejectBtn = page.getByRole('button', { name: 'close Revert' }) await test.step('wait for scene to load select body and check selection came through', async () => { await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15) await clickBody1Cap() await scene.expectPixelColor(yellow, body1CapCoords, 20) await editor.expectState({ highlightedCode: '', activeLines: ['|>startProfile(at=[-114,85.52])'], diagnostics: [], }) }) await test.step('fire off edit prompt', async () => { await cmdBar.openCmdBar('promptToEdit') await page.waitForTimeout(100) await cmdBar.progressCmdBar() // being specific about the color with a hex means asserting pixel color is more stable await page .getByTestId('cmd-bar-arg-value') .fill('make this neon green please, use #39FF14') await page.waitForTimeout(100) await cmdBar.progressCmdBar() await expect(submittingToast).toBeVisible() await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000, }) // can take a while await expect(successToast).toBeVisible() }) await test.step('verify initial change', async () => { await editor.expectEditor.toContain('appearance(') }) if (!shouldReject) { await test.step('check accept works', async () => { await acceptBtn.click() await expect(successToast).not.toBeVisible() await editor.expectEditor.toContain('appearance(') }) } else { await test.step('check reject works', async () => { await rejectBtn.click() await expect(successToast).not.toBeVisible() await editor.expectEditor.not.toContain('appearance(') }) } }) } }) test('bad edit prompt', async ({ context, homePage, cmdBar, editor, toolbar, page, scene, }) => { await context.addInitScript((file) => { localStorage.setItem('persistCode', file) }, file) await homePage.goToModelingScene() await scene.settled(cmdBar) const body1CapCoords = { x: 571, y: 311 } const [clickBody1Cap] = scene.makeMouseHelpers( body1CapCoords.x, body1CapCoords.y ) const yellow: [number, number, number] = [179, 179, 131] const submittingToast = page.getByText('Submitting to Text-to-CAD API...') const failToast = page.getByText( 'Failed to edit your KCL code, please try again with a different prompt or selection' ) await test.step('wait for scene to load and select body', async () => { await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15) await clickBody1Cap() await scene.expectPixelColor(yellow, body1CapCoords, 20) await editor.expectState({ highlightedCode: '', activeLines: ['|>startProfile(at=[-114,85.52])'], diagnostics: [], }) }) await test.step('fire of bad prompt', async () => { await cmdBar.openCmdBar('promptToEdit') await page.waitForTimeout(100) await cmdBar.progressCmdBar() await page .getByTestId('cmd-bar-arg-value') .fill('ansheusha asnthuatshoeuhtaoetuhthaeu laughs in dvorak') await page.waitForTimeout(100) await cmdBar.progressCmdBar() await expect(submittingToast).toBeVisible() }) await test.step('check fail toast appeared', async () => { await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000 }) // can take a while await expect(failToast).toBeVisible() }) }) test(`manual code selection rename`, async ({ context, homePage, cmdBar, editor, page, scene, }) => { const body1CapCoords = { x: 571, y: 311 } await context.addInitScript((file) => { localStorage.setItem('persistCode', file) }, file) await homePage.goToModelingScene() await scene.settled(cmdBar) const submittingToast = page.getByText('Submitting to Text-to-CAD API...') const successToast = page.getByText('Prompt to edit successful') const acceptBtn = page.getByRole('button', { name: 'checkmark Continue' }) await test.step('wait for scene to load and select code in editor', async () => { // Find and select the text "sketch002" in the editor await editor.selectText('sketch002') // Verify the selection was made await editor.expectState({ highlightedCode: '', activeLines: ['sketch002 = startSketchOn(XZ)'], diagnostics: [], }) }) await test.step('fire off edit prompt', async () => { await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15) await cmdBar.openCmdBar('promptToEdit') await page .getByTestId('cmd-bar-arg-value') .fill('Please rename to mySketch001') await page.waitForTimeout(100) await cmdBar.progressCmdBar() await expect(submittingToast).toBeVisible() await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000, }) await expect(successToast).toBeVisible() }) await test.step('verify rename change and accept it', async () => { await editor.expectEditor.toContain('mySketch001 = startSketchOn') await editor.expectEditor.not.toContain('sketch002 = startSketchOn') await editor.expectEditor.toContain( 'extrude002 = extrude(mySketch001, length = 50)' ) await acceptBtn.click() await expect(successToast).not.toBeVisible() }) }) test('multiple body selections', async ({ context, homePage, cmdBar, editor, page, scene, }) => { const body1CapCoords = { x: 571, y: 311 } const body2WallCoords = { x: 620, y: 152 } const [clickBody1Cap] = scene.makeMouseHelpers( body1CapCoords.x, body1CapCoords.y ) const [clickBody2Cap] = scene.makeMouseHelpers( body2WallCoords.x, body2WallCoords.y ) const grey: [number, number, number] = [132, 132, 132] await context.addInitScript((file) => { localStorage.setItem('persistCode', file) }, file) await homePage.goToModelingScene() await scene.settled(cmdBar) const submittingToast = page.getByText('Submitting to Text-to-CAD API...') const successToast = page.getByText('Prompt to edit successful') const acceptBtn = page.getByRole('button', { name: 'checkmark Continue' }) await test.step('select multiple bodies and fire prompt', async () => { // Initial color check await scene.expectPixelColor(grey, body1CapCoords, 15) // Open command bar first (without selection) await cmdBar.openCmdBar('promptToEdit') // Select first body await page.waitForTimeout(100) await clickBody1Cap() // Hold shift and select second body await editor.expectState({ highlightedCode: '', activeLines: ['|>startProfile(at=[-114,85.52])'], diagnostics: [], }) await page.keyboard.down('Shift') await page.waitForTimeout(100) await clickBody2Cap() await editor.expectState({ highlightedCode: 'line(end=[121.13,56.63],tag=$seg02)extrude(profile001,length=200)', activeLines: [ '|>line(end=[121.13,56.63],tag=$seg02)', '|>startProfile(at=[-114,85.52])', ], diagnostics: [], }) await page.keyboard.up('Shift') await page.waitForTimeout(100) await cmdBar.progressCmdBar() // Enter prompt and submit await page .getByTestId('cmd-bar-arg-value') .fill('make these neon green please, use #39FF14') await page.waitForTimeout(100) await cmdBar.progressCmdBar() // Wait for API response await expect(submittingToast).toBeVisible() await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000, }) await expect(successToast).toBeVisible() }) await test.step('verify code changed', async () => { await editor.expectEditor.toContain('appearance(') // Accept changes await acceptBtn.click() await expect(successToast).not.toBeVisible() }) }) })