diff --git a/e2e/playwright/fixtures/sceneFixture.ts b/e2e/playwright/fixtures/sceneFixture.ts index 03a063a50..d81339117 100644 --- a/e2e/playwright/fixtures/sceneFixture.ts +++ b/e2e/playwright/fixtures/sceneFixture.ts @@ -52,10 +52,12 @@ export class SceneFixture { } expectState = async (expected: SceneSerialised) => { - return expect.poll(async () => await this._serialiseScene(), { - intervals: [1_000, 2_000, 10_000], - timeout: 60000, - }).toEqual(expected) + return expect + .poll(async () => await this._serialiseScene(), { + intervals: [1_000, 2_000, 10_000], + timeout: 60000, + }) + .toEqual(expected) } reConstruct = (page: Page) => { diff --git a/e2e/playwright/onboarding-tests.spec.ts b/e2e/playwright/onboarding-tests.spec.ts index 41a8f2ec7..954dd079d 100644 --- a/e2e/playwright/onboarding-tests.spec.ts +++ b/e2e/playwright/onboarding-tests.spec.ts @@ -130,9 +130,7 @@ test.describe('Onboarding tests', () => { await replayButton.click() // Ensure we see the warning, and that the code has not yet updated - await expect( - page.getByText('Would you like to create') - ).toBeVisible() + await expect(page.getByText('Would you like to create')).toBeVisible() await expect(page.locator('.cm-content')).toHaveText(initialCode) const nextButton = page.getByTestId('onboarding-next') @@ -278,7 +276,9 @@ test.describe('Onboarding tests', () => { await page.setBodyDimensions({ width: 1200, height: 1080 }) await homePage.goToModelingScene() - await expect.poll(() => page.url()).toContain(onboardingPaths.PARAMETRIC_MODELING) + await expect + .poll(() => page.url()) + .toContain(onboardingPaths.PARAMETRIC_MODELING) const bracketNoNewLines = bracket.replace(/\n/g, '') diff --git a/e2e/playwright/point-click.spec.ts b/e2e/playwright/point-click.spec.ts index 2d196e379..ed77d368b 100644 --- a/e2e/playwright/point-click.spec.ts +++ b/e2e/playwright/point-click.spec.ts @@ -7,27 +7,42 @@ import path from 'node:path' // test file is for testing point an click code gen functionality that's not sketch mode related -test( - 'verify extruding circle works', - async ({ context, homePage, cmdBar, editor, toolbar, scene }) => { - const file = await fs.readFile( - path.resolve( - __dirname, - '../../', - './src/wasm-lib/tests/executor/inputs/test-circle-extrude.kcl' - ), - 'utf-8' - ) - await context.addInitScript((file) => { - localStorage.setItem('persistCode', file) - }, file) - await homePage.goToModelingScene() +test('verify extruding circle works', async ({ + context, + homePage, + cmdBar, + editor, + toolbar, + scene, +}) => { + const file = await fs.readFile( + path.resolve( + __dirname, + '../../', + './src/wasm-lib/tests/executor/inputs/test-circle-extrude.kcl' + ), + 'utf-8' + ) + await context.addInitScript((file) => { + localStorage.setItem('persistCode', file) + }, file) + await homePage.goToModelingScene() - const [clickCircle, moveToCircle] = scene.makeMouseHelpers(582, 217) + const [clickCircle, moveToCircle] = scene.makeMouseHelpers(582, 217) - await test.step('because there is sweepable geometry, verify extrude is enable when nothing is selected', async () => { - await scene.clickNoWhere() - await expect(toolbar.extrudeButton).toBeEnabled() + await test.step('because there is sweepable geometry, verify extrude is enable when nothing is selected', async () => { + await scene.clickNoWhere() + await expect(toolbar.extrudeButton).toBeEnabled() + }) + + await test.step('check code model connection works and that button is still enable once circle is selected ', async () => { + await moveToCircle() + const circleSnippet = + 'circle({ center: [318.33, 168.1], radius: 182.8 }, %)' + await editor.expectState({ + activeLines: ["constsketch002=startSketchOn('XZ')"], + highlightedCode: circleSnippet, + diagnostics: [], }) await test.step('check code model connection works and that button is still enable once circle is selected ', async () => { @@ -35,9 +50,7 @@ test( const circleSnippet = 'circle({ center = [318.33, 168.1], radius = 182.8 }, %)' await editor.expectState({ - activeLines: [ - "constsketch002=startSketchOn('XZ')" - ], + activeLines: ["constsketch002=startSketchOn('XZ')"], highlightedCode: circleSnippet, diagnostics: [], }) @@ -50,34 +63,35 @@ test( }) await expect(toolbar.extrudeButton).toBeEnabled() }) + await expect(toolbar.extrudeButton).toBeEnabled() + }) - await test.step('do extrude flow and check extrude code is added to editor', async () => { - await toolbar.extrudeButton.click() + await test.step('do extrude flow and check extrude code is added to editor', async () => { + await toolbar.extrudeButton.click() - await cmdBar.expectState({ - stage: 'arguments', - currentArgKey: 'distance', - currentArgValue: '5', - headerArguments: { Selection: '1 face', Distance: '' }, - highlightedHeaderArg: 'distance', - commandName: 'Extrude', - }) - await cmdBar.progressCmdBar() - - const expectString = 'extrude001 = extrude(5, sketch001)' - await editor.expectEditor.not.toContain(expectString) - - await cmdBar.expectState({ - stage: 'review', - headerArguments: { Selection: '1 face', Distance: '5' }, - commandName: 'Extrude', - }) - await cmdBar.progressCmdBar() - - await editor.expectEditor.toContain(expectString) + await cmdBar.expectState({ + stage: 'arguments', + currentArgKey: 'distance', + currentArgValue: '5', + headerArguments: { Selection: '1 face', Distance: '' }, + highlightedHeaderArg: 'distance', + commandName: 'Extrude', }) - } -) + await cmdBar.progressCmdBar() + + const expectString = 'extrude001 = extrude(5, sketch001)' + await editor.expectEditor.not.toContain(expectString) + + await cmdBar.expectState({ + stage: 'review', + headerArguments: { Selection: '1 face', Distance: '5' }, + commandName: 'Extrude', + }) + await cmdBar.progressCmdBar() + + await editor.expectEditor.toContain(expectString) + }) +}) test.describe('verify sketch on chamfer works', () => { const _sketchOnAChamfer = @@ -145,7 +159,9 @@ test.describe('verify sketch on chamfer works', () => { pixelDiff: 50, }) await rectangle2ndClick() - await editor.expectEditor.toContain(afterRectangle2ndClickSnippet, { shouldNormalise: true }) + await editor.expectEditor.toContain(afterRectangle2ndClickSnippet, { + shouldNormalise: true, + }) }) await test.step('Clean up so that `_sketchOnAChamfer` util can be called again', async () => { @@ -160,30 +176,35 @@ test.describe('verify sketch on chamfer works', () => { }) }) } - test( - 'works on all edge selections and can break up multi edges in a chamfer array', - async ({ context, page, homePage, editor, toolbar, scene }) => { - const file = await fs.readFile( - path.resolve( - __dirname, - '../../', - './src/wasm-lib/tests/executor/inputs/e2e-can-sketch-on-chamfer.kcl' - ), - 'utf-8' - ) - await context.addInitScript((file) => { - localStorage.setItem('persistCode', file) - }, file) - await page.setBodyDimensions({ width: 1000, height: 500 }) - await homePage.goToModelingScene() + test('works on all edge selections and can break up multi edges in a chamfer array', async ({ + context, + page, + homePage, + editor, + toolbar, + scene, + }) => { + const file = await fs.readFile( + path.resolve( + __dirname, + '../../', + './src/wasm-lib/tests/executor/inputs/e2e-can-sketch-on-chamfer.kcl' + ), + 'utf-8' + ) + await context.addInitScript((file) => { + localStorage.setItem('persistCode', file) + }, file) + await page.setBodyDimensions({ width: 1000, height: 500 }) + await homePage.goToModelingScene() - const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene) + const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene) - await sketchOnAChamfer({ - clickCoords: { x: 570, y: 220 }, - cameraPos: { x: 16020, y: -2000, z: 10500 }, - cameraTarget: { x: -150, y: -4500, z: -80 }, - beforeChamferSnippet: `angledLine([segAng(rectangleSegmentA001)-90,217.26],%,$seg01) + await sketchOnAChamfer({ + clickCoords: { x: 570, y: 220 }, + cameraPos: { x: 16020, y: -2000, z: 10500 }, + cameraTarget: { x: -150, y: -4500, z: -80 }, + beforeChamferSnippet: `angledLine([segAng(rectangleSegmentA001)-90,217.26],%,$seg01) chamfer({length = 30,tags = [ seg01, getNextAdjacentEdge(yo), @@ -191,10 +212,9 @@ test.describe('verify sketch on chamfer works', () => { getOppositeEdge(seg01) ]}, %)`, - afterChamferSelectSnippet: - 'sketch002 = startSketchOn(extrude001, seg03)', - afterRectangle1stClickSnippet: 'startProfileAt([160.39, 254.59], %)', - afterRectangle2ndClickSnippet: `angledLine([0, 11.39], %, $rectangleSegmentA002) + afterChamferSelectSnippet: 'sketch002 = startSketchOn(extrude001, seg03)', + afterRectangle1stClickSnippet: 'startProfileAt([160.39, 254.59], %)', + afterRectangle2ndClickSnippet: `angledLine([0, 11.39], %, $rectangleSegmentA002) |> angledLine([ segAng(rectangleSegmentA002) - 90, 105.26 @@ -205,13 +225,13 @@ test.describe('verify sketch on chamfer works', () => { ], %, $rectangleSegmentC001) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%)`, - }) + }) - await sketchOnAChamfer({ - clickCoords: { x: 690, y: 250 }, - cameraPos: { x: 16020, y: -2000, z: 10500 }, - cameraTarget: { x: -150, y: -4500, z: -80 }, - beforeChamferSnippet: `angledLine([ + await sketchOnAChamfer({ + clickCoords: { x: 690, y: 250 }, + cameraPos: { x: 16020, y: -2000, z: 10500 }, + cameraTarget: { x: -150, y: -4500, z: -80 }, + beforeChamferSnippet: `angledLine([ segAng(rectangleSegmentA001) - 90, 217.26 ], %, $seg01)chamfer({ @@ -223,10 +243,9 @@ test.describe('verify sketch on chamfer works', () => { ] }, %)`, - afterChamferSelectSnippet: - 'sketch003 = startSketchOn(extrude001, seg04)', - afterRectangle1stClickSnippet: 'startProfileAt([-255.89, 255.28], %)', - afterRectangle2ndClickSnippet: `angledLine([0, 11.56], %, $rectangleSegmentA003) + afterChamferSelectSnippet: 'sketch003 = startSketchOn(extrude001, seg04)', + afterRectangle1stClickSnippet: 'startProfileAt([-255.89, 255.28], %)', + afterRectangle2ndClickSnippet: `angledLine([0, 11.56], %, $rectangleSegmentA003) |> angledLine([ segAng(rectangleSegmentA003) - 90, 106.84 @@ -237,22 +256,21 @@ test.describe('verify sketch on chamfer works', () => { ], %, $rectangleSegmentC002) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%)`, - }) - await sketchOnAChamfer({ - clickCoords: { x: 677, y: 87 }, - cameraPos: { x: -6200, y: 1500, z: 6200 }, - cameraTarget: { x: 8300, y: 1100, z: 4800 }, - beforeChamferSnippet: `angledLine([0, 268.43], %, $rectangleSegmentA001)chamfer({ + }) + await sketchOnAChamfer({ + clickCoords: { x: 677, y: 87 }, + cameraPos: { x: -6200, y: 1500, z: 6200 }, + cameraTarget: { x: 8300, y: 1100, z: 4800 }, + beforeChamferSnippet: `angledLine([0, 268.43], %, $rectangleSegmentA001)chamfer({ length = 30, tags = [ getNextAdjacentEdge(yo), getNextAdjacentEdge(seg02) ] }, %)`, - afterChamferSelectSnippet: - 'sketch003 = startSketchOn(extrude001, seg04)', - afterRectangle1stClickSnippet: 'startProfileAt([37.95, 322.96], %)', - afterRectangle2ndClickSnippet: `angledLine([0, 11.56], %, $rectangleSegmentA003) + afterChamferSelectSnippet: 'sketch003 = startSketchOn(extrude001, seg04)', + afterRectangle1stClickSnippet: 'startProfileAt([37.95, 322.96], %)', + afterRectangle2ndClickSnippet: `angledLine([0, 11.56], %, $rectangleSegmentA003) |> angledLine([ segAng(rectangleSegmentA003) - 90, 106.84 @@ -263,20 +281,19 @@ test.describe('verify sketch on chamfer works', () => { ], %, $rectangleSegmentC002) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%)`, - }) - /// last one - await sketchOnAChamfer({ - clickCoords: { x: 620, y: 300 }, - cameraPos: { x: -1100, y: -7700, z: 1600 }, - cameraTarget: { x: 1450, y: 670, z: 4000 }, - beforeChamferSnippet: `chamfer({ + }) + /// last one + await sketchOnAChamfer({ + clickCoords: { x: 620, y: 300 }, + cameraPos: { x: -1100, y: -7700, z: 1600 }, + cameraTarget: { x: 1450, y: 670, z: 4000 }, + beforeChamferSnippet: `chamfer({ length = 30, tags = [getNextAdjacentEdge(yo)] }, %)`, - afterChamferSelectSnippet: - 'sketch005 = startSketchOn(extrude001, seg06)', - afterRectangle1stClickSnippet: 'startProfileAt([-59.83, 19.69], %)', - afterRectangle2ndClickSnippet: `angledLine([0, 9.1], %, $rectangleSegmentA005) + afterChamferSelectSnippet: 'sketch005 = startSketchOn(extrude001, seg06)', + afterRectangle1stClickSnippet: 'startProfileAt([-59.83, 19.69], %)', + afterRectangle2ndClickSnippet: `angledLine([0, 9.1], %, $rectangleSegmentA005) |> angledLine([ segAng(rectangleSegmentA005) - 90, @@ -288,11 +305,11 @@ test.describe('verify sketch on chamfer works', () => { ], %, $rectangleSegmentC004) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%)`, - }) + }) - await test.step('verify at the end of the test that final code is what is expected', async () => { - await editor.expectEditor.toContain( - `sketch001 = startSketchOn('XZ') + await test.step('verify at the end of the test that final code is what is expected', async () => { + await editor.expectEditor.toContain( + `sketch001 = startSketchOn('XZ') |> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag] |> angledLine([0, 268.43], %, $rectangleSegmentA001) @@ -373,47 +390,48 @@ test.describe('verify sketch on chamfer works', () => { |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) `, - { shouldNormalise: true } - ) - }) - } - ) - - test( - 'Works on chamfers that are non in a pipeExpression can break up multi edges in a chamfer array', - async ({ context, page, homePage, editor, toolbar, scene }) => { - const file = await fs.readFile( - path.resolve( - __dirname, - '../../', - './src/wasm-lib/tests/executor/inputs/e2e-can-sketch-on-chamfer-no-pipeExpr.kcl' - ), - 'utf-8' + { shouldNormalise: true } ) - await context.addInitScript((file) => { - localStorage.setItem('persistCode', file) - }, file) - await page.setBodyDimensions({ width: 1000, height: 500 }) - await homePage.goToModelingScene() + }) + }) - const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene) + test('Works on chamfers that are non in a pipeExpression can break up multi edges in a chamfer array', async ({ + context, + page, + homePage, + editor, + toolbar, + scene, + }) => { + const file = await fs.readFile( + path.resolve( + __dirname, + '../../', + './src/wasm-lib/tests/executor/inputs/e2e-can-sketch-on-chamfer-no-pipeExpr.kcl' + ), + 'utf-8' + ) + await context.addInitScript((file) => { + localStorage.setItem('persistCode', file) + }, file) + await page.setBodyDimensions({ width: 1000, height: 500 }) + await homePage.goToModelingScene() - await sketchOnAChamfer({ - clickCoords: { x: 570, y: 220 }, - cameraPos: { x: 16020, y: -2000, z: 10500 }, - cameraTarget: { x: -150, y: -4500, z: -80 }, - beforeChamferSnippet: `angledLine([segAng(rectangleSegmentA001)-90,217.26],%,$seg01) + await sketchOnAChamfer({ + clickCoords: { x: 570, y: 220 }, + cameraPos: { x: 16020, y: -2000, z: 10500 }, + cameraTarget: { x: -150, y: -4500, z: -80 }, + beforeChamferSnippet: `angledLine([segAng(rectangleSegmentA001)-90,217.26],%,$seg01) chamfer({length=30,tags=[ seg01, getNextAdjacentEdge(yo), getNextAdjacentEdge(seg02), getOppositeEdge(seg01) ]}, extrude001)`, - beforeChamferSnippetEnd: '}, extrude001)', - afterChamferSelectSnippet: - 'sketch002 = startSketchOn(extrude001, seg03)', - afterRectangle1stClickSnippet: 'startProfileAt([160.39, 254.59], %)', - afterRectangle2ndClickSnippet: `angledLine([0, 11.39], %, $rectangleSegmentA002) + beforeChamferSnippetEnd: '}, extrude001)', + afterChamferSelectSnippet: 'sketch002 = startSketchOn(extrude001, seg03)', + afterRectangle1stClickSnippet: 'startProfileAt([160.39, 254.59], %)', + afterRectangle2ndClickSnippet: `angledLine([0, 11.39], %, $rectangleSegmentA002) |> angledLine([ segAng(rectangleSegmentA002) - 90, 105.26 @@ -424,9 +442,9 @@ test.describe('verify sketch on chamfer works', () => { ], %, $rectangleSegmentC001) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%)`, - }) - await editor.expectEditor.toContain( - `sketch001 = startSketchOn('XZ') + }) + await editor.expectEditor.toContain( + `sketch001 = startSketchOn('XZ') |> startProfileAt([75.8, 317.2], %) |> angledLine([0, 268.43], %, $rectangleSegmentA001) |> angledLine([ @@ -466,10 +484,9 @@ sketch002 = startSketchOn(extrude001, seg03) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) `, - { shouldNormalise: true } - ) - } - ) + { shouldNormalise: true } + ) + }) }) test(`Verify axis, origin, and horizontal snapping`, async ({ diff --git a/e2e/playwright/projects.spec.ts b/e2e/playwright/projects.spec.ts index 1f8a7a603..0130383a3 100644 --- a/e2e/playwright/projects.spec.ts +++ b/e2e/playwright/projects.spec.ts @@ -56,7 +56,6 @@ test( }) await expect(projectLinks).toHaveCount(0) - } ) @@ -64,7 +63,6 @@ test( 'click help/keybindings from home page', { tag: '@electron' }, async ({ page }, testInfo) => { - await page.setBodyDimensions({ width: 1200, height: 500 }) page.on('console', console.log) @@ -76,7 +74,6 @@ test( await page.getByTestId('keybindings-button').click() // Make sure the keyboard shortcuts modal is visible. await expect(page.getByText('Enter Sketch Mode')).toBeVisible() - } ) @@ -114,7 +111,6 @@ test( await page.getByTestId('keybindings-button').click() // Make sure the keyboard shortcuts modal is visible. await expect(page.getByText('Enter Sketch Mode')).toBeVisible() - } ) @@ -477,7 +473,6 @@ test( await page.hover('.cm-lint-marker-error') const crypticErrorText = `Expected a tag declarator` await expect(page.getByText(crypticErrorText).first()).toBeVisible() - } ) @@ -569,7 +564,6 @@ test.describe('Can export from electron app', () => { // clean up exported file await fsp.rm(filepath) }) - } ) } @@ -577,7 +571,7 @@ test.describe('Can export from electron app', () => { test( 'Rename and delete projects, also spam arrow keys when renaming', { tag: '@electron' }, - async ({ context, page}, testInfo) => { + async ({ context, page }, testInfo) => { await context.folderSetupFn(async (dir) => { await fsp.mkdir(`${dir}/router-template-slate`, { recursive: true }) await fsp.copyFile( @@ -770,7 +764,6 @@ test( // expect the name not to have changed await expect(page.getByText('bracket')).toBeVisible() }) - } ) @@ -799,7 +792,6 @@ test( // expect to still be on the home page await expect(page.getByText('router-template-slate')).toBeVisible() await expect(page.getByText('Your Projects')).toBeVisible() - } ) @@ -862,7 +854,6 @@ test.describe(`Project management commands`, () => { await expect(projectHomeLink.first()).toBeVisible() await expect(projectHomeLink.first()).toContainText(projectRenamedName) }) - } ) @@ -915,7 +906,6 @@ test.describe(`Project management commands`, () => { await test.step(`Check the project was deleted and we navigated home`, async () => { await expect(noProjectsMessage).toBeVisible() }) - } ) test( @@ -971,7 +961,6 @@ test.describe(`Project management commands`, () => { ).toBeVisible() await expect(projectHomeLink).not.toHaveText(projectName) }) - } ) test( @@ -1021,7 +1010,6 @@ test.describe(`Project management commands`, () => { await expect(projectHomeLink).not.toBeVisible() await expect(noProjectsMessage).toBeVisible() }) - } ) }) @@ -1067,7 +1055,6 @@ test( await expect(u.codeLocator).toContainText( 'A mounting bracket for the Focusrite Scarlett Solo audio interface' ) - } ) @@ -1123,10 +1110,11 @@ test( ).rejects.toThrow() // eslint-disable-next-line jest/no-conditional-expect await expect( - fsp.access(path.join(testDir, 'router-template-slate', 'nested', 'main.kcl')) + fsp.access( + path.join(testDir, 'router-template-slate', 'nested', 'main.kcl') + ) ).rejects.toThrow() } - } ) @@ -1205,7 +1193,6 @@ test.fixme( page.getByTestId('project-link').filter({ hasText: 'project-000' }) ).toBeVisible() }) - } ) @@ -1243,7 +1230,6 @@ test( await expect(u.codeLocator).toContainText('routerDiameter') await expect(u.codeLocator).toContainText('templateGap') await expect(u.codeLocator).toContainText('minClampingDistance') - } ) @@ -1351,7 +1337,6 @@ test( ) } }) - } ) @@ -1540,7 +1525,6 @@ test( await expect(page.getByText('router-template-slate')).toBeVisible() await expect(page.getByText('New Project')).toBeVisible() }) - } ) @@ -1600,9 +1584,9 @@ test( await page.getByTestId('project-directory-button').click() await handleFile - await expect.poll(() => page.locator('section#projectDirectory input').inputValue()).toContain( - newProjectDirName - ) + await expect + .poll(() => page.locator('section#projectDirectory input').inputValue()) + .toContain(newProjectDirName) await page.getByTestId('settings-close-button').click() @@ -1620,7 +1604,6 @@ test( await page.getByTestId('project-directory-settings-link').click() - const handleFile = electronApp.evaluate( async ({ dialog }, filePaths) => { dialog.showOpenDialog = () => @@ -1698,7 +1681,6 @@ test( await expect(page.getByText(name)).toBeVisible() } }) - } ) @@ -1804,7 +1786,6 @@ test( false ) }) - } ) @@ -1863,7 +1844,6 @@ test( expect(selectedText.length).toBe(0) await expect(u.codeLocator).toHaveText('') }) - } ) @@ -1883,7 +1863,6 @@ test( await expect(page.getByTestId('app-theme')).toHaveValue('dark') await page.getByTestId('app-theme').selectOption('light') - }) await test.step('Starting the app again and we can see the same theme', async () => { @@ -1892,7 +1871,6 @@ test( page.on('console', console.log) await expect(page.getByTestId('app-theme')).toHaveValue('light') - }) } ) @@ -1934,6 +1912,5 @@ test.fixme( await expect(projectLink).toContainText(projectNames[index]) } }) - } ) diff --git a/e2e/playwright/regression-tests.spec.ts b/e2e/playwright/regression-tests.spec.ts index 8454730f6..7166d21e0 100644 --- a/e2e/playwright/regression-tests.spec.ts +++ b/e2e/playwright/regression-tests.spec.ts @@ -1,55 +1,62 @@ import { test, expect, Page } from './zoo-test' import path from 'path' import * as fsp from 'fs/promises' -import { - getUtils, - executorInputPath, -} from './test-utils' +import { getUtils, executorInputPath } from './test-utils' import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates' import { bracket } from 'lib/exampleKcl' test.describe('Regression tests', () => { // bugs we found that don't fit neatly into other categories - test('bad model has inline error #3251', async ({ context, page, homePage }) => { // because the model has `line([0,0]..` it is valid code, but the model is invalid - // regression test for https://github.com/KittyCAD/modeling-app/issues/3251 - // Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics - const u = await getUtils(page) - await context.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `sketch2 = startSketchOn("XY") + test('bad model has inline error #3251', async ({ + context, + page, + homePage, + }) => { + // because the model has `line([0,0]..` it is valid code, but the model is invalid + // regression test for https://github.com/KittyCAD/modeling-app/issues/3251 + // Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics + const u = await getUtils(page) + await context.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `sketch2 = startSketchOn("XY") sketch001 = startSketchAt([-0, -0]) |> line([0, 0], %) |> line([-4.84, -5.29], %) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%)` - ) + ) + }) + + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + // error in guter + await expect(page.locator('.cm-lint-marker-error')).toBeVisible() + + // error text on hover + await page.hover('.cm-lint-marker-error') + // this is a cryptic error message, fact that all the lines are co-linear from the `line([0,0])` is the issue why + // the close doesn't work + // when https://github.com/KittyCAD/modeling-app/issues/3268 is closed + // this test will need updating + const crypticErrorText = `ApiError` + await expect(page.getByText(crypticErrorText).first()).toBeVisible() }) - - await page.setBodyDimensions({ width: 1000, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - // error in guter - await expect(page.locator('.cm-lint-marker-error')).toBeVisible() - - // error text on hover - await page.hover('.cm-lint-marker-error') - // this is a cryptic error message, fact that all the lines are co-linear from the `line([0,0])` is the issue why - // the close doesn't work - // when https://github.com/KittyCAD/modeling-app/issues/3268 is closed - // this test will need updating - const crypticErrorText = `ApiError` - await expect(page.getByText(crypticErrorText).first()).toBeVisible() }) - test('user should not have to press down twice in cmdbar', async ({ page, homePage }) => { // because the model has `line([0,0]..` it is valid code, but the model is invalid - // regression test for https://github.com/KittyCAD/modeling-app/issues/3251 - // Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics - const u = await getUtils(page) - await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `sketch001 = startSketchOn('XY') + test('user should not have to press down twice in cmdbar', async ({ + page, + homePage, + }) => { + // because the model has `line([0,0]..` it is valid code, but the model is invalid + // regression test for https://github.com/KittyCAD/modeling-app/issues/3251 + // Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics + const u = await getUtils(page) + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `sketch001 = startSketchOn('XY') |> startProfileAt([82.33, 238.21], %) |> angledLine([0, 288.63], %, $rectangleSegmentA001) |> angledLine([ @@ -64,114 +71,121 @@ test.describe('Regression tests', () => { |> close(%) extrude001 = extrude(50, sketch001) ` - ) - }) - - await page.setBodyDimensions({ width: 1000, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await test.step('Check arrow down works', async () => { - await page.getByTestId('command-bar-open-button').hover() - await page.getByTestId('command-bar-open-button').click() - - const floppy = page - .getByRole('option', { name: 'floppy disk arrow Export' }) + ) + }) - await floppy.click() - - // press arrow down key twice - await page.keyboard.press('ArrowDown') - await page.waitForTimeout(100) - await page.keyboard.press('ArrowDown') - - // STL is the third option, which makes sense for two arrow downs - await expect(page.locator('[data-headlessui-state="active"]')).toHaveText( - 'STL' - ) - - await page.keyboard.press('Escape') - await page.waitForTimeout(200) - await page.keyboard.press('Escape') - await page.waitForTimeout(200) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await test.step('Check arrow down works', async () => { + await page.getByTestId('command-bar-open-button').hover() + await page.getByTestId('command-bar-open-button').click() + + const floppy = page.getByRole('option', { + name: 'floppy disk arrow Export', + }) + + await floppy.click() + + // press arrow down key twice + await page.keyboard.press('ArrowDown') + await page.waitForTimeout(100) + await page.keyboard.press('ArrowDown') + + // STL is the third option, which makes sense for two arrow downs + await expect(page.locator('[data-headlessui-state="active"]')).toHaveText( + 'STL' + ) + + await page.keyboard.press('Escape') + await page.waitForTimeout(200) + await page.keyboard.press('Escape') + await page.waitForTimeout(200) + }) + + await test.step('Check arrow up works', async () => { + // theme in test is dark, which is the second option, which means we can test arrow up + await page.getByTestId('command-bar-open-button').click() + + await page.getByText('The overall appearance of the').click() + + await page.keyboard.press('ArrowUp') + await page.waitForTimeout(100) + + await expect(page.locator('[data-headlessui-state="active"]')).toHaveText( + 'light' + ) + }) }) - - await test.step('Check arrow up works', async () => { - // theme in test is dark, which is the second option, which means we can test arrow up - await page.getByTestId('command-bar-open-button').click() - - await page.getByText('The overall appearance of the').click() - - await page.keyboard.press('ArrowUp') - await page.waitForTimeout(100) - - await expect(page.locator('[data-headlessui-state="active"]')).toHaveText( - 'light' - ) - }) }) - test('executes on load', async ({ page, homePage }) => { const u = await getUtils(page) - await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `sketch001 = startSketchOn('-XZ') + test('executes on load', async ({ page, homePage }) => { + const u = await getUtils(page) + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `sketch001 = startSketchOn('-XZ') |> startProfileAt([-6.95, 4.98], %) |> line([25.1, 0.41], %) |> line([0.73, -14.93], %) |> line([-23.44, 0.52], %)` - ) - }) - await page.setBodyDimensions({ width: 1000, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - // expand variables section - const variablesTabButton = page.getByTestId('variables-pane-button') - await variablesTabButton.click() - - // can find sketch001 in the variables summary (pretty-json-container, makes sure we're not looking in the code editor) - // sketch001 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('sketch001') - }) - await expect( - page.locator('.pretty-json-container >> text=sketch001') - ).toBeVisible() }) + ) + }) + await page.setBodyDimensions({ width: 1000, height: 500 }) - test('re-executes', async ({ page, homePage }) => { const u = await getUtils(page) - await page.addInitScript(async () => { - localStorage.setItem('persistCode', `myVar = 5`) + await homePage.goToModelingScene() + await u.waitForPageLoad() + + // expand variables section + const variablesTabButton = page.getByTestId('variables-pane-button') + await variablesTabButton.click() + + // can find sketch001 in the variables summary (pretty-json-container, makes sure we're not looking in the code editor) + // sketch001 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('sketch001') + }) + await expect( + page.locator('.pretty-json-container >> text=sketch001') + ).toBeVisible() }) - await page.setBodyDimensions({ width: 1000, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - const variablesTabButton = page.getByTestId('variables-pane-button') - await variablesTabButton.click() - // expect to see "myVar:5" - await expect( - page.locator('.pretty-json-container >> text=myVar:5') - ).toBeVisible() - - // change 5 to 67 - await page.locator('#code-mirror-override').getByText('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('ProgramMemory can be serialised', async ({ page, homePage }) => { const u = await getUtils(page) - await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `part = startSketchOn('XY') + + test('re-executes', async ({ page, homePage }) => { + const u = await getUtils(page) + await page.addInitScript(async () => { + localStorage.setItem('persistCode', `myVar = 5`) + }) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + const variablesTabButton = page.getByTestId('variables-pane-button') + await variablesTabButton.click() + // expect to see "myVar:5" + await expect( + page.locator('.pretty-json-container >> text=myVar:5') + ).toBeVisible() + + // change 5 to 67 + await page.locator('#code-mirror-override').getByText('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('ProgramMemory can be serialised', async ({ page, homePage }) => { + const u = await getUtils(page) + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `part = startSketchOn('XY') |> startProfileAt([0, 0], %) |> line([0, 1], %) |> line([1, 0], %) @@ -183,51 +197,61 @@ extrude001 = extrude(50, sketch001) repetitions: 3, distance: 6 }, %)` - ) - }) - await page.setBodyDimensions({ width: 1000, height: 500 }) - - const messages: string[] = [] - - // Listen for all console events and push the message text to an array - page.on('console', (message) => messages.push(message.text())) - await homePage.goToModelingScene() - await u.waitForPageLoad() - - // wait for execution done - await u.openDebugPanel() - await u.expectCmdLog('[data-message-type="execution-done"]') - - const forbiddenMessages = ['cannot serialize tagged newtype variant'] - forbiddenMessages.forEach((forbiddenMessage) => { - messages.forEach((message) => { - expect(message).not.toContain(forbiddenMessage) + ) }) - }) }) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + const messages: string[] = [] + + // Listen for all console events and push the message text to an array + page.on('console', (message) => messages.push(message.text())) + await homePage.goToModelingScene() + await u.waitForPageLoad() + + // wait for execution done + await u.openDebugPanel() + await u.expectCmdLog('[data-message-type="execution-done"]') + + const forbiddenMessages = ['cannot serialize tagged newtype variant'] + forbiddenMessages.forEach((forbiddenMessage) => { + messages.forEach((message) => { + expect(message).not.toContain(forbiddenMessage) + }) + }) + }) // Not relevant to us anymore, or at least for the time being. - test.skip('ensure the Zoo logo is not a link in browser app', async ({ page, homePage }) => { const u = await getUtils(page) - await page.setBodyDimensions({ width: 1000, height: 500 }) - await homePage.goToModelingScene() - await u.waitForPageLoad() - - const zooLogo = page.locator('[data-testid="app-logo"]') - // Make sure it's not a link - await expect(zooLogo).not.toHaveAttribute('href') }) + test.skip('ensure the Zoo logo is not a link in browser app', async ({ + page, + homePage, + }) => { + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1000, height: 500 }) + await homePage.goToModelingScene() + await u.waitForPageLoad() - test('Position _ Is Out Of Range... regression test', { tag: ['@skipWin'] }, async ({ context, page, homePage }) => { // SKip on windows, its being weird. - test.skip( - process.platform === 'win32', - 'This test is being weird on windows' - ) - - const u = await getUtils(page) - // const PUR = 400 / 37.5 //pixeltoUnitRatio - await page.setBodyDimensions({ width: 1200, height: 500 }) - await context.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `exampleSketch = startSketchOn("XZ") + const zooLogo = page.locator('[data-testid="app-logo"]') + // Make sure it's not a link + await expect(zooLogo).not.toHaveAttribute('href') + }) + + test( + 'Position _ Is Out Of Range... regression test', + { tag: ['@skipWin'] }, + async ({ context, page, homePage }) => { + // SKip on windows, its being weird. + test.skip( + process.platform === 'win32', + 'This test is being weird on windows' + ) + + const u = await getUtils(page) + // const PUR = 400 / 37.5 //pixeltoUnitRatio + await page.setBodyDimensions({ width: 1200, height: 500 }) + await context.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `exampleSketch = startSketchOn("XZ") |> startProfileAt([0, 0], %) |> angledLine({ angle: 50, length: 45 }, %) |> yLineTo(0, %) @@ -236,247 +260,259 @@ extrude001 = extrude(50, sketch001) example = extrude(5, exampleSketch) shell({ faces: ['end'], thickness: 0.25 }, exampleSketch)` - ) - }) - - await expect(async () => { - - await homePage.goToModelingScene() - await u.waitForPageLoad() + ) + }) - // error in guter - await expect(page.locator('.cm-lint-marker-error')).toBeVisible({ - timeout: 1_000, - }) - await page.waitForTimeout(200) - // expect it still to be there (sometimes it just clears for a bit?) - await expect(page.locator('.cm-lint-marker-error')).toBeVisible({ - timeout: 1_000, - }) - }).toPass({ timeout: 40_000, intervals: [1_000] }) - - // error text on hover - await page.hover('.cm-lint-marker-error') - await expect(page.getByText('Unexpected token: |').first()).toBeVisible() - - // Okay execution finished, let's start editing text below the error. - await u.codeLocator.click() - // Go to the end of the editor - // This bug happens when there is a diagnostic in the editor and you try to - // edit text below it. - // Or delete a huge chunk of text and then try to edit below it. - await page.keyboard.press('End') - await page.keyboard.down('Shift') - await page.keyboard.press('ArrowUp') - await page.keyboard.press('ArrowUp') - await page.keyboard.press('ArrowUp') - await page.keyboard.press('ArrowUp') - await page.keyboard.press('ArrowUp') - await page.keyboard.press('End') - await page.keyboard.up('Shift') - await page.keyboard.press('Backspace') - await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() - - await page.keyboard.press('Enter') - await page.keyboard.press('Enter') - await page.keyboard.type('thing: "blah"', { delay: 100 }) - await page.keyboard.press('Enter') - await page.keyboard.press('ArrowLeft') - - await expect(page.locator('.cm-content')) - .toContainText(`exampleSketch = startSketchOn("XZ") + await expect(async () => { + await homePage.goToModelingScene() + await u.waitForPageLoad() + + // error in guter + await expect(page.locator('.cm-lint-marker-error')).toBeVisible({ + timeout: 1_000, + }) + await page.waitForTimeout(200) + // expect it still to be there (sometimes it just clears for a bit?) + await expect(page.locator('.cm-lint-marker-error')).toBeVisible({ + timeout: 1_000, + }) + }).toPass({ timeout: 40_000, intervals: [1_000] }) + + // error text on hover + await page.hover('.cm-lint-marker-error') + await expect(page.getByText('Unexpected token: |').first()).toBeVisible() + + // Okay execution finished, let's start editing text below the error. + await u.codeLocator.click() + // Go to the end of the editor + // This bug happens when there is a diagnostic in the editor and you try to + // edit text below it. + // Or delete a huge chunk of text and then try to edit below it. + await page.keyboard.press('End') + await page.keyboard.down('Shift') + await page.keyboard.press('ArrowUp') + await page.keyboard.press('ArrowUp') + await page.keyboard.press('ArrowUp') + await page.keyboard.press('ArrowUp') + await page.keyboard.press('ArrowUp') + await page.keyboard.press('End') + await page.keyboard.up('Shift') + await page.keyboard.press('Backspace') + await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() + + await page.keyboard.press('Enter') + await page.keyboard.press('Enter') + await page.keyboard.type('thing: "blah"', { delay: 100 }) + await page.keyboard.press('Enter') + await page.keyboard.press('ArrowLeft') + + await expect(page.locator('.cm-content')) + .toContainText(`exampleSketch = startSketchOn("XZ") |> startProfileAt([0, 0], %) |> angledLine({ angle: 50, length: 45 }, %) |> yLineTo(0, %) |> close(%) thing: "blah"`) - - await expect(page.locator('.cm-lint-marker-error')).toBeVisible() }) - test('when engine fails export we handle the failure and alert the user', async ({ page, homePage }) => { const u = await getUtils(page) - await page.addInitScript( - async ({ code }) => { - localStorage.setItem('persistCode', code) - ;(window as any).playwrightSkipFilePicker = true - }, - { code: TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } + await expect(page.locator('.cm-lint-marker-error')).toBeVisible() + } ) - - await page.setBodyDimensions({ width: 1000, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - // wait for execution done - await u.openDebugPanel() - await u.expectCmdLog('[data-message-type="execution-done"]') - await u.closeDebugPanel() - - // expect zero errors in guter - await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() - - // export the model - const exportButton = page.getByTestId('export-pane-button') - await expect(exportButton).toBeVisible() - - // Click the export button - await exportButton.click() - - // Click the stl. - const stlOption = page.getByText('glTF') - await expect(stlOption).toBeVisible() - - await page.keyboard.press('Enter') - - // Click the checkbox - const submitButton = page.getByText('Confirm Export') - await expect(submitButton).toBeVisible() - - await page.keyboard.press('Enter') - - // Find the toast. - // Look out for the toast message - const exportingToastMessage = page.getByText(`Exporting...`) - const errorToastMessage = page.getByText(`Error while exporting`) - - const engineErrorToastMessage = page.getByText(`Nothing to export`) - await expect(engineErrorToastMessage).toBeVisible() - - // Make sure the exporting toast is gone - await expect(exportingToastMessage).not.toBeVisible() - - // Click the code editor - await page.locator('.cm-content').click() - - await page.waitForTimeout(2000) - - // Expect the toast to be gone - await expect(errorToastMessage).not.toBeVisible() - await expect(engineErrorToastMessage).not.toBeVisible() - - // Now add in code that works. - await page.locator('.cm-content').fill(bracket) - await page.keyboard.press('End') - await page.keyboard.press('Enter') - - // wait for execution done - await u.openDebugPanel() - await u.expectCmdLog('[data-message-type="execution-done"]') - await u.closeDebugPanel() - - // Now try exporting - - // Click the export button - await exportButton.click() - - // Click the stl. - await expect(stlOption).toBeVisible() - - await page.keyboard.press('Enter') - - // Click the checkbox - await expect(submitButton).toBeVisible() - - await page.keyboard.press('Enter') - - // Find the toast. - // Look out for the toast message - await expect(exportingToastMessage).toBeVisible() - - // Expect it to succeed. - await expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 }) - await expect(errorToastMessage).not.toBeVisible() - await expect(engineErrorToastMessage).not.toBeVisible() - - const successToastMessage = page.getByText(`Exported successfully`) - await expect(successToastMessage).toBeVisible() }) - test('ensure you can not export while an export is already going', { tag: ['@skipLinux', '@skipWin'] }, async ({ page, homePage }) => { // This is being weird on ubuntu and windows. - test.skip( - // eslint-disable-next-line jest/valid-title - process.platform === 'linux' || process.platform === 'win32', - 'This test is being weird on ubuntu' - ) - - const u = await getUtils(page) - await test.step('Set up the code and durations', async () => { + + test('when engine fails export we handle the failure and alert the user', async ({ + page, + homePage, + }) => { + const u = await getUtils(page) await page.addInitScript( async ({ code }) => { localStorage.setItem('persistCode', code) ;(window as any).playwrightSkipFilePicker = true }, - { - code: bracket, - } + { code: TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } ) - + await page.setBodyDimensions({ width: 1000, height: 500 }) - + await homePage.goToModelingScene() - await u.waitForPageLoad() - + await u.waitForPageLoad() + // wait for execution done await u.openDebugPanel() await u.expectCmdLog('[data-message-type="execution-done"]') await u.closeDebugPanel() - + // expect zero errors in guter await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() - }) - - const errorToastMessage = page.getByText(`Error while exporting`) - const exportingToastMessage = page.getByText(`Exporting...`) - const engineErrorToastMessage = page.getByText(`Nothing to export`) - const alreadyExportingToastMessage = page.getByText(`Already exporting`) - const successToastMessage = page.getByText(`Exported successfully`) - - await test.step('Blocked second export', async () => { - await clickExportButton(page) - - await expect(exportingToastMessage).toBeVisible() - - await clickExportButton(page) - - await test.step('The second export is blocked', async () => { - // Find the toast. - // Look out for the toast message - await Promise.all([ - expect(exportingToastMessage.first()).toBeVisible(), - expect(alreadyExportingToastMessage).toBeVisible(), - ]) - }) - - await test.step('The first export still succeeds', async () => { - await Promise.all([ - expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 }), - expect(errorToastMessage).not.toBeVisible(), - expect(engineErrorToastMessage).not.toBeVisible(), - expect(successToastMessage).toBeVisible({ timeout: 15_000 }), - expect(alreadyExportingToastMessage).not.toBeVisible({ - timeout: 15_000, - }), - ]) - }) - }) - - await test.step('Successful, unblocked export', async () => { - // Try exporting again. - await clickExportButton(page) - + + // export the model + const exportButton = page.getByTestId('export-pane-button') + await expect(exportButton).toBeVisible() + + // Click the export button + await exportButton.click() + + // Click the stl. + const stlOption = page.getByText('glTF') + await expect(stlOption).toBeVisible() + + await page.keyboard.press('Enter') + + // Click the checkbox + const submitButton = page.getByText('Confirm Export') + await expect(submitButton).toBeVisible() + + await page.keyboard.press('Enter') + + // Find the toast. + // Look out for the toast message + const exportingToastMessage = page.getByText(`Exporting...`) + const errorToastMessage = page.getByText(`Error while exporting`) + + const engineErrorToastMessage = page.getByText(`Nothing to export`) + await expect(engineErrorToastMessage).toBeVisible() + + // Make sure the exporting toast is gone + await expect(exportingToastMessage).not.toBeVisible() + + // Click the code editor + await page.locator('.cm-content').click() + + await page.waitForTimeout(2000) + + // Expect the toast to be gone + await expect(errorToastMessage).not.toBeVisible() + await expect(engineErrorToastMessage).not.toBeVisible() + + // Now add in code that works. + await page.locator('.cm-content').fill(bracket) + await page.keyboard.press('End') + await page.keyboard.press('Enter') + + // wait for execution done + await u.openDebugPanel() + await u.expectCmdLog('[data-message-type="execution-done"]') + await u.closeDebugPanel() + + // Now try exporting + + // Click the export button + await exportButton.click() + + // Click the stl. + await expect(stlOption).toBeVisible() + + await page.keyboard.press('Enter') + + // Click the checkbox + await expect(submitButton).toBeVisible() + + await page.keyboard.press('Enter') + // Find the toast. // Look out for the toast message await expect(exportingToastMessage).toBeVisible() - + // Expect it to succeed. - await Promise.all([ - expect(exportingToastMessage).not.toBeVisible(), - expect(errorToastMessage).not.toBeVisible(), - expect(engineErrorToastMessage).not.toBeVisible(), - expect(alreadyExportingToastMessage).not.toBeVisible(), - ]) - + await expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 }) + await expect(errorToastMessage).not.toBeVisible() + await expect(engineErrorToastMessage).not.toBeVisible() + + const successToastMessage = page.getByText(`Exported successfully`) await expect(successToastMessage).toBeVisible() - }) }) + }) + test( + 'ensure you can not export while an export is already going', + { tag: ['@skipLinux', '@skipWin'] }, + async ({ page, homePage }) => { + // This is being weird on ubuntu and windows. + test.skip( + // eslint-disable-next-line jest/valid-title + process.platform === 'linux' || process.platform === 'win32', + 'This test is being weird on ubuntu' + ) + + const u = await getUtils(page) + await test.step('Set up the code and durations', async () => { + await page.addInitScript( + async ({ code }) => { + localStorage.setItem('persistCode', code) + ;(window as any).playwrightSkipFilePicker = true + }, + { + code: bracket, + } + ) + + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + // wait for execution done + await u.openDebugPanel() + await u.expectCmdLog('[data-message-type="execution-done"]') + await u.closeDebugPanel() + + // expect zero errors in guter + await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() + }) + + const errorToastMessage = page.getByText(`Error while exporting`) + const exportingToastMessage = page.getByText(`Exporting...`) + const engineErrorToastMessage = page.getByText(`Nothing to export`) + const alreadyExportingToastMessage = page.getByText(`Already exporting`) + const successToastMessage = page.getByText(`Exported successfully`) + + await test.step('Blocked second export', async () => { + await clickExportButton(page) + + await expect(exportingToastMessage).toBeVisible() + + await clickExportButton(page) + + await test.step('The second export is blocked', async () => { + // Find the toast. + // Look out for the toast message + await Promise.all([ + expect(exportingToastMessage.first()).toBeVisible(), + expect(alreadyExportingToastMessage).toBeVisible(), + ]) + }) + + await test.step('The first export still succeeds', async () => { + await Promise.all([ + expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 }), + expect(errorToastMessage).not.toBeVisible(), + expect(engineErrorToastMessage).not.toBeVisible(), + expect(successToastMessage).toBeVisible({ timeout: 15_000 }), + expect(alreadyExportingToastMessage).not.toBeVisible({ + timeout: 15_000, + }), + ]) + }) + }) + + await test.step('Successful, unblocked export', async () => { + // Try exporting again. + await clickExportButton(page) + + // Find the toast. + // Look out for the toast message + await expect(exportingToastMessage).toBeVisible() + + // Expect it to succeed. + await Promise.all([ + expect(exportingToastMessage).not.toBeVisible(), + expect(errorToastMessage).not.toBeVisible(), + expect(engineErrorToastMessage).not.toBeVisible(), + expect(alreadyExportingToastMessage).not.toBeVisible(), + ]) + + await expect(successToastMessage).toBeVisible() + }) + } + ) test( `Network health indicator only appears in modeling view`, @@ -520,57 +556,62 @@ extrude001 = extrude(50, sketch001) } ) - test(`View gizmo stays visible even when zoomed out all the way`, async ({ page, homePage }) => { const u = await getUtils(page) - - // Constants and locators - const planeColor: [number, number, number] = [170, 220, 170] - const bgColor: [number, number, number] = [27, 27, 27] - const middlePixelIsColor = async (color: [number, number, number]) => { - return u.getGreatestPixDiff({ x: 600, y: 250 }, color) - } - const gizmo = page.locator('[aria-label*=gizmo]') - - await test.step(`Load an empty file`, async () => { - await page.addInitScript(async () => { - localStorage.setItem('persistCode', '') - }) - await page.setBodyDimensions({ width: 1200, height: 500 }) - await homePage.goToModelingScene() - await u.waitForPageLoad() - await u.closeKclCodePanel() - }) - - await test.step(`Zoom out until you can't see the default planes`, async () => { - await expect - .poll(async () => middlePixelIsColor(planeColor), { - timeout: 5000, - message: 'Plane color is visible', - }) - .toBeLessThan(15) - - let maxZoomOuts = 10 - let middlePixelIsBackgroundColor = - (await middlePixelIsColor(bgColor)) < 10 - while (!middlePixelIsBackgroundColor && maxZoomOuts > 0) { - await page.keyboard.down('Control') - await page.mouse.move(600, 460) - await page.mouse.down({ button: 'right' }) - await page.mouse.move(600, 50, { steps: 20 }) - await page.mouse.up({ button: 'right' }) - await page.keyboard.up('Control') - await page.waitForTimeout(100) - maxZoomOuts-- - middlePixelIsBackgroundColor = (await middlePixelIsColor(bgColor)) < 10 + test(`View gizmo stays visible even when zoomed out all the way`, async ({ + page, + homePage, + }) => { + const u = await getUtils(page) + + // Constants and locators + const planeColor: [number, number, number] = [170, 220, 170] + const bgColor: [number, number, number] = [27, 27, 27] + const middlePixelIsColor = async (color: [number, number, number]) => { + return u.getGreatestPixDiff({ x: 600, y: 250 }, color) } - - expect(middlePixelIsBackgroundColor, { - message: 'We no longer the default planes', - }).toBeTruthy() + const gizmo = page.locator('[aria-label*=gizmo]') + + await test.step(`Load an empty file`, async () => { + await page.addInitScript(async () => { + localStorage.setItem('persistCode', '') + }) + await page.setBodyDimensions({ width: 1200, height: 500 }) + await homePage.goToModelingScene() + await u.waitForPageLoad() + await u.closeKclCodePanel() + }) + + await test.step(`Zoom out until you can't see the default planes`, async () => { + await expect + .poll(async () => middlePixelIsColor(planeColor), { + timeout: 5000, + message: 'Plane color is visible', + }) + .toBeLessThan(15) + + let maxZoomOuts = 10 + let middlePixelIsBackgroundColor = + (await middlePixelIsColor(bgColor)) < 10 + while (!middlePixelIsBackgroundColor && maxZoomOuts > 0) { + await page.keyboard.down('Control') + await page.mouse.move(600, 460) + await page.mouse.down({ button: 'right' }) + await page.mouse.move(600, 50, { steps: 20 }) + await page.mouse.up({ button: 'right' }) + await page.keyboard.up('Control') + await page.waitForTimeout(100) + maxZoomOuts-- + middlePixelIsBackgroundColor = (await middlePixelIsColor(bgColor)) < 10 + } + + expect(middlePixelIsBackgroundColor, { + message: 'We no longer the default planes', + }).toBeTruthy() + }) + + await test.step(`Check that the gizmo is still visible`, async () => { + await expect(gizmo).toBeVisible() + }) }) - - await test.step(`Check that the gizmo is still visible`, async () => { - await expect(gizmo).toBeVisible() - }) }) }) async function clickExportButton(page: Page) { diff --git a/e2e/playwright/test-network-and-connection-issues.spec.ts b/e2e/playwright/test-network-and-connection-issues.spec.ts index b0ad1c399..b13681f82 100644 --- a/e2e/playwright/test-network-and-connection-issues.spec.ts +++ b/e2e/playwright/test-network-and-connection-issues.spec.ts @@ -3,210 +3,221 @@ import { test, expect } from './zoo-test' import { commonPoints, getUtils } from './test-utils' test.describe('Test network and connection issues', () => { - test('simulate network down and network little widget', async ({ page, homePage }) => { const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - - const networkToggle = page.getByTestId('network-toggle') - - // This is how we wait until the stream is online - await expect( - page.getByRole('button', { name: 'Start Sketch' }) - ).not.toBeDisabled({ timeout: 15000 }) - - const networkWidget = page.locator('[data-testid="network-toggle"]') - await expect(networkWidget).toBeVisible() - await networkWidget.hover() - - const networkPopover = page.locator('[data-testid="network-popover"]') - await expect(networkPopover).not.toBeVisible() - - // (First check) Expect the network to be up - await expect(networkToggle).toContainText('Connected') - - // Click the network widget - await networkWidget.click() - - // Check the modal opened. - await expect(networkPopover).toBeVisible() - - // Click off the modal. - await page.mouse.click(100, 100) - await expect(networkPopover).not.toBeVisible() - - // Turn off the network - await u.emulateNetworkConditions({ - offline: true, - // values of 0 remove any active throttling. crbug.com/456324#c9 - latency: 0, - downloadThroughput: -1, - uploadThroughput: -1, - }) - - // Expect the network to be down - await expect(networkToggle).toContainText('Problem') - - // Click the network widget - await networkWidget.click() - - // Check the modal opened. - await expect(networkPopover).toBeVisible() - - // Click off the modal. - await page.mouse.click(0, 0) - await expect(networkPopover).not.toBeVisible() - - // Turn back on the network - await u.emulateNetworkConditions({ - offline: false, - // values of 0 remove any active throttling. crbug.com/456324#c9 - latency: 0, - downloadThroughput: -1, - uploadThroughput: -1, - }) - - await expect( - page.getByRole('button', { name: 'Start Sketch' }) - ).not.toBeDisabled({ timeout: 15000 }) - - // (Second check) expect the network to be up - await expect(networkToggle).toContainText('Connected') }) + test('simulate network down and network little widget', async ({ + page, + homePage, + }) => { + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) - test('Engine disconnect & reconnect in sketch mode', async ({ page, browserName, homePage }) => { // TODO: Don't skip Mac for these. After `window.tearDown` is working in Safari, these should work on webkit - const networkToggle = page.getByTestId('network-toggle') - - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - const PUR = 400 / 37.5 //pixeltoUnitRatio - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await u.openDebugPanel() - // click on "Start Sketch" button - await u.clearCommandLogs() - await page.getByRole('button', { name: 'Start Sketch' }).click() - await page.waitForTimeout(100) - - // select a plane - await page.mouse.click(700, 200) - - await expect(page.locator('.cm-content')).toHaveText( - `sketch001 = startSketchOn('XZ')` - ) - await u.closeDebugPanel() - - await page.waitForTimeout(500) // TODO detect animation ending, or disable animation - - const startXPx = 600 - await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) - await expect(page.locator('.cm-content')) - .toHaveText(`sketch001 = startSketchOn('XZ') + await homePage.goToModelingScene() + + const networkToggle = page.getByTestId('network-toggle') + + // This is how we wait until the stream is online + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).not.toBeDisabled({ timeout: 15000 }) + + const networkWidget = page.locator('[data-testid="network-toggle"]') + await expect(networkWidget).toBeVisible() + await networkWidget.hover() + + const networkPopover = page.locator('[data-testid="network-popover"]') + await expect(networkPopover).not.toBeVisible() + + // (First check) Expect the network to be up + await expect(networkToggle).toContainText('Connected') + + // Click the network widget + await networkWidget.click() + + // Check the modal opened. + await expect(networkPopover).toBeVisible() + + // Click off the modal. + await page.mouse.click(100, 100) + await expect(networkPopover).not.toBeVisible() + + // Turn off the network + await u.emulateNetworkConditions({ + offline: true, + // values of 0 remove any active throttling. crbug.com/456324#c9 + latency: 0, + downloadThroughput: -1, + uploadThroughput: -1, + }) + + // Expect the network to be down + await expect(networkToggle).toContainText('Problem') + + // Click the network widget + await networkWidget.click() + + // Check the modal opened. + await expect(networkPopover).toBeVisible() + + // Click off the modal. + await page.mouse.click(0, 0) + await expect(networkPopover).not.toBeVisible() + + // Turn back on the network + await u.emulateNetworkConditions({ + offline: false, + // values of 0 remove any active throttling. crbug.com/456324#c9 + latency: 0, + downloadThroughput: -1, + uploadThroughput: -1, + }) + + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).not.toBeDisabled({ timeout: 15000 }) + + // (Second check) expect the network to be up + await expect(networkToggle).toContainText('Connected') + }) + + test('Engine disconnect & reconnect in sketch mode', async ({ + page, + browserName, + homePage, + }) => { + // TODO: Don't skip Mac for these. After `window.tearDown` is working in Safari, these should work on webkit + const networkToggle = page.getByTestId('network-toggle') + + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + const PUR = 400 / 37.5 //pixeltoUnitRatio + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await u.openDebugPanel() + // click on "Start Sketch" button + await u.clearCommandLogs() + await page.getByRole('button', { name: 'Start Sketch' }).click() + await page.waitForTimeout(100) + + // select a plane + await page.mouse.click(700, 200) + + await expect(page.locator('.cm-content')).toHaveText( + `sketch001 = startSketchOn('XZ')` + ) + await u.closeDebugPanel() + + await page.waitForTimeout(500) // TODO detect animation ending, or disable animation + + const startXPx = 600 + await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) + await expect(page.locator('.cm-content')) + .toHaveText(`sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %)`) - await page.waitForTimeout(100) - - await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) - await page.waitForTimeout(100) - - await expect(page.locator('.cm-content')) - .toHaveText(`sketch001 = startSketchOn('XZ') + await page.waitForTimeout(100) + + await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) + await page.waitForTimeout(100) + + await expect(page.locator('.cm-content')) + .toHaveText(`sketch001 = startSketchOn('XZ') |> startProfileAt(${commonPoints.startAt}, %) |> xLine(${commonPoints.num1}, %)`) - - // Expect the network to be up - await expect(networkToggle).toContainText('Connected') - - // simulate network down - await u.emulateNetworkConditions({ - offline: true, - // values of 0 remove any active throttling. crbug.com/456324#c9 - latency: 0, - downloadThroughput: -1, - uploadThroughput: -1, - }) - - // Expect the network to be down - await expect(networkToggle).toContainText('Problem') - - // Ensure we are not in sketch mode - await expect( - page.getByRole('button', { name: 'Exit Sketch' }) - ).not.toBeVisible() - await expect( - page.getByRole('button', { name: 'Start Sketch' }) - ).toBeVisible() - - // simulate network up - await u.emulateNetworkConditions({ - offline: false, - // values of 0 remove any active throttling. crbug.com/456324#c9 - latency: 0, - downloadThroughput: -1, - uploadThroughput: -1, - }) - - // Wait for the app to be ready for use - await expect( - page.getByRole('button', { name: 'Start Sketch' }) - ).not.toBeDisabled({ timeout: 15000 }) - - // Expect the network to be up - await expect(networkToggle).toContainText('Connected') - await expect(page.getByTestId('loading-stream')).not.toBeAttached() - - // Click off the code pane. - await page.mouse.click(100, 100) - - // select a line - await page.getByText(`startProfileAt(${commonPoints.startAt}, %)`).click() - - // enter sketch again - await u.doAndWaitForCmd( - () => page.getByRole('button', { name: 'Edit Sketch' }).click(), - 'default_camera_get_settings' - ) - await page.waitForTimeout(150) - - // Click the line tool - await page.getByRole('button', { name: 'line Line', exact: true }).click() - - await page.waitForTimeout(150) - - // Ensure we can continue sketching - await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20) - await expect.poll(u.normalisedEditorCode) - .toBe(`sketch001 = startSketchOn('XZ') + + // Expect the network to be up + await expect(networkToggle).toContainText('Connected') + + // simulate network down + await u.emulateNetworkConditions({ + offline: true, + // values of 0 remove any active throttling. crbug.com/456324#c9 + latency: 0, + downloadThroughput: -1, + uploadThroughput: -1, + }) + + // Expect the network to be down + await expect(networkToggle).toContainText('Problem') + + // Ensure we are not in sketch mode + await expect( + page.getByRole('button', { name: 'Exit Sketch' }) + ).not.toBeVisible() + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).toBeVisible() + + // simulate network up + await u.emulateNetworkConditions({ + offline: false, + // values of 0 remove any active throttling. crbug.com/456324#c9 + latency: 0, + downloadThroughput: -1, + uploadThroughput: -1, + }) + + // Wait for the app to be ready for use + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).not.toBeDisabled({ timeout: 15000 }) + + // Expect the network to be up + await expect(networkToggle).toContainText('Connected') + await expect(page.getByTestId('loading-stream')).not.toBeAttached() + + // Click off the code pane. + await page.mouse.click(100, 100) + + // select a line + await page.getByText(`startProfileAt(${commonPoints.startAt}, %)`).click() + + // enter sketch again + await u.doAndWaitForCmd( + () => page.getByRole('button', { name: 'Edit Sketch' }).click(), + 'default_camera_get_settings' + ) + await page.waitForTimeout(150) + + // Click the line tool + await page.getByRole('button', { name: 'line Line', exact: true }).click() + + await page.waitForTimeout(150) + + // Ensure we can continue sketching + await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20) + await expect.poll(u.normalisedEditorCode) + .toBe(`sketch001 = startSketchOn('XZ') |> startProfileAt([12.34, -12.34], %) |> xLine(12.34, %) |> line([-12.34, 12.34], %) `) - await page.waitForTimeout(100) - await page.mouse.click(startXPx, 500 - PUR * 20) - - await expect.poll(u.normalisedEditorCode) - .toBe(`sketch001 = startSketchOn('XZ') + await page.waitForTimeout(100) + await page.mouse.click(startXPx, 500 - PUR * 20) + + await expect.poll(u.normalisedEditorCode) + .toBe(`sketch001 = startSketchOn('XZ') |> startProfileAt([12.34, -12.34], %) |> xLine(12.34, %) |> line([-12.34, 12.34], %) |> xLine(-12.34, %) `) - - // Unequip line tool - await page.keyboard.press('Escape') - // Make sure we didn't pop out of sketch mode. - await expect( - page.getByRole('button', { name: 'Exit Sketch' }) - ).toBeVisible() - await expect( - page.getByRole('button', { name: 'line Line', exact: true }) - ).not.toHaveAttribute('aria-pressed', 'true') - - // Exit sketch - await page.keyboard.press('Escape') - await expect( - page.getByRole('button', { name: 'Exit Sketch' }) - ).not.toBeVisible() }) + + // Unequip line tool + await page.keyboard.press('Escape') + // Make sure we didn't pop out of sketch mode. + await expect( + page.getByRole('button', { name: 'Exit Sketch' }) + ).toBeVisible() + await expect( + page.getByRole('button', { name: 'line Line', exact: true }) + ).not.toHaveAttribute('aria-pressed', 'true') + + // Exit sketch + await page.keyboard.press('Escape') + await expect( + page.getByRole('button', { name: 'Exit Sketch' }) + ).not.toBeVisible() + }) }) diff --git a/e2e/playwright/test-utils.ts b/e2e/playwright/test-utils.ts index 5adc4a8de..45b27b43c 100644 --- a/e2e/playwright/test-utils.ts +++ b/e2e/playwright/test-utils.ts @@ -1157,3 +1157,12 @@ export function getPixelRGBs(page: Page) { }) } } + +export async function pollEditorLinesSelectedLength(page: Page, lines: number) { + return expect + .poll(async () => { + const lines = await page.locator('.cm-activeLine').all() + return lines.length + }) + .toBe(lines) +} diff --git a/e2e/playwright/testing-camera-movement.spec.ts b/e2e/playwright/testing-camera-movement.spec.ts index c24499ea3..e168cbd48 100644 --- a/e2e/playwright/testing-camera-movement.spec.ts +++ b/e2e/playwright/testing-camera-movement.spec.ts @@ -1,30 +1,118 @@ import { test, expect } from './zoo-test' import { EngineCommand } from 'lang/std/artifactGraph' import { uuidv4 } from 'lib/utils' -import { getUtils, } from './test-utils' +import { getUtils } from './test-utils' test.describe('Testing Camera Movement', () => { test('Can move camera reliably', async ({ page, context, homePage }) => { - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.openAndClearDebugPanel() - await u.closeKclCodePanel() - - const camPos: [number, number, number] = [0, 85, 85] - const bakeInRetries = async ( - mouseActions: any, - xyz: [number, number, number], - cnt = 0 - ) => { - // hack that we're implemented our own retry instead of using retries built into playwright. - // however each of these camera drags can be flaky, because of udp - // and so putting them together means only one needs to fail to make this test extra flaky. - // this way we can retry within the test - // We could break them out into separate tests, but the longest past of the test is waiting - // for the stream to start, so it can be good to bundle related things together. - + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.openAndClearDebugPanel() + await u.closeKclCodePanel() + + const camPos: [number, number, number] = [0, 85, 85] + const bakeInRetries = async ( + mouseActions: any, + xyz: [number, number, number], + cnt = 0 + ) => { + // hack that we're implemented our own retry instead of using retries built into playwright. + // however each of these camera drags can be flaky, because of udp + // and so putting them together means only one needs to fail to make this test extra flaky. + // this way we can retry within the test + // We could break them out into separate tests, but the longest past of the test is waiting + // for the stream to start, so it can be good to bundle related things together. + + const camCommand: EngineCommand = { + type: 'modeling_cmd_req', + cmd_id: uuidv4(), + cmd: { + type: 'default_camera_look_at', + center: { x: 0, y: 0, z: 0 }, + vantage: { x: camPos[0], y: camPos[1], z: camPos[2] }, + up: { x: 0, y: 0, z: 1 }, + }, + } + const updateCamCommand: EngineCommand = { + type: 'modeling_cmd_req', + cmd_id: uuidv4(), + cmd: { + type: 'default_camera_get_settings', + }, + } + await u.sendCustomCmd(camCommand) + await page.waitForTimeout(100) + await u.sendCustomCmd(updateCamCommand) + await page.waitForTimeout(100) + + // rotate + await u.closeDebugPanel() + await page.getByRole('button', { name: 'Start Sketch' }).click() + await page.waitForTimeout(100) + // const yo = page.getByTestId('cam-x-position').inputValue() + + await u.doAndWaitForImageDiff(async () => { + await mouseActions() + + await u.openAndClearDebugPanel() + + await u.closeDebugPanel() + await page.waitForTimeout(100) + }, 300) + + await u.openAndClearDebugPanel() + await page.getByTestId('cam-x-position').isVisible() + + const vals = await Promise.all([ + page.getByTestId('cam-x-position').inputValue(), + page.getByTestId('cam-y-position').inputValue(), + page.getByTestId('cam-z-position').inputValue(), + ]) + const xError = Math.abs(Number(vals[0]) + xyz[0]) + const yError = Math.abs(Number(vals[1]) + xyz[1]) + const zError = Math.abs(Number(vals[2]) + xyz[2]) + + let shouldRetry = false + + if (xError > 5 || yError > 5 || zError > 5) { + if (cnt > 2) { + console.log('xVal', vals[0], 'xError', xError) + console.log('yVal', vals[1], 'yError', yError) + console.log('zVal', vals[2], 'zError', zError) + + throw new Error('Camera position not as expected') + } + shouldRetry = true + } + await page.getByRole('button', { name: 'Exit Sketch' }).click() + await page.waitForTimeout(100) + if (shouldRetry) await bakeInRetries(mouseActions, xyz, cnt + 1) + } + await bakeInRetries(async () => { + await page.mouse.move(700, 200) + await page.mouse.down({ button: 'right' }) + const appLogoBBox = await page.getByTestId('app-logo').boundingBox() + expect(appLogoBBox).not.toBeNull() + if (!appLogoBBox) throw new Error('app logo not found') + await page.mouse.move( + appLogoBBox.x + appLogoBBox.width / 2, + appLogoBBox.y + appLogoBBox.height / 2 + ) + await page.mouse.move(600, 303) + await page.mouse.up({ button: 'right' }) + }, [4, -10.5, -120]) + + await bakeInRetries(async () => { + await page.keyboard.down('Shift') + await page.mouse.move(600, 200) + await page.mouse.down({ button: 'right' }) + await page.mouse.move(700, 200, { steps: 2 }) + await page.mouse.up({ button: 'right' }) + await page.keyboard.up('Shift') + }, [-19, -85, -85]) + const camCommand: EngineCommand = { type: 'modeling_cmd_req', cmd_id: uuidv4(), @@ -46,418 +134,283 @@ test.describe('Testing Camera Movement', () => { await page.waitForTimeout(100) await u.sendCustomCmd(updateCamCommand) await page.waitForTimeout(100) - - // rotate + + await u.clearCommandLogs() await u.closeDebugPanel() + + await page.getByRole('button', { name: 'Start Sketch' }).click() + await page.waitForTimeout(200) + + // zoom + await u.doAndWaitForImageDiff(async () => { + await page.keyboard.down('Control') + await page.mouse.move(700, 400) + await page.mouse.down({ button: 'right' }) + await page.mouse.move(700, 300) + await page.mouse.up({ button: 'right' }) + await page.keyboard.up('Control') + + await u.openDebugPanel() + await page.waitForTimeout(300) + await u.clearCommandLogs() + + await u.closeDebugPanel() + }, 300) + + // zoom with scroll + await u.openAndClearDebugPanel() + // TODO, it appears we don't get the cam setting back from the engine when the interaction is zoom into `backInRetries` once the information is sent back on zoom + // await expect(Math.abs(Number(await page.getByTestId('cam-x-position').inputValue()) + 12)).toBeLessThan(1.5) + // await expect(Math.abs(Number(await page.getByTestId('cam-y-position').inputValue()) - 85)).toBeLessThan(1.5) + // await expect(Math.abs(Number(await page.getByTestId('cam-z-position').inputValue()) - 85)).toBeLessThan(1.5) + + await page.getByRole('button', { name: 'Exit Sketch' }).click() + + await bakeInRetries(async () => { + await page.mouse.move(700, 400) + await page.mouse.wheel(0, -100) + }, [0, -85, -85]) + }) + + test('Zoom should be consistent when exiting or entering sketches', async ({ + page, + homePage, + }) => { + // start new sketch pan and zoom before exiting, when exiting the sketch should stay in the same place + // than zoom and pan outside of sketch mode and enter again and it should not change from where it is + // than again for sketching + + test.skip(process.platform !== 'darwin', 'Zoom should be consistent') + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.openDebugPanel() + + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).not.toBeDisabled() + 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 page.waitForTimeout(100) - // const yo = page.getByTestId('cam-x-position').inputValue() - - await u.doAndWaitForImageDiff(async () => { - await mouseActions() - - await u.openAndClearDebugPanel() - - await u.closeDebugPanel() - await page.waitForTimeout(100) - }, 300) - - await u.openAndClearDebugPanel() - await page.getByTestId('cam-x-position').isVisible() - - const vals = await Promise.all([ - page.getByTestId('cam-x-position').inputValue(), - page.getByTestId('cam-y-position').inputValue(), - page.getByTestId('cam-z-position').inputValue(), - ]) - const xError = Math.abs(Number(vals[0]) + xyz[0]) - const yError = Math.abs(Number(vals[1]) + xyz[1]) - const zError = Math.abs(Number(vals[2]) + xyz[2]) - - let shouldRetry = false - - if (xError > 5 || yError > 5 || zError > 5) { - if (cnt > 2) { - console.log('xVal', vals[0], 'xError', xError) - console.log('yVal', vals[1], 'yError', yError) - console.log('zVal', vals[2], 'zError', zError) - - throw new Error('Camera position not as expected') - } - shouldRetry = true - } - await page.getByRole('button', { name: 'Exit Sketch' }).click() - await page.waitForTimeout(100) - if (shouldRetry) await bakeInRetries(mouseActions, xyz, cnt + 1) - } - await bakeInRetries(async () => { - await page.mouse.move(700, 200) - await page.mouse.down({ button: 'right' }) - const appLogoBBox = await page.getByTestId('app-logo').boundingBox() - expect(appLogoBBox).not.toBeNull() - if (!appLogoBBox) throw new Error('app logo not found') - await page.mouse.move( - appLogoBBox.x + appLogoBBox.width / 2, - appLogoBBox.y + appLogoBBox.height / 2 - ) - await page.mouse.move(600, 303) - await page.mouse.up({ button: 'right' }) - }, [4, -10.5, -120]) - - await bakeInRetries(async () => { + + // select a plane + await page.mouse.click(700, 325) + + let code = `sketch001 = startSketchOn('XY')` + await expect(u.codeLocator).toHaveText(code) + await u.closeDebugPanel() + + await page.waitForTimeout(500) // TODO detect animation ending, or disable animation + + // move the camera slightly await page.keyboard.down('Shift') - await page.mouse.move(600, 200) + await page.mouse.move(700, 300) await page.mouse.down({ button: 'right' }) - await page.mouse.move(700, 200, { steps: 2 }) + await page.mouse.move(800, 200) await page.mouse.up({ button: 'right' }) await page.keyboard.up('Shift') - }, [-19, -85, -85]) - - const camCommand: EngineCommand = { - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'default_camera_look_at', - center: { x: 0, y: 0, z: 0 }, - vantage: { x: camPos[0], y: camPos[1], z: camPos[2] }, - up: { x: 0, y: 0, z: 1 }, - }, - } - const updateCamCommand: EngineCommand = { - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'default_camera_get_settings', - }, - } - await u.sendCustomCmd(camCommand) - await page.waitForTimeout(100) - await u.sendCustomCmd(updateCamCommand) - await page.waitForTimeout(100) - - await u.clearCommandLogs() - await u.closeDebugPanel() - - await page.getByRole('button', { name: 'Start Sketch' }).click() - await page.waitForTimeout(200) - - // zoom - await u.doAndWaitForImageDiff(async () => { - await page.keyboard.down('Control') - await page.mouse.move(700, 400) - await page.mouse.down({ button: 'right' }) - await page.mouse.move(700, 300) - await page.mouse.up({ button: 'right' }) - await page.keyboard.up('Control') - - await u.openDebugPanel() - await page.waitForTimeout(300) - await u.clearCommandLogs() - - await u.closeDebugPanel() - }, 300) - - // zoom with scroll - await u.openAndClearDebugPanel() - // TODO, it appears we don't get the cam setting back from the engine when the interaction is zoom into `backInRetries` once the information is sent back on zoom - // await expect(Math.abs(Number(await page.getByTestId('cam-x-position').inputValue()) + 12)).toBeLessThan(1.5) - // await expect(Math.abs(Number(await page.getByTestId('cam-y-position').inputValue()) - 85)).toBeLessThan(1.5) - // await expect(Math.abs(Number(await page.getByTestId('cam-z-position').inputValue()) - 85)).toBeLessThan(1.5) - - await page.getByRole('button', { name: 'Exit Sketch' }).click() - - await bakeInRetries(async () => { - await page.mouse.move(700, 400) - await page.mouse.wheel(0, -100) - }, [0, -85, -85]) }) - test('Zoom should be consistent when exiting or entering sketches', async ({ page, homePage }) => { // start new sketch pan and zoom before exiting, when exiting the sketch should stay in the same place - // than zoom and pan outside of sketch mode and enter again and it should not change from where it is - // than again for sketching - - test.skip(process.platform !== 'darwin', 'Zoom should be consistent') - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.openDebugPanel() - - await expect( - page.getByRole('button', { name: 'Start Sketch' }) - ).not.toBeDisabled() - 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 page.waitForTimeout(100) - - // select a plane - await page.mouse.click(700, 325) - - let code = `sketch001 = startSketchOn('XY')` - await expect(u.codeLocator).toHaveText(code) - await u.closeDebugPanel() - - await page.waitForTimeout(500) // TODO detect animation ending, or disable animation - - // move the camera slightly - await page.keyboard.down('Shift') - await page.mouse.move(700, 300) - await page.mouse.down({ button: 'right' }) - await page.mouse.move(800, 200) - await page.mouse.up({ button: 'right' }) - await page.keyboard.up('Shift') - - let y = 350, - x = 948 - - await u.canvasLocator.click({ position: { x: 783, y } }) - code += `\n |> startProfileAt([8.12, -12.98], %)` - // await expect(u.codeLocator).toHaveText(code) - await u.canvasLocator.click({ position: { x, y } }) - code += `\n |> line([11.18, 0], %)` - // await expect(u.codeLocator).toHaveText(code) - await u.canvasLocator.click({ position: { x, y: 275 } }) - code += `\n |> line([0, 6.99], %)` - // await expect(u.codeLocator).toHaveText(code) - - // click the line button - await page.getByRole('button', { name: 'line Line', exact: true }).click() - - const hoverOverNothing = async () => { - // await u.canvasLocator.hover({position: {x: 700, y: 325}}) - await page.mouse.move(700, 325) - await page.waitForTimeout(100) - await expect(page.getByTestId('hover-highlight')).not.toBeVisible({ + let y = 350, + x = 948 + + await u.canvasLocator.click({ position: { x: 783, y } }) + code += `\n |> startProfileAt([8.12, -12.98], %)` + // await expect(u.codeLocator).toHaveText(code) + await u.canvasLocator.click({ position: { x, y } }) + code += `\n |> line([11.18, 0], %)` + // await expect(u.codeLocator).toHaveText(code) + await u.canvasLocator.click({ position: { x, y: 275 } }) + code += `\n |> line([0, 6.99], %)` + // await expect(u.codeLocator).toHaveText(code) + + // click the line button + await page.getByRole('button', { name: 'line Line', exact: true }).click() + + const hoverOverNothing = async () => { + // await u.canvasLocator.hover({position: {x: 700, y: 325}}) + await page.mouse.move(700, 325) + await page.waitForTimeout(100) + await expect(page.getByTestId('hover-highlight')).not.toBeVisible({ + timeout: 10_000, + }) + } + + await expect(page.getByTestId('hover-highlight')).not.toBeVisible() + + await page.waitForTimeout(200) + // hover over horizontal line + await u.canvasLocator.hover({ position: { x: 800, y } }) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ timeout: 10_000, }) - } - - await expect(page.getByTestId('hover-highlight')).not.toBeVisible() - - await page.waitForTimeout(200) - // hover over horizontal line - await u.canvasLocator.hover({ position: { x: 800, y } }) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - await page.waitForTimeout(200) - - await hoverOverNothing() - await page.waitForTimeout(200) - // hover over vertical line - await u.canvasLocator.hover({ position: { x, y: 325 } }) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - - await hoverOverNothing() - - // click exit sketch - await page.getByRole('button', { name: 'Exit Sketch' }).click() - await page.waitForTimeout(400) - - await hoverOverNothing() - await page.waitForTimeout(200) - // hover over horizontal line - await page.mouse.move(858, y, { steps: 5 }) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - - await hoverOverNothing() - - // hover over vertical line - await page.mouse.move(x, 325) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - - await hoverOverNothing() - - // hover over vertical line - await page.mouse.move(857, y) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - // now click it - await page.mouse.click(857, y) - - await expect( - page.getByRole('button', { name: 'Edit Sketch' }) - ).toBeVisible() - await hoverOverNothing() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - await page.waitForTimeout(400) - - x = 975 - y = 468 - - await page.waitForTimeout(100) - await page.mouse.move(x, 419, { steps: 5 }) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - - await hoverOverNothing() - - await page.mouse.move(855, y) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - - await hoverOverNothing() - - await page.getByRole('button', { name: 'Exit Sketch' }).click() - await page.waitForTimeout(200) - - await hoverOverNothing() - await page.waitForTimeout(200) - - await page.mouse.move(x, 419) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) - - await hoverOverNothing() - - await page.mouse.move(855, y) - await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ - timeout: 10_000, - }) }) + await page.waitForTimeout(200) - test(`Zoom by scroll should not fire while orbiting`, async ({ page, homePage }) => { /** - * Currently we only allow zooming by scroll when no other camera movement is happening, - * set within cameraMouseDragGuards in cameraControls.ts, - * until the engine supports unifying multiple camera movements. - * This verifies that scrollCallback's guard is working as expected. - */ - const u = await getUtils(page) - - // Constants and locators - const settingsLink = page.getByTestId('settings-link') - const settingsDialogHeading = page.getByRole('heading', { - name: 'Settings', - exact: true, - }) - const userSettingsTab = page.getByRole('radio', { name: 'User' }) - const mouseControlsSetting = page - .locator('#mouseControls') - .getByRole('combobox') - const mouseControlSuccesToast = page.getByText( - 'Set mouse controls to "Solidworks"' - ) - const settingsCloseButton = page.getByTestId('settings-close-button') - const gizmo = page.locator('[aria-label*=gizmo]') - const resetCameraButton = page.getByRole('button', { name: 'Reset view' }) - const orbitMouseStart = { x: 800, y: 130 } - const orbitMouseEnd = { x: 0, y: 130 } - const mid = (v1: number, v2: number) => v1 + (v2 - v1) / 2 - type Point = { x: number; y: number } - const midPoint = (p1: Point, p2: Point) => ({ - x: mid(p1.x, p2.x), - y: mid(p1.y, p2.y), - }) - const orbitMouseStepOne = midPoint(orbitMouseStart, orbitMouseEnd) - const expectedStartCamZPosition = 64.0 - const expectedZoomCamZPosition = 32.0 - const expectedOrbitCamZPosition = 64.0 - - await test.step(`Test setup`, async () => { - await homePage.goToModelingScene() - await u.closeKclCodePanel() - // This test requires the mouse controls to be set to Solidworks - await u.openDebugPanel() - await test.step(`Set mouse controls setting to Solidworks`, async () => { - await settingsLink.click() - await expect(settingsDialogHeading).toBeVisible() - await userSettingsTab.click() - await mouseControlsSetting.selectOption({ label: 'Solidworks' }) - await expect(mouseControlSuccesToast).toBeVisible() - await settingsCloseButton.click() + await hoverOverNothing() + await page.waitForTimeout(200) + // hover over vertical line + await u.canvasLocator.hover({ position: { x, y: 325 } }) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, + }) + + await hoverOverNothing() + + // click exit sketch + await page.getByRole('button', { name: 'Exit Sketch' }).click() + await page.waitForTimeout(400) + + await hoverOverNothing() + await page.waitForTimeout(200) + // hover over horizontal line + await page.mouse.move(858, y, { steps: 5 }) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, + }) + + await hoverOverNothing() + + // hover over vertical line + await page.mouse.move(x, 325) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, + }) + + await hoverOverNothing() + + // hover over vertical line + await page.mouse.move(857, y) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, + }) + // now click it + await page.mouse.click(857, y) + + await expect( + page.getByRole('button', { name: 'Edit Sketch' }) + ).toBeVisible() + await hoverOverNothing() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + await page.waitForTimeout(400) + + x = 975 + y = 468 + + await page.waitForTimeout(100) + await page.mouse.move(x, 419, { steps: 5 }) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, + }) + + await hoverOverNothing() + + await page.mouse.move(855, y) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, + }) + + await hoverOverNothing() + + await page.getByRole('button', { name: 'Exit Sketch' }).click() + await page.waitForTimeout(200) + + await hoverOverNothing() + await page.waitForTimeout(200) + + await page.mouse.move(x, 419) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, + }) + + await hoverOverNothing() + + await page.mouse.move(855, y) + await expect(page.getByTestId('hover-highlight').first()).toBeVisible({ + timeout: 10_000, }) }) - - await test.step(`Test scrolling zoom works`, async () => { - await resetCamera() - await page.mouse.move(orbitMouseStart.x, orbitMouseStart.y) - await page.mouse.wheel(0, -100) - await test.step(`Force a refresh of the camera position`, async () => { - await u.openAndClearDebugPanel() - await u.sendCustomCmd({ - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'default_camera_get_settings', - }, - }) - await u.waitForCmdReceive('default_camera_get_settings') + + test(`Zoom by scroll should not fire while orbiting`, async ({ + page, + homePage, + }) => { + /** + * Currently we only allow zooming by scroll when no other camera movement is happening, + * set within cameraMouseDragGuards in cameraControls.ts, + * until the engine supports unifying multiple camera movements. + * This verifies that scrollCallback's guard is working as expected. + */ + const u = await getUtils(page) + + // Constants and locators + const settingsLink = page.getByTestId('settings-link') + const settingsDialogHeading = page.getByRole('heading', { + name: 'Settings', + exact: true, }) - - await expect - .poll(getCameraZValue, { - message: 'Camera should be at expected position after zooming', - }) - .toEqual(expectedZoomCamZPosition) - }) - - await test.step(`Test orbiting works`, async () => { - await doOrbitWith() - }) - - await test.step(`Test scrolling while orbiting doesn't zoom`, async () => { - await doOrbitWith(async () => { - await page.mouse.wheel(0, -100) + const userSettingsTab = page.getByRole('radio', { name: 'User' }) + const mouseControlsSetting = page + .locator('#mouseControls') + .getByRole('combobox') + const mouseControlSuccesToast = page.getByText( + 'Set mouse controls to "Solidworks"' + ) + const settingsCloseButton = page.getByTestId('settings-close-button') + const gizmo = page.locator('[aria-label*=gizmo]') + const resetCameraButton = page.getByRole('button', { name: 'Reset view' }) + const orbitMouseStart = { x: 800, y: 130 } + const orbitMouseEnd = { x: 0, y: 130 } + const mid = (v1: number, v2: number) => v1 + (v2 - v1) / 2 + type Point = { x: number; y: number } + const midPoint = (p1: Point, p2: Point) => ({ + x: mid(p1.x, p2.x), + y: mid(p1.y, p2.y), }) - }) - - // Helper functions - async function resetCamera() { - await test.step(`Reset camera`, async () => { + const orbitMouseStepOne = midPoint(orbitMouseStart, orbitMouseEnd) + const expectedStartCamZPosition = 64.0 + const expectedZoomCamZPosition = 32.0 + const expectedOrbitCamZPosition = 64.0 + + await test.step(`Test setup`, async () => { + await homePage.goToModelingScene() + await u.closeKclCodePanel() + // This test requires the mouse controls to be set to Solidworks await u.openDebugPanel() - await u.clearCommandLogs() - await u.doAndWaitForCmd(async () => { - await gizmo.click({ button: 'right' }) - await resetCameraButton.click() - }, 'zoom_to_fit') - await expect - .poll(getCameraZValue, { - message: 'Camera Z should be at expected position after reset', - }) - .toEqual(expectedStartCamZPosition) + await test.step(`Set mouse controls setting to Solidworks`, async () => { + await settingsLink.click() + await expect(settingsDialogHeading).toBeVisible() + await userSettingsTab.click() + await mouseControlsSetting.selectOption({ label: 'Solidworks' }) + await expect(mouseControlSuccesToast).toBeVisible() + await settingsCloseButton.click() + }) }) - } - - async function getCameraZValue() { - return page - .getByTestId('cam-z-position') - .inputValue() - .then((value) => parseFloat(value)) - } - - async function doOrbitWith(callback = async () => {}) { - await resetCamera() - - await test.step(`Perform orbit`, async () => { + + await test.step(`Test scrolling zoom works`, async () => { + await resetCamera() await page.mouse.move(orbitMouseStart.x, orbitMouseStart.y) - await page.mouse.down({ button: 'middle' }) - await page.mouse.move(orbitMouseStepOne.x, orbitMouseStepOne.y, { - steps: 3, + await page.mouse.wheel(0, -100) + await test.step(`Force a refresh of the camera position`, async () => { + await u.openAndClearDebugPanel() + await u.sendCustomCmd({ + type: 'modeling_cmd_req', + cmd_id: uuidv4(), + cmd: { + type: 'default_camera_get_settings', + }, + }) + await u.waitForCmdReceive('default_camera_get_settings') }) - await callback() - await page.mouse.move(orbitMouseEnd.x, orbitMouseEnd.y, { - steps: 3, - }) - }) - - await test.step(`Verify orbit`, async () => { + await expect .poll(getCameraZValue, { - message: 'Camera should be at expected position after orbiting', + message: 'Camera should be at expected position after zooming', }) await callback() await page.mouse.move(orbitMouseEnd.x, orbitMouseEnd.y, { diff --git a/e2e/playwright/testing-constraints.spec.ts b/e2e/playwright/testing-constraints.spec.ts index b3be95873..81aba7891 100644 --- a/e2e/playwright/testing-constraints.spec.ts +++ b/e2e/playwright/testing-constraints.spec.ts @@ -1,74 +1,83 @@ import { test, expect } from './zoo-test' -import { getUtils, TEST_COLORS } from './test-utils' +import { + getUtils, + TEST_COLORS, + pollEditorLinesSelectedLength, +} from './test-utils' import { XOR } from 'lib/utils' test.describe('Testing constraints', () => { test('Can constrain line length', async ({ page, homePage }) => { - await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `sketch001 = startSketchOn('XY') + localStorage.setItem( + 'persistCode', + `sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> line([0, 20], %) |> xLine(-20, %) ` + ) + }) + + const u = await getUtils(page) + const PUR = 400 / 37.5 //pixeltoUnitRatio + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await u.openDebugPanel() + await u.expectCmdLog('[data-message-type="execution-done"]') + await u.closeDebugPanel() + + // Click the line of code for line. + await page.getByText(`line([0, 20], %)`).click() // TODO remove this and reinstate // await topHorzSegmentClick() + await page.waitForTimeout(100) + + // enter sketch again + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const startXPx = 500 + await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10) + await page.keyboard.down('Shift') + await page.mouse.click(834, 244) + await page.keyboard.up('Shift') + + await page + .getByRole('button', { name: 'dimension Length', exact: true }) + .click() + await page.getByText('Add constraining value').click() + + await expect(page.locator('.cm-content')).toHaveText( + `length001 = 20sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> angledLine([90, length001], %) |> xLine(-20, %)` ) + + // Make sure we didn't pop out of sketch mode. + await expect( + page.getByRole('button', { name: 'Exit Sketch' }) + ).toBeVisible() + + await page.waitForTimeout(500) // wait for animation + + // Exit sketch + await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10) + await expect + .poll(async () => { + await page.keyboard.press('Escape', { delay: 500 }) + return page.getByRole('button', { name: 'Exit Sketch' }).isVisible() + }) + .toBe(true) }) - - const u = await getUtils(page) - const PUR = 400 / 37.5 //pixeltoUnitRatio - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await u.openDebugPanel() - await u.expectCmdLog('[data-message-type="execution-done"]') - await u.closeDebugPanel() - - // Click the line of code for line. - await page.getByText(`line([0, 20], %)`).click() // TODO remove this and reinstate // await topHorzSegmentClick() - await page.waitForTimeout(100) - - // enter sketch again - await page.getByRole('button', { name: 'Edit Sketch' }).click() - await page.waitForTimeout(500) // wait for animation - - const startXPx = 500 - await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10) - await page.keyboard.down('Shift') - await page.mouse.click(834, 244) - await page.keyboard.up('Shift') - - await page - .getByRole('button', { name: 'dimension Length', exact: true }) - .click() - await page.getByText('Add constraining value').click() - - await expect(page.locator('.cm-content')).toHaveText( - `length001 = 20sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> angledLine([90, length001], %) |> xLine(-20, %)` - ) - - // Make sure we didn't pop out of sketch mode. - await expect( - page.getByRole('button', { name: 'Exit Sketch' }) - ).toBeVisible() - - await page.waitForTimeout(500) // wait for animation - - // Exit sketch - await page.mouse.move(startXPx + PUR * 15, 250 - PUR * 10) - await page.keyboard.press('Escape') - await expect( - page.getByRole('button', { name: 'Exit Sketch' }) - ).not.toBeVisible() }) - test(`Remove constraints`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 79 + test(`Remove constraints`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 79 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %, $seg01) @@ -81,35 +90,39 @@ test.describe('Testing constraints', () => { |> yLine(-170.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` - ) - }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %, $seg01)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const line3 = await u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`) - - await page.mouse.click(line3.x, line3.y) - await page.waitForTimeout(100) // this wait is needed for webkit - not sure why - await page - .getByRole('button', { - name: 'Length: open menu', + ) }) - .click() - await page.getByRole('button', { name: 'remove constraints' }).click() - - await page.getByText('line([39.13, 68.63], %)').click() - const activeLinesContent = await page.locator('.cm-activeLine').all() - await expect(activeLinesContent).toHaveLength(1) - await expect(activeLinesContent[0]).toHaveText('|> line([39.13, 68.63], %)') - - // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state - await expect(page.getByTestId('segment-overlay')).toHaveCount(4) }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %, $seg01)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const line3 = await u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`) + + await page.mouse.click(line3.x, line3.y) + await page.waitForTimeout(100) // this wait is needed for webkit - not sure why + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + await page.getByRole('button', { name: 'remove constraints' }).click() + + await page.getByText('line([39.13, 68.63], %)').click() + await pollEditorLinesSelectedLength(page, 1) + const activeLinesContent = await page.locator('.cm-activeLine').all() + await expect(activeLinesContent[0]).toHaveText('|> line([39.13, 68.63], %)') + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(4) + }) test.describe('Test perpendicular distance constraint', () => { const cases = [ { @@ -122,10 +135,11 @@ test.describe('Testing constraints', () => { }, ] as const for (const { testName, offset } of cases) { - test(`${testName}`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${testName}`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %, $seg01) @@ -138,62 +152,95 @@ test.describe('Testing constraints', () => { |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` - ) - }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %, $seg01)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const [line1, line3] = await Promise.all([ - u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`), - u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), - ]) - - await page.mouse.click(line1.x, line1.y) - await page.keyboard.down('Shift') - await page.mouse.click(line3.x, line3.y) - await page.waitForTimeout(100) // this wait is needed for webkit - not sure why - await page.keyboard.up('Shift') - await page - .getByRole('button', { - name: 'Length: open menu', + ) + + const isChecked = await createNewVariableCheckbox.isChecked() + const addVariable = testName === 'Add variable' + XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct + (await createNewVariableCheckbox.click()) + + await page + .getByRole('button', { name: 'Add constraining value' }) + .click() + + // Wait for the codemod to take effect + await expect(page.locator('.cm-content')).toContainText(`angle: -57,`) + await expect(page.locator('.cm-content')).toContainText( + `offset: ${offset},` + ) + + await pollEditorLinesSelectedLength(page, 2) + const activeLinesContent = await page.locator('.cm-activeLine').all() + await expect(activeLinesContent[0]).toHaveText( + `|> line([74.36, 130.4], %, $seg01)` + ) + await expect(activeLinesContent[1]).toHaveText(`}, %)`) + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(4) }) - .click() - await page - .getByRole('button', { name: 'Perpendicular Distance' }) - .click() - - const createNewVariableCheckbox = page.getByTestId( - 'create-new-variable-checkbox' - ) - const isChecked = await createNewVariableCheckbox.isChecked() - const addVariable = testName === 'Add variable' - XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct - (await createNewVariableCheckbox.click()) - - await page - .getByRole('button', { name: 'Add constraining value' }) - .click() - - // Wait for the codemod to take effect - await expect(page.locator('.cm-content')).toContainText(`angle: -57,`) - await expect(page.locator('.cm-content')).toContainText( - `offset: ${offset},` - ) - - const activeLinesContent = await page.locator('.cm-activeLine').all() - await expect(activeLinesContent[0]).toHaveText( - `|> line([74.36, 130.4], %, $seg01)` - ) - await expect(activeLinesContent[1]).toHaveText(`}, %)`) - - // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state - await expect(page.getByTestId('segment-overlay')).toHaveCount(4) }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %, $seg01)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Give time for overlays to populate + await page.waitForTimeout(1000) + + const [line1, line3] = await Promise.all([ + u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`), + u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), + ]) + + await page.mouse.click(line1.x, line1.y) + await page.keyboard.up('Shift') + await page.keyboard.down('Shift') + await page.waitForTimeout(100) + await page.mouse.click(line3.x, line3.y) + await page.waitForTimeout(100) + await page.keyboard.up('Shift') + await page.waitForTimeout(100) + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + await page + .getByRole('button', { name: 'Perpendicular Distance' }) + .click() + + const createNewVariableCheckbox = page.getByTestId( + 'create-new-variable-checkbox' + ) + const isChecked = await createNewVariableCheckbox.isChecked() + const addVariable = testName === 'Add variable' + XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct + (await createNewVariableCheckbox.click()) + + await page + .getByRole('button', { name: 'Add constraining value' }) + .click() + + // Wait for the codemod to take effect + await expect(page.locator('.cm-content')).toContainText(`angle = -57,`) + await expect(page.locator('.cm-content')).toContainText( + `offset = ${offset},` + ) + + await pollEditorLinesSelectedLength(page, 2) + const activeLinesContent = await page.locator('.cm-activeLine').all() + await expect(activeLinesContent[0]).toHaveText( + `|> line([74.36, 130.4], %, $seg01)` + ) + await expect(activeLinesContent[1]).toHaveText(`}, %)`) + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(4) + }) } }) test.describe('Test distance between constraint', () => { @@ -220,10 +267,11 @@ test.describe('Testing constraints', () => { }, ] as const for (const { testName, value, constraint } of cases) { - test(`${constraint} - ${testName}`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${constraint} - ${testName}`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %) @@ -236,65 +284,69 @@ test.describe('Testing constraints', () => { |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` - ) - }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const [line1, line3] = await Promise.all([ - u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`), - u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), - ]) - - await page.mouse.click(line1.x, line1.y) - await page.keyboard.down('Shift') - await page.mouse.click(line3.x, line3.y) - await page.waitForTimeout(100) // this wait is needed for webkit - not sure why - await page.keyboard.up('Shift') - await page - .getByRole('button', { - name: 'Length: open menu', - }) - .click() - await page.getByRole('button', { name: constraint }).click() - - const createNewVariableCheckbox = page.getByTestId( - 'create-new-variable-checkbox' - ) - const isChecked = await createNewVariableCheckbox.isChecked() - const addVariable = testName === 'Add variable' - XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct - (await createNewVariableCheckbox.click()) - - await page - .getByRole('button', { name: 'Add constraining value' }) - .click() - - // checking activeLines assures the cursors are where they should be - const codeAfter = [ - `|> line([74.36, 130.4], %, $seg01)`, - `|> lineTo([${value}], %)`, - ] - - const activeLinesContent = await page.locator('.cm-activeLine').all() - await Promise.all( - activeLinesContent.map(async (line, i) => { - await expect(page.locator('.cm-content')).toContainText( - codeAfter[i] ) - // if the code is an active line then the cursor should be on that line - await expect(line).toHaveText(codeAfter[i]) }) - ) - - // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state - await expect(page.getByTestId('segment-overlay')).toHaveCount(4) }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const [line1, line3] = await Promise.all([ + u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`), + u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), + ]) + + await page.mouse.click(line1.x, line1.y) + await page.keyboard.down('Shift') + await page.mouse.click(line3.x, line3.y) + await page.waitForTimeout(100) // this wait is needed for webkit - not sure why + await page.keyboard.up('Shift') + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + await page.getByRole('button', { name: constraint }).click() + + const createNewVariableCheckbox = page.getByTestId( + 'create-new-variable-checkbox' + ) + const isChecked = await createNewVariableCheckbox.isChecked() + const addVariable = testName === 'Add variable' + XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct + (await createNewVariableCheckbox.click()) + + await page + .getByRole('button', { name: 'Add constraining value' }) + .click() + + // checking activeLines assures the cursors are where they should be + const codeAfter = [ + `|> line([74.36, 130.4], %, $seg01)`, + `|> lineTo([${value}], %)`, + ] + + const activeLinesContent = await page.locator('.cm-activeLine').all() + await Promise.all( + activeLinesContent.map(async (line, i) => { + await expect(page.locator('.cm-content')).toContainText( + codeAfter[i] + ) + // if the code is an active line then the cursor should be on that line + await expect(line).toHaveText(codeAfter[i]) + }) + ) + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(4) + }) } }) test.describe('Test ABS distance constraint', () => { @@ -325,10 +377,11 @@ test.describe('Testing constraints', () => { }, ] as const for (const { testName, addVariable, value, constraint } of cases) { - test(`${constraint} - ${testName}`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${constraint} - ${testName}`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %) @@ -341,66 +394,72 @@ test.describe('Testing constraints', () => { |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` - ) - }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const [line3] = await Promise.all([ - u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), - ]) - - if (constraint === 'Absolute X') { - await page.mouse.click(600, 130) - } else { - await page.mouse.click(900, 250) - } - await page.keyboard.down('Shift') - await page.mouse.click(line3.x, line3.y) - await page.waitForTimeout(100) // this wait is needed for webkit - not sure why - await page.keyboard.up('Shift') - await page - .getByRole('button', { - name: 'Length: open menu', - }) - .click() - await page - .getByRole('button', { name: constraint, exact: true }) - .click() - - const createNewVariableCheckbox = page.getByTestId( - 'create-new-variable-checkbox' - ) - const isChecked = await createNewVariableCheckbox.isChecked() - XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct - (await createNewVariableCheckbox.click()) - - await page - .getByRole('button', { name: 'Add constraining value' }) - .click() - - // checking activeLines assures the cursors are where they should be - const codeAfter = [`|> lineTo([${value}], %)`] - - const activeLinesContent = await page.locator('.cm-activeLine').all() - await Promise.all( - activeLinesContent.map(async (line, i) => { - await expect(page.locator('.cm-content')).toContainText( - codeAfter[i] ) - // if the code is an active line then the cursor should be on that line - await expect(line).toHaveText(codeAfter[i]) }) - ) - - // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state - await expect(page.getByTestId('segment-overlay')).toHaveCount(4) }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const [line3] = await Promise.all([ + u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), + ]) + + if (constraint === 'Absolute X') { + await page.mouse.click(600, 130) + } else { + await page.mouse.click(900, 250) + } + await page.keyboard.down('Shift') + await page.waitForTimeout(100) + await page.mouse.click(line3.x, line3.y) + await page.waitForTimeout(100) + await page.keyboard.up('Shift') + await page.waitForTimeout(100) + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + await page + .getByRole('button', { name: constraint, exact: true }) + .click() + + const createNewVariableCheckbox = page.getByTestId( + 'create-new-variable-checkbox' + ) + const isChecked = await createNewVariableCheckbox.isChecked() + XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct + (await createNewVariableCheckbox.click()) + + await page + .getByRole('button', { name: 'Add constraining value' }) + .click() + + // checking activeLines assures the cursors are where they should be + const codeAfter = [`|> lineTo([${value}], %)`] + + const activeLinesContent = await page.locator('.cm-activeLine').all() + await Promise.all( + activeLinesContent.map(async (line, i) => { + await expect(page.locator('.cm-content')).toContainText( + codeAfter[i] + ) + // if the code is an active line then the cursor should be on that line + await expect(line).toHaveText(codeAfter[i]) + }) + ) + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(4) + }) } }) test.describe('Test Angle constraint double segment selection', () => { @@ -431,10 +490,11 @@ test.describe('Testing constraints', () => { }, ] as const for (const { testName, addVariable, value, axisSelect } of cases) { - test(`${testName}`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${testName}`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %) @@ -447,69 +507,73 @@ test.describe('Testing constraints', () => { |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` - ) - }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const [line1, line3] = await Promise.all([ - u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`), - u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), - ]) - - if (axisSelect) { - await page.mouse.click(600, 130) - } else { - await page.mouse.click(line1.x, line1.y) - } - await page.keyboard.down('Shift') - await page.mouse.click(line3.x, line3.y) - await page.waitForTimeout(100) // this wait is needed for webkit - not sure why - await page.keyboard.up('Shift') - await page - .getByRole('button', { - name: 'Length: open menu', - }) - .click() - await page.getByTestId('dropdown-constraint-angle').click() - - const createNewVariableCheckbox = page.getByTestId( - 'create-new-variable-checkbox' - ) - const isChecked = await createNewVariableCheckbox.isChecked() - XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct - (await createNewVariableCheckbox.click()) - - await page - .getByRole('button', { name: 'Add constraining value' }) - .click() - - // checking activeLines assures the cursors are where they should be - const codeAfter = [ - '|> line([74.36, 130.4], %, $seg01)', - `|> angledLine([${value}, 78.33], %)`, - ] - if (axisSelect) codeAfter.shift() - - const activeLinesContent = await page.locator('.cm-activeLine').all() - await Promise.all( - activeLinesContent.map(async (line, i) => { - await expect(page.locator('.cm-content')).toContainText( - codeAfter[i] ) - // if the code is an active line then the cursor should be on that line - await expect(line).toHaveText(codeAfter[i]) }) - ) - - // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state - await expect(page.getByTestId('segment-overlay')).toHaveCount(4) }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const [line1, line3] = await Promise.all([ + u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`), + u.getSegmentBodyCoords(`[data-overlay-index="${2}"]`), + ]) + + if (axisSelect) { + await page.mouse.click(600, 130) + } else { + await page.mouse.click(line1.x, line1.y) + } + await page.keyboard.down('Shift') + await page.mouse.click(line3.x, line3.y) + await page.waitForTimeout(100) // this wait is needed for webkit - not sure why + await page.keyboard.up('Shift') + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + await page.getByTestId('dropdown-constraint-angle').click() + + const createNewVariableCheckbox = page.getByTestId( + 'create-new-variable-checkbox' + ) + const isChecked = await createNewVariableCheckbox.isChecked() + XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct + (await createNewVariableCheckbox.click()) + + await page + .getByRole('button', { name: 'Add constraining value' }) + .click() + + // checking activeLines assures the cursors are where they should be + const codeAfter = [ + '|> line([74.36, 130.4], %, $seg01)', + `|> angledLine([${value}, 78.33], %)`, + ] + if (axisSelect) codeAfter.shift() + + const activeLinesContent = await page.locator('.cm-activeLine').all() + await Promise.all( + activeLinesContent.map(async (line, i) => { + await expect(page.locator('.cm-content')).toContainText( + codeAfter[i] + ) + // if the code is an active line then the cursor should be on that line + await expect(line).toHaveText(codeAfter[i]) + }) + ) + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(4) + }) } }) test.describe('Test Angle constraint single selection', () => { @@ -528,10 +592,11 @@ test.describe('Testing constraints', () => { }, ] as const for (const { testName, addVariable, value, constraint } of cases) { - test(`${testName}`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${testName}`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %) @@ -544,43 +609,47 @@ test.describe('Testing constraints', () => { |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` - ) - }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const line3 = await u.getSegmentBodyCoords( - `[data-overlay-index="${2}"]` - ) - - await page.mouse.click(line3.x, line3.y) - await page - .getByRole('button', { - name: 'Length: open menu', + ) }) - .click() - await page.getByTestId('dropdown-constraint-' + constraint).click() - - if (!addVariable) { - await page.getByTestId('create-new-variable-checkbox').click() - } - await page - .getByRole('button', { name: 'Add constraining value' }) - .click() - - const changedCode = `|> angledLine([${value}], %)` - await expect(page.locator('.cm-content')).toContainText(changedCode) - // checking active assures the cursor is where it should be - await expect(page.locator('.cm-activeLine')).toHaveText(changedCode) - - // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state - await expect(page.getByTestId('segment-overlay')).toHaveCount(4) }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const line3 = await u.getSegmentBodyCoords( + `[data-overlay-index="${2}"]` + ) + + await page.mouse.click(line3.x, line3.y) + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + await page.getByTestId('dropdown-constraint-' + constraint).click() + + if (!addVariable) { + await page.getByTestId('create-new-variable-checkbox').click() + } + await page + .getByRole('button', { name: 'Add constraining value' }) + .click() + + const changedCode = `|> angledLine([${value}], %)` + await expect(page.locator('.cm-content')).toContainText(changedCode) + // checking active assures the cursor is where it should be + await expect(page.locator('.cm-activeLine')).toHaveText(changedCode) + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(4) + }) } }) test.describe('Test Length constraint single selection', () => { @@ -687,10 +756,11 @@ part002 = startSketchOn('XZ') }, ] as const for (const { codeAfter, constraintName } of cases) { - test(`${constraintName}`, async ({ page, homePage }) => { await page.addInitScript(async (customCode) => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${constraintName}`, async ({ page, homePage }) => { + await page.addInitScript(async (customCode) => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %) @@ -703,64 +773,68 @@ part002 = startSketchOn('XZ') |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` + ) + }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const line1 = await u.getSegmentBodyCoords( + `[data-overlay-index="${0}"]` + ) + const line3 = await u.getSegmentBodyCoords( + `[data-overlay-index="${2}"]` + ) + const line4 = await u.getSegmentBodyCoords( + `[data-overlay-index="${3}"]` + ) + + // select two segments by holding down shift + await page.mouse.click(line1.x, line1.y) + await page.keyboard.down('Shift') + await page.mouse.click(line3.x, line3.y) + await page.mouse.click(line4.x, line4.y) + await page.keyboard.up('Shift') + + // check actives lines + await pollEditorLinesSelectedLength(page, codeAfter.length) + const activeLinesContent = await page.locator('.cm-activeLine').all() + + const constraintMenuButton = page.getByRole('button', { + name: 'Length: open menu', + }) + const constraintButton = page + .getByRole('button', { + name: constraintName, + }) + .first() + + // apply the constraint + await constraintMenuButton.click() + await constraintButton.click({ delay: 200 }) + + // check there are still 3 cursors (they should stay on the same lines as before constraint was applied) + await expect(page.locator('.cm-cursor')).toHaveCount(codeAfter.length) + + // check both cursors are where they should be after constraint is applied and the code is correct + await Promise.all( + activeLinesContent.map(async (line, i) => { + await expect(page.locator('.cm-content')).toContainText( + codeAfter[i] + ) + // if the code is an active line then the cursor should be on that line + await expect(line).toHaveText(codeAfter[i]) + }) ) }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const line1 = await u.getSegmentBodyCoords( - `[data-overlay-index="${0}"]` - ) - const line3 = await u.getSegmentBodyCoords( - `[data-overlay-index="${2}"]` - ) - const line4 = await u.getSegmentBodyCoords( - `[data-overlay-index="${3}"]` - ) - - // select two segments by holding down shift - await page.mouse.click(line1.x, line1.y) - await page.keyboard.down('Shift') - await page.mouse.click(line3.x, line3.y) - await page.mouse.click(line4.x, line4.y) - await page.keyboard.up('Shift') - - // check actives lines - const activeLinesContent = await page.locator('.cm-activeLine').all() - await expect(activeLinesContent).toHaveLength(codeAfter.length) - - const constraintMenuButton = page.getByRole('button', { - name: 'Length: open menu', - }) - const constraintButton = page - .getByRole('button', { - name: constraintName, - }) - .first() - - // apply the constraint - await constraintMenuButton.click() - await constraintButton.click({ delay: 200 }) - - // check there are still 3 cursors (they should stay on the same lines as before constraint was applied) - await expect(page.locator('.cm-cursor')).toHaveCount(codeAfter.length) - - // check both cursors are where they should be after constraint is applied and the code is correct - await Promise.all( - activeLinesContent.map(async (line, i) => { - await expect(page.locator('.cm-content')).toContainText( - codeAfter[i] - ) - // if the code is an active line then the cursor should be on that line - await expect(line).toHaveText(codeAfter[i]) - }) - ) }) } }) test.describe('Two segment - no modal constraints', () => { @@ -783,10 +857,11 @@ part002 = startSketchOn('XZ') }, ] as const for (const { codeAfter, constraintName } of cases) { - test(`${constraintName}`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${constraintName}`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %) @@ -798,51 +873,55 @@ part002 = startSketchOn('XZ') |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` + ) + }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const line1 = await u.getBoundingBox(`[data-overlay-index="${0}"]`) + const line3 = await u.getBoundingBox(`[data-overlay-index="${2}"]`) + + // select two segments by holding down shift + await page.mouse.click(line1.x - 20, line1.y + 20) + await page.keyboard.down('Shift') + await page.mouse.click(line3.x - 3, line3.y + 20) + await page.keyboard.up('Shift') + const constraintMenuButton = page.getByRole('button', { + name: 'Length: open menu', + }) + const constraintButton = page.getByRole('button', { + name: constraintName, + }) + + // apply the constraint + await constraintMenuButton.click() + await constraintButton.click() + + await expect(page.locator('.cm-content')).toContainText(codeAfter) + // expect the string 'seg01' to appear twice in '.cm-content' the tag segment and referencing the tag + const content = await page.locator('.cm-content').innerText() + await expect(content.match(/seg01/g)).toHaveLength(2) + // check there are still 2 cursors (they should stay on the same lines as before constraint was applied) + await expect(page.locator('.cm-cursor')).toHaveCount(2) + // check actives lines + await pollEditorLinesSelectedLength(page, 2) + const activeLinesContent = await page.locator('.cm-activeLine').all() + + // check both cursors are where they should be after constraint is applied + await expect(activeLinesContent[0]).toHaveText( + '|> line([74.36, 130.4], %, $seg01)' ) + await expect(activeLinesContent[1]).toHaveText(codeAfter) }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const line1 = await u.getBoundingBox(`[data-overlay-index="${0}"]`) - const line3 = await u.getBoundingBox(`[data-overlay-index="${2}"]`) - - // select two segments by holding down shift - await page.mouse.click(line1.x - 20, line1.y + 20) - await page.keyboard.down('Shift') - await page.mouse.click(line3.x - 3, line3.y + 20) - await page.keyboard.up('Shift') - const constraintMenuButton = page.getByRole('button', { - name: 'Length: open menu', - }) - const constraintButton = page.getByRole('button', { - name: constraintName, - }) - - // apply the constraint - await constraintMenuButton.click() - await constraintButton.click() - - await expect(page.locator('.cm-content')).toContainText(codeAfter) - // expect the string 'seg01' to appear twice in '.cm-content' the tag segment and referencing the tag - const content = await page.locator('.cm-content').innerText() - await expect(content.match(/seg01/g)).toHaveLength(2) - // check there are still 2 cursors (they should stay on the same lines as before constraint was applied) - await expect(page.locator('.cm-cursor')).toHaveCount(2) - // check actives lines - const activeLinesContent = await page.locator('.cm-activeLine').all() - await expect(activeLinesContent).toHaveLength(2) - - // check both cursors are where they should be after constraint is applied - await expect(activeLinesContent[0]).toHaveText( - '|> line([74.36, 130.4], %, $seg01)' - ) - await expect(activeLinesContent[1]).toHaveText(codeAfter) }) } }) test.describe('Axis & segment - no modal constraints', () => { @@ -859,10 +938,11 @@ part002 = startSketchOn('XZ') }, ] as const for (const { codeAfter, constraintName, axisClick } of cases) { - test(`${constraintName}`, async ({ page, homePage }) => { await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `yo = 5 + test(`${constraintName}`, async ({ page, homePage }) => { + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `yo = 5 part001 = startSketchOn('XZ') |> startProfileAt([-7.54, -26.74], %) |> line([74.36, 130.4], %) @@ -874,120 +954,148 @@ part002 = startSketchOn('XZ') |> yLine(-264.06, %) |> xLine(segLen(seg_what), %) |> lineTo([profileStartX(%), profileStartY(%)], %)` - ) + ) + }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([74.36, 130.4], %)').click() + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + const line3 = await u.getBoundingBox(`[data-overlay-index="${2}"]`) + + // select segment and axis by holding down shift + await page.mouse.click(line3.x - 3, line3.y + 20) + await page.waitForTimeout(100) + await page.keyboard.down('Shift') + await page.waitForTimeout(100) + await page.mouse.click(axisClick.x, axisClick.y) + await page.waitForTimeout(100) + await page.keyboard.up('Shift') + await page.waitForTimeout(100) + const constraintMenuButton = page.getByRole('button', { + name: 'Length: open menu', + }) + const constraintButton = page.getByRole('button', { + name: constraintName, + }) + + // apply the constraint + await constraintMenuButton.click() + await expect(constraintButton).toBeVisible() + await constraintButton.click() + + // check the cursor is where is should be after constraint is applied + await expect(page.locator('.cm-content')).toContainText(codeAfter) + await expect(page.locator('.cm-activeLine')).toHaveText(codeAfter) }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([74.36, 130.4], %)').click() - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - const line3 = await u.getBoundingBox(`[data-overlay-index="${2}"]`) - - // select segment and axis by holding down shift - await page.mouse.click(line3.x - 3, line3.y + 20) - await page.keyboard.down('Shift') - await page.waitForTimeout(100) - await page.mouse.click(axisClick.x, axisClick.y) - await page.keyboard.up('Shift') - const constraintMenuButton = page.getByRole('button', { - name: 'Length: open menu', - }) - const constraintButton = page.getByRole('button', { - name: constraintName, - }) - - // apply the constraint - await constraintMenuButton.click() - await expect(constraintButton).toBeVisible() - await constraintButton.click() - - // check the cursor is where is should be after constraint is applied - await expect(page.locator('.cm-content')).toContainText(codeAfter) - await expect(page.locator('.cm-activeLine')).toHaveText(codeAfter) }) } }) - test('Horizontally constrained line remains selected after applying constraint', async ({ page, homePage }) => { test.setTimeout(70_000) - await page.addInitScript(async () => { - localStorage.setItem( - 'persistCode', - `sketch001 = startSketchOn('XY') + test('Horizontally constrained line remains selected after applying constraint', async ({ + page, + homePage, + }) => { + test.setTimeout(70_000) + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `sketch001 = startSketchOn('XY') |> startProfileAt([-1.05, -1.07], %) |> line([3.79, 2.68], %, $seg01) |> line([3.13, -2.4], %)` + ) + }) + const u = await getUtils(page) + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.getByText('line([3.79, 2.68], %, $seg01)').click() + await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeEnabled( + { timeout: 10_000 } ) + await page.getByRole('button', { name: 'Edit Sketch' }).click() + + // Wait for overlays to populate + await page.waitForTimeout(1000) + + await page.waitForTimeout(100) + const lineBefore = await u.getSegmentBodyCoords( + `[data-overlay-index="1"]`, + 0 + ) + expect( + await u.getGreatestPixDiff(lineBefore, TEST_COLORS.WHITE) + ).toBeLessThan(3) + await page.mouse.move(lineBefore.x, lineBefore.y) + await page.waitForTimeout(50) + await page.mouse.click(lineBefore.x, lineBefore.y) + expect( + await u.getGreatestPixDiff(lineBefore, TEST_COLORS.BLUE) + ).toBeLessThan(3) + + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + await page.waitForTimeout(500) + await page.getByRole('button', { name: 'Horizontal', exact: true }).click() + await page.waitForTimeout(500) + + await pollEditorLinesSelectedLength(page, 1) + let activeLinesContent = await page.locator('.cm-activeLine').all() + await expect(activeLinesContent[0]).toHaveText(`|> xLine(3.13, %)`) + + // Wait for code editor to settle. + await page.waitForTimeout(2000) + + // If the overlay-angle is updated the THREE.js scene is in a good state + await expect( + await page.locator('[data-overlay-index="1"]') + ).toHaveAttribute('data-overlay-angle', '0') + + const lineAfter = await u.getSegmentBodyCoords( + `[data-overlay-index="1"]`, + 0 + ) + + const linebb = await u.getBoundingBox('[data-overlay-index="1"]') + await page.mouse.move(linebb.x, linebb.y, { step: 25 }) + await page.mouse.click(linebb.x, linebb.y) + + expect + .poll(async () => await u.getGreatestPixDiff(lineAfter, TEST_COLORS.BLUE)) + .toBeLessThan(3) + + await page.waitForTimeout(500) + + await page + .getByRole('button', { + name: 'Length: open menu', + }) + .click() + // await expect(page.getByRole('button', { name: 'length', exact: true })).toBeVisible() + await page.waitForTimeout(200) + // await page.getByRole('button', { name: 'length', exact: true }).click() + await page.getByTestId('dropdown-constraint-length').click() + + await page.getByLabel('length Value').fill('10') + await page.getByRole('button', { name: 'Add constraining value' }).click() + + await pollEditorLinesSelectedLength(page, 1) + activeLinesContent = await page.locator('.cm-activeLine').all() + await expect(activeLinesContent[0]).toHaveText(`|> xLine(length001, %)`) + + // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state + await expect(page.getByTestId('segment-overlay')).toHaveCount(2) }) - const u = await getUtils(page) - await page.setBodyDimensions({ width: 1200, height: 500 }) - - await homePage.goToModelingScene() - await u.waitForPageLoad() - - await page.getByText('line([3.79, 2.68], %, $seg01)').click() - await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeEnabled( - { timeout: 10_000 } - ) - await page.getByRole('button', { name: 'Edit Sketch' }).click() - - await page.waitForTimeout(100) - const lineBefore = await u.getSegmentBodyCoords( - `[data-overlay-index="1"]`, - 0 - ) - expect( - await u.getGreatestPixDiff(lineBefore, TEST_COLORS.WHITE) - ).toBeLessThan(3) - await page.mouse.move(lineBefore.x, lineBefore.y) - await page.waitForTimeout(50) - await page.mouse.click(lineBefore.x, lineBefore.y) - expect( - await u.getGreatestPixDiff(lineBefore, TEST_COLORS.BLUE) - ).toBeLessThan(3) - - await page - .getByRole('button', { - name: 'Length: open menu', - }) - .click() - await page.getByRole('button', { name: 'Horizontal', exact: true }).click() - - let activeLinesContent = await page.locator('.cm-activeLine').all() - await expect(activeLinesContent[0]).toHaveText(`|> xLine(3.13, %)`) - - // If the overlay-angle is updated the THREE.js scene is in a good state - await expect( - await page.locator('[data-overlay-index="1"]') - ).toHaveAttribute('data-overlay-angle', '0') - - const lineAfter = await u.getSegmentBodyCoords( - `[data-overlay-index="1"]`, - 0 - ) - expect( - await u.getGreatestPixDiff(lineAfter, TEST_COLORS.BLUE) - ).toBeLessThan(3) - - await page.waitForTimeout(300) - await page - .getByRole('button', { - name: 'Length: open menu', - }) - .click() - // await expect(page.getByRole('button', { name: 'length', exact: true })).toBeVisible() - await page.waitForTimeout(200) - // await page.getByRole('button', { name: 'length', exact: true }).click() - await page.getByTestId('dropdown-constraint-length').click() - - await page.getByLabel('length Value').fill('10') - await page.getByRole('button', { name: 'Add constraining value' }).click() - - activeLinesContent = await page.locator('.cm-activeLine').all() - await expect(activeLinesContent[0]).toHaveText(`|> xLine(length001, %)`) - - // checking the count of the overlays is a good proxy check that the client sketch scene is in a good state - await expect(page.getByTestId('segment-overlay')).toHaveCount(2) }) }) diff --git a/e2e/playwright/testing-gizmo.spec.ts b/e2e/playwright/testing-gizmo.spec.ts index e410261ad..f502b3a1b 100644 --- a/e2e/playwright/testing-gizmo.spec.ts +++ b/e2e/playwright/testing-gizmo.spec.ts @@ -52,15 +52,105 @@ test.describe('Testing Gizmo', () => { } of cases) { test(`check ${testDescription}`, async ({ page, homePage }) => { const u = await getUtils(page) + await page.addInitScript((TEST_CODE_GIZMO) => { + localStorage.setItem('persistCode', TEST_CODE_GIZMO) + }, TEST_CODE_GIZMO) + + await page.setBodyDimensions({ width: 1000, height: 500 }) + + await homePage.goToModelingScene() + await u.waitForPageLoad() + + await page.waitForTimeout(100) + // wait for execution done + await u.openDebugPanel() + await u.expectCmdLog('[data-message-type="execution-done"]') + await u.sendCustomCmd({ + type: 'modeling_cmd_req', + cmd_id: uuidv4(), + cmd: { + type: 'default_camera_look_at', + vantage: { + x: 3000, + y: 3000, + z: 3000, + }, + center: { + x: 800, + y: -152, + z: 26, + }, + up: { x: 0, y: 0, z: 1 }, + }, + }) + await page.waitForTimeout(100) + await u.clearCommandLogs() + await u.sendCustomCmd({ + type: 'modeling_cmd_req', + cmd_id: uuidv4(), + cmd: { + type: 'default_camera_get_settings', + }, + }) + await u.waitForCmdReceive('default_camera_get_settings') + + await u.clearCommandLogs() + await page.mouse.move(clickPosition.x, clickPosition.y) + await page.waitForTimeout(100) + await page.mouse.click(clickPosition.x, clickPosition.y) + await page.mouse.move(0, 0) + await u.waitForCmdReceive('default_camera_look_at') + await u.clearCommandLogs() + + await u.sendCustomCmd({ + type: 'modeling_cmd_req', + cmd_id: uuidv4(), + cmd: { + type: 'default_camera_get_settings', + }, + }) + await u.waitForCmdReceive('default_camera_get_settings') + + await Promise.all([ + // position + expect(page.getByTestId('cam-x-position')).toHaveValue( + expectedCameraPosition.x.toString() + ), + expect(page.getByTestId('cam-y-position')).toHaveValue( + expectedCameraPosition.y.toString() + ), + expect(page.getByTestId('cam-z-position')).toHaveValue( + expectedCameraPosition.z.toString() + ), + // target + expect(page.getByTestId('cam-x-target')).toHaveValue( + expectedCameraTarget.x.toString() + ), + expect(page.getByTestId('cam-y-target')).toHaveValue( + expectedCameraTarget.y.toString() + ), + expect(page.getByTestId('cam-z-target')).toHaveValue( + expectedCameraTarget.z.toString() + ), + ]) + }) + } + + test('Context menu and popover menu', async ({ page, homePage }) => { + const testCase = { + testDescription: 'Right view', + expectedCameraPosition: { x: 5660.02, y: -152, z: 26 }, + expectedCameraTarget: { x: 800, y: -152, z: 26 }, + } + + // Test prelude taken from the above test + const u = await getUtils(page) await page.addInitScript((TEST_CODE_GIZMO) => { localStorage.setItem('persistCode', TEST_CODE_GIZMO) }, TEST_CODE_GIZMO) - await page.setBodyDimensions({ width: 1000, height: 500 }) await homePage.goToModelingScene() - await u.waitForPageLoad() - await page.waitForTimeout(100) // wait for execution done await u.openDebugPanel() @@ -93,15 +183,22 @@ test.describe('Testing Gizmo', () => { }, }) await u.waitForCmdReceive('default_camera_get_settings') - + + // Now find and select the correct + // view from the context menu await u.clearCommandLogs() - await page.mouse.move(clickPosition.x, clickPosition.y) - await page.waitForTimeout(100) - await page.mouse.click(clickPosition.x, clickPosition.y) - await page.mouse.move(0, 0) + const gizmo = page.locator('[aria-label*=gizmo]') + await gizmo.click({ button: 'right' }) + const buttonToTest = page.getByRole('button', { + name: testCase.testDescription, + }) + await expect(buttonToTest).toBeVisible() + await buttonToTest.click() + + // Now assert we've moved to the correct view + // Taken from the above test await u.waitForCmdReceive('default_camera_look_at') - await u.clearCommandLogs() - + await u.sendCustomCmd({ type: 'modeling_cmd_req', cmd_id: uuidv4(), @@ -110,135 +207,41 @@ test.describe('Testing Gizmo', () => { }, }) await u.waitForCmdReceive('default_camera_get_settings') - + await page.waitForTimeout(400) + await Promise.all([ // position expect(page.getByTestId('cam-x-position')).toHaveValue( - expectedCameraPosition.x.toString() + testCase.expectedCameraPosition.x.toString() ), expect(page.getByTestId('cam-y-position')).toHaveValue( - expectedCameraPosition.y.toString() + testCase.expectedCameraPosition.y.toString() ), expect(page.getByTestId('cam-z-position')).toHaveValue( - expectedCameraPosition.z.toString() + testCase.expectedCameraPosition.z.toString() ), // target expect(page.getByTestId('cam-x-target')).toHaveValue( - expectedCameraTarget.x.toString() + testCase.expectedCameraTarget.x.toString() ), expect(page.getByTestId('cam-y-target')).toHaveValue( - expectedCameraTarget.y.toString() + testCase.expectedCameraTarget.y.toString() ), expect(page.getByTestId('cam-z-target')).toHaveValue( - expectedCameraTarget.z.toString() + testCase.expectedCameraTarget.z.toString() ), - ]) }) - } + ]) - test('Context menu and popover menu', async ({ page, homePage }) => { const testCase = { - testDescription: 'Right view', - expectedCameraPosition: { x: 5660.02, y: -152, z: 26 }, - expectedCameraTarget: { x: 800, y: -152, z: 26 }, - } - - // Test prelude taken from the above test - const u = await getUtils(page) - await page.addInitScript((TEST_CODE_GIZMO) => { - localStorage.setItem('persistCode', TEST_CODE_GIZMO) - }, TEST_CODE_GIZMO) - await page.setBodyDimensions({ width: 1000, height: 500 }) - - await homePage.goToModelingScene() - await page.waitForTimeout(100) - // wait for execution done - await u.openDebugPanel() - await u.expectCmdLog('[data-message-type="execution-done"]') - await u.sendCustomCmd({ - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'default_camera_look_at', - vantage: { - x: 3000, - y: 3000, - z: 3000, - }, - center: { - x: 800, - y: -152, - z: 26, - }, - up: { x: 0, y: 0, z: 1 }, - }, + // Now test the popover menu. + // It has the same click handlers, so we can just + // test that it opens and contains the same content. + const gizmoPopoverButton = page.getByRole('button', { + name: 'view settings', + }) + await expect(gizmoPopoverButton).toBeVisible() + await gizmoPopoverButton.click() + await expect(buttonToTest).toBeVisible() }) - await page.waitForTimeout(100) - await u.clearCommandLogs() - await u.sendCustomCmd({ - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'default_camera_get_settings', - }, - }) - await u.waitForCmdReceive('default_camera_get_settings') - - // Now find and select the correct - // view from the context menu - await u.clearCommandLogs() - const gizmo = page.locator('[aria-label*=gizmo]') - await gizmo.click({ button: 'right' }) - const buttonToTest = page.getByRole('button', { - name: testCase.testDescription, - }) - await expect(buttonToTest).toBeVisible() - await buttonToTest.click() - - // Now assert we've moved to the correct view - // Taken from the above test - await u.waitForCmdReceive('default_camera_look_at') - - await u.sendCustomCmd({ - type: 'modeling_cmd_req', - cmd_id: uuidv4(), - cmd: { - type: 'default_camera_get_settings', - }, - }) - await u.waitForCmdReceive('default_camera_get_settings') - await page.waitForTimeout(400) - - await Promise.all([ - // position - expect(page.getByTestId('cam-x-position')).toHaveValue( - testCase.expectedCameraPosition.x.toString() - ), - expect(page.getByTestId('cam-y-position')).toHaveValue( - testCase.expectedCameraPosition.y.toString() - ), - expect(page.getByTestId('cam-z-position')).toHaveValue( - testCase.expectedCameraPosition.z.toString() - ), - // target - expect(page.getByTestId('cam-x-target')).toHaveValue( - testCase.expectedCameraTarget.x.toString() - ), - expect(page.getByTestId('cam-y-target')).toHaveValue( - testCase.expectedCameraTarget.y.toString() - ), - expect(page.getByTestId('cam-z-target')).toHaveValue( - testCase.expectedCameraTarget.z.toString() - ), - ]) - - // Now test the popover menu. - // It has the same click handlers, so we can just - // test that it opens and contains the same content. - const gizmoPopoverButton = page.getByRole('button', { - name: 'view settings', - }) - await expect(gizmoPopoverButton).toBeVisible() - await gizmoPopoverButton.click() - await expect(buttonToTest).toBeVisible() }) }) test.describe(`Testing gizmo, fixture-based`, () => { @@ -252,7 +255,9 @@ test.describe(`Testing gizmo, fixture-based`, () => { scene, }) => { await context.addInitScript(() => { - localStorage.setItem('persistCode', ` + localStorage.setItem( + 'persistCode', + ` const sketch002 = startSketchOn('XZ') |> startProfileAt([-108.83, -57.48], %) |> angledLine([0, 105.13], %, $rectangleSegmentA001) @@ -271,7 +276,8 @@ test.describe(`Testing gizmo, fixture-based`, () => { radius: 182.8 }, %) |> extrude(50, %) - `) + ` + ) }) await page.setBodyDimensions({ width: 1000, height: 500 }) diff --git a/e2e/playwright/testing-perspective-toggle.spec.ts b/e2e/playwright/testing-perspective-toggle.spec.ts index 11face6cd..308fffa91 100644 --- a/e2e/playwright/testing-perspective-toggle.spec.ts +++ b/e2e/playwright/testing-perspective-toggle.spec.ts @@ -1,18 +1,10 @@ -import { test, expect } from '@playwright/test' -import { getUtils, setup, tearDown } from './test-utils' +import { test, expect } from './zoo-test' +import { getUtils } from './test-utils' import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates' import * as TOML from '@iarna/toml' -test.beforeEach(async ({ context, page }, testInfo) => { - await setup(context, page, testInfo) -}) - -test.afterEach(async ({ page }, testInfo) => { - await tearDown(page, testInfo) -}) - test.describe('Test toggling perspective', () => { - test('via command palette and toggle', async ({ page }) => { + test('via command palette and toggle', async ({ page, homePage }) => { const u = await getUtils(page) // Locators and constants @@ -40,8 +32,8 @@ test.describe('Test toggling perspective', () => { }) await test.step('Setup', async () => { - await page.setViewportSize({ width: screenWidth, height: screenHeight }) - await u.waitForAuthSkipAppStart() + await page.setBodyDimensions({ width: screenWidth, height: screenHeight }) + await homePage.goToModelingScene() await u.closeKclCodePanel() await expect .poll(async () => locationToHaveColor(backgroundColor), { @@ -87,7 +79,7 @@ test.describe('Test toggling perspective', () => { } ) await page.reload() - await u.waitForAuthSkipAppStart() + await homePage.goToModelingScene() await expect .poll(async () => locationToHaveColor(xzPlaneColor), { timeout: 5000, diff --git a/src/preload.ts b/src/preload.ts index 6ec8ed3c3..af655c027 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -7,7 +7,8 @@ import packageJson from '../package.json' import { MachinesListing } from 'components/MachineManagerProvider' import chokidar from 'chokidar' -const resizeWindow = (width: number, height: number) => ipcRenderer.invoke('app.resizeWindow', [width, height]) +const resizeWindow = (width: number, height: number) => + ipcRenderer.invoke('app.resizeWindow', [width, height]) const open = (args: any) => ipcRenderer.invoke('dialog.showOpenDialog', args) const save = (args: any) => ipcRenderer.invoke('dialog.showSaveDialog', args) const openExternal = (url: any) => ipcRenderer.invoke('shell.openExternal', url)