Opt-in tests that cover Windows-specific capabilities (#6489)

* Opt-in tests that cover Windows-specific capabilities

* Remove unnecessary quotes
This commit is contained in:
Jace Browning
2025-04-24 20:50:26 -04:00
committed by GitHub
parent 6001b71f06
commit bff13f6bfe
22 changed files with 3780 additions and 3730 deletions

View File

@ -155,7 +155,7 @@ async function doBasicSketch(
|> xLine(length = -segLen(seg01))`) |> xLine(length = -segLen(seg01))`)
} }
test.describe('Basic sketch', { tag: ['@skipWin'] }, () => { test.describe('Basic sketch', () => {
test('code pane open at start', async ({ page, homePage }) => { test('code pane open at start', async ({ page, homePage }) => {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
await doBasicSketch(page, homePage, ['code']) await doBasicSketch(page, homePage, ['code'])

View File

@ -8,130 +8,126 @@ import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import { getUtils } from '@e2e/playwright/test-utils' import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe( test.describe('Can create sketches on all planes and their back sides', () => {
'Can create sketches on all planes and their back sides', const sketchOnPlaneAndBackSideTest = async (
{ tag: ['@skipWin'] }, page: Page,
() => { homePage: HomePageFixture,
const sketchOnPlaneAndBackSideTest = async ( scene: SceneFixture,
page: Page, toolbar: ToolbarFixture,
homePage: HomePageFixture, plane: string,
scene: SceneFixture, clickCoords: { x: number; y: number }
toolbar: ToolbarFixture, ) => {
plane: string, const u = await getUtils(page)
clickCoords: { x: number; y: number } await page.setBodyDimensions({ width: 1200, height: 500 })
) => {
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
const XYPlanRed: [number, number, number] = [98, 50, 51] const XYPlanRed: [number, number, number] = [98, 50, 51]
await scene.expectPixelColor(XYPlanRed, { x: 700, y: 300 }, 15) await scene.expectPixelColor(XYPlanRed, { x: 700, y: 300 }, 15)
await u.openDebugPanel() await u.openDebugPanel()
const coord = const coord =
plane === '-XY' || plane === '-YZ' || plane === 'XZ' ? -100 : 100 plane === '-XY' || plane === '-YZ' || plane === 'XZ' ? -100 : 100
const camCommand: EngineCommand = { const camCommand: EngineCommand = {
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_look_at', type: 'default_camera_look_at',
center: { x: 0, y: 0, z: 0 }, center: { x: 0, y: 0, z: 0 },
vantage: { x: coord, y: coord, z: coord }, vantage: { x: coord, y: coord, z: coord },
up: { x: 0, y: 0, z: 1 }, up: { x: 0, y: 0, z: 1 },
}, },
} }
const updateCamCommand: EngineCommand = { const updateCamCommand: EngineCommand = {
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_get_settings', type: 'default_camera_get_settings',
}, },
}
const code = `@settings(defaultLengthUnit = in)sketch001 = startSketchOn(${plane})profile001 = startProfileAt([0.91, -1.22], sketch001)`
await u.openDebugPanel()
await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click()
await u.sendCustomCmd(camCommand)
await page.waitForTimeout(100)
await u.sendCustomCmd(updateCamCommand)
await u.closeDebugPanel()
await page.mouse.click(clickCoords.x, clickCoords.y)
await page.waitForTimeout(600) // wait for animation
await toolbar.waitUntilSketchingReady()
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
).toBeVisible()
await u.closeDebugPanel()
await page.mouse.click(707, 393)
await expect(page.locator('.cm-content')).toHaveText(code)
await page
.getByRole('button', { name: 'line Line', exact: true })
.first()
.click()
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearCommandLogs()
await u.removeCurrentCode()
} }
const planeConfigs = [ const code = `@settings(defaultLengthUnit = in)sketch001 = startSketchOn(${plane})profile001 = startProfileAt([0.91, -1.22], sketch001)`
{
plane: 'XY',
coords: { x: 600, y: 388 },
description: 'red plane',
},
{
plane: 'YZ',
coords: { x: 700, y: 250 },
description: 'green plane',
},
{
plane: 'XZ',
coords: { x: 684, y: 427 },
description: 'blue plane',
},
{
plane: '-XY',
coords: { x: 600, y: 118 },
description: 'back of red plane',
},
{
plane: '-YZ',
coords: { x: 700, y: 219 },
description: 'back of green plane',
},
{
plane: '-XZ',
coords: { x: 700, y: 80 },
description: 'back of blue plane',
},
]
for (const config of planeConfigs) { await u.openDebugPanel()
test(config.plane, async ({ page, homePage, scene, toolbar }) => {
await sketchOnPlaneAndBackSideTest( await u.clearCommandLogs()
page, await page.getByRole('button', { name: 'Start Sketch' }).click()
homePage,
scene, await u.sendCustomCmd(camCommand)
toolbar, await page.waitForTimeout(100)
config.plane, await u.sendCustomCmd(updateCamCommand)
config.coords
) await u.closeDebugPanel()
})
} await page.mouse.click(clickCoords.x, clickCoords.y)
await page.waitForTimeout(600) // wait for animation
await toolbar.waitUntilSketchingReady()
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
).toBeVisible()
await u.closeDebugPanel()
await page.mouse.click(707, 393)
await expect(page.locator('.cm-content')).toHaveText(code)
await page
.getByRole('button', { name: 'line Line', exact: true })
.first()
.click()
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearCommandLogs()
await u.removeCurrentCode()
} }
)
const planeConfigs = [
{
plane: 'XY',
coords: { x: 600, y: 388 },
description: 'red plane',
},
{
plane: 'YZ',
coords: { x: 700, y: 250 },
description: 'green plane',
},
{
plane: 'XZ',
coords: { x: 684, y: 427 },
description: 'blue plane',
},
{
plane: '-XY',
coords: { x: 600, y: 118 },
description: 'back of red plane',
},
{
plane: '-YZ',
coords: { x: 700, y: 219 },
description: 'back of green plane',
},
{
plane: '-XZ',
coords: { x: 700, y: 80 },
description: 'back of blue plane',
},
]
for (const config of planeConfigs) {
test(config.plane, async ({ page, homePage, scene, toolbar }) => {
await sketchOnPlaneAndBackSideTest(
page,
homePage,
scene,
toolbar,
config.plane,
config.coords
)
})
}
})

View File

@ -10,7 +10,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => { test.describe('Code pane and errors', () => {
test('Typing KCL errors induces a badge on the code pane button', async ({ test('Typing KCL errors induces a badge on the code pane button', async ({
page, page,
homePage, homePage,

View File

@ -9,7 +9,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Command bar tests', { tag: ['@skipWin'] }, () => { test.describe('Command bar tests', () => {
test('Extrude from command bar selects extrude line after', async ({ test('Extrude from command bar selects extrude line after', async ({
page, page,
homePage, homePage,
@ -179,57 +179,57 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
await expect(commandLevelArgButton).toHaveText('level: project') await expect(commandLevelArgButton).toHaveText('level: project')
}) })
test( test('Command bar keybinding works from code editor and can change a setting', async ({
'Command bar keybinding works from code editor and can change a setting', page,
{ tag: ['@skipWin'] }, homePage,
async ({ page, homePage }) => { }) => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
// FIXME: No KCL code, unable to wait for engine execution // FIXME: No KCL code, unable to wait for engine execution
await page.waitForTimeout(10000) await page.waitForTimeout(10000)
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
// Put the cursor in the code editor // Put the cursor in the code editor
await page.locator('.cm-content').click() await page.locator('.cm-content').click()
// Now try the same, but with the keyboard shortcut, check focus // Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('ControlOrMeta+K') await page.keyboard.press('ControlOrMeta+K')
let cmdSearchBar = page.getByPlaceholder('Search commands') let cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).toBeVisible() await expect(cmdSearchBar).toBeVisible()
await expect(cmdSearchBar).toBeFocused() await expect(cmdSearchBar).toBeFocused()
// Try typing in the command bar // Try typing in the command bar
await cmdSearchBar.fill('theme') await cmdSearchBar.fill('theme')
const themeOption = page.getByRole('option', { const themeOption = page.getByRole('option', {
name: 'Settings · app · theme', name: 'Settings · app · theme',
}) })
await expect(themeOption).toBeVisible() await expect(themeOption).toBeVisible()
await themeOption.click() await themeOption.click()
const themeInput = page.getByPlaceholder('dark') const themeInput = page.getByPlaceholder('dark')
await expect(themeInput).toBeVisible() await expect(themeInput).toBeVisible()
await expect(themeInput).toBeFocused() await expect(themeInput).toBeFocused()
// Select dark theme // Select dark theme
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
await expect( await expect(page.getByRole('option', { name: 'system' })).toHaveAttribute(
page.getByRole('option', { name: 'system' }) 'data-headlessui-state',
).toHaveAttribute('data-headlessui-state', 'active') 'active'
await page.keyboard.press('Enter') )
await page.keyboard.press('Enter')
// Check the toast appeared // Check the toast appeared
await expect( await expect(
page.getByText(`Set theme to "system" as a user default`) page.getByText(`Set theme to "system" as a user default`)
).toBeVisible() ).toBeVisible()
// Check that the theme changed // Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`) await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
} })
)
test('Can extrude from the command bar', async ({ test('Can extrude from the command bar', async ({
page, page,

View File

@ -10,7 +10,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
test( test(
'export works on the first try', 'export works on the first try',
{ tag: ['@electron', '@macOS', '@skipLocalEngine'] }, { tag: ['@electron', '@macos', '@windows', '@skipLocalEngine'] },
async ({ page, context, scene, tronApp, cmdBar }, testInfo) => { async ({ page, context, scene, tronApp, cmdBar }, testInfo) => {
if (!tronApp) { if (!tronApp) {
fail() fail()

View File

@ -10,7 +10,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Editor tests', { tag: ['@skipWin'] }, () => { test.describe('Editor tests', () => {
test('can comment out code with ctrl+/', async ({ page, homePage }) => { test('can comment out code with ctrl+/', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
@ -989,162 +989,162 @@ sketch001 = startSketchOn(XZ)
|> close()`) |> close()`)
}) })
test( test('Can undo a sketch modification with ctrl+z', async ({
'Can undo a sketch modification with ctrl+z', page,
{ tag: ['@skipWin'] }, homePage,
async ({ page, homePage, editor }) => { editor,
const u = await getUtils(page) }) => {
await page.addInitScript(async () => { const u = await getUtils(page)
localStorage.setItem( await page.addInitScript(async () => {
'persistCode', localStorage.setItem(
`@settings(defaultLengthUnit=in) 'persistCode',
`@settings(defaultLengthUnit=in)
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArc(endAbsolute = [24.95, -0.38])
|> close() |> close()
|> extrude(length = 5)` |> extrude(length = 5)`
) )
}) })
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.openAndClearDebugPanel() await u.openAndClearDebugPanel()
await u.sendCustomCmd({ await u.sendCustomCmd({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_look_at', type: 'default_camera_look_at',
vantage: { x: 0, y: -1250, z: 580 }, vantage: { x: 0, y: -1250, z: 580 },
center: { x: 0, y: 0, z: 0 }, center: { x: 0, y: 0, z: 0 },
up: { x: 0, y: 0, z: 1 }, up: { x: 0, y: 0, z: 1 },
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.sendCustomCmd({ await u.sendCustomCmd({
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_get_settings', type: 'default_camera_get_settings',
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
const startPX = [1200 / 2, 500 / 2] const startPX = [1200 / 2, 500 / 2]
const dragPX = 40 const dragPX = 40
await page.getByText('startProfileAt([4.61, -10.01], %)').click() await page.getByText('startProfileAt([4.61, -10.01], %)').click()
await expect( await expect(
page.getByRole('button', { name: 'Edit Sketch' }) page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible() ).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click() await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(400) await page.waitForTimeout(400)
let prevContent = await page.locator('.cm-content').innerText() let prevContent = await page.locator('.cm-content').innerText()
await expect(page.getByTestId('segment-overlay')).toHaveCount(2) await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
// drag startProfileAt handle // drag startProfileAt handle
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: startPX[0] + 68, y: startPX[1] + 147 }, sourcePosition: { x: startPX[0] + 68, y: startPX[1] + 147 },
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX }, targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText() prevContent = await page.locator('.cm-content').innerText()
// drag line handle // drag line handle
// we wait so it saves the code // we wait so it saves the code
await page.waitForTimeout(800) await page.waitForTimeout(800)
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]') const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
await page.waitForTimeout(100) await page.waitForTimeout(100)
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y }, sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX }, targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
}) })
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText() prevContent = await page.locator('.cm-content').innerText()
// we wait so it saves the code // we wait so it saves the code
await page.waitForTimeout(800) await page.waitForTimeout(800)
// drag tangentialArc handle // drag tangentialArc handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]') const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 }, sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
targetPosition: { targetPosition: {
x: tangentEnd.x + dragPX, x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX, y: tangentEnd.y + dragPX,
}, },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent) await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// expect the code to have changed // expect the code to have changed
await editor.expectEditor.toContain( await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78]) |> line(end = [15.4, -2.78])
|> tangentialArc(endAbsolute = [27.6, -3.05]) |> tangentialArc(endAbsolute = [27.6, -3.05])
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
) )
// Hit undo // Hit undo
await page.keyboard.down('Control') await page.keyboard.down('Control')
await page.keyboard.press('KeyZ') await page.keyboard.press('KeyZ')
await page.keyboard.up('Control') await page.keyboard.up('Control')
await editor.expectEditor.toContain( await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78]) |> line(end = [15.4, -2.78])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArc(endAbsolute = [24.95, -0.38])
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
) )
// Hit undo again. // Hit undo again.
await page.keyboard.down('Control') await page.keyboard.down('Control')
await page.keyboard.press('KeyZ') await page.keyboard.press('KeyZ')
await page.keyboard.up('Control') await page.keyboard.up('Control')
await editor.expectEditor.toContain( await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %) |> startProfileAt([2.71, -2.71], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArc(endAbsolute = [24.95, -0.38])
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
) )
// Hit undo again. // Hit undo again.
await page.keyboard.down('Control') await page.keyboard.down('Control')
await page.keyboard.press('KeyZ') await page.keyboard.press('KeyZ')
await page.keyboard.up('Control') await page.keyboard.up('Control')
await page.waitForTimeout(100) await page.waitForTimeout(100)
await editor.expectEditor.toContain( await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09]) |> line(end = [12.73, -0.09])
|> tangentialArc(endAbsolute = [24.95, -0.38]) |> tangentialArc(endAbsolute = [24.95, -0.38])
|> close() |> close()
|> extrude(length = 5)`, |> extrude(length = 5)`,
{ shouldNormalise: true } { shouldNormalise: true }
) )
} })
)
test( test(
`Can import a local OBJ file`, `Can import a local OBJ file`,

View File

@ -41,7 +41,7 @@ class MyAPIReporter implements Reporter {
annotations: test.annotations.map((a) => a.type), // e.g. 'fail' or 'fixme' annotations: test.annotations.map((a) => a.type), // e.g. 'fail' or 'fixme'
id: test.id, // computed file/test/project ID used for reruns id: test.id, // computed file/test/project ID used for reruns
retry: result.retry, retry: result.retry,
tags: test.tags, // e.g. '@snapshot' or '@skipWin' tags: test.tags, // e.g. '@snapshot' or '@skipLocalEngine'
// Extra environment variables // Extra environment variables
CI_COMMIT_SHA: process.env.CI_COMMIT_SHA || null, CI_COMMIT_SHA: process.env.CI_COMMIT_SHA || null,
CI_PR_NUMBER: process.env.CI_PR_NUMBER || null, CI_PR_NUMBER: process.env.CI_PR_NUMBER || null,

File diff suppressed because it is too large Load Diff

View File

@ -18,7 +18,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
test( test(
'projects reload if a new one is created, deleted, or renamed externally', 'projects reload if a new one is created, deleted, or renamed externally',
{ tag: ['@electron', '@macOS'] }, { tag: ['@electron', '@macos', '@windows'] },
async ({ context, page }, testInfo) => { async ({ context, page }, testInfo) => {
let externalCreatedProjectName = 'external-created-project' let externalCreatedProjectName = 'external-created-project'

View File

@ -29,7 +29,7 @@ sketch003 = startSketchOn(XY)
extrude003 = extrude(sketch003, length = 20) extrude003 = extrude(sketch003, length = 20)
` `
test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => { test.describe('Prompt-to-edit tests', () => {
test.describe('Check the happy path, for basic changing color', () => { test.describe('Check the happy path, for basic changing color', () => {
const cases = [ const cases = [
{ {

View File

@ -14,7 +14,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Regression tests', { tag: ['@skipWin'] }, () => { test.describe('Regression tests', () => {
// bugs we found that don't fit neatly into other categories // bugs we found that don't fit neatly into other categories
test('bad model has inline error #3251', async ({ test('bad model has inline error #3251', async ({
context, context,
@ -239,17 +239,18 @@ extrude001 = extrude(sketch001, length = 50)
await expect(zooLogo).not.toHaveAttribute('href') await expect(zooLogo).not.toHaveAttribute('href')
}) })
test( test('Position _ Is Out Of Range... regression test', async ({
'Position _ Is Out Of Range... regression test', context,
{ tag: ['@skipWin'] }, page,
async ({ context, page, homePage }) => { homePage,
const u = await getUtils(page) }) => {
// const PUR = 400 / 37.5 //pixeltoUnitRatio const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) // const PUR = 400 / 37.5 //pixeltoUnitRatio
await context.addInitScript(async () => { await page.setBodyDimensions({ width: 1200, height: 500 })
localStorage.setItem( await context.addInitScript(async () => {
'persistCode', localStorage.setItem(
`exampleSketch = startSketchOn("XZ") 'persistCode',
`exampleSketch = startSketchOn("XZ")
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 45 ) |> angledLine(angle = 50, length = 45 )
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
@ -258,55 +259,55 @@ extrude001 = extrude(sketch001, length = 50)
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)
shell(exampleSketch, faces = ['end'], thickness = 0.25)` shell(exampleSketch, faces = ['end'], thickness = 0.25)`
) )
})
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] })
await expect(async () => { // error text on hover
await homePage.goToModelingScene() await page.hover('.cm-lint-marker-error')
await u.waitForPageLoad() await expect(page.getByText('Unexpected token: |').first()).toBeVisible()
// error in guter // Okay execution finished, let's start editing text below the error.
await expect(page.locator('.cm-lint-marker-error')).toBeVisible({ await u.codeLocator.click()
timeout: 1_000, // Go to the end of the editor
}) // This bug happens when there is a diagnostic in the editor and you try to
await page.waitForTimeout(200) // edit text below it.
// expect it still to be there (sometimes it just clears for a bit?) // Or delete a huge chunk of text and then try to edit below it.
await expect(page.locator('.cm-lint-marker-error')).toBeVisible({ await page.keyboard.press('End')
timeout: 1_000, await page.keyboard.down('Shift')
}) await page.keyboard.press('ArrowUp')
}).toPass({ timeout: 40_000, intervals: [1_000] }) 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()
// error text on hover await page.keyboard.press('Enter')
await page.hover('.cm-lint-marker-error') await page.keyboard.press('Enter')
await expect(page.getByText('Unexpected token: |').first()).toBeVisible() await page.keyboard.type('thing: "blah"', { delay: 100 })
await page.keyboard.press('Enter')
await page.keyboard.press('ArrowLeft')
// Okay execution finished, let's start editing text below the error. await expect(
await u.codeLocator.click() page.locator('.cm-content')
// Go to the end of the editor ).toContainText(`exampleSketch = startSketchOn("XZ")
// 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], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 45 ) |> angledLine(angle = 50, length = 45 )
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
@ -314,9 +315,8 @@ extrude001 = extrude(sketch001, length = 50)
thing: "blah"`) thing: "blah"`)
await expect(page.locator('.cm-lint-marker-error')).toBeVisible() await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
} })
)
test( test(
'window resize updates should reconfigure the stream', 'window resize updates should reconfigure the stream',
@ -486,82 +486,81 @@ extrude002 = extrude(profile002, length = 150)
} }
) )
// We updated this test such that you can have multiple exports going at once. // We updated this test such that you can have multiple exports going at once.
test( test('ensure you CAN export while an export is already going', async ({
'ensure you CAN export while an export is already going', page,
{ tag: ['@skipLinux', '@skipWin'] }, homePage,
async ({ page, homePage }) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await test.step('Set up the code and durations', async () => { await test.step('Set up the code and durations', async () => {
await page.addInitScript( await page.addInitScript(
async ({ code }) => { async ({ code }) => {
localStorage.setItem('persistCode', code) localStorage.setItem('persistCode', code)
;(window as any).playwrightSkipFilePicker = true ;(window as any).playwrightSkipFilePicker = true
}, },
{ {
code: bracket, code: bracket,
} }
) )
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await u.waitForPageLoad() await u.waitForPageLoad()
// wait for execution done // wait for execution done
await u.openDebugPanel() await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel() await u.closeDebugPanel()
// expect zero errors in guter // expect zero errors in guter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
}) })
const errorToastMessage = page.getByText(`Error while exporting`) const errorToastMessage = page.getByText(`Error while exporting`)
const exportingToastMessage = page.getByText(`Exporting...`) const exportingToastMessage = page.getByText(`Exporting...`)
const engineErrorToastMessage = page.getByText(`Nothing to export`) const engineErrorToastMessage = page.getByText(`Nothing to export`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`) const alreadyExportingToastMessage = page.getByText(`Already exporting`)
const successToastMessage = page.getByText(`Exported successfully`) const successToastMessage = page.getByText(`Exported successfully`)
await test.step('second export', async () => { await test.step('second export', async () => {
await clickExportButton(page) await clickExportButton(page)
await expect(exportingToastMessage).toBeVisible() await expect(exportingToastMessage).toBeVisible()
await clickExportButton(page) await clickExportButton(page)
await test.step('The first export still succeeds', async () => { 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([ await Promise.all([
expect(exportingToastMessage).not.toBeVisible(), expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 }),
expect(errorToastMessage).not.toBeVisible(), expect(errorToastMessage).not.toBeVisible(),
expect(engineErrorToastMessage).not.toBeVisible(), expect(engineErrorToastMessage).not.toBeVisible(),
expect(alreadyExportingToastMessage).not.toBeVisible(), expect(successToastMessage).toBeVisible({ timeout: 15_000 }),
expect(alreadyExportingToastMessage).not.toBeVisible({
timeout: 15_000,
}),
]) ])
await expect(successToastMessage).toHaveCount(2)
}) })
} })
)
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).toHaveCount(2)
})
})
test( test(
`Network health indicator only appears in modeling view`, `Network health indicator only appears in modeling view`,

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,7 @@ test.setTimeout(60_000)
// up with another PR if we want this back. // up with another PR if we want this back.
test( test(
'exports of each format should work', 'exports of each format should work',
{ tag: ['@snapshot', '@skipWin', '@skipMacos'] }, { tag: ['@snapshot'] },
async ({ page, context, scene, cmdBar, tronApp }) => { async ({ page, context, scene, cmdBar, tronApp }) => {
if (!tronApp) { if (!tronApp) {
fail() fail()

View File

@ -8,230 +8,235 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Test network and connection issues', { test.describe(
tag: ['@macOS'], 'Test network and connection issues',
}, () => { {
test( tag: ['@macos', '@windows'],
'simulate network down and network little widget', },
{ tag: '@skipLocalEngine' }, () => {
async ({ page, homePage }) => { test(
test.fixme(orRunWhenFullSuiteEnabled()) 'simulate network down and network little widget',
const u = await getUtils(page) { tag: '@skipLocalEngine' },
await page.setBodyDimensions({ width: 1200, height: 500 }) async ({ page, homePage }) => {
test.fixme(orRunWhenFullSuiteEnabled())
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
const networkToggle = page.getByTestId('network-toggle') const networkToggle = page.getByTestId('network-toggle')
// This is how we wait until the stream is online // This is how we wait until the stream is online
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 }) ).not.toBeDisabled({ timeout: 15000 })
const networkWidget = page.locator('[data-testid="network-toggle"]') const networkWidget = page.locator('[data-testid="network-toggle"]')
await expect(networkWidget).toBeVisible() await expect(networkWidget).toBeVisible()
await networkWidget.hover() await networkWidget.hover()
const networkPopover = page.locator('[data-testid="network-popover"]') const networkPopover = page.locator('[data-testid="network-popover"]')
await expect(networkPopover).not.toBeVisible() await expect(networkPopover).not.toBeVisible()
// (First check) Expect the network to be up // (First check) Expect the network to be up
await expect(networkToggle).toContainText('Connected') await expect(networkToggle).toContainText('Connected')
// Click the network widget // Click the network widget
await networkWidget.click() await networkWidget.click()
// Check the modal opened. // Check the modal opened.
await expect(networkPopover).toBeVisible() await expect(networkPopover).toBeVisible()
// Click off the modal. // Click off the modal.
await page.mouse.click(100, 100) await page.mouse.click(100, 100)
await expect(networkPopover).not.toBeVisible() await expect(networkPopover).not.toBeVisible()
// Turn off the network // Turn off the network
await u.emulateNetworkConditions({ await u.emulateNetworkConditions({
offline: true, offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9 // values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0, latency: 0,
downloadThroughput: -1, downloadThroughput: -1,
uploadThroughput: -1, uploadThroughput: -1,
}) })
// Expect the network to be down // Expect the network to be down
await expect(networkToggle).toContainText('Problem') await expect(networkToggle).toContainText('Problem')
// Click the network widget // Click the network widget
await networkWidget.click() await networkWidget.click()
// Check the modal opened. // Check the modal opened.
await expect(networkPopover).toBeVisible() await expect(networkPopover).toBeVisible()
// Click off the modal. // Click off the modal.
await page.mouse.click(0, 0) await page.mouse.click(0, 0)
await expect(networkPopover).not.toBeVisible() await expect(networkPopover).not.toBeVisible()
// Turn back on the network // Turn back on the network
await u.emulateNetworkConditions({ await u.emulateNetworkConditions({
offline: false, offline: false,
// values of 0 remove any active throttling. crbug.com/456324#c9 // values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0, latency: 0,
downloadThroughput: -1, downloadThroughput: -1,
uploadThroughput: -1, uploadThroughput: -1,
}) })
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 }) ).not.toBeDisabled({ timeout: 15000 })
// (Second check) expect the network to be up // (Second check) expect the network to be up
await expect(networkToggle).toContainText('Connected') await expect(networkToggle).toContainText('Connected')
} }
) )
test( test(
'Engine disconnect & reconnect in sketch mode', 'Engine disconnect & reconnect in sketch mode',
{ tag: '@skipLocalEngine' }, { tag: '@skipLocalEngine' },
async ({ page, homePage, toolbar, scene, cmdBar }) => { async ({ page, homePage, toolbar, scene, cmdBar }) => {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
const networkToggle = page.getByTestId('network-toggle') const networkToggle = page.getByTestId('network-toggle')
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
await homePage.goToModelingScene() await homePage.goToModelingScene()
await u.waitForPageLoad() await u.waitForPageLoad()
await u.openDebugPanel() await u.openDebugPanel()
// click on "Start Sketch" button // click on "Start Sketch" button
await u.clearCommandLogs() await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click() await page.getByRole('button', { name: 'Start Sketch' }).click()
await page.waitForTimeout(100) await page.waitForTimeout(100)
// select a plane // select a plane
await page.mouse.click(700, 200) await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ)` `sketch001 = startSketchOn(XZ)`
) )
await u.closeDebugPanel() await u.closeDebugPanel()
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
const startXPx = 600 const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10) await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)` `sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)`
) )
await page.waitForTimeout(100) await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect( await expect(
page.locator('.cm-content') page.locator('.cm-content')
).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001) ).toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|> xLine(length = ${commonPoints.num1})`) |> xLine(length = ${commonPoints.num1})`)
// Expect the network to be up // Expect the network to be up
await expect(networkToggle).toContainText('Connected') await expect(networkToggle).toContainText('Connected')
// simulate network down // simulate network down
await u.emulateNetworkConditions({ await u.emulateNetworkConditions({
offline: true, offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9 // values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0, latency: 0,
downloadThroughput: -1, downloadThroughput: -1,
uploadThroughput: -1, uploadThroughput: -1,
}) })
// Expect the network to be down // Expect the network to be down
await expect(networkToggle).toContainText('Problem') await expect(networkToggle).toContainText('Problem')
// Ensure we are not in sketch mode // Ensure we are not in sketch mode
await expect( await expect(
page.getByRole('button', { name: 'Exit Sketch' }) page.getByRole('button', { name: 'Exit Sketch' })
).not.toBeVisible() ).not.toBeVisible()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible() ).toBeVisible()
// simulate network up // simulate network up
await u.emulateNetworkConditions({ await u.emulateNetworkConditions({
offline: false, offline: false,
// values of 0 remove any active throttling. crbug.com/456324#c9 // values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0, latency: 0,
downloadThroughput: -1, downloadThroughput: -1,
uploadThroughput: -1, uploadThroughput: -1,
}) })
// Wait for the app to be ready for use // Wait for the app to be ready for use
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled({ timeout: 15000 }) ).not.toBeDisabled({ timeout: 15000 })
// Expect the network to be up // Expect the network to be up
await expect(networkToggle).toContainText('Connected') await expect(networkToggle).toContainText('Connected')
await scene.settled(cmdBar) await scene.settled(cmdBar)
// Click off the code pane. // Click off the code pane.
await page.mouse.click(100, 100) await page.mouse.click(100, 100)
// select a line // select a line
await page await page
.getByText(`startProfileAt(${commonPoints.startAt}, sketch001)`) .getByText(`startProfileAt(${commonPoints.startAt}, sketch001)`)
.click() .click()
// enter sketch again // enter sketch again
await toolbar.editSketch() await toolbar.editSketch()
// Click the line tool // Click the line tool
await page.getByRole('button', { name: 'line Line', exact: true }).click() await page
.getByRole('button', { name: 'line Line', exact: true })
.click()
await page.waitForTimeout(150) await page.waitForTimeout(150)
const camCommand: EngineCommand = { const camCommand: EngineCommand = {
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_look_at', type: 'default_camera_look_at',
center: { x: 109, y: 0, z: -152 }, center: { x: 109, y: 0, z: -152 },
vantage: { x: 115, y: -505, z: -152 }, vantage: { x: 115, y: -505, z: -152 },
up: { x: 0, y: 0, z: 1 }, up: { x: 0, y: 0, z: 1 },
}, },
} }
const updateCamCommand: EngineCommand = { const updateCamCommand: EngineCommand = {
type: 'modeling_cmd_req', type: 'modeling_cmd_req',
cmd_id: uuidv4(), cmd_id: uuidv4(),
cmd: { cmd: {
type: 'default_camera_get_settings', type: 'default_camera_get_settings',
}, },
} }
await toolbar.openPane('debug') await toolbar.openPane('debug')
await u.sendCustomCmd(camCommand) await u.sendCustomCmd(camCommand)
await page.waitForTimeout(100) await page.waitForTimeout(100)
await u.sendCustomCmd(updateCamCommand) await u.sendCustomCmd(updateCamCommand)
await page.waitForTimeout(100) await page.waitForTimeout(100)
// click to continue profile // click to continue profile
await page.mouse.click(1007, 400) await page.mouse.click(1007, 400)
await page.waitForTimeout(100) await page.waitForTimeout(100)
// Ensure we can continue sketching // Ensure we can continue sketching
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20) await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect await expect
.poll(u.normalisedEditorCode) .poll(u.normalisedEditorCode)
.toBe(`sketch001 = startSketchOn(XZ) .toBe(`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([12.34, -12.34], sketch001) profile001 = startProfileAt([12.34, -12.34], sketch001)
|> xLine(length = 12.34) |> xLine(length = 12.34)
|> line(end = [-12.34, 12.34]) |> line(end = [-12.34, 12.34])
`) `)
await page.waitForTimeout(100) await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20) await page.mouse.click(startXPx, 500 - PUR * 20)
await expect await expect
.poll(u.normalisedEditorCode) .poll(u.normalisedEditorCode)
.toBe(`sketch001 = startSketchOn(XZ) .toBe(`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([12.34, -12.34], sketch001) profile001 = startProfileAt([12.34, -12.34], sketch001)
|> xLine(length = 12.34) |> xLine(length = 12.34)
|> line(end = [-12.34, 12.34]) |> line(end = [-12.34, 12.34])
@ -239,21 +244,22 @@ profile001 = startProfileAt([12.34, -12.34], sketch001)
`) `)
// Unequip line tool // Unequip line tool
await page.keyboard.press('Escape') await page.keyboard.press('Escape')
// Make sure we didn't pop out of sketch mode. // Make sure we didn't pop out of sketch mode.
await expect( await expect(
page.getByRole('button', { name: 'Exit Sketch' }) page.getByRole('button', { name: 'Exit Sketch' })
).toBeVisible() ).toBeVisible()
await expect( await expect(
page.getByRole('button', { name: 'line Line', exact: true }) page.getByRole('button', { name: 'line Line', exact: true })
).not.toHaveAttribute('aria-pressed', 'true') ).not.toHaveAttribute('aria-pressed', 'true')
// Exit sketch // Exit sketch
await page.keyboard.press('Escape') await page.keyboard.press('Escape')
await expect( await expect(
page.getByRole('button', { name: 'Exit Sketch' }) page.getByRole('button', { name: 'Exit Sketch' })
).not.toBeVisible() ).not.toBeVisible()
} }
) )
}) }
)

View File

@ -4,7 +4,7 @@ import { uuidv4 } from '@src/lib/utils'
import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils' import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Testing Camera Movement', { tag: ['@skipWin'] }, () => { test.describe('Testing Camera Movement', () => {
test('Can move camera reliably', async ({ test('Can move camera reliably', async ({
page, page,
context, context,

View File

@ -10,7 +10,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Testing constraints', { tag: ['@skipWin'] }, () => { test.describe('Testing constraints', () => {
test('Can constrain line length', async ({ page, homePage }) => { test('Can constrain line length', async ({ page, homePage }) => {
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(

View File

@ -4,7 +4,7 @@ import { TEST_CODE_GIZMO } from '@e2e/playwright/storageStates'
import { getUtils } from '@e2e/playwright/test-utils' import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Testing Gizmo', { tag: ['@skipWin'] }, () => { test.describe('Testing Gizmo', () => {
const cases = [ const cases = [
{ {
testDescription: 'top view', testDescription: 'top view',

View File

@ -11,7 +11,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => { test.describe('Testing segment overlays', () => {
test('Hover over a segment should show its overlay, hovering over the input overlays should show its popover, clicking the input overlay should constrain/unconstrain it:\nfor the following segments', () => { test('Hover over a segment should show its overlay, hovering over the input overlays should show its popover, clicking the input overlay should constrain/unconstrain it:\nfor the following segments', () => {
// TODO: fix this test on mac after the electron migration // TODO: fix this test on mac after the electron migration
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())

View File

@ -9,7 +9,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Testing selections', { tag: ['@skipWin'] }, () => { test.describe('Testing selections', () => {
test.setTimeout(90_000) test.setTimeout(90_000)
test('Selections work on fresh and edited sketch', async ({ test('Selections work on fresh and edited sketch', async ({
page, page,

View File

@ -29,7 +29,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
test.describe( test.describe(
'Testing settings', 'Testing settings',
{ {
tag: ['@macOS'], tag: ['@macos', '@windows'],
}, },
() => { () => {
test('Stored settings are validated and fall back to defaults', async ({ test('Stored settings are validated and fall back to defaults', async ({
@ -281,7 +281,7 @@ test.describe(
test( test(
`Project settings override user settings on desktop`, `Project settings override user settings on desktop`,
{ tag: ['@electron', '@skipWin'] }, { tag: ['@electron'] },
async ({ context, page }, testInfo) => { async ({ context, page }, testInfo) => {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
const projectName = 'bracket' const projectName = 'bracket'

View File

@ -9,7 +9,7 @@ import {
} from '@e2e/playwright/test-utils' } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Text-to-CAD tests', { tag: ['@skipWin'] }, () => { test.describe('Text-to-CAD tests', () => {
test('basic lego happy case', async ({ page, homePage }) => { test('basic lego happy case', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
@ -436,93 +436,92 @@ test.describe('Text-to-CAD tests', { tag: ['@skipWin'] }, () => {
}) })
// This will be fine once greg makes prompt at top of file deterministic // This will be fine once greg makes prompt at top of file deterministic
test( test('can do many at once and get many prompts back, and interact with many', async ({
'can do many at once and get many prompts back, and interact with many', page,
{ tag: ['@skipWin'] }, homePage,
async ({ page, homePage }) => { }) => {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
// Let this test run longer since we've seen it timeout. // Let this test run longer since we've seen it timeout.
test.setTimeout(180_000) test.setTimeout(180_000)
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await u.waitForPageLoad() await u.waitForPageLoad()
await sendPromptFromCommandBar(page, 'a 2x4 lego') await sendPromptFromCommandBar(page, 'a 2x4 lego')
await sendPromptFromCommandBar(page, 'a 2x8 lego') await sendPromptFromCommandBar(page, 'a 2x8 lego')
await sendPromptFromCommandBar(page, 'a 2x10 lego') await sendPromptFromCommandBar(page, 'a 2x10 lego')
// Find the toast. // Find the toast.
// Look out for the toast message // Look out for the toast message
const submittingToastMessage = page.getByText( const submittingToastMessage = page.getByText(
`Submitting to Text-to-CAD API...` `Submitting to Text-to-CAD API...`
) )
await expect(submittingToastMessage.first()).toBeVisible() await expect(submittingToastMessage.first()).toBeVisible()
const generatingToastMessage = page.getByText( const generatingToastMessage = page.getByText(
`Generating parametric model...` `Generating parametric model...`
) )
await expect(generatingToastMessage.first()).toBeVisible({ await expect(generatingToastMessage.first()).toBeVisible({
timeout: 10_000, timeout: 10_000,
}) })
const successToastMessage = page.getByText(`Text-to-CAD successful`) const successToastMessage = page.getByText(`Text-to-CAD successful`)
// We should have three success toasts. // We should have three success toasts.
await expect(successToastMessage).toHaveCount(3, { timeout: 25_000 }) await expect(successToastMessage).toHaveCount(3, { timeout: 25_000 })
await expect(page.getByText(`a 2x4 lego`)).toBeVisible() await expect(page.getByText(`a 2x4 lego`)).toBeVisible()
await expect(page.getByText(`a 2x8 lego`)).toBeVisible() await expect(page.getByText(`a 2x8 lego`)).toBeVisible()
await expect(page.getByText(`a 2x10 lego`)).toBeVisible() await expect(page.getByText(`a 2x10 lego`)).toBeVisible()
// Ensure if you reject one, the others stay. // Ensure if you reject one, the others stay.
const rejectButton = page.getByRole('button', { name: 'Reject' }) const rejectButton = page.getByRole('button', { name: 'Reject' })
await expect(rejectButton.first()).toBeVisible() await expect(rejectButton.first()).toBeVisible()
// Click the reject button on the first toast. // Click the reject button on the first toast.
await rejectButton.first().click() await rejectButton.first().click()
// The first toast should disappear, but not the others. // The first toast should disappear, but not the others.
await expect(page.getByText(`a 2x10 lego`)).not.toBeVisible() await expect(page.getByText(`a 2x10 lego`)).not.toBeVisible()
await expect(page.getByText(`a 2x8 lego`)).toBeVisible() await expect(page.getByText(`a 2x8 lego`)).toBeVisible()
await expect(page.getByText(`a 2x4 lego`)).toBeVisible() await expect(page.getByText(`a 2x4 lego`)).toBeVisible()
// Ensure you can copy the code for one of the models remaining. // Ensure you can copy the code for one of the models remaining.
const copyToClipboardButton = page.getByRole('button', { const copyToClipboardButton = page.getByRole('button', {
name: 'Accept', name: 'Accept',
}) })
await expect(copyToClipboardButton.first()).toBeVisible() await expect(copyToClipboardButton.first()).toBeVisible()
// Click the button. // Click the button.
await copyToClipboardButton.first().click() await copyToClipboardButton.first().click()
// Do NOT do AI tests like this: "Expect the code to be pasted." // Do NOT do AI tests like this: "Expect the code to be pasted."
// Reason: AI tests are NONDETERMINISTIC. Thus we need to be as most // Reason: AI tests are NONDETERMINISTIC. Thus we need to be as most
// general as we can for the assertion. // general as we can for the assertion.
// We can use Kolmogorov complexity as a measurement of the // We can use Kolmogorov complexity as a measurement of the
// "probably most minimal version of this program" to have a lower // "probably most minimal version of this program" to have a lower
// bound to work with. It is completely by feel because there are // bound to work with. It is completely by feel because there are
// no proofs that any program is its smallest self. // no proofs that any program is its smallest self.
const code2x8 = await page.locator('.cm-content').innerText() const code2x8 = await page.locator('.cm-content').innerText()
await expect(code2x8.length).toBeGreaterThan(249) await expect(code2x8.length).toBeGreaterThan(249)
// Ensure the final toast remains. // Ensure the final toast remains.
await expect(page.getByText(`a 2x10 lego`)).not.toBeVisible() await expect(page.getByText(`a 2x10 lego`)).not.toBeVisible()
await expect(page.getByText(`Prompt: "a 2x8 lego`)).not.toBeVisible() await expect(page.getByText(`Prompt: "a 2x8 lego`)).not.toBeVisible()
await expect(page.getByText(`a 2x4 lego`)).toBeVisible() await expect(page.getByText(`a 2x4 lego`)).toBeVisible()
// Ensure you can copy the code for the final model. // Ensure you can copy the code for the final model.
await expect(copyToClipboardButton).toBeVisible() await expect(copyToClipboardButton).toBeVisible()
// Click the button. // Click the button.
await copyToClipboardButton.click() await copyToClipboardButton.click()
// Expect the code to be pasted. // Expect the code to be pasted.
const code2x4 = await page.locator('.cm-content').innerText() const code2x4 = await page.locator('.cm-content').innerText()
await expect(code2x4.length).toBeGreaterThan(249) await expect(code2x4.length).toBeGreaterThan(249)
} })
)
test('can do many at once with errors, clicking dismiss error does not dismiss all', async ({ test('can do many at once with errors, clicking dismiss error does not dismiss all', async ({
page, page,

View File

@ -126,7 +126,7 @@
"generate:machine-api": "npx openapi-typescript ./openapi/machine-api.json -o src/lib/machine-api.d.ts", "generate:machine-api": "npx openapi-typescript ./openapi/machine-api.json -o src/lib/machine-api.d.ts",
"generate:samples-manifest": "cd public/kcl-samples && node generate-manifest.js", "generate:samples-manifest": "cd public/kcl-samples && node generate-manifest.js",
"tron:start": "electron-forge start", "tron:start": "electron-forge start",
"chrome:test": "PLATFORM=web NODE_ENV=development playwright test --config=playwright.config.ts --project='Google Chrome' --grep-invert='@snapshot'", "chrome:test": "PLATFORM=web NODE_ENV=development playwright test --config=playwright.config.ts --project='Google Chrome' --grep-invert=@snapshot",
"tronb:vite:dev": "vite build -c vite.main.config.ts -m development && vite build -c vite.preload.config.ts -m development && vite build -c vite.renderer.config.ts -m development", "tronb:vite:dev": "vite build -c vite.main.config.ts -m development && vite build -c vite.preload.config.ts -m development && vite build -c vite.renderer.config.ts -m development",
"tronb:vite:prod": "vite build -c vite.main.config.ts && vite build -c vite.preload.config.ts && vite build -c vite.renderer.config.ts", "tronb:vite:prod": "vite build -c vite.main.config.ts && vite build -c vite.preload.config.ts && vite build -c vite.renderer.config.ts",
"tronb:package:dev": "npm run tronb:vite:dev && electron-builder --config electron-builder.yml", "tronb:package:dev": "npm run tronb:vite:dev && electron-builder --config electron-builder.yml",
@ -136,15 +136,15 @@
"test:snapshots": "PLATFORM=web NODE_ENV=development playwright test --config=playwright.config.ts --grep=@snapshot --trace=on --shard=1/1", "test:snapshots": "PLATFORM=web NODE_ENV=development playwright test --config=playwright.config.ts --grep=@snapshot --trace=on --shard=1/1",
"test:unit": "vitest run --mode development --exclude **/kclSamples.test.ts", "test:unit": "vitest run --mode development --exclude **/kclSamples.test.ts",
"test:unit:kcl-samples": "vitest run --mode development ./src/lang/kclSamples.test.ts", "test:unit:kcl-samples": "vitest run --mode development ./src/lang/kclSamples.test.ts",
"test:playwright:electron": "playwright test --config=playwright.electron.config.ts --grep-invert='@snapshot'", "test:playwright:electron": "playwright test --config=playwright.electron.config.ts --grep-invert=@snapshot",
"test:playwright:electron:windows": "playwright test --config=playwright.electron.config.ts --grep-invert=\"@skipWin|@snapshot\" --quiet", "test:playwright:electron:windows": "playwright test --config=playwright.electron.config.ts --grep=@windows --quiet",
"test:playwright:electron:macos": "playwright test --config=playwright.electron.config.ts --grep='@macOS' --quiet", "test:playwright:electron:macos": "playwright test --config=playwright.electron.config.ts --grep=@macos --quiet",
"test:playwright:electron:ubuntu": "playwright test --config=playwright.electron.config.ts --grep-invert='@skipLinux|@snapshot' --quiet", "test:playwright:electron:ubuntu": "playwright test --config=playwright.electron.config.ts --grep-invert=@snapshot --quiet",
"test:playwright:electron:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@snapshot'", "test:playwright:electron:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert=@snapshot",
"test:playwright:electron:windows:local": "npm run tronb:vite:dev && set NODE_ENV='development' && playwright test --config=playwright.electron.config.ts --grep-invert=\"@skipWin|@snapshot\"", "test:playwright:electron:windows:local": "npm run tronb:vite:dev && set NODE_ENV='development' && playwright test --config=playwright.electron.config.ts --grep-invert=@snapshot",
"test:playwright:electron:macos:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@skipMacos|@snapshot'", "test:playwright:electron:macos:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert=@snapshot",
"test:playwright:electron:ubuntu:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@skipLinux|@snapshot'", "test:playwright:electron:ubuntu:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert=@snapshot",
"test:playwright:electron:ubuntu:engine:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert='@skipLinux|@snapshot|@skipLocalEngine'", "test:playwright:electron:ubuntu:engine:local": "npm run tronb:vite:dev && NODE_ENV=development playwright test --config=playwright.electron.config.ts --grep-invert=@snapshot|@skipLocalEngine",
"test:unit:local": "npm run simpleserver:bg && npm run test:unit; kill-port 3000", "test:unit:local": "npm run simpleserver:bg && npm run test:unit; kill-port 3000",
"test:unit:kcl-samples:local": "npm run simpleserver:bg && npm run test:unit:kcl-samples; kill-port 3000" "test:unit:kcl-samples:local": "npm run simpleserver:bg && npm run test:unit:kcl-samples; kill-port 3000"
}, },