2024-05-24 20:54:42 +10:00
import { test , expect , Page } from '@playwright/test'
2024-06-04 08:32:24 -04:00
import {
makeTemplate ,
getUtils ,
getMovementUtils ,
wiggleMove ,
doExport ,
2024-06-04 14:36:34 -04:00
metaModifier ,
2024-06-04 08:32:24 -04:00
} from './test-utils'
2023-11-24 08:59:24 +11:00
import waitOn from 'wait-on'
2024-06-03 15:37:23 +10:00
import { XOR , roundOff , uuidv4 } from 'lib/utils'
2024-04-02 10:29:34 -04:00
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
2024-04-11 13:37:49 -04:00
import { secrets } from './secrets'
import {
TEST_SETTINGS ,
TEST_SETTINGS_KEY ,
TEST_SETTINGS_CORRUPTED ,
2024-04-26 13:20:03 -04:00
TEST_SETTINGS_ONBOARDING_EXPORT ,
TEST_SETTINGS_ONBOARDING_START ,
2024-04-11 13:37:49 -04:00
} from './storageStates'
2024-04-16 21:36:19 -07:00
import * as TOML from '@iarna/toml'
2024-05-24 20:54:42 +10:00
import { LineInputsType } from 'lang/std/sketchcombos'
2024-05-09 15:04:33 +10:00
import { Coords2d } from 'lang/std/sketch'
2024-05-17 10:29:04 -04:00
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
2024-05-23 22:02:25 +02:00
import { EngineCommand } from 'lang/std/engineConnection'
2023-11-24 08:59:24 +11:00
/ *
debug helper : unfortunately we do rely on exact coord mouse clicks in a few places
just from the nature of the stream , running the test with debugger and pasting the below
into the console can be useful to get coords
document . addEventListener ( 'mousemove' , ( e ) = >
console . log ( ` await page.mouse.click( ${ e . clientX } , ${ e . clientY } ) ` )
)
* /
2024-06-04 08:32:24 -04:00
const deg = ( Math . PI * 2 ) / 360
2024-02-26 19:53:44 +11:00
const commonPoints = {
2024-03-02 08:20:50 +11:00
startAt : '[9.06, -12.22]' ,
num1 : 9.14 ,
num2 : 18.2 ,
2024-03-22 10:23:04 +11:00
// num1: 9.64,
// num2: 19.19,
2024-02-26 19:53:44 +11:00
}
2024-06-04 08:32:24 -04:00
// Utilities for writing tests that depend on test values
2023-11-24 08:59:24 +11:00
test . beforeEach ( async ( { context , page } ) = > {
// wait for Vite preview server to be up
await waitOn ( {
resources : [ 'tcp:3000' ] ,
timeout : 5000 ,
} )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
await context . addInitScript (
async ( { token , settingsKey , settings } ) = > {
localStorage . setItem ( 'TOKEN_PERSIST_KEY' , token )
localStorage . setItem ( 'persistCode' , ` ` )
localStorage . setItem ( settingsKey , settings )
2024-05-24 21:59:51 +10:00
localStorage . setItem ( 'playwright' , 'true' )
2024-04-11 13:37:49 -04:00
} ,
{
token : secrets.token ,
settingsKey : TEST_SETTINGS_KEY ,
settings : TOML.stringify ( { settings : TEST_SETTINGS } ) ,
}
)
2023-11-24 08:59:24 +11:00
// kill animations, speeds up tests and reduced flakiness
await page . emulateMedia ( { reducedMotion : 'reduce' } )
} )
test . setTimeout ( 60000 )
2024-04-11 13:37:49 -04:00
test ( 'Basic sketch' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2023-11-24 08:59:24 +11:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
const PUR = 400 / 37.5 //pixeltoUnitRatio
2023-11-28 21:23:20 +11:00
await page . goto ( '/' )
2023-11-24 08:59:24 +11:00
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
2024-02-26 21:02:33 +11:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
2023-11-24 08:59:24 +11:00
await expect ( page . getByRole ( 'button' , { name : 'Start Sketch' } ) ) . toBeVisible ( )
// click on "Start Sketch" button
await u . clearCommandLogs ( )
2024-03-02 11:25:50 +11:00
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
// select a plane
2024-02-11 12:59:00 +11:00
await page . mouse . click ( 700 , 200 )
2023-11-24 08:59:24 +11:00
2024-02-11 12:59:00 +11:00
await expect ( page . locator ( '.cm-content' ) ) . toHaveText (
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XZ') `
2023-11-24 08:59:24 +11:00
)
2024-03-22 10:23:04 +11:00
await u . closeDebugPanel ( )
2023-11-24 08:59:24 +11:00
2024-02-19 12:41:36 +11:00
await page . waitForTimeout ( 300 ) // TODO detect animation ending, or disable animation
2024-02-11 12:59:00 +11:00
2023-11-24 08:59:24 +11:00
const startXPx = 600
2024-02-11 12:59:00 +11:00
await page . mouse . click ( startXPx + PUR * 10 , 500 - PUR * 10 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % ) ` )
2024-02-11 12:59:00 +11:00
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
await page . mouse . click ( startXPx + PUR * 20 , 500 - PUR * 10 )
2024-02-11 12:59:00 +11:00
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % ) ` )
2023-11-24 08:59:24 +11:00
await page . mouse . click ( startXPx + PUR * 20 , 500 - PUR * 20 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % )
2024-03-02 08:20:50 +11:00
| > line ( [ 0 , $ { commonPoints . num1 } ] , % ) ` )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
await page . mouse . click ( startXPx , 500 - PUR * 20 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % )
2024-03-02 08:20:50 +11:00
| > line ( [ 0 , $ { commonPoints . num1 } ] , % )
2024-02-26 19:53:44 +11:00
| > line ( [ - $ { commonPoints . num2 } , 0 ] , % ) ` )
2023-11-24 08:59:24 +11:00
// deselect line tool
2024-02-11 12:59:00 +11:00
await page . getByRole ( 'button' , { name : 'Line' } ) . click ( )
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
// click between first two clicks to get center of the line
2024-02-11 12:59:00 +11:00
await page . mouse . click ( startXPx + PUR * 15 , 500 - PUR * 10 )
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
// hold down shift
await page . keyboard . down ( 'Shift' )
// click between the latest two clicks to get center of the line
await page . mouse . click ( startXPx + PUR * 10 , 500 - PUR * 20 )
// selected two lines therefore there should be two cursors
await expect ( page . locator ( '.cm-cursor' ) ) . toHaveCount ( 2 )
2024-05-10 19:02:11 -04:00
await page . getByRole ( 'button' , { name : 'Constrain' } ) . click ( )
2023-11-24 08:59:24 +11:00
await page . getByRole ( 'button' , { name : 'Equal Length' } ) . click ( )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
2024-03-15 17:03:42 -04:00
| > line ( [ $ { commonPoints . num1 } , 0 ] , % , 'seg01' )
2024-03-02 08:20:50 +11:00
| > line ( [ 0 , $ { commonPoints . num1 } ] , % )
2023-11-24 08:59:24 +11:00
| > angledLine ( [ 180 , segLen ( 'seg01' , % ) ] , % ) ` )
} )
2024-03-04 10:36:54 +11:00
test ( 'Can moving camera' , async ( { page , context } ) = > {
2024-03-04 14:18:08 +11:00
test . skip ( process . platform === 'darwin' , 'Can moving camera' )
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-03-04 10:36:54 +11:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openAndClearDebugPanel ( )
2024-04-15 12:04:17 -04:00
await u . closeKclCodePanel ( )
2024-03-04 10:36:54 +11:00
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.
2024-05-23 22:02:25 +02:00
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 )
2024-03-04 10:36:54 +11:00
await page . waitForTimeout ( 100 )
// rotate
await u . closeDebugPanel ( )
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
await page . waitForTimeout ( 100 )
2024-03-04 12:18:56 +11:00
// const yo = page.getByTestId('cam-x-position').inputValue()
2024-03-04 10:36:54 +11:00
await u . doAndWaitForImageDiff ( async ( ) = > {
await mouseActions ( )
await u . openAndClearDebugPanel ( )
await u . closeDebugPanel ( )
await page . waitForTimeout ( 100 )
} , 300 )
await u . openAndClearDebugPanel ( )
2024-04-15 12:04:17 -04:00
await page . getByTestId ( 'cam-x-position' ) . isVisible ( )
2024-03-04 12:18:56 +11:00
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 ] )
2024-03-04 10:36:54 +11:00
let shouldRetry = false
if ( xError > 5 || yError > 5 || zError > 5 ) {
if ( cnt > 2 ) {
2024-03-04 12:18:56 +11:00
console . log ( 'xVal' , vals [ 0 ] , 'xError' , xError )
console . log ( 'yVal' , vals [ 1 ] , 'yError' , yError )
console . log ( 'zVal' , vals [ 2 ] , 'zError' , zError )
2024-03-04 10:36:54 +11:00
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' } )
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' )
2024-05-23 22:02:25 +02:00
} , [ - 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 )
2024-03-04 10:36:54 +11:00
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 )
2024-05-23 22:02:25 +02:00
} , [ 1 , - 68 , - 68 ] )
2024-03-04 10:36:54 +11:00
} )
2024-05-10 15:30:40 -07:00
test ( 'if you click the format button it formats your code' , async ( {
page ,
} ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-05-10 15:30:40 -07:00
await page . setViewportSize ( { width : 1000 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
// check no error to begin with
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . not . toBeVisible ( )
await page . click ( '.cm-content' )
2024-06-04 13:57:01 -04:00
await page . keyboard . type ( ` const sketch001 = startSketchOn('XY')
2024-05-10 15:30:40 -07:00
| > startProfileAt ( [ - 10 , - 10 ] , % )
| > line ( [ 20 , 0 ] , % )
| > line ( [ 0 , 20 ] , % )
| > line ( [ - 20 , 0 ] , % )
| > close ( % ) ` )
await page . click ( '#code-pane button:first-child' )
await page . click ( 'button:has-text("Format code")' )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XY')
2024-05-10 15:30:40 -07:00
| > startProfileAt ( [ - 10 , - 10 ] , % )
| > line ( [ 20 , 0 ] , % )
| > line ( [ 0 , 20 ] , % )
| > line ( [ - 20 , 0 ] , % )
| > close ( % ) ` )
} )
test ( 'if you use the format keyboard binding it formats your code' , async ( {
page ,
} ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-05-10 16:51:54 -07:00
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XY')
2024-05-10 16:51:54 -07:00
| > startProfileAt ( [ - 10 , - 10 ] , % )
| > line ( [ 20 , 0 ] , % )
| > line ( [ 0 , 20 ] , % )
| > line ( [ - 20 , 0 ] , % )
| > close ( % ) `
)
} )
2024-05-10 15:30:40 -07:00
await page . setViewportSize ( { width : 1000 , height : 500 } )
const lspStartPromise = page . waitForEvent ( 'console' , async ( message ) = > {
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
// but that doesn't seem to make it to the console for macos/safari :(
if ( message . text ( ) . includes ( 'start kcl lsp' ) ) {
await new Promise ( ( resolve ) = > setTimeout ( resolve , 200 ) )
return true
}
return false
} )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await lspStartPromise
// check no error to begin with
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . not . toBeVisible ( )
2024-05-10 16:51:54 -07:00
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-10 15:30:40 -07:00
2024-05-10 16:51:54 -07:00
// focus the editor
await page . click ( '.cm-line' )
2024-05-10 15:30:40 -07:00
// Hit alt+shift+f to format the code
await page . keyboard . press ( 'Alt+Shift+KeyF' )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XY')
2024-05-10 15:30:40 -07:00
| > startProfileAt ( [ - 10 , - 10 ] , % )
| > line ( [ 20 , 0 ] , % )
| > line ( [ 0 , 20 ] , % )
| > line ( [ - 20 , 0 ] , % )
| > close ( % ) ` )
} )
2024-05-20 14:59:59 -04:00
test ( 'ensure the Zoo logo is not a link in browser app' , async ( { page } ) = > {
await page . setViewportSize ( { width : 1000 , height : 500 } )
await page . goto ( '/' )
const zooLogo = page . locator ( '[data-testid="app-logo"]' )
// Make sure it's not a link
await expect ( zooLogo ) . not . toHaveAttribute ( 'href' )
} )
2023-11-24 08:59:24 +11:00
test ( 'if you write invalid kcl you get inlined errors' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2023-11-24 08:59:24 +11:00
await page . setViewportSize ( { width : 1000 , height : 500 } )
2023-11-28 21:23:20 +11:00
await page . goto ( '/' )
2023-11-24 08:59:24 +11:00
await u . waitForAuthSkipAppStart ( )
// check no error to begin with
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . not . toBeVisible ( )
/ * a d d t h e f o l l o w i n g c o d e t o t h e e d i t o r ( # e r r o r i s n o t a v a l i d l i n e )
# error
const topAng = 30
const bottomAng = 25
* /
await page . click ( '.cm-content' )
2024-05-02 15:13:00 -07:00
await page . keyboard . type ( '$ error' )
2023-11-28 21:23:20 +11:00
// press arrows to clear autocomplete
await page . keyboard . press ( 'ArrowLeft' )
await page . keyboard . press ( 'ArrowRight' )
2023-11-24 08:59:24 +11:00
await page . keyboard . press ( 'Enter' )
await page . keyboard . type ( 'const topAng = 30' )
await page . keyboard . press ( 'Enter' )
await page . keyboard . type ( 'const bottomAng = 25' )
await page . keyboard . press ( 'Enter' )
// error in guter
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . toBeVisible ( )
// error text on hover
await page . hover ( '.cm-lint-marker-error' )
2024-05-02 15:13:00 -07:00
await expect ( page . getByText ( "found unknown token '$'" ) ) . toBeVisible ( )
2023-11-24 08:59:24 +11:00
// select the line that's causing the error and delete it
2024-05-02 15:13:00 -07:00
await page . getByText ( '$ error' ) . click ( )
2023-11-24 08:59:24 +11:00
await page . keyboard . press ( 'End' )
await page . keyboard . down ( 'Shift' )
await page . keyboard . press ( 'Home' )
await page . keyboard . up ( 'Shift' )
await page . keyboard . press ( 'Backspace' )
// wait for .cm-lint-marker-error not to be visible
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . not . toBeVisible ( )
2023-12-05 06:34:23 +11:00
// let's check we get an error when defining the same variable twice
await page . getByText ( 'const bottomAng = 25' ) . click ( )
await page . keyboard . press ( 'Enter' )
await page . keyboard . type ( "// Let's define the same thing twice" )
await page . keyboard . press ( 'Enter' )
await page . keyboard . type ( 'const topAng = 42' )
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . toBeVisible ( )
await expect ( page . locator ( '.cm-lintRange.cm-lintRange-error' ) ) . toBeVisible ( )
await page . locator ( '.cm-lintRange.cm-lintRange-error' ) . hover ( )
await expect ( page . locator ( '.cm-diagnosticText' ) ) . toBeVisible ( )
await expect ( page . getByText ( 'Cannot redefine topAng' ) ) . toBeVisible ( )
const secondTopAng = await page . getByText ( 'topAng' ) . first ( )
await secondTopAng ? . dblclick ( )
await page . keyboard . type ( 'otherAng' )
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . not . toBeVisible ( )
2023-11-24 08:59:24 +11:00
} )
2024-05-21 00:49:57 -07:00
test ( 'error with 2 source ranges gets 2 diagnostics' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-05-21 00:49:57 -07:00
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const length = .750
const width = 0.500
const height = 0.500
const dia = 4
fn squareHole = ( l , w ) = > {
const squareHoleSketch = startSketchOn ( 'XY' )
| > startProfileAt ( [ - width / 2 , - length / 2 ] , % )
| > lineTo ( [ width / 2 , - length / 2 ] , % )
| > lineTo ( [ width / 2 , length / 2 ] , % )
| > lineTo ( [ - width / 2 , length / 2 ] , % )
| > close ( % )
return squareHoleSketch
}
`
)
} )
await page . setViewportSize ( { width : 1000 , height : 500 } )
await page . goto ( '/' )
const lspStartPromise = page . waitForEvent ( 'console' , async ( message ) = > {
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
// but that doesn't seem to make it to the console for macos/safari :(
if ( message . text ( ) . includes ( 'start kcl lsp' ) ) {
await new Promise ( ( resolve ) = > setTimeout ( resolve , 200 ) )
return true
}
return false
} )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await lspStartPromise
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
// check no error to begin with
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . not . toBeVisible ( )
// Click on the bottom of the code editor to add a new line
await page . click ( '.cm-content' )
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 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 page . keyboard . press ( 'ArrowDown' )
await page . keyboard . press ( 'Enter' )
await page . keyboard . type ( ` const extrusion = startSketchOn('XY')
| > circle ( [ 0 , 0 ] , dia / 2 , % )
| > hole ( squareHole ( length , width , height ) , % )
| > extrude ( height , % ) ` )
// error in gutter
await expect ( page . locator ( '.cm-lint-marker-error' ) . first ( ) ) . toBeVisible ( )
await page . hover ( '.cm-lint-marker-error:first-child' )
await expect ( page . getByText ( 'Expected 2 arguments, got 3' ) ) . toBeVisible ( )
// Make sure there are two diagnostics
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . toHaveCount ( 2 )
} )
2024-04-19 18:16:33 -07:00
test ( 'if your kcl gets an error from the engine it is inlined' , async ( {
2024-04-17 09:11:35 -07:00
page ,
} ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-17 09:11:35 -07:00
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const box = startSketchOn('XY')
| > startProfileAt ( [ 0 , 0 ] , % )
| > line ( [ 0 , 10 ] , % )
| > line ( [ 10 , 0 ] , % )
| > line ( [ 0 , - 10 ] , % , 'revolveAxis' )
| > close ( % )
| > extrude ( 10 , % )
const sketch001 = startSketchOn ( box , "revolveAxis" )
| > startProfileAt ( [ 5 , 10 ] , % )
| > line ( [ 0 , - 10 ] , % )
| > line ( [ 2 , 0 ] , % )
2024-04-19 18:16:33 -07:00
| > line ( [ 0 , - 10 ] , % )
2024-04-17 09:11:35 -07:00
| > close ( % )
| > revolve ( {
axis : getEdge ( 'revolveAxis' , box ) ,
angle : 90
} , % )
`
)
} )
await page . setViewportSize ( { width : 1000 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-04-22 20:14:06 +10:00
await u . openDebugPanel ( )
2024-04-17 09:11:35 -07:00
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
// error in guter
await expect ( page . locator ( '.cm-lint-marker-error' ) ) . toBeVisible ( )
// error text on hover
await page . hover ( '.cm-lint-marker-error' )
await expect (
page . getByText (
'sketch profile must lie entirely on one side of the revolution axis'
)
) . toBeVisible ( )
2024-04-19 18:16:33 -07:00
} )
2024-04-17 09:11:35 -07:00
2024-04-11 13:37:49 -04:00
test ( 'executes on load' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-11 13:37:49 -04:00
await page . addInitScript ( async ( ) = > {
2023-11-24 08:59:24 +11:00
localStorage . setItem (
'persistCode' ,
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('-XZ')
2023-11-24 08:59:24 +11:00
| > startProfileAt ( [ - 6.95 , 4.98 ] , % )
| > line ( [ 25.1 , 0.41 ] , % )
| > line ( [ 0.73 , - 14.93 ] , % )
| > line ( [ - 23.44 , 0.52 ] , % ) `
)
} )
await page . setViewportSize ( { width : 1000 , height : 500 } )
2023-11-28 21:23:20 +11:00
await page . goto ( '/' )
2023-11-24 08:59:24 +11:00
await u . waitForAuthSkipAppStart ( )
// expand variables section
2024-04-15 12:04:17 -04:00
const variablesTabButton = page . getByRole ( 'tab' , {
name : 'Variables' ,
exact : false ,
} )
await variablesTabButton . click ( )
2023-11-24 08:59:24 +11:00
2024-06-04 13:57:01 -04:00
// 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
2023-11-24 08:59:24 +11:00
await page . waitForFunction ( ( ) = > {
const variablesElement = document . querySelector (
'.pretty-json-container'
) as HTMLDivElement
2024-06-04 13:57:01 -04:00
return variablesElement . innerHTML . includes ( 'sketch001' )
2023-11-24 08:59:24 +11:00
} )
await expect (
2024-06-04 13:57:01 -04:00
page . locator ( '.pretty-json-container >> text=sketch001' )
2023-11-24 08:59:24 +11:00
) . toBeVisible ( )
} )
2024-04-11 13:37:49 -04:00
test ( 're-executes' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-11 13:37:49 -04:00
await page . addInitScript ( async ( ) = > {
2023-11-24 08:59:24 +11:00
localStorage . setItem ( 'persistCode' , ` const myVar = 5 ` )
} )
await page . setViewportSize ( { width : 1000 , height : 500 } )
2023-11-28 21:23:20 +11:00
await page . goto ( '/' )
2023-11-24 08:59:24 +11:00
await u . waitForAuthSkipAppStart ( )
2024-04-15 12:04:17 -04:00
const variablesTabButton = page . getByRole ( 'tab' , {
name : 'Variables' ,
exact : false ,
} )
await variablesTabButton . click ( )
2023-11-24 08:59:24 +11:00
// expect to see "myVar:5"
await expect (
page . locator ( '.pretty-json-container >> text=myVar:5' )
) . toBeVisible ( )
// change 5 to 67
await page . getByText ( 'const myVar' ) . click ( )
await page . keyboard . press ( 'End' )
await page . keyboard . press ( 'Backspace' )
await page . keyboard . type ( '67' )
await expect (
page . locator ( '.pretty-json-container >> text=myVar:67' )
) . toBeVisible ( )
} )
2024-04-18 15:16:08 -07:00
const sketchOnPlaneAndBackSideTest = async (
page : any ,
plane : string ,
clickCoords : { x : number ; y : number }
) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2023-11-24 08:59:24 +11:00
const PUR = 400 / 37.5 //pixeltoUnitRatio
await page . setViewportSize ( { width : 1200 , height : 500 } )
2023-11-28 21:23:20 +11:00
await page . goto ( '/' )
2023-11-24 08:59:24 +11:00
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
2024-02-11 12:59:00 +11:00
2024-05-23 22:02:25 +02:00
const coord =
plane === '-XY' || plane === '-YZ' || plane === 'XZ' ? - 100 : 100
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 : coord , y : coord , z : coord } ,
up : { x : 0 , y : 0 , z : 1 } ,
} ,
}
const updateCamCommand : EngineCommand = {
type : 'modeling_cmd_req' ,
cmd_id : uuidv4 ( ) ,
cmd : {
type : 'default_camera_get_settings' ,
} ,
2024-04-18 15:16:08 -07:00
}
2024-02-11 12:59:00 +11:00
2024-06-04 13:57:01 -04:00
const code = ` const sketch001 = startSketchOn(' ${ plane } ')
2024-04-18 15:16:08 -07:00
| > startProfileAt ( [ 1.14 , - 1.54 ] , % ) `
2023-11-24 08:59:24 +11:00
2024-04-18 15:16:08 -07:00
await u . openDebugPanel ( )
2023-11-24 08:59:24 +11:00
2024-04-18 15:16:08 -07:00
await u . clearCommandLogs ( )
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
2024-05-23 22:02:25 +02:00
await u . sendCustomCmd ( camCommand )
await page . waitForTimeout ( 100 )
await u . sendCustomCmd ( updateCamCommand )
2023-11-24 08:59:24 +11:00
2024-04-18 15:16:08 -07:00
await u . closeDebugPanel ( )
await page . mouse . click ( clickCoords . x , clickCoords . y )
await page . waitForTimeout ( 300 ) // wait for animation
2024-02-11 12:59:00 +11:00
2024-04-18 15:16:08 -07:00
await expect ( page . getByRole ( 'button' , { name : 'Line' } ) ) . toBeVisible ( )
2023-11-24 08:59:24 +11:00
2024-04-18 15:16:08 -07:00
// draw a line
const startXPx = 600
2023-11-24 08:59:24 +11:00
2024-04-18 15:16:08 -07:00
await u . closeDebugPanel ( )
await page . mouse . click ( startXPx + PUR * 10 , 500 - PUR * 10 )
2023-11-24 08:59:24 +11:00
2024-04-18 15:16:08 -07:00
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( code )
2023-11-24 08:59:24 +11:00
2024-04-18 15:16:08 -07:00
await page . getByRole ( 'button' , { name : 'Line' } ) . 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 ( )
}
test . describe ( 'Can create sketches on all planes and their back sides' , ( ) = > {
test ( 'XY' , async ( { page } ) = > {
await sketchOnPlaneAndBackSideTest (
page ,
'XY' ,
{ x : 600 , y : 388 } // red plane
// { x: 600, y: 400 }, // red plane // clicks grid helper and that causes problems, should fix so that these coords work too.
)
2023-11-24 08:59:24 +11:00
} )
2024-04-18 15:16:08 -07:00
test ( 'YZ' , async ( { page } ) = > {
await sketchOnPlaneAndBackSideTest ( page , 'YZ' , { x : 700 , y : 250 } ) // green plane
2023-11-24 08:59:24 +11:00
} )
2024-04-18 15:16:08 -07:00
test ( 'XZ' , async ( { page } ) = > {
2024-05-21 23:35:33 -07:00
await sketchOnPlaneAndBackSideTest ( page , '-XZ' , { x : 700 , y : 80 } ) // blue plane
2023-11-24 08:59:24 +11:00
} )
2024-04-18 15:16:08 -07:00
test ( '-XY' , async ( { page } ) = > {
await sketchOnPlaneAndBackSideTest ( page , '-XY' , { x : 600 , y : 118 } ) // back of red plane
2023-11-24 08:59:24 +11:00
} )
2024-04-18 15:16:08 -07:00
test ( '-YZ' , async ( { page } ) = > {
await sketchOnPlaneAndBackSideTest ( page , '-YZ' , { x : 700 , y : 219 } ) // back of green plane
2023-11-24 08:59:24 +11:00
} )
2024-04-18 15:16:08 -07:00
test ( '-XZ' , async ( { page } ) = > {
2024-05-21 23:35:33 -07:00
await sketchOnPlaneAndBackSideTest ( page , 'XZ' , { x : 700 , y : 427 } ) // back of blue plane
2023-11-24 08:59:24 +11:00
} )
} )
test ( 'Auto complete works' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2023-11-24 08:59:24 +11:00
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page . setViewportSize ( { width : 1200 , height : 500 } )
2024-03-22 18:10:49 +11:00
const lspStartPromise = page . waitForEvent ( 'console' , async ( message ) = > {
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
// but that doesn't seem to make it to the console for macos/safari :(
if ( message . text ( ) . includes ( 'start kcl lsp' ) ) {
await new Promise ( ( resolve ) = > setTimeout ( resolve , 200 ) )
return true
}
return false
} )
2023-11-28 21:23:20 +11:00
await page . goto ( '/' )
2023-11-24 08:59:24 +11:00
await u . waitForAuthSkipAppStart ( )
2024-03-22 18:10:49 +11:00
await lspStartPromise
2023-11-24 08:59:24 +11:00
// this test might be brittle as we add and remove functions
// but should also be easy to update.
// tests clicking on an option, selection the first option
// and arrowing down to an option
await page . click ( '.cm-content' )
2024-06-04 13:57:01 -04:00
await page . keyboard . type ( 'const sketch001 = start' )
2023-11-24 08:59:24 +11:00
2024-05-21 03:44:02 -04:00
// expect there to be six auto complete options
await expect ( page . locator ( '.cm-completionLabel' ) ) . toHaveCount ( 6 )
2023-11-24 08:59:24 +11:00
await page . getByText ( 'startSketchOn' ) . click ( )
2024-04-17 20:18:07 -07:00
await page . keyboard . type ( "'XZ'" )
2024-04-12 15:36:20 -07:00
await page . keyboard . press ( 'Tab' )
2023-11-24 08:59:24 +11:00
await page . keyboard . press ( 'Enter' )
await page . keyboard . type ( ' |> startProfi' )
// expect there be a single auto complete option that we can just hit enter on
await expect ( page . locator ( '.cm-completionLabel' ) ) . toBeVisible ( )
2024-02-19 12:15:57 +11:00
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
await page . keyboard . press ( 'Enter' ) // accepting the auto complete, not a new line
2024-04-12 15:36:20 -07:00
await page . keyboard . press ( 'Tab' )
2024-04-17 20:18:07 -07:00
await page . keyboard . type ( '12' )
2024-04-22 17:21:24 -07:00
await page . waitForTimeout ( 100 )
2024-04-12 15:36:20 -07:00
await page . keyboard . press ( 'Tab' )
2024-04-22 17:21:24 -07:00
await page . waitForTimeout ( 100 )
2024-04-12 15:36:20 -07:00
await page . keyboard . press ( 'Tab' )
await page . keyboard . press ( 'Tab' )
2023-11-24 08:59:24 +11:00
await page . keyboard . press ( 'Enter' )
await page . keyboard . type ( ' |> lin' )
await expect ( page . locator ( '.cm-tooltip-autocomplete' ) ) . toBeVisible ( )
2024-02-20 09:22:33 +11:00
await page . waitForTimeout ( 100 )
2023-11-24 08:59:24 +11:00
// press arrow down twice then enter to accept xLine
await page . keyboard . press ( 'ArrowDown' )
await page . keyboard . press ( 'ArrowDown' )
await page . keyboard . press ( 'Enter' )
2024-03-02 03:22:04 +11:00
// finish line with comment
2024-04-12 13:28:58 -07:00
await page . keyboard . type ( '5' )
2024-04-12 15:36:20 -07:00
await page . keyboard . press ( 'Tab' )
await page . keyboard . press ( 'Tab' )
2024-04-12 13:28:58 -07:00
await page . keyboard . type ( ' // lin' )
2024-03-02 03:22:04 +11:00
await page . waitForTimeout ( 100 )
// there shouldn't be any auto complete options for 'lin' in the comment
await expect ( page . locator ( '.cm-completionLabel' ) ) . not . toBeVisible ( )
2023-11-24 08:59:24 +11:00
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-04-17 20:18:07 -07:00
| > startProfileAt ( [ 3.14 , 12 ] , % )
2024-03-02 03:22:04 +11:00
| > xLine ( 5 , % ) // lin`)
2023-11-24 08:59:24 +11:00
} )
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
test ( 'Stored settings are validated and fall back to defaults' , async ( {
page ,
} ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-15 12:04:17 -04:00
2024-04-11 13:37:49 -04:00
// Override beforeEach test setup
2024-03-14 15:56:45 -04:00
// with corrupted settings
2024-04-25 00:13:09 -07:00
await page . addInitScript (
2024-04-11 13:37:49 -04:00
async ( { settingsKey , settings } ) = > {
localStorage . setItem ( settingsKey , settings )
} ,
{
settingsKey : TEST_SETTINGS_KEY ,
settings : TOML.stringify ( { settings : TEST_SETTINGS_CORRUPTED } ) ,
}
)
2024-03-14 15:56:45 -04:00
2024-04-11 13:37:49 -04:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
2024-04-15 12:04:17 -04:00
await u . waitForAuthSkipAppStart ( )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
// Check the settings were reset
const storedSettings = TOML . parse (
await page . evaluate (
2024-04-25 00:13:09 -07:00
( { settingsKey } ) = > localStorage . getItem ( settingsKey ) || '' ,
2024-04-11 13:37:49 -04:00
{ settingsKey : TEST_SETTINGS_KEY }
)
) as { settings : SaveSettingsPayload }
2024-04-02 10:29:34 -04:00
2024-04-25 00:13:09 -07:00
expect ( storedSettings . settings ? . app ? . theme ) . toBe ( undefined )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
// Check that the invalid settings were removed
2024-04-25 00:13:09 -07:00
expect ( storedSettings . settings ? . modeling ? . defaultUnit ) . toBe ( undefined )
expect ( storedSettings . settings ? . modeling ? . mouseControls ) . toBe ( undefined )
expect ( storedSettings . settings ? . app ? . projectDirectory ) . toBe ( undefined )
expect ( storedSettings . settings ? . projects ? . defaultProjectName ) . toBe ( undefined )
2024-04-11 13:37:49 -04:00
} )
2024-03-14 15:56:45 -04:00
2024-04-11 13:37:49 -04:00
test ( 'Project settings can be set and override user settings' , async ( {
page ,
} ) = > {
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' , { waitUntil : 'domcontentloaded' } )
await page
. getByRole ( 'button' , { name : 'Start Sketch' } )
. waitFor ( { state : 'visible' } )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
// Open the settings modal with the browser keyboard shortcut
await page . keyboard . press ( 'Meta+Shift+,' )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
await expect (
page . getByRole ( 'heading' , { name : 'Settings' , exact : true } )
) . toBeVisible ( )
await page
. locator ( 'select[name="app-theme"]' )
. selectOption ( { value : 'light' } )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
// Verify the toast appeared
await expect (
page . getByText ( ` Set theme to "light" for this project ` )
) . toBeVisible ( )
// Check that the theme changed
await expect ( page . locator ( 'body' ) ) . not . toHaveClass ( ` body-bg dark ` )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
// Check that the user setting was not changed
await page . getByRole ( 'radio' , { name : 'User' } ) . click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'dark' )
2024-04-02 10:29:34 -04:00
2024-04-11 13:37:49 -04:00
// Roll back to default "system" theme
await page
. getByText (
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
. hover ( )
await page
. getByRole ( 'button' , {
name : 'Roll back theme ; Has tooltip: Roll back to match default' ,
} )
. click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'system' )
2024-03-14 15:56:45 -04:00
2024-04-11 13:37:49 -04:00
// Check that the project setting did not change
await page . getByRole ( 'radio' , { name : 'Project' } ) . click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'light' )
2024-03-14 15:56:45 -04:00
} )
2024-05-20 20:52:33 -07:00
test ( 'Project settings can be opened with keybinding from the editor' , async ( {
page ,
} ) = > {
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' , { waitUntil : 'domcontentloaded' } )
await page
. getByRole ( 'button' , { name : 'Start Sketch' } )
. waitFor ( { state : 'visible' } )
// Put the cursor in the editor
await page . click ( '.cm-content' )
// Open the settings modal with the browser keyboard shortcut
await page . keyboard . press ( 'Meta+Shift+,' )
await expect (
page . getByRole ( 'heading' , { name : 'Settings' , exact : true } )
) . toBeVisible ( )
await page
. locator ( 'select[name="app-theme"]' )
. selectOption ( { value : 'light' } )
// Verify the toast appeared
await expect (
page . getByText ( ` Set theme to "light" for this project ` )
) . toBeVisible ( )
// Check that the theme changed
await expect ( page . locator ( 'body' ) ) . not . toHaveClass ( ` body-bg dark ` )
// Check that the user setting was not changed
await page . getByRole ( 'radio' , { name : 'User' } ) . click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'dark' )
// Roll back to default "system" theme
await page
. getByText (
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
. hover ( )
await page
. getByRole ( 'button' , {
name : 'Roll back theme ; Has tooltip: Roll back to match default' ,
} )
. click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'system' )
// Check that the project setting did not change
await page . getByRole ( 'radio' , { name : 'Project' } ) . click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'light' )
} )
2024-05-21 13:33:52 -07:00
test ( 'Project and user settings can be reset' , async ( { page } ) = > {
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' , { waitUntil : 'domcontentloaded' } )
await page
. getByRole ( 'button' , { name : 'Start Sketch' } )
. waitFor ( { state : 'visible' } )
// Put the cursor in the editor
await page . click ( '.cm-content' )
// Open the settings modal with the browser keyboard shortcut
await page . keyboard . press ( 'Meta+Shift+,' )
await expect (
page . getByRole ( 'heading' , { name : 'Settings' , exact : true } )
) . toBeVisible ( )
// Click the reset settings button.
await page . getByRole ( 'button' , { name : 'Restore default settings' } ) . click ( )
await page
. locator ( 'select[name="app-theme"]' )
. selectOption ( { value : 'light' } )
// Verify the toast appeared
await expect (
page . getByText ( ` Set theme to "light" for this project ` )
) . toBeVisible ( )
// Check that the theme changed
await expect ( page . locator ( 'body' ) ) . not . toHaveClass ( ` body-bg dark ` )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'light' )
// Check that the user setting was not changed
await page . getByRole ( 'radio' , { name : 'User' } ) . click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'system' )
// Click the reset settings button.
await page . getByRole ( 'button' , { name : 'Restore default settings' } ) . click ( )
// Verify it is now set to the default value
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'system' )
// Set the user theme to light.
await page
. locator ( 'select[name="app-theme"]' )
. selectOption ( { value : 'light' } )
// Verify the toast appeared
await expect (
page . getByText ( ` Set theme to "light" as a user default ` )
) . toBeVisible ( )
// Check that the theme changed
await expect ( page . locator ( 'body' ) ) . not . toHaveClass ( ` body-bg dark ` )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'light' )
await page . getByRole ( 'radio' , { name : 'Project' } ) . click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'light' )
// Click the reset settings button.
await page . getByRole ( 'button' , { name : 'Restore default settings' } ) . click ( )
// Verify it is now set to the default value
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'system' )
await page . getByRole ( 'radio' , { name : 'User' } ) . click ( )
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'system' )
// Click the reset settings button.
await page . getByRole ( 'button' , { name : 'Restore default settings' } ) . click ( )
// Verify it is now set to the default value
await expect ( page . locator ( 'select[name="app-theme"]' ) ) . toHaveValue ( 'system' )
} )
2024-06-04 13:56:20 -04:00
test ( 'Keyboard shortcuts can be viewed through the help menu' , async ( {
page ,
} ) = > {
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await page . waitForURL ( '**/file/**' , { waitUntil : 'domcontentloaded' } )
await page
. getByRole ( 'button' , { name : 'Start Sketch' } )
. waitFor ( { state : 'visible' } )
// Open the help menu
await page . getByRole ( 'button' , { name : 'Help' , exact : false } ) . click ( )
// Open the keyboard shortcuts
await page . getByRole ( 'button' , { name : 'Keyboard Shortcuts' } ) . click ( )
// Verify the URL and that you can see a list of shortcuts
await expect ( page . url ( ) ) . toContain ( '?tab=keybindings' )
await expect (
page . getByRole ( 'heading' , { name : 'Enter Sketch Mode' } )
) . toBeAttached ( )
} )
2024-04-26 13:20:03 -04:00
test ( 'Click through each onboarding step' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-26 13:20:03 -04:00
// Override beforeEach test setup
await page . addInitScript (
async ( { settingsKey , settings } ) = > {
// Give no initial code, so that the onboarding start is shown immediately
localStorage . setItem ( 'persistCode' , '' )
localStorage . setItem ( settingsKey , settings )
} ,
{
settingsKey : TEST_SETTINGS_KEY ,
settings : TOML.stringify ( { settings : TEST_SETTINGS_ONBOARDING_START } ) ,
}
)
await page . setViewportSize ( { width : 1200 , height : 1080 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
// Test that the onboarding pane loaded
await expect ( page . getByText ( 'Welcome to Modeling App! This' ) ) . toBeVisible ( )
const nextButton = page . getByTestId ( 'onboarding-next' )
while ( ( await nextButton . innerText ( ) ) !== 'Finish' ) {
await expect ( nextButton ) . toBeVisible ( )
await nextButton . click ( )
}
// Finish the onboarding
await expect ( nextButton ) . toBeVisible ( )
await nextButton . click ( )
// Test that the onboarding pane is gone
await expect ( page . getByTestId ( 'onboarding-content' ) ) . not . toBeVisible ( )
await expect ( page . url ( ) ) . not . toContain ( 'onboarding' )
} )
2024-04-11 13:37:49 -04:00
test ( 'Onboarding redirects and code updating' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
// Override beforeEach test setup
await page . addInitScript (
async ( { settingsKey , settings } ) = > {
// Give some initial code, so we can test that it's cleared
localStorage . setItem ( 'persistCode' , 'const sigmaAllow = 15000' )
localStorage . setItem ( settingsKey , settings )
} ,
{
settingsKey : TEST_SETTINGS_KEY ,
2024-04-26 13:20:03 -04:00
settings : TOML.stringify ( { settings : TEST_SETTINGS_ONBOARDING_EXPORT } ) ,
2024-04-11 13:37:49 -04:00
}
)
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
// Test that the redirect happened
await expect ( page . url ( ) . split ( ':3000' ) . slice ( - 1 ) [ 0 ] ) . toBe (
` /file/%2Fbrowser%2Fmain.kcl/onboarding/export `
)
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
// Test that you come back to this page when you refresh
await page . reload ( )
await expect ( page . url ( ) . split ( ':3000' ) . slice ( - 1 ) [ 0 ] ) . toBe (
` /file/%2Fbrowser%2Fmain.kcl/onboarding/export `
)
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
// Test that the onboarding pane loaded
const title = page . locator ( '[data-testid="onboarding-content"]' )
await expect ( title ) . toBeAttached ( )
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
// Test that the code changes when you advance to the next step
await page . locator ( '[data-testid="onboarding-next"]' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( '' )
2023-11-27 19:46:15 -05:00
2024-04-11 13:37:49 -04:00
// Test that the code is not empty when you click on the next step
await page . locator ( '[data-testid="onboarding-next"]' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( /.+/ )
2023-11-27 19:46:15 -05:00
} )
2023-11-28 21:23:20 +11:00
test ( 'Selections work on fresh and edited sketch' , async ( { page } ) = > {
// tests mapping works on fresh sketch and edited sketch
// tests using hovers which is the same as selections, because if
// source ranges are wrong, hovers won't work
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2023-11-28 21:23:20 +11:00
const PUR = 400 / 37.5 //pixeltoUnitRatio
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
2024-02-11 12:59:00 +11:00
const xAxisClick = ( ) = >
2024-04-22 20:14:06 +10:00
page . mouse . click ( 700 , 253 ) . then ( ( ) = > page . waitForTimeout ( 100 ) )
2024-02-11 12:59:00 +11:00
const emptySpaceClick = ( ) = >
2024-05-24 20:54:42 +10:00
page . mouse . click ( 700 , 343 ) . then ( ( ) = > page . waitForTimeout ( 100 ) )
2024-02-11 12:59:00 +11:00
const topHorzSegmentClick = ( ) = >
2024-03-22 10:23:04 +11:00
page . mouse . click ( 709 , 290 ) . then ( ( ) = > page . waitForTimeout ( 100 ) )
2024-02-11 12:59:00 +11:00
const bottomHorzSegmentClick = ( ) = >
page . mouse . click ( 767 , 396 ) . then ( ( ) = > page . waitForTimeout ( 100 ) )
2023-12-01 20:18:51 +11:00
2023-11-28 21:23:20 +11:00
await u . clearCommandLogs ( )
2024-02-26 21:02:33 +11:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
2023-11-28 21:23:20 +11:00
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
// select a plane
2024-02-11 12:59:00 +11:00
await page . mouse . click ( 700 , 200 )
await page . waitForTimeout ( 700 ) // wait for animation
2023-11-28 21:23:20 +11:00
const startXPx = 600
2024-03-22 10:23:04 +11:00
await u . closeDebugPanel ( )
2024-02-11 12:59:00 +11:00
await page . mouse . click ( startXPx + PUR * 10 , 500 - PUR * 10 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % ) ` )
2024-02-11 12:59:00 +11:00
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2023-11-28 21:23:20 +11:00
await page . mouse . click ( startXPx + PUR * 20 , 500 - PUR * 10 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % ) ` )
2023-11-28 21:23:20 +11:00
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2023-11-28 21:23:20 +11:00
await page . mouse . click ( startXPx + PUR * 20 , 500 - PUR * 20 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % )
2024-03-02 08:20:50 +11:00
| > line ( [ 0 , $ { commonPoints . num1 } ] , % ) ` )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2023-11-28 21:23:20 +11:00
await page . mouse . click ( startXPx , 500 - PUR * 20 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-02-26 19:53:44 +11:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % )
2024-03-02 08:20:50 +11:00
| > line ( [ 0 , $ { commonPoints . num1 } ] , % )
2024-02-26 19:53:44 +11:00
| > line ( [ - $ { commonPoints . num2 } , 0 ] , % ) ` )
2023-11-28 21:23:20 +11:00
// deselect line tool
2024-02-11 12:59:00 +11:00
await page . getByRole ( 'button' , { name : 'Line' } ) . click ( )
2023-11-28 21:23:20 +11:00
await u . closeDebugPanel ( )
2024-04-22 20:14:06 +10:00
const selectionSequence = async ( isSecondTime = false ) = > {
2023-11-28 21:23:20 +11:00
await expect ( page . getByTestId ( 'hover-highlight' ) ) . not . toBeVisible ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
await page . mouse . move (
startXPx + PUR * 15 ,
isSecondTime ? 430 : 500 - PUR * 10
)
2023-11-28 21:23:20 +11:00
await expect ( page . getByTestId ( 'hover-highlight' ) ) . toBeVisible ( )
// bg-yellow-200 is more brittle than hover-highlight, but is closer to the user experience
// and will be an easy fix if it breaks because we change the colour
await expect ( page . locator ( '.bg-yellow-200' ) ) . toBeVisible ( )
// check mousing off, than mousing onto another line
await page . mouse . move ( startXPx + PUR * 10 , 500 - PUR * 15 ) // mouse off
await expect ( page . getByTestId ( 'hover-highlight' ) ) . not . toBeVisible ( )
2024-04-22 20:14:06 +10:00
await page . mouse . move (
startXPx + PUR * 10 ,
isSecondTime ? 295 : 500 - PUR * 20
) // mouse onto another line
2023-11-28 21:23:20 +11:00
await expect ( page . getByTestId ( 'hover-highlight' ) ) . toBeVisible ( )
2023-12-01 20:18:51 +11:00
// now check clicking works including axis
// click a segment hold shift and click an axis, see that a relevant constraint is enabled
2024-02-11 12:59:00 +11:00
await topHorzSegmentClick ( )
2023-12-01 20:18:51 +11:00
await page . keyboard . down ( 'Shift' )
2024-05-10 19:02:11 -04:00
const constrainButton = page . getByRole ( 'button' , { name : 'Constrain' } )
2023-12-01 20:18:51 +11:00
const absYButton = page . getByRole ( 'button' , { name : 'ABS Y' } )
2024-05-10 19:02:11 -04:00
await constrainButton . click ( )
2023-12-01 20:18:51 +11:00
await expect ( absYButton ) . toBeDisabled ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-02-11 12:59:00 +11:00
await xAxisClick ( )
2023-12-01 20:18:51 +11:00
await page . keyboard . up ( 'Shift' )
2024-05-10 19:02:11 -04:00
await constrainButton . click ( )
2023-12-01 20:18:51 +11:00
await absYButton . and ( page . locator ( ':not([disabled])' ) ) . waitFor ( )
await expect ( absYButton ) . not . toBeDisabled ( )
// clear selection by clicking on nothing
2024-02-11 12:59:00 +11:00
await emptySpaceClick ( )
2023-12-01 20:18:51 +11:00
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2023-12-01 20:18:51 +11:00
// same selection but click the axis first
2024-02-11 12:59:00 +11:00
await xAxisClick ( )
2024-05-10 19:02:11 -04:00
await constrainButton . click ( )
2023-12-01 20:18:51 +11:00
await expect ( absYButton ) . toBeDisabled ( )
await page . keyboard . down ( 'Shift' )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-02-11 12:59:00 +11:00
await topHorzSegmentClick ( )
2024-05-24 20:54:42 +10:00
await page . waitForTimeout ( 100 )
2024-02-11 12:59:00 +11:00
2023-12-01 20:18:51 +11:00
await page . keyboard . up ( 'Shift' )
2024-05-10 19:02:11 -04:00
await constrainButton . click ( )
2023-12-01 20:18:51 +11:00
await expect ( absYButton ) . not . toBeDisabled ( )
// clear selection by clicking on nothing
2024-02-11 12:59:00 +11:00
await emptySpaceClick ( )
2023-12-01 20:18:51 +11:00
// check the same selection again by putting cursor in code first then selecting axis
2024-02-26 19:53:44 +11:00
await page . getByText ( ` |> line([- ${ commonPoints . num2 } , 0], %) ` ) . click ( )
2023-12-01 20:18:51 +11:00
await page . keyboard . down ( 'Shift' )
2024-05-10 19:02:11 -04:00
await constrainButton . click ( )
2023-12-01 20:18:51 +11:00
await expect ( absYButton ) . toBeDisabled ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-02-11 12:59:00 +11:00
await xAxisClick ( )
2023-12-01 20:18:51 +11:00
await page . keyboard . up ( 'Shift' )
2024-05-10 19:02:11 -04:00
await constrainButton . click ( )
2023-12-01 20:18:51 +11:00
await expect ( absYButton ) . not . toBeDisabled ( )
// clear selection by clicking on nothing
2024-02-11 12:59:00 +11:00
await emptySpaceClick ( )
2023-12-01 20:18:51 +11:00
// select segment in editor than another segment in scene and check there are two cursors
2024-03-22 10:23:04 +11:00
// TODO change this back to shift click in the scene, not cmd click in the editor
2024-02-11 12:59:00 +11:00
await bottomHorzSegmentClick ( )
2024-03-22 10:23:04 +11:00
await expect ( page . locator ( '.cm-cursor' ) ) . toHaveCount ( 1 )
await page . keyboard . down ( process . platform === 'linux' ? 'Control' : 'Meta' )
await page . waitForTimeout ( 100 )
await page . getByText ( ` |> line([- ${ commonPoints . num2 } , 0], %) ` ) . click ( )
2023-12-01 20:18:51 +11:00
await expect ( page . locator ( '.cm-cursor' ) ) . toHaveCount ( 2 )
2024-03-22 10:23:04 +11:00
await page . waitForTimeout ( 500 )
await page . keyboard . up ( process . platform === 'linux' ? 'Control' : 'Meta' )
2023-12-01 20:18:51 +11:00
// clear selection by clicking on nothing
2024-02-11 12:59:00 +11:00
await emptySpaceClick ( )
2023-11-28 21:23:20 +11:00
}
2023-12-01 20:18:51 +11:00
await selectionSequence ( )
2023-11-28 21:23:20 +11:00
// hovering in fresh sketch worked, lets try exiting and re-entering
2024-02-11 12:59:00 +11:00
await u . openAndClearDebugPanel ( )
await page . getByRole ( 'button' , { name : 'Exit Sketch' } ) . click ( )
await page . waitForTimeout ( 200 )
2023-12-01 20:18:51 +11:00
// wait for execution done
2024-02-11 12:59:00 +11:00
2023-12-01 20:18:51 +11:00
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
2024-02-11 12:59:00 +11:00
await u . closeDebugPanel ( )
2023-11-28 21:23:20 +11:00
// select a line
2024-02-20 17:55:06 -08:00
// await topHorzSegmentClick()
2024-02-26 19:53:44 +11:00
await page . getByText ( commonPoints . startAt ) . click ( ) // TODO remove this and reinstate // await topHorzSegmentClick()
2024-02-20 17:55:06 -08:00
await page . waitForTimeout ( 100 )
2023-11-28 21:23:20 +11:00
// enter sketch again
2024-04-22 20:14:06 +10:00
await u . doAndWaitForCmd (
( ) = > page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( ) ,
'default_camera_get_settings'
)
await page . waitForTimeout ( 150 )
2024-02-20 17:55:06 -08:00
await page . waitForTimeout ( 300 ) // wait for animation
2023-11-28 21:23:20 +11:00
// hover again and check it works
2024-04-22 20:14:06 +10:00
await selectionSequence ( true )
2023-11-28 21:23:20 +11:00
} )
2023-12-06 14:44:13 -05:00
2024-04-02 10:29:34 -04:00
test . describe ( 'Command bar tests' , ( ) = > {
test ( 'Command bar works and can change a setting' , async ( { page } ) = > {
// Brief boilerplate
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' , { waitUntil : 'domcontentloaded' } )
let cmdSearchBar = page . getByPlaceholder ( 'Search commands' )
// First try opening the command bar and closing it
await page
2024-05-08 09:57:16 -04:00
. getByRole ( 'button' , { name : 'Commands' , exact : false } )
2024-04-02 10:29:34 -04:00
. or ( page . getByRole ( 'button' , { name : '⌘K' } ) )
. click ( )
await expect ( cmdSearchBar ) . toBeVisible ( )
await page . keyboard . press ( 'Escape' )
await expect ( cmdSearchBar ) . not . toBeVisible ( )
// Now try the same, but with the keyboard shortcut, check focus
await page . keyboard . press ( 'Meta+K' )
await expect ( cmdSearchBar ) . toBeVisible ( )
await expect ( cmdSearchBar ) . toBeFocused ( )
// Try typing in the command bar
await page . keyboard . type ( 'theme' )
const themeOption = page . getByRole ( 'option' , {
name : 'Settings · app · theme' ,
} )
await expect ( themeOption ) . toBeVisible ( )
await themeOption . click ( )
const themeInput = page . getByPlaceholder ( 'Select an option' )
await expect ( themeInput ) . toBeVisible ( )
await expect ( themeInput ) . toBeFocused ( )
// Select dark theme
await page . keyboard . press ( 'ArrowDown' )
await page . keyboard . press ( 'ArrowDown' )
2024-05-20 20:52:33 -07:00
await page . keyboard . press ( 'ArrowDown' )
await expect ( page . getByRole ( 'option' , { name : 'system' } ) ) . toHaveAttribute (
'data-headlessui-state' ,
'active'
)
await page . keyboard . press ( 'Enter' )
// Check the toast appeared
await expect (
page . getByText ( ` Set theme to "system" for this project ` )
) . toBeVisible ( )
// Check that the theme changed
await expect ( page . locator ( 'body' ) ) . not . toHaveClass ( ` body-bg dark ` )
} )
test ( 'Command bar keybinding works from code editor and can change a setting' , async ( {
page ,
} ) = > {
// Brief boilerplate
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' , { waitUntil : 'domcontentloaded' } )
let cmdSearchBar = page . getByPlaceholder ( 'Search commands' )
// Put the cursor in the code editor
await page . click ( '.cm-content' )
// Now try the same, but with the keyboard shortcut, check focus
await page . keyboard . press ( 'Meta+K' )
await expect ( cmdSearchBar ) . toBeVisible ( )
await expect ( cmdSearchBar ) . toBeFocused ( )
// Try typing in the command bar
await page . keyboard . type ( 'theme' )
const themeOption = page . getByRole ( 'option' , {
name : 'Settings · app · theme' ,
} )
await expect ( themeOption ) . toBeVisible ( )
await themeOption . click ( )
const themeInput = page . getByPlaceholder ( 'Select an option' )
await expect ( themeInput ) . toBeVisible ( )
await expect ( themeInput ) . toBeFocused ( )
// Select dark theme
await page . keyboard . press ( 'ArrowDown' )
await page . keyboard . press ( 'ArrowDown' )
2024-04-02 10:29:34 -04:00
await page . keyboard . press ( 'ArrowDown' )
await expect ( page . getByRole ( 'option' , { name : 'system' } ) ) . toHaveAttribute (
'data-headlessui-state' ,
'active'
Command bar: add extrude command, nonlinear editing, etc (#1204)
* Tweak toaster look and feel
* Add icons, tweak plus icon names
* Rename commandBarMeta to commandBarConfig
* Refactor command bar, add support for icons
* Create a tailwind plugin for aria-pressed button state
* Remove overlay from behind command bar
* Clean up toolbar
* Button and other style tweaks
* Icon tweaks follow-up: make old icons work with new sizing
* Delete unused static icons
* More CSS tweaks
* Small CSS tweak to project sidebar
* Add command bar E2E test
* fumpt
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* fix typo in a comment
* Fix icon padding (built version only)
* Update onboarding and warning banner icons padding
* Misc minor style fixes
* Get Extrude opening and canceling from command bar
* Iconography tweaks
* Get extrude kind of working
* Refactor command bar config types and organization
* Move command bar configs to be co-located with each other
* Start building a state machine for the command bar
* Start converting command bar to state machine
* Add support for multiple args, confirmation step
* Submission behavior, hotkeys, code organization
* Add new test for extruding from command bar
* Polish step back and selection hotkeys, CSS tweaks
* Loading style tweaks
* Validate selection inputs, polish UX of args re-editing
* Prevent submission with multiple selection on singlular arg
* Remove stray console logs
* Tweak test, CSS nit, remove extrude "result" argument
* Fix linting warnings
* Show Ctrl+/ instead of ⌘K on all platforms but Mac
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* Add "Enter sketch" to command bar
* fix command bar test
* Fix flaky cmd bar extrude test by waiting for engine select response
* Cover both button labels '⌘K' and 'Ctrl+/' in test
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-12-13 12:49:01 -05:00
)
2024-04-02 10:29:34 -04:00
await page . keyboard . press ( 'Enter' )
// Check the toast appeared
await expect (
page . getByText ( ` Set theme to "system" for this project ` )
) . toBeVisible ( )
// Check that the theme changed
await expect ( page . locator ( 'body' ) ) . not . toHaveClass ( ` body-bg dark ` )
Command bar: add extrude command, nonlinear editing, etc (#1204)
* Tweak toaster look and feel
* Add icons, tweak plus icon names
* Rename commandBarMeta to commandBarConfig
* Refactor command bar, add support for icons
* Create a tailwind plugin for aria-pressed button state
* Remove overlay from behind command bar
* Clean up toolbar
* Button and other style tweaks
* Icon tweaks follow-up: make old icons work with new sizing
* Delete unused static icons
* More CSS tweaks
* Small CSS tweak to project sidebar
* Add command bar E2E test
* fumpt
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* fix typo in a comment
* Fix icon padding (built version only)
* Update onboarding and warning banner icons padding
* Misc minor style fixes
* Get Extrude opening and canceling from command bar
* Iconography tweaks
* Get extrude kind of working
* Refactor command bar config types and organization
* Move command bar configs to be co-located with each other
* Start building a state machine for the command bar
* Start converting command bar to state machine
* Add support for multiple args, confirmation step
* Submission behavior, hotkeys, code organization
* Add new test for extruding from command bar
* Polish step back and selection hotkeys, CSS tweaks
* Loading style tweaks
* Validate selection inputs, polish UX of args re-editing
* Prevent submission with multiple selection on singlular arg
* Remove stray console logs
* Tweak test, CSS nit, remove extrude "result" argument
* Fix linting warnings
* Show Ctrl+/ instead of ⌘K on all platforms but Mac
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* Add "Enter sketch" to command bar
* fix command bar test
* Fix flaky cmd bar extrude test by waiting for engine select response
* Cover both button labels '⌘K' and 'Ctrl+/' in test
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-12-13 12:49:01 -05:00
} )
2024-04-11 13:37:49 -04:00
test ( 'Can extrude from the command bar' , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
2024-04-15 12:04:17 -04:00
` const distance = sqrt(20)
2024-06-04 13:57:01 -04:00
const sketch001 = startSketchOn ( 'XZ' )
2024-05-07 20:01:52 -04:00
| > startProfileAt ( [ - 6.95 , 10.98 ] , % )
| > line ( [ 25.1 , 0.41 ] , % )
| > line ( [ 0.73 , - 20.93 ] , % )
| > line ( [ - 23.44 , 0.52 ] , % )
| > close ( % )
`
2024-04-11 13:37:49 -04:00
)
} )
2024-04-02 10:29:34 -04:00
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-02 10:29:34 -04:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
// Make sure the stream is up
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
2024-03-02 03:22:04 +11:00
2024-04-02 10:29:34 -04:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
2024-04-15 12:04:17 -04:00
await u . clearCommandLogs ( )
await page . getByRole ( 'button' , { name : 'Extrude' } ) . isEnabled ( )
2024-04-02 10:29:34 -04:00
let cmdSearchBar = page . getByPlaceholder ( 'Search commands' )
await page . keyboard . press ( 'Meta+K' )
await expect ( cmdSearchBar ) . toBeVisible ( )
// Search for extrude command and choose it
await page . getByRole ( 'option' , { name : 'Extrude' } ) . click ( )
2024-05-07 20:01:52 -04:00
// Assert that we're on the selection step
await expect ( page . getByRole ( 'button' , { name : 'selection' } ) ) . toBeDisabled ( )
// Select a face
await page . mouse . move ( 700 , 200 )
await page . mouse . click ( 700 , 200 )
2024-04-02 10:29:34 -04:00
// Assert that we're on the distance step
await expect ( page . getByRole ( 'button' , { name : 'distance' } ) ) . toBeDisabled ( )
// Assert that the an alternative variable name is chosen,
// since the default variable name is already in use (distance)
await page . getByRole ( 'button' , { name : 'Create new variable' } ) . click ( )
await expect ( page . getByPlaceholder ( 'Variable name' ) ) . toHaveValue (
'distance001'
)
2024-04-15 12:04:17 -04:00
const continueButton = page . getByRole ( 'button' , { name : 'Continue' } )
const submitButton = page . getByRole ( 'button' , { name : 'Submit command' } )
await continueButton . click ( )
2024-04-02 10:29:34 -04:00
// Review step and argument hotkeys
2024-04-15 12:04:17 -04:00
await expect ( submitButton ) . toBeEnabled ( )
2024-04-02 10:29:34 -04:00
await page . keyboard . press ( 'Backspace' )
2024-04-15 12:04:17 -04:00
// Assert we're back on the distance step
2024-04-02 10:29:34 -04:00
await expect (
2024-05-17 10:29:04 -04:00
page . getByRole ( 'button' , { name : 'Distance 5' , exact : false } )
2024-04-02 10:29:34 -04:00
) . toBeDisabled ( )
2024-04-15 12:04:17 -04:00
await continueButton . click ( )
await submitButton . click ( )
2024-04-02 10:29:34 -04:00
// Check that the code was updated
2024-04-15 12:04:17 -04:00
await u . waitForCmdReceive ( 'extrude' )
2024-04-02 10:29:34 -04:00
// Unfortunately this indentation seems to matter for the test
await expect ( page . locator ( '.cm-content' ) ) . toHaveText (
` const distance = sqrt(20)
2024-05-17 10:29:04 -04:00
const distance001 = $ { KCL_DEFAULT_LENGTH }
2024-06-04 13:57:01 -04:00
const sketch001 = startSketchOn ( 'XZ' )
2024-05-07 20:01:52 -04:00
| > startProfileAt ( [ - 6.95 , 10.98 ] , % )
2024-04-02 10:29:34 -04:00
| > line ( [ 25.1 , 0.41 ] , % )
2024-05-07 20:01:52 -04:00
| > line ( [ 0.73 , - 20.93 ] , % )
2024-04-02 10:29:34 -04:00
| > line ( [ - 23.44 , 0.52 ] , % )
| > close ( % )
2024-06-04 13:57:01 -04:00
const extrude001 = extrude ( distance001 , sketch001 ) ` .replace(
/(\r\n|\n|\r)/gm ,
''
) // remove newlines
2024-04-02 10:29:34 -04:00
)
} )
Command bar: add extrude command, nonlinear editing, etc (#1204)
* Tweak toaster look and feel
* Add icons, tweak plus icon names
* Rename commandBarMeta to commandBarConfig
* Refactor command bar, add support for icons
* Create a tailwind plugin for aria-pressed button state
* Remove overlay from behind command bar
* Clean up toolbar
* Button and other style tweaks
* Icon tweaks follow-up: make old icons work with new sizing
* Delete unused static icons
* More CSS tweaks
* Small CSS tweak to project sidebar
* Add command bar E2E test
* fumpt
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* fix typo in a comment
* Fix icon padding (built version only)
* Update onboarding and warning banner icons padding
* Misc minor style fixes
* Get Extrude opening and canceling from command bar
* Iconography tweaks
* Get extrude kind of working
* Refactor command bar config types and organization
* Move command bar configs to be co-located with each other
* Start building a state machine for the command bar
* Start converting command bar to state machine
* Add support for multiple args, confirmation step
* Submission behavior, hotkeys, code organization
* Add new test for extruding from command bar
* Polish step back and selection hotkeys, CSS tweaks
* Loading style tweaks
* Validate selection inputs, polish UX of args re-editing
* Prevent submission with multiple selection on singlular arg
* Remove stray console logs
* Tweak test, CSS nit, remove extrude "result" argument
* Fix linting warnings
* Show Ctrl+/ instead of ⌘K on all platforms but Mac
* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)
* Add "Enter sketch" to command bar
* fix command bar test
* Fix flaky cmd bar extrude test by waiting for engine select response
* Cover both button labels '⌘K' and 'Ctrl+/' in test
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-12-13 12:49:01 -05:00
} )
2024-02-11 12:59:00 +11:00
test ( 'Can add multiple sketches' , async ( { page } ) = > {
2024-04-25 06:09:39 +10:00
test . skip ( process . platform === 'darwin' , 'Can add multiple sketches' )
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-06-04 08:32:24 -04:00
const viewportSize = { width : 1200 , height : 500 }
await page . setViewportSize ( viewportSize )
2024-02-11 12:59:00 +11:00
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
2024-06-04 08:32:24 -04:00
const center = { x : viewportSize.width / 2 , y : viewportSize.height / 2 }
const { toSU , click00r , expectCodeToBe } = getMovementUtils ( { center , page } )
2024-02-26 21:02:33 +11:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
2024-02-11 12:59:00 +11:00
await expect ( page . getByRole ( 'button' , { name : 'Start Sketch' } ) ) . toBeVisible ( )
// click on "Start Sketch" button
await u . clearCommandLogs ( )
await u . doAndWaitForImageDiff (
( ) = > page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( ) ,
200
)
2024-06-04 13:57:01 -04:00
let codeStr = "const sketch001 = startSketchOn('XY')"
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await page . mouse . click ( center . x , viewportSize . height * 0.55 )
await expectCodeToBe ( codeStr )
2024-03-22 10:23:04 +11:00
await u . closeDebugPanel ( )
2024-06-04 08:32:24 -04:00
await page . waitForTimeout ( 500 ) // TODO detect animation ending, or disable animation
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await click00r ( 0 , 0 )
codeStr += ` |> startProfileAt( ${ toSU ( [ 0 , 0 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await click00r ( 50 , 0 )
codeStr += ` |> line( ${ toSU ( [ 50 , 0 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await click00r ( 0 , 50 )
codeStr += ` |> line( ${ toSU ( [ 0 , 50 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await click00r ( - 50 , 0 )
codeStr += ` |> line( ${ toSU ( [ - 50 , 0 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
// exit the sketch, reset relative clicker
click00r ( undefined , undefined )
2024-02-11 12:59:00 +11:00
await u . openAndClearDebugPanel ( )
await page . getByRole ( 'button' , { name : 'Exit Sketch' } ) . click ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 250 )
2024-06-04 08:32:24 -04:00
await u . clearCommandLogs ( )
2024-02-11 12:59:00 +11:00
// start a new sketch
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
2024-06-04 08:32:24 -04:00
// when exiting the sketch above the camera is still looking down at XY,
// so selecting the plane again is a bit easier.
await page . mouse . click ( center . x + 30 , center . y )
2024-02-11 12:59:00 +11:00
await page . waitForTimeout ( 500 ) // TODO detect animation ending, or disable animation
2024-06-04 13:57:01 -04:00
codeStr += "const sketch002 = startSketchOn('XY')"
2024-06-04 08:32:24 -04:00
await expectCodeToBe ( codeStr )
await u . closeDebugPanel ( )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await click00r ( 30 , 0 )
codeStr += ` |> startProfileAt( ${ toSU ( [ 30 , 0 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-04-22 20:14:06 +10:00
2024-06-04 08:32:24 -04:00
await click00r ( 30 , 0 )
codeStr += ` |> line( ${ toSU ( [ 30 - 0.1 /* imprecision */ , 0 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await click00r ( 0 , 30 )
codeStr += ` |> line( ${ toSU ( [ 0 , 30 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
await click00r ( - 30 , 0 )
codeStr += ` |> line( ${ toSU ( [ - 30 + 0.1 , 0 ] ) } , %) `
await expectCodeToBe ( codeStr )
2024-02-11 12:59:00 +11:00
2024-06-04 08:32:24 -04:00
click00r ( undefined , undefined )
await u . openAndClearDebugPanel ( )
await page . getByRole ( 'button' , { name : 'Exit Sketch' } ) . click ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . updateCamPosition ( [ 100 , 100 , 100 ] )
await page . waitForTimeout ( 250 )
await u . clearCommandLogs ( )
2024-02-11 12:59:00 +11:00
} )
2024-02-11 15:08:54 -08:00
2024-04-11 13:37:49 -04:00
test ( 'ProgramMemory can be serialised' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-11 13:37:49 -04:00
await page . addInitScript ( async ( ) = > {
2024-02-11 15:08:54 -08:00
localStorage . setItem (
'persistCode' ,
` const part = startSketchOn('XY')
| > startProfileAt ( [ 0 , 0 ] , % )
| > line ( [ 0 , 1 ] , % )
| > line ( [ 1 , 0 ] , % )
| > line ( [ 0 , - 1 ] , % )
| > close ( % )
| > extrude ( 1 , % )
2024-04-15 17:18:32 -07:00
| > patternLinear3d ( {
2024-02-11 15:08:54 -08:00
axis : [ 1 , 0 , 1 ] ,
repetitions : 3 ,
distance : 6
} , % ) `
)
} )
await page . setViewportSize ( { width : 1000 , height : 500 } )
await page . goto ( '/' )
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 u . waitForAuthSkipAppStart ( )
// 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 )
} )
} )
} )
2024-02-19 17:23:03 +11:00
2024-05-09 15:04:33 +10:00
test ( 'Hovering over 3d features highlights code' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-05-17 10:29:04 -04:00
await page . addInitScript ( async ( KCL_DEFAULT_LENGTH ) = > {
2024-05-09 15:04:33 +10:00
localStorage . setItem (
'persistCode' ,
2024-05-21 23:35:33 -07:00
` const part001 = startSketchOn('XZ')
2024-05-09 15:04:33 +10:00
| > startProfileAt ( [ 20 , 0 ] , % )
| > line ( [ 7.13 , 4 + 0 ] , % )
| > angledLine ( { angle : 3 + 0 , length : 3.14 + 0 } , % )
| > lineTo ( [ 20.14 + 0 , - 0.14 + 0 ] , % )
| > xLineTo ( 29 + 0 , % )
| > yLine ( - 3.14 + 0 , % , 'a' )
| > xLine ( 1.63 , % )
| > angledLineOfXLength ( { angle : 3 + 0 , length : 3.14 } , % )
| > angledLineOfYLength ( { angle : 30 , length : 3 + 0 } , % )
| > angledLineToX ( { angle : 22.14 + 0 , to : 12 } , % )
| > angledLineToY ( { angle : 30 , to : 11.14 } , % )
| > angledLineThatIntersects ( {
angle : 3.14 ,
intersectTag : 'a' ,
offset : 0
} , % )
| > tangentialArcTo ( [ 13.14 + 0 , 13.14 ] , % )
| > close ( % )
2024-05-21 23:35:33 -07:00
| > extrude ( 5 + 7 , % )
2024-05-09 15:04:33 +10:00
`
)
2024-05-17 10:29:04 -04:00
} , KCL_DEFAULT_LENGTH )
2024-05-09 15:04:33 +10:00
await page . setViewportSize ( { width : 1000 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-23 17:05:54 -07:00
await u . openAndClearDebugPanel ( )
await u . sendCustomCmd ( {
type : 'modeling_cmd_req' ,
cmd_id : uuidv4 ( ) ,
cmd : {
type : 'default_camera_look_at' ,
vantage : { x : 0 , y : - 1250 , z : 580 } ,
center : { x : 0 , y : 0 , z : 0 } ,
up : { x : 0 , y : 0 , z : 1 } ,
} ,
} )
await page . waitForTimeout ( 100 )
await u . sendCustomCmd ( {
type : 'modeling_cmd_req' ,
cmd_id : uuidv4 ( ) ,
cmd : {
type : 'default_camera_get_settings' ,
} ,
} )
await page . waitForTimeout ( 100 )
2024-05-09 15:04:33 +10:00
const extrusionTop : Coords2d = [ 800 , 240 ]
const flatExtrusionFace : Coords2d = [ 960 , 160 ]
const arc : Coords2d = [ 840 , 160 ]
const close : Coords2d = [ 720 , 200 ]
const nothing : Coords2d = [ 600 , 200 ]
await page . mouse . move ( nothing [ 0 ] , nothing [ 1 ] )
await page . mouse . click ( nothing [ 0 ] , nothing [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . not . toBeVisible ( )
await page . waitForTimeout ( 200 )
await page . mouse . move ( extrusionTop [ 0 ] , extrusionTop [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . toBeVisible ( )
await page . mouse . move ( nothing [ 0 ] , nothing [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . not . toBeVisible ( )
await page . mouse . move ( arc [ 0 ] , arc [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . toBeVisible ( )
await page . mouse . move ( nothing [ 0 ] , nothing [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . not . toBeVisible ( )
await page . mouse . move ( close [ 0 ] , close [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . toBeVisible ( )
await page . mouse . move ( nothing [ 0 ] , nothing [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . not . toBeVisible ( )
await page . mouse . move ( flatExtrusionFace [ 0 ] , flatExtrusionFace [ 1 ] )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . toHaveCount ( 5 ) // multiple lines
await page . mouse . move ( nothing [ 0 ] , nothing [ 1 ] )
await page . waitForTimeout ( 100 )
await expect ( page . getByTestId ( 'hover-highlight' ) ) . not . toBeVisible ( )
} )
2024-02-20 11:04:42 +11:00
test ( "Various pipe expressions should and shouldn't allow edit and or extrude" , async ( {
page ,
} ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-02-19 17:23:03 +11:00
const selectionsSnippets = {
extrudeAndEditBlocked : '|> startProfileAt([10.81, 32.99], %)' ,
extrudeAndEditBlockedInFunction : '|> startProfileAt(pos, %)' ,
extrudeAndEditAllowed : '|> startProfileAt([15.72, 4.7], %)' ,
editOnly : '|> startProfileAt([15.79, -14.6], %)' ,
}
2024-04-11 13:37:49 -04:00
await page . addInitScript (
2024-02-19 17:23:03 +11:00
async ( {
extrudeAndEditBlocked ,
extrudeAndEditBlockedInFunction ,
extrudeAndEditAllowed ,
editOnly ,
} : any ) = > {
localStorage . setItem (
'persistCode' ,
2024-05-21 23:35:33 -07:00
` const part001 = startSketchOn('XZ')
2024-02-19 17:23:03 +11:00
$ { extrudeAndEditBlocked }
| > line ( [ 25.96 , 2.93 ] , % )
| > line ( [ 5.25 , - 5.72 ] , % )
| > line ( [ - 2.01 , - 10.35 ] , % )
| > line ( [ - 27.65 , - 2.78 ] , % )
| > close ( % )
| > extrude ( 5 , % )
2024-06-04 13:57:01 -04:00
const sketch002 = startSketchOn ( 'XZ' )
2024-02-19 17:23:03 +11:00
$ { extrudeAndEditAllowed }
| > line ( [ 10.32 , 6.47 ] , % )
| > line ( [ 9.71 , - 6.16 ] , % )
| > line ( [ - 3.08 , - 9.86 ] , % )
| > line ( [ - 12.02 , - 1.54 ] , % )
| > close ( % )
2024-06-04 13:57:01 -04:00
const sketch003 = startSketchOn ( 'XZ' )
2024-02-19 17:23:03 +11:00
$ { editOnly }
| > line ( [ 27.55 , - 1.65 ] , % )
| > line ( [ 4.95 , - 8 ] , % )
| > line ( [ - 20.38 , - 10.12 ] , % )
| > line ( [ - 15.79 , 17.08 ] , % )
fn yohey = ( pos ) = > {
2024-06-04 13:57:01 -04:00
const sketch004 = startSketchOn ( 'XZ' )
2024-02-19 17:23:03 +11:00
$ { extrudeAndEditBlockedInFunction }
| > line ( [ 27.55 , - 1.65 ] , % )
| > line ( [ 4.95 , - 10.53 ] , % )
| > line ( [ - 20.38 , - 8 ] , % )
| > line ( [ - 15.79 , 17.08 ] , % )
return ''
}
2024-03-02 03:22:04 +11:00
2024-02-19 17:23:03 +11:00
yohey ( [ 15.79 , - 34.6 ] )
`
)
} ,
selectionsSnippets
)
2024-04-17 20:18:07 -07:00
await page . setViewportSize ( { width : 1200 , height : 1000 } )
2024-02-19 17:23:03 +11:00
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-02-26 21:02:33 +11:00
// wait for start sketch as a proxy for the stream being ready
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
2024-02-19 17:23:03 +11:00
await page . getByText ( selectionsSnippets . extrudeAndEditBlocked ) . click ( )
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . toBeDisabled ( )
await expect (
page . getByRole ( 'button' , { name : 'Edit Sketch' } )
) . not . toBeVisible ( )
await page . getByText ( selectionsSnippets . extrudeAndEditAllowed ) . click ( )
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . not . toBeDisabled ( )
await expect (
page . getByRole ( 'button' , { name : 'Edit Sketch' } )
) . not . toBeDisabled ( )
await page . getByText ( selectionsSnippets . editOnly ) . click ( )
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . toBeDisabled ( )
await expect (
page . getByRole ( 'button' , { name : 'Edit Sketch' } )
) . not . toBeDisabled ( )
await page
. getByText ( selectionsSnippets . extrudeAndEditBlockedInFunction )
. click ( )
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . toBeDisabled ( )
await expect (
page . getByRole ( 'button' , { name : 'Edit Sketch' } )
) . not . toBeVisible ( )
2024-06-04 13:57:01 -04:00
// selecting an editable sketch but clicking "start sketch" should start a new sketch and not edit the existing one
2024-02-19 17:23:03 +11:00
await page . getByText ( selectionsSnippets . extrudeAndEditAllowed ) . click ( )
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
2024-05-23 17:05:54 -07:00
await page . getByTestId ( 'KCL Code' ) . click ( )
2024-05-24 12:32:15 -07:00
await page . mouse . click ( 734 , 134 )
2024-05-23 17:05:54 -07:00
await page . getByTestId ( 'KCL Code' ) . click ( )
2024-06-04 13:57:01 -04:00
// expect main content to contain `sketch005` i.e. started a new sketch
2024-02-19 17:23:03 +11:00
await expect ( page . locator ( '.cm-content' ) ) . toHaveText (
2024-06-04 13:57:01 -04:00
/sketch001 = startSketchOn\('XZ'\)/
2024-02-19 17:23:03 +11:00
)
} )
2024-02-20 11:04:42 +11:00
test ( 'Deselecting line tool should mean nothing happens on click' , async ( {
page ,
} ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-02-20 11:04:42 +11:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
2024-02-26 21:02:33 +11:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
2024-02-20 11:04:42 +11:00
await expect ( page . getByRole ( 'button' , { name : 'Start Sketch' } ) ) . toBeVisible ( )
// click on "Start Sketch" button
await u . clearCommandLogs ( )
await u . doAndWaitForImageDiff (
( ) = > page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( ) ,
200
)
await page . mouse . click ( 700 , 200 )
await expect ( page . locator ( '.cm-content' ) ) . toHaveText (
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XZ') `
2024-02-20 11:04:42 +11:00
)
2024-05-06 19:28:30 +10:00
await page . waitForTimeout ( 600 )
2024-02-20 11:04:42 +11:00
let previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
// deselect the line tool by clicking it
await page . getByRole ( 'button' , { name : 'Line' } ) . click ( )
await page . mouse . click ( 700 , 200 )
await page . waitForTimeout ( 100 )
await page . mouse . click ( 700 , 250 )
await page . waitForTimeout ( 100 )
await page . mouse . click ( 750 , 200 )
await page . waitForTimeout ( 100 )
// expect no change
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( previousCodeContent )
// select line tool again
await page . getByRole ( 'button' , { name : 'Line' } ) . click ( )
await u . closeDebugPanel ( )
// line tool should work as expected again
await page . mouse . click ( 700 , 200 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-02-20 11:04:42 +11:00
await page . mouse . click ( 700 , 300 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-02-20 11:04:42 +11:00
await page . mouse . click ( 750 , 300 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
} )
2024-03-02 20:08:13 +11:00
2024-05-22 13:19:29 -04:00
test ( 'multi-sketch file shows multiple Edit Sketch buttons' , async ( {
page ,
context ,
} ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-05-22 13:19:29 -04:00
const selectionsSnippets = {
startProfileAt1 :
'|> startProfileAt([-width / 4 + screwRadius, height / 2], %)' ,
startProfileAt2 : '|> startProfileAt([-width / 2, 0], %)' ,
startProfileAt3 : '|> startProfileAt([0, thickness], %)' ,
}
await context . addInitScript (
async ( { startProfileAt1 , startProfileAt2 , startProfileAt3 } : any ) = > {
localStorage . setItem (
'persistCode' ,
`
const width = 20
const height = 10
const thickness = 5
const screwRadius = 3
const wireRadius = 2
const wireOffset = 0.5
const screwHole = startSketchOn ( 'XY' )
$ { startProfileAt1 }
| > arc ( {
radius : screwRadius ,
angle_start : 0 ,
angle_end : 360
} , % )
const part001 = startSketchOn ( 'XY' )
$ { startProfileAt2 }
| > xLine ( width * . 5 , % )
| > yLine ( height , % )
| > xLine ( - width * . 5 , % )
| > close ( % )
| > hole ( screwHole , % )
| > extrude ( thickness , % )
const part002 = startSketchOn ( '-XZ' )
$ { startProfileAt3 }
| > xLine ( width / 4 , % )
| > tangentialArcTo ( [ width / 2 , 0 ] , % )
| > xLine ( - width / 4 + wireRadius , % )
| > yLine ( wireOffset , % )
| > arc ( {
radius : wireRadius ,
angle_start : 0 ,
angle_end : 180
} , % )
| > yLine ( - wireOffset , % )
| > xLine ( - width / 4 , % )
| > close ( % )
| > extrude ( - height , % )
`
)
} ,
selectionsSnippets
)
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
await page . getByText ( selectionsSnippets . startProfileAt1 ) . click ( )
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . toBeDisabled ( )
await expect ( page . getByRole ( 'button' , { name : 'Edit Sketch' } ) ) . toBeVisible ( )
await page . getByText ( selectionsSnippets . startProfileAt2 ) . click ( )
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . toBeDisabled ( )
await expect ( page . getByRole ( 'button' , { name : 'Edit Sketch' } ) ) . toBeVisible ( )
await page . getByText ( selectionsSnippets . startProfileAt3 ) . click ( )
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . toBeDisabled ( )
await expect ( page . getByRole ( 'button' , { name : 'Edit Sketch' } ) ) . toBeVisible ( )
} )
2024-04-11 13:37:49 -04:00
test ( 'Can edit segments by dragging their handles' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-11 13:37:49 -04:00
await page . addInitScript ( async ( ) = > {
2024-03-02 20:08:13 +11:00
localStorage . setItem (
'persistCode' ,
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XZ')
2024-03-02 20:08:13 +11:00
| > startProfileAt ( [ 4.61 , - 14.01 ] , % )
| > line ( [ 12.73 , - 0.09 ] , % )
| > tangentialArcTo ( [ 24.95 , - 5.38 ] , % ) `
)
} )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
2024-05-23 17:05:54 -07:00
await page . waitForTimeout ( 100 )
await u . openAndClearDebugPanel ( )
await u . sendCustomCmd ( {
type : 'modeling_cmd_req' ,
cmd_id : uuidv4 ( ) ,
cmd : {
type : 'default_camera_look_at' ,
vantage : { x : 0 , y : - 1250 , z : 580 } ,
center : { x : 0 , y : 0 , z : 0 } ,
up : { x : 0 , y : 0 , z : 1 } ,
} ,
} )
await page . waitForTimeout ( 100 )
await u . sendCustomCmd ( {
type : 'modeling_cmd_req' ,
cmd_id : uuidv4 ( ) ,
cmd : {
type : 'default_camera_get_settings' ,
} ,
} )
await page . waitForTimeout ( 100 )
2024-04-22 20:14:06 +10:00
const startPX = [ 665 , 458 ]
2024-03-02 20:08:13 +11:00
const dragPX = 30
await page . getByText ( 'startProfileAt([4.61, -14.01], %)' ) . click ( )
await expect ( page . getByRole ( 'button' , { name : 'Edit Sketch' } ) ) . toBeVisible ( )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 400 )
2024-03-02 20:08:13 +11:00
let prevContent = await page . locator ( '.cm-content' ) . innerText ( )
const step5 = { steps : 5 }
2024-05-24 20:54:42 +10:00
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 2 )
2024-03-02 20:08:13 +11:00
// drag startProfieAt handle
await page . mouse . move ( startPX [ 0 ] , startPX [ 1 ] )
await page . mouse . down ( )
await page . mouse . move ( startPX [ 0 ] + dragPX , startPX [ 1 ] - dragPX , step5 )
await page . mouse . up ( )
2024-04-22 20:14:06 +10:00
2024-03-02 20:08:13 +11:00
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( prevContent )
prevContent = await page . locator ( '.cm-content' ) . innerText ( )
// drag line handle
2024-05-24 20:54:42 +10:00
await page . waitForTimeout ( 100 )
const lineEnd = await u . getBoundingBox ( '[data-overlay-index="0"]' )
await page . mouse . move ( lineEnd . x - 5 , lineEnd . y )
2024-03-02 20:08:13 +11:00
await page . mouse . down ( )
2024-05-24 20:54:42 +10:00
await page . mouse . move ( lineEnd . x + dragPX , lineEnd . y - dragPX , step5 )
2024-03-02 20:08:13 +11:00
await page . mouse . up ( )
await page . waitForTimeout ( 100 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( prevContent )
prevContent = await page . locator ( '.cm-content' ) . innerText ( )
// drag tangentialArcTo handle
2024-05-24 20:54:42 +10:00
const tangentEnd = await u . getBoundingBox ( '[data-overlay-index="1"]' )
await page . mouse . move ( tangentEnd . x , tangentEnd . y - 5 )
2024-03-02 20:08:13 +11:00
await page . mouse . down ( )
2024-05-24 20:54:42 +10:00
await page . mouse . move ( tangentEnd . x + dragPX , tangentEnd . y - dragPX , step5 )
2024-03-02 20:08:13 +11:00
await page . mouse . up ( )
await page . waitForTimeout ( 100 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( prevContent )
// expect the code to have changed
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-04-22 20:14:06 +10:00
| > startProfileAt ( [ 6.44 , - 12.07 ] , % )
2024-05-24 20:54:42 +10:00
| > line ( [ 14.72 , 1.97 ] , % )
| > tangentialArcTo ( [ 26.92 , - 3.32 ] , % ) ` )
2024-03-02 20:08:13 +11:00
} )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
const doSnapAtDifferentScales = async (
page : any ,
camPos : [ number , number , number ] ,
scale = 1 ,
fudge = 0
) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-03-04 08:14:37 +11:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
2024-06-04 13:57:01 -04:00
const code = ` const sketch001 = startSketchOn('-XZ')
2024-04-18 15:16:08 -07:00
| > startProfileAt ( [ $ { roundOff ( scale * 87.68 ) } , $ { roundOff ( scale * 43.84 ) } ] , % )
| > line ( [ $ { roundOff ( scale * 175.36 ) } , 0 ] , % )
| > line ( [ 0 , - $ { roundOff ( scale * 175.36 ) + fudge } ] , % )
2024-05-23 00:53:15 -04:00
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % )
2024-04-18 15:16:08 -07:00
| > close ( % ) `
2024-03-04 08:14:37 +11:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
await expect ( page . getByRole ( 'button' , { name : 'Start Sketch' } ) ) . toBeVisible ( )
2024-04-18 15:16:08 -07:00
await u . clearCommandLogs ( )
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
await page . waitForTimeout ( 100 )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
await u . openAndClearDebugPanel ( )
await u . updateCamPosition ( camPos )
await u . closeDebugPanel ( )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
// select a plane
await page . mouse . click ( 700 , 200 )
await expect ( page . locator ( '.cm-content' ) ) . toHaveText (
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('-XZ') `
2024-04-18 15:16:08 -07:00
)
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
let prevContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
const pointA = [ 700 , 200 ]
const pointB = [ 900 , 200 ]
const pointC = [ 900 , 400 ]
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
// draw three lines
await page . mouse . click ( pointA [ 0 ] , pointA [ 1 ] )
await page . waitForTimeout ( 100 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( prevContent )
prevContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
await page . mouse . click ( pointB [ 0 ] , pointB [ 1 ] )
await page . waitForTimeout ( 100 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( prevContent )
prevContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
await page . mouse . click ( pointC [ 0 ] , pointC [ 1 ] )
await page . waitForTimeout ( 100 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( prevContent )
prevContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
await page . mouse . move ( pointA [ 0 ] - 12 , pointA [ 1 ] + 12 )
const pointNotQuiteA = [ pointA [ 0 ] - 7 , pointA [ 1 ] + 7 ]
await page . mouse . move ( pointNotQuiteA [ 0 ] , pointNotQuiteA [ 1 ] , { steps : 10 } )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
await page . mouse . click ( pointNotQuiteA [ 0 ] , pointNotQuiteA [ 1 ] )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( prevContent )
prevContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( code )
2024-05-23 00:53:15 -04:00
// Assert the tool was unequipped
await expect ( page . getByRole ( 'button' , { name : 'Line' } ) ) . not . toHaveAttribute (
'aria-pressed' ,
'true'
)
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
// exit sketch
await u . openAndClearDebugPanel ( )
await page . getByRole ( 'button' , { name : 'Exit Sketch' } ) . click ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . removeCurrentCode ( )
}
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
test . describe ( 'Snap to close works (at any scale)' , ( ) = > {
test ( '[0, 100, 100]' , async ( { page } ) = > {
await doSnapAtDifferentScales ( page , [ 0 , 100 , 100 ] , 0.01 , 0.01 )
} )
2024-03-04 08:14:37 +11:00
2024-04-18 15:16:08 -07:00
test ( '[0, 10000, 10000]' , async ( { page } ) = > {
await doSnapAtDifferentScales ( page , [ 0 , 10000 , 10000 ] )
} )
2024-03-04 08:14:37 +11:00
} )
2024-03-22 10:23:04 +11:00
2024-04-11 13:37:49 -04:00
test ( 'Sketch on face' , async ( { page } ) = > {
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-11 13:37:49 -04:00
await page . addInitScript ( async ( ) = > {
2024-03-22 10:23:04 +11:00
localStorage . setItem (
'persistCode' ,
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XZ')
2024-03-22 10:23:04 +11:00
| > startProfileAt ( [ 3.29 , 7.86 ] , % )
| > line ( [ 2.48 , 2.44 ] , % )
| > line ( [ 2.66 , 1.17 ] , % )
| > line ( [ 3.75 , 0.46 ] , % )
| > line ( [ 4.99 , - 0.46 ] , % )
| > line ( [ 3.3 , - 2.12 ] , % )
| > line ( [ 2.16 , - 3.33 ] , % )
| > line ( [ 0.85 , - 3.08 ] , % )
| > line ( [ - 0.18 , - 3.36 ] , % )
| > line ( [ - 3.86 , - 2.73 ] , % )
| > line ( [ - 17.67 , 0.85 ] , % )
| > close ( % )
2024-06-04 13:57:01 -04:00
const extrude001 = extrude ( 5 + 7 , sketch001 ) `
2024-03-22 10:23:04 +11:00
)
} )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-03-22 10:23:04 +11:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( )
await page . getByRole ( 'button' , { name : 'Start Sketch' } ) . click ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 300 )
2024-03-22 10:23:04 +11:00
let previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-04-22 20:14:06 +10:00
await u . openAndClearDebugPanel ( )
await u . doAndWaitForCmd (
2024-05-23 17:05:54 -07:00
( ) = > page . mouse . click ( 625 , 133 ) ,
2024-04-22 20:14:06 +10:00
'default_camera_get_settings' ,
true
)
await page . waitForTimeout ( 150 )
2024-03-22 10:23:04 +11:00
const firstClickPosition = [ 612 , 238 ]
const secondClickPosition = [ 661 , 242 ]
const thirdClickPosition = [ 609 , 267 ]
await page . mouse . click ( firstClickPosition [ 0 ] , firstClickPosition [ 1 ] )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-03-22 10:23:04 +11:00
await page . mouse . click ( secondClickPosition [ 0 ] , secondClickPosition [ 1 ] )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-03-22 10:23:04 +11:00
await page . mouse . click ( thirdClickPosition [ 0 ] , thirdClickPosition [ 1 ] )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-04-22 20:14:06 +10:00
await page . waitForTimeout ( 100 )
2024-03-22 10:23:04 +11:00
await page . mouse . click ( firstClickPosition [ 0 ] , firstClickPosition [ 1 ] )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toContainText ( ` const sketch002 = startSketchOn(extrude001, 'seg01')
2024-05-24 12:32:15 -07:00
| > startProfileAt ( [ - 12.94 , 6.6 ] , % )
| > line ( [ 2.45 , - 0.2 ] , % )
| > line ( [ - 2.6 , - 1.25 ] , % )
2024-05-23 00:53:15 -04:00
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % )
2024-03-22 10:23:04 +11:00
| > close ( % ) ` )
await u . openAndClearDebugPanel ( )
await page . getByRole ( 'button' , { name : 'Exit Sketch' } ) . click ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . updateCamPosition ( [ 1049 , 239 , 686 ] )
await u . closeDebugPanel ( )
2024-05-24 12:32:15 -07:00
await page . getByText ( 'startProfileAt([-12.94, 6.6], %)' ) . click ( )
2024-03-22 10:23:04 +11:00
await expect ( page . getByRole ( 'button' , { name : 'Edit Sketch' } ) ) . toBeVisible ( )
2024-04-22 20:14:06 +10:00
await u . doAndWaitForCmd (
( ) = > page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( ) ,
'default_camera_get_settings' ,
true
)
await page . waitForTimeout ( 150 )
2024-04-03 13:22:56 +11:00
await page . setViewportSize ( { width : 1200 , height : 1200 } )
await u . openAndClearDebugPanel ( )
await u . updateCamPosition ( [ 452 , - 152 , 1166 ] )
await u . closeDebugPanel ( )
2024-03-22 10:23:04 +11:00
await page . waitForTimeout ( 200 )
2024-04-03 13:22:56 +11:00
const pointToDragFirst = [ 787 , 565 ]
2024-03-22 10:23:04 +11:00
await page . mouse . move ( pointToDragFirst [ 0 ] , pointToDragFirst [ 1 ] )
await page . mouse . down ( )
await page . mouse . move ( pointToDragFirst [ 0 ] - 20 , pointToDragFirst [ 1 ] , {
steps : 5 ,
} )
await page . mouse . up ( )
await page . waitForTimeout ( 100 )
await expect ( page . locator ( '.cm-content' ) ) . not . toHaveText ( previousCodeContent )
previousCodeContent = await page . locator ( '.cm-content' ) . innerText ( )
2024-06-04 13:57:01 -04:00
const result = makeTemplate ` const sketch002 = startSketchOn(extrude001, 'seg01')
2024-05-02 15:26:23 +10:00
| > startProfileAt ( [ - 12.83 , 6.7 ] , % )
| > line ( [ $ { [ 2.28 , 2.35 ] } , - $ { 0.07 } ] , % )
| > line ( [ - 3.05 , - 1.47 ] , % )
2024-05-23 00:53:15 -04:00
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % )
2024-05-02 15:26:23 +10:00
| > close ( % ) `
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( result . regExp )
2024-03-22 10:23:04 +11:00
// exit sketch
await u . openAndClearDebugPanel ( )
await page . getByRole ( 'button' , { name : 'Exit Sketch' } ) . click ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
2024-05-24 12:32:15 -07:00
await page . getByText ( 'startProfileAt([-12.94, 6.6], %)' ) . click ( )
2024-03-22 10:23:04 +11:00
await expect ( page . getByRole ( 'button' , { name : 'Extrude' } ) ) . not . toBeDisabled ( )
2024-05-23 17:05:54 -07:00
await page . waitForTimeout ( 100 )
2024-03-22 10:23:04 +11:00
await page . getByRole ( 'button' , { name : 'Extrude' } ) . click ( )
await expect ( page . getByTestId ( 'command-bar' ) ) . toBeVisible ( )
2024-04-04 11:07:51 +11:00
await page . waitForTimeout ( 100 )
2024-03-22 10:23:04 +11:00
await page . keyboard . press ( 'Enter' )
2024-05-23 17:05:54 -07:00
await page . waitForTimeout ( 100 )
2024-03-22 10:23:04 +11:00
await expect ( page . getByText ( 'Confirm Extrude' ) ) . toBeVisible ( )
await page . keyboard . press ( 'Enter' )
2024-05-02 15:26:23 +10:00
const result2 = result . genNext `
2024-06-04 13:57:01 -04:00
const sketch002 = extrude ( $ { [ 5 , 5 ] } + 7 , sketch002 ) `
2024-05-02 15:26:23 +10:00
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( result2 . regExp )
2024-03-22 10:23:04 +11:00
} )
2024-04-18 20:09:40 -07:00
test ( 'Can code mod a line length' , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XY')
2024-04-18 20:09:40 -07:00
| > startProfileAt ( [ - 10 , - 10 ] , % )
| > line ( [ 20 , 0 ] , % )
| > line ( [ 0 , 20 ] , % )
| > xLine ( - 20 , % )
`
)
} )
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-18 20:09:40 -07:00
const PUR = 400 / 37.5 //pixeltoUnitRatio
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
2024-04-18 20:09:40 -07:00
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-23 17:05:54 -07:00
// Click the line of code for line.
await page . getByText ( ` line([0, 20], %) ` ) . click ( ) // TODO remove this and reinstate // await topHorzSegmentClick()
2024-04-18 20:09:40 -07:00
await page . waitForTimeout ( 100 )
// enter sketch again
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
2024-05-23 17:05:54 -07:00
await page . waitForTimeout ( 500 ) // wait for animation
2024-04-18 20:09:40 -07:00
const startXPx = 500
await page . mouse . move ( startXPx + PUR * 15 , 250 - PUR * 10 )
2024-05-23 17:05:54 -07:00
await page . keyboard . down ( 'Shift' )
await page . mouse . click ( 834 , 244 )
await page . keyboard . up ( 'Shift' )
2024-05-10 19:02:11 -04:00
await page . getByRole ( 'button' , { name : 'Constrain' , exact : true } ) . click ( )
2024-04-18 20:09:40 -07:00
await page . getByRole ( 'button' , { name : 'length' , exact : true } ) . click ( )
await page . getByText ( 'Add constraining value' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toHaveText (
2024-06-04 13:57:01 -04:00
` const length001 = 20const sketch001 = startSketchOn('XY') |> startProfileAt([-10, -10], %) |> line([20, 0], %) |> angledLine([90, length001], %) |> xLine(-20, %) `
2024-04-18 20:09:40 -07:00
)
2024-05-23 17:05:54 -07:00
// 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 ( )
2024-04-18 20:09:40 -07:00
} )
2024-04-19 14:24:40 -07:00
test ( 'Extrude from command bar selects extrude line after' , async ( {
page ,
} ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XY')
2024-04-19 14:24:40 -07:00
| > startProfileAt ( [ - 10 , - 10 ] , % )
| > line ( [ 20 , 0 ] , % )
| > line ( [ 0 , 20 ] , % )
| > xLine ( - 20 , % )
| > close ( % )
`
)
} )
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-04-19 14:24:40 -07:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
2024-04-19 14:24:40 -07:00
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
// Click the line of code for xLine.
await page . getByText ( ` close(%) ` ) . click ( ) // TODO remove this and reinstate // await topHorzSegmentClick()
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Extrude' } ) . click ( )
await page . waitForTimeout ( 100 )
await page . keyboard . press ( 'Enter' )
await page . waitForTimeout ( 100 )
await page . keyboard . press ( 'Enter' )
await page . waitForTimeout ( 100 )
await expect ( page . locator ( '.cm-activeLine' ) ) . toHaveText (
2024-06-04 13:57:01 -04:00
` const extrude001 = extrude( ${ KCL_DEFAULT_LENGTH } , sketch001) `
2024-04-19 14:24:40 -07:00
)
} )
2024-05-22 11:07:02 -04:00
2024-05-30 13:28:29 +10:00
test . describe ( 'Testing constraints' , ( ) = > {
2024-06-03 22:40:59 +10:00
test ( ` Test remove constraints ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 79
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % , 'seg01' )
| > line ( [ 78.92 , - 120.11 ] , % )
| > angledLine ( [ segAng ( 'seg01' , % ) , yo ] , % )
| > line ( [ 41.19 , 28.97 + 5 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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(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 : 'Constrain' ,
} )
. click ( )
await page
. getByRole ( 'button' , { name : 'remove constraints' , exact : true } )
. 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 )
} )
test . describe ( 'Test perpendicular distance constraint' , ( ) = > {
const cases = [
{
testName : 'Add variable' ,
offset : '-offset001' ,
} ,
{
testName : 'No variable' ,
offset : '-128.05' ,
} ,
] as const
for ( const { testName , offset } of cases ) {
test ( ` ${ testName } ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 5
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % , 'seg01' )
| > line ( [ 78.92 , - 120.11 ] , % )
| > angledLine ( [ segAng ( 'seg01' , % ) , 78.33 ] , % )
| > line ( [ 41.19 , 28.97 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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 : 'Constrain' ,
} )
. click ( )
await page
. getByRole ( 'button' , { name : 'perpendicular distance' , exact : true } )
. 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 ( )
const activeLinesContent = await page . locator ( '.cm-activeLine' ) . all ( )
await expect ( activeLinesContent [ 0 ] ) . toHaveText (
` |> line([74.36, 130.4], %, 'seg01') `
)
await expect ( activeLinesContent [ 1 ] ) . toHaveText ( ` }, %) ` )
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( ` angle: -57, ` )
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
` offset: ${ offset } , `
)
// 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 )
} )
}
} )
2024-06-03 15:37:23 +10:00
test . describe ( 'Test distance between constraint' , ( ) = > {
const cases = [
{
testName : 'Add variable' ,
constraint : 'horizontal distance' ,
value : "segEndX('seg01', %) + xDis001, 61.34" ,
} ,
{
testName : 'No variable' ,
constraint : 'horizontal distance' ,
value : "segEndX('seg01', %) + 88.08, 61.34" ,
} ,
{
testName : 'Add variable' ,
constraint : 'vertical distance' ,
value : "154.9, segEndY('seg01', %) - yDis001" ,
} ,
{
testName : 'No variable' ,
constraint : 'vertical distance' ,
value : "154.9, segEndY('seg01', %) - 42.32" ,
} ,
] as const
for ( const { testName , value , constraint } of cases ) {
test ( ` ${ constraint } - ${ testName } ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 5
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % )
| > line ( [ 78.92 , - 120.11 ] , % )
| > line ( [ 9.16 , 77.79 ] , % )
| > line ( [ 41.19 , 28.97 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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 : 'Constrain' ,
} )
. click ( )
await page
. getByRole ( 'button' , { name : constraint , exact : true } )
. 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 )
} )
}
} )
2024-05-31 14:00:32 +10:00
test . describe ( 'Test ABS distance constraint' , ( ) = > {
const cases = [
{
testName : 'Add variable' ,
addVariable : true ,
constraint : 'ABS X' ,
value : 'xDis001, 61.34' ,
} ,
{
testName : 'No variable' ,
addVariable : false ,
constraint : 'ABS X' ,
value : '154.9, 61.34' ,
} ,
{
testName : 'Add variable' ,
addVariable : true ,
constraint : 'ABS Y' ,
value : '154.9, yDis001' ,
} ,
{
testName : 'No variable' ,
addVariable : false ,
constraint : 'ABS Y' ,
value : '154.9, 61.34' ,
} ,
] as const
for ( const { testName , addVariable , value , constraint } of cases ) {
test ( ` ${ constraint } - ${ testName } ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 5
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % )
| > line ( [ 78.92 , - 120.11 ] , % )
| > line ( [ 9.16 , 77.79 ] , % )
| > line ( [ 41.19 , 28.97 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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 === 'ABS 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 : 'Constrain' ,
} )
. click ( )
await page
. getByRole ( 'button' , { name : constraint , exact : true } )
. click ( )
const createNewVariableCheckbox = page . getByTestId (
'create-new-variable-checkbox'
)
const isChecked = await createNewVariableCheckbox . isChecked ( )
2024-06-03 15:37:23 +10:00
XOR ( isChecked , addVariable ) && // XOR because no need to click the checkbox if the state is already correct
2024-05-31 14:00:32 +10:00
( 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 )
} )
}
} )
2024-05-31 11:36:08 +10:00
test . describe ( 'Test Angle constraint double segment selection' , ( ) = > {
const cases = [
{
testName : 'Add variable' ,
addVariable : true ,
axisSelect : false ,
value : "segAng('seg01', %) + angle001" ,
} ,
{
testName : 'No variable' ,
addVariable : false ,
axisSelect : false ,
value : "segAng('seg01', %) + 22.69" ,
} ,
{
testName : 'Add variable, selecting axis' ,
addVariable : true ,
axisSelect : true ,
value : 'QUARTER_TURN - angle001' ,
} ,
{
testName : 'No variable, selecting axis' ,
addVariable : false ,
axisSelect : true ,
value : 'QUARTER_TURN - 7' ,
} ,
] as const
for ( const { testName , addVariable , value , axisSelect } of cases ) {
test ( ` ${ testName } ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 5
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % )
| > line ( [ 78.92 , - 120.11 ] , % )
| > line ( [ 9.16 , 77.79 ] , % )
| > line ( [ 41.19 , 28.97 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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 : 'Constrain' ,
} )
. click ( )
await page . getByTestId ( 'angle' ) . click ( )
const createNewVariableCheckbox = page . getByTestId (
'create-new-variable-checkbox'
)
const isChecked = await createNewVariableCheckbox . isChecked ( )
2024-06-03 15:37:23 +10:00
XOR ( isChecked , addVariable ) && // XOR because no need to click the checkbox if the state is already correct
2024-05-31 11:36:08 +10:00
( 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 )
} )
}
} )
2024-06-03 18:30:30 +10:00
test . describe ( 'Test Angle/Length constraint single selection' , ( ) = > {
2024-05-31 11:36:08 +10:00
const cases = [
{
2024-06-03 18:30:30 +10:00
testName : 'Angle - Add variable' ,
2024-05-31 11:36:08 +10:00
addVariable : true ,
2024-06-03 18:30:30 +10:00
constraint : 'angle' ,
value : 'angle001, 78.33' ,
2024-05-31 11:36:08 +10:00
} ,
{
2024-06-03 18:30:30 +10:00
testName : 'Angle - No variable' ,
2024-05-31 11:36:08 +10:00
addVariable : false ,
2024-06-03 18:30:30 +10:00
constraint : 'angle' ,
value : '83, 78.33' ,
} ,
{
testName : 'Length - Add variable' ,
addVariable : true ,
constraint : 'length' ,
value : '83, length001' ,
} ,
{
testName : 'Length - No variable' ,
addVariable : false ,
constraint : 'length' ,
value : '83, 78.33' ,
2024-05-31 11:36:08 +10:00
} ,
] as const
2024-06-03 18:30:30 +10:00
for ( const { testName , addVariable , value , constraint } of cases ) {
2024-05-31 11:36:08 +10:00
test ( ` ${ testName } ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 5
2024-06-03 18:30:30 +10:00
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % )
| > line ( [ 78.92 , - 120.11 ] , % )
| > line ( [ 9.16 , 77.79 ] , % )
| > line ( [ 41.19 , 28.97 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
2024-05-31 11:36:08 +10:00
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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 : 'Constrain' ,
} )
. click ( )
2024-06-03 18:30:30 +10:00
await page . getByTestId ( constraint ) . click ( )
2024-05-31 11:36:08 +10:00
if ( ! addVariable ) {
await page . getByTestId ( 'create-new-variable-checkbox' ) . click ( )
}
await page
. getByRole ( 'button' , { name : 'Add constraining value' } )
. click ( )
2024-06-03 18:30:30 +10:00
const changedCode = ` |> angledLine([ ${ value } ], %) `
2024-05-31 11:36:08 +10:00
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 )
} )
}
} )
2024-05-30 19:43:35 +10:00
test . describe ( 'Many segments - no modal constraints' , ( ) = > {
const cases = [
{
constraintName : 'Vertical' ,
codeAfter : [
` |> yLine(130.4, %) ` ,
` |> yLine(77.79, %) ` ,
` |> yLine(28.97, %) ` ,
] ,
} ,
{
codeAfter : [
` |> xLine(74.36, %) ` ,
` |> xLine(9.16, %) ` ,
` |> xLine(41.19, %) ` ,
] ,
constraintName : 'Horizontal' ,
} ,
] as const
for ( const { codeAfter , constraintName } of cases ) {
test ( ` ${ constraintName } ` , async ( { page } ) = > {
2024-06-03 22:40:59 +10:00
await page . addInitScript ( async ( customCode ) = > {
2024-05-30 19:43:35 +10:00
localStorage . setItem (
'persistCode' ,
` const yo = 5
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % )
| > line ( [ 78.92 , - 120.11 ] , % )
| > line ( [ 9.16 , 77.79 ] , % )
| > line ( [ 41.19 , 28.97 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await page . getByText ( 'line([74.36, 130.4], %)' ) . click ( )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
2024-06-03 22:40:59 +10:00
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 } "] `
)
2024-05-30 19:43:35 +10:00
// select two segments by holding down shift
2024-06-03 22:40:59 +10:00
await page . mouse . click ( line1 . x , line1 . y )
2024-05-30 19:43:35 +10:00
await page . keyboard . down ( 'Shift' )
2024-06-03 22:40:59 +10:00
await page . mouse . click ( line3 . x , line3 . y )
await page . mouse . click ( line4 . x , line4 . y )
2024-05-30 19:43:35 +10:00
await page . keyboard . up ( 'Shift' )
const constraintMenuButton = page . getByRole ( 'button' , {
name : 'Constrain' ,
} )
const constraintButton = page
. getByRole ( 'button' , {
name : constraintName ,
} )
. first ( )
// apply the constraint
await constraintMenuButton . click ( )
await constraintButton . click ( )
// check actives lines
const activeLinesContent = await page . locator ( '.cm-activeLine' ) . all ( )
await expect ( activeLinesContent ) . toHaveLength ( codeAfter . length )
// 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 ] )
} )
)
} )
}
} )
2024-05-30 13:28:29 +10:00
test . describe ( 'Two segment - no modal constraints' , ( ) = > {
const cases = [
{
codeAfter : ` |> angledLine([83, segLen('seg01', %)], %) ` ,
constraintName : 'Equal Length' ,
} ,
{
codeAfter : ` |> angledLine([segAng('seg01', %), 78.33], %) ` ,
constraintName : 'Parallel' ,
} ,
{
codeAfter : ` |> lineTo([segEndX('seg01', %), 61.34], %) ` ,
constraintName : 'Vertically Align' ,
} ,
{
codeAfter : ` |> lineTo([154.9, segEndY('seg01', %)], %) ` ,
constraintName : 'Horizontally Align' ,
} ,
] as const
for ( const { codeAfter , constraintName } of cases ) {
test ( ` ${ constraintName } ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 5
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % )
| > line ( [ 78.92 , - 120.11 ] , % )
| > line ( [ 9.16 , 77.79 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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 : 'Constrain' ,
} )
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' , ( ) = > {
const cases = [
{
codeAfter : ` |> lineTo([154.9, ZERO], %) ` ,
axisClick : { x : 950 , y : 250 } ,
constraintName : 'Snap To X' ,
} ,
{
codeAfter : ` |> lineTo([ZERO, 61.34], %) ` ,
axisClick : { x : 600 , y : 150 } ,
constraintName : 'Snap To Y' ,
} ,
] as const
for ( const { codeAfter , constraintName , axisClick } of cases ) {
test ( ` ${ constraintName } ` , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yo = 5
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ - 7.54 , - 26.74 ] , % )
| > line ( [ 74.36 , 130.4 ] , % )
| > line ( [ 78.92 , - 120.11 ] , % )
| > line ( [ 9.16 , 77.79 ] , % )
const part002 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 299.05 , 231.45 ] , % )
| > xLine ( - 425.34 , % , 'seg-what' )
| > yLine ( - 264.06 , % )
| > xLine ( segLen ( 'seg-what' , % ) , % )
| > lineTo ( [ profileStartX ( % ) , profileStartY ( % ) ] , % ) `
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
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 : 'Constrain' ,
} )
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 )
} )
}
} )
} )
2024-05-24 20:54:42 +10:00
test . describe ( 'Testing segment overlays' , ( ) = > {
test . describe ( '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' , ( ) = > {
/ * *
* Clicks on an constrained element
* @param { Page } page - The page to perform the action on
* @param { Object } options - The options for the action
* @param { Object } options . hoverPos - The position to hover over
* @param { Object } options . constraintType - The type of constraint
* @param { number } options . ang - The angle
* @param { number } options . steps - The number of steps to perform
* /
const _clickConstrained =
( page : Page ) = >
async ( {
hoverPos ,
constraintType ,
expectBeforeUnconstrained ,
expectAfterUnconstrained ,
expectFinal ,
ang = 45 ,
2024-06-04 08:32:24 -04:00
steps = 10 ,
2024-05-24 20:54:42 +10:00
} : {
hoverPos : { x : number ; y : number }
constraintType :
| 'horizontal'
| 'vertical'
| 'tangentialWithPrevious'
| LineInputsType
expectBeforeUnconstrained : string
expectAfterUnconstrained : string
expectFinal : string
ang? : number
steps? : number
} ) = > {
await expect ( page . getByText ( 'Added variable' ) ) . not . toBeVisible ( )
2024-06-04 08:32:24 -04:00
await page . mouse . move ( 0 , 0 )
await page . waitForTimeout ( 1000 )
let x = 0 ,
y = 0
x = hoverPos . x + Math . cos ( ang * deg ) * 32
y = hoverPos . y - Math . sin ( ang * deg ) * 32
await page . mouse . move ( x , y )
await wiggleMove ( page , x , y , 20 , 30 , ang , 10 , 5 )
2024-05-24 20:54:42 +10:00
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
expectBeforeUnconstrained
)
const constrainedLocator = page . locator (
` [data-constraint-type=" ${ constraintType } "][data-is-constrained="true"] `
)
await expect ( constrainedLocator ) . toBeVisible ( )
await constrainedLocator . hover ( )
await expect (
await page . getByTestId ( 'constraint-symbol-popover' ) . count ( )
) . toBeGreaterThan ( 0 )
await constrainedLocator . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
expectAfterUnconstrained
)
2024-06-04 08:32:24 -04:00
await page . mouse . move ( 0 , 0 )
await page . waitForTimeout ( 1000 )
x = hoverPos . x + Math . cos ( ang * deg ) * 32
y = hoverPos . y - Math . sin ( ang * deg ) * 32
await page . mouse . move ( x , y )
await wiggleMove ( page , x , y , 20 , 30 , ang , 10 , 5 )
2024-05-24 20:54:42 +10:00
const unconstrainedLocator = page . locator (
` [data-constraint-type=" ${ constraintType } "][data-is-constrained="false"] `
)
await expect ( unconstrainedLocator ) . toBeVisible ( )
await unconstrainedLocator . hover ( )
await expect (
await page . getByTestId ( 'constraint-symbol-popover' ) . count ( )
) . toBeGreaterThan ( 0 )
await unconstrainedLocator . click ( )
await page . getByText ( 'Add variable' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( expectFinal )
}
/ * *
* Clicks on an unconstrained element
* @param { Page } page - The page to perform the action on
* @param { Object } options - The options for the action
* @param { Object } options . hoverPos - The position to hover over
* @param { Object } options . constraintType - The type of constraint
* @param { number } options . ang - The angle
* @param { number } options . steps - The number of steps to perform
* /
const _clickUnconstrained =
( page : Page ) = >
async ( {
hoverPos ,
constraintType ,
expectBeforeUnconstrained ,
expectAfterUnconstrained ,
expectFinal ,
ang = 45 ,
steps = 5 ,
} : {
hoverPos : { x : number ; y : number }
constraintType :
| 'horizontal'
| 'vertical'
| 'tangentialWithPrevious'
| LineInputsType
expectBeforeUnconstrained : string
expectAfterUnconstrained : string
expectFinal : string
ang? : number
steps? : number
} ) = > {
2024-06-04 08:32:24 -04:00
await page . mouse . move ( 0 , 0 )
await page . waitForTimeout ( 1000 )
let x = 0 ,
y = 0
x = hoverPos . x + Math . cos ( ang * deg ) * 32
y = hoverPos . y - Math . sin ( ang * deg ) * 32
await page . mouse . move ( x , y )
await wiggleMove ( page , x , y , 20 , 30 , ang , 10 , 5 )
2024-05-24 20:54:42 +10:00
await expect ( page . getByText ( 'Added variable' ) ) . not . toBeVisible ( )
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
expectBeforeUnconstrained
)
const unconstrainedLocator = page . locator (
` [data-constraint-type=" ${ constraintType } "][data-is-constrained="false"] `
)
await expect ( unconstrainedLocator ) . toBeVisible ( )
await unconstrainedLocator . hover ( )
await expect (
await page . getByTestId ( 'constraint-symbol-popover' ) . count ( )
) . toBeGreaterThan ( 0 )
await unconstrainedLocator . click ( )
await page . getByText ( 'Add variable' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
expectAfterUnconstrained
)
await expect ( page . getByText ( 'Added variable' ) ) . not . toBeVisible ( )
2024-06-04 08:32:24 -04:00
await page . mouse . move ( 0 , 0 )
await page . waitForTimeout ( 1000 )
x = hoverPos . x + Math . cos ( ang * deg ) * 32
y = hoverPos . y - Math . sin ( ang * deg ) * 32
await page . mouse . move ( x , y )
await wiggleMove ( page , x , y , 20 , 30 , ang , 10 , 5 )
2024-05-24 20:54:42 +10:00
const constrainedLocator = page . locator (
` [data-constraint-type=" ${ constraintType } "][data-is-constrained="true"] `
)
await expect ( constrainedLocator ) . toBeVisible ( )
await constrainedLocator . hover ( )
await expect (
await page . getByTestId ( 'constraint-symbol-popover' ) . count ( )
) . toBeGreaterThan ( 0 )
await constrainedLocator . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( expectFinal )
}
2024-06-04 08:32:24 -04:00
test . setTimeout ( 120000 )
2024-05-24 20:54:42 +10:00
test ( 'for segments [line, angledLine, lineTo, xLineTo]' , async ( {
page ,
} ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const part001 = startSketchOn('XZ')
2024-06-04 08:32:24 -04:00
| > startProfileAt ( [ 5 + 0 , 20 + 0 ] , % )
2024-05-24 20:54:42 +10:00
| > line ( [ 0.5 , - 14 + 0 ] , % )
| > angledLine ( { angle : 3 + 0 , length : 32 + 0 } , % )
2024-06-04 08:32:24 -04:00
| > lineTo ( [ 5 + 33 , 20 + 11.5 + 0 ] , % )
| > xLineTo ( 5 + 9 - 5 , % )
| > yLineTo ( 20 + - 10.77 , % , 'a' )
2024-05-24 20:54:42 +10:00
| > xLine ( 26.04 , % )
| > yLine ( 21.14 + 0 , % )
| > angledLineOfXLength ( { angle : 181 + 0 , length : 23.14 } , % )
| > angledLineOfYLength ( { angle : - 91 , length : 19 + 0 } , % )
2024-06-04 08:32:24 -04:00
| > angledLineToX ( { angle : 3 + 0 , to : 5 + 26 } , % )
| > angledLineToY ( { angle : 89 , to : 20 + 9.14 + 0 } , % )
2024-05-24 20:54:42 +10:00
| > angledLineThatIntersects ( {
angle : 4.14 ,
intersectTag : 'a' ,
offset : 9
} , % )
2024-06-04 08:32:24 -04:00
| > tangentialArcTo ( [ 5 + 3.14 + 13 , 20 + 3.14 ] , % )
2024-05-24 20:54:42 +10:00
`
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-24 20:54:42 +10:00
await u . openAndClearDebugPanel ( )
await u . sendCustomCmd ( {
type : 'modeling_cmd_req' ,
cmd_id : uuidv4 ( ) ,
cmd : {
type : 'default_camera_look_at' ,
vantage : { x : 0 , y : - 1250 , z : 580 } ,
center : { x : 0 , y : 0 , z : 0 } ,
up : { x : 0 , y : 0 , z : 1 } ,
} ,
} )
await page . waitForTimeout ( 100 )
await u . sendCustomCmd ( {
type : 'modeling_cmd_req' ,
cmd_id : uuidv4 ( ) ,
cmd : {
type : 'default_camera_get_settings' ,
} ,
} )
await page . waitForTimeout ( 100 )
2024-06-04 08:32:24 -04:00
await u . closeDebugPanel ( )
2024-05-24 20:54:42 +10:00
2024-06-04 08:32:24 -04:00
await page . getByText ( 'xLineTo(5 + 9 - 5, %)' ) . click ( )
2024-05-24 20:54:42 +10:00
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 13 )
const clickUnconstrained = _clickUnconstrained ( page )
const clickConstrained = _clickConstrained ( page )
2024-06-04 08:32:24 -04:00
// Drag the sketch into view
await page . mouse . move ( 600 , 64 )
await page . mouse . down ( { button : 'middle' } )
await page . mouse . move ( 600 , 450 , { steps : 10 } )
await page . mouse . up ( { button : 'middle' } )
await page . mouse . move ( 600 , 64 )
await page . mouse . down ( { button : 'middle' } )
await page . mouse . move ( 600 , 120 , { steps : 10 } )
await page . mouse . up ( { button : 'middle' } )
let ang = 0
2024-05-24 20:54:42 +10:00
const line = await u . getBoundingBox ( ` [data-overlay-index=" ${ 0 } "] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index=" ${ 0 } "] ` )
console . log ( 'line1' , line , ang )
2024-05-24 20:54:42 +10:00
await clickConstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : line.x , y : line.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'yRelative' ,
expectBeforeUnconstrained : '|> line([0.5, -14 + 0], %)' ,
expectAfterUnconstrained : '|> line([0.5, -14], %)' ,
expectFinal : '|> line([0.5, yRel001], %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
console . log ( 'line2' )
await clickUnconstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : line.x , y : line.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'xRelative' ,
expectBeforeUnconstrained : '|> line([0.5, yRel001], %)' ,
expectAfterUnconstrained : 'line([xRel001, yRel001], %)' ,
expectFinal : '|> line([0.5, yRel001], %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
const angledLine = await u . getBoundingBox ( ` [data-overlay-index="1"] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="1"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'angledLine1' )
await clickConstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : angledLine.x , y : angledLine.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'angle' ,
expectBeforeUnconstrained :
'angledLine({ angle: 3 + 0, length: 32 + 0 }, %)' ,
expectAfterUnconstrained : 'angledLine({ angle: 3, length: 32 + 0 }, %)' ,
expectFinal : 'angledLine({ angle: angle001, length: 32 + 0 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
console . log ( 'angledLine2' )
await clickConstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : angledLine.x , y : angledLine.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'length' ,
expectBeforeUnconstrained :
'angledLine({ angle: angle001, length: 32 + 0 }, %)' ,
expectAfterUnconstrained :
'angledLine({ angle: angle001, length: 32 }, %)' ,
expectFinal : 'angledLine({ angle: angle001, length: len001 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
await page . mouse . move ( 700 , 250 )
for ( let i = 0 ; i < 5 ; i ++ ) {
await page . mouse . wheel ( 0 , 100 )
await page . waitForTimeout ( 25 )
}
await page . waitForTimeout ( 200 )
2024-06-04 08:32:24 -04:00
let lineTo = await u . getBoundingBox ( ` [data-overlay-index="2"] ` )
ang = await u . getAngle ( ` [data-overlay-index="2"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'lineTo1' )
await clickConstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : lineTo.x , y : lineTo.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'yAbsolute' ,
2024-06-04 08:32:24 -04:00
expectBeforeUnconstrained : 'lineTo([5 + 33, 20 + 11.5 + 0], %)' ,
expectAfterUnconstrained : 'lineTo([5 + 33, 31.5], %)' ,
expectFinal : 'lineTo([5 + 33, yAbs001], %)' ,
2024-05-24 20:54:42 +10:00
steps : 8 ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
console . log ( 'lineTo2' )
2024-06-04 08:32:24 -04:00
await clickConstrained ( {
hoverPos : { x : lineTo.x , y : lineTo.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'xAbsolute' ,
2024-06-04 08:32:24 -04:00
expectBeforeUnconstrained : 'lineTo([5 + 33, yAbs001], %)' ,
expectAfterUnconstrained : 'lineTo([38, yAbs001], %)' ,
expectFinal : 'lineTo([xAbs001, yAbs001], %)' ,
2024-05-24 20:54:42 +10:00
steps : 8 ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
const xLineTo = await u . getBoundingBox ( ` [data-overlay-index="3"] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="3"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'xlineTo1' )
await clickConstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : xLineTo.x , y : xLineTo.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'xAbsolute' ,
2024-06-04 08:32:24 -04:00
expectBeforeUnconstrained : 'xLineTo(5 + 9 - 5, %)' ,
expectAfterUnconstrained : 'xLineTo(9, %)' ,
2024-05-24 20:54:42 +10:00
expectFinal : 'xLineTo(xAbs002, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
steps : 8 ,
} )
} )
test ( 'for segments [yLineTo, xLine]' , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const yRel001 = -14
const xRel001 = 0.5
const angle001 = 3
const len001 = 32
const yAbs001 = 11.5
const xAbs001 = 33
const xAbs002 = 4
const part001 = startSketchOn ( 'XZ' )
| > startProfileAt ( [ 0 , 0 ] , % )
| > line ( [ 0.5 , yRel001 ] , % )
| > angledLine ( { angle : angle001 , length : len001 } , % )
| > lineTo ( [ 33 , yAbs001 ] , % )
| > xLineTo ( xAbs002 , % )
| > yLineTo ( - 10.77 , % , 'a' )
| > xLine ( 26.04 , % )
| > yLine ( 21.14 + 0 , % )
| > angledLineOfXLength ( { angle : 181 + 0 , length : 23.14 } , % )
`
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-24 20:54:42 +10:00
await page . getByText ( 'xLine(26.04, %)' ) . click ( )
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 8 )
const clickUnconstrained = _clickUnconstrained ( page )
await page . mouse . move ( 700 , 250 )
for ( let i = 0 ; i < 7 ; i ++ ) {
await page . mouse . wheel ( 0 , 100 )
await page . waitForTimeout ( 25 )
}
await page . waitForTimeout ( 300 )
2024-06-04 08:32:24 -04:00
let ang = 0
2024-05-24 20:54:42 +10:00
const yLineTo = await u . getBoundingBox ( ` [data-overlay-index="4"] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="4"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'ylineTo1' )
await clickUnconstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : yLineTo.x , y : yLineTo.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'yAbsolute' ,
expectBeforeUnconstrained : "yLineTo(-10.77, %, 'a')" ,
expectAfterUnconstrained : "yLineTo(yAbs002, %, 'a')" ,
expectFinal : "yLineTo(-10.77, %, 'a')" ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
const xLine = await u . getBoundingBox ( ` [data-overlay-index="5"] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="5"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'xline' )
await clickUnconstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : xLine.x , y : xLine.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'xRelative' ,
expectBeforeUnconstrained : 'xLine(26.04, %)' ,
expectAfterUnconstrained : 'xLine(xRel002, %)' ,
expectFinal : 'xLine(26.04, %)' ,
steps : 10 ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
} )
test ( 'for segments [yLine, angledLineOfXLength, angledLineOfYLength]' , async ( {
page ,
} ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const part001 = startSketchOn('XZ')
| > startProfileAt ( [ 0 , 0 ] , % )
| > line ( [ 0.5 , - 14 + 0 ] , % )
| > angledLine ( { angle : 3 + 0 , length : 32 + 0 } , % )
| > lineTo ( [ 33 , 11.5 + 0 ] , % )
| > xLineTo ( 9 - 5 , % )
| > yLineTo ( - 10.77 , % , 'a' )
| > xLine ( 26.04 , % )
| > yLine ( 21.14 + 0 , % )
| > angledLineOfXLength ( { angle : 181 + 0 , length : 23.14 } , % )
| > angledLineOfYLength ( { angle : - 91 , length : 19 + 0 } , % )
| > angledLineToX ( { angle : 3 + 0 , to : 26 } , % )
| > angledLineToY ( { angle : 89 , to : 9.14 + 0 } , % )
| > angledLineThatIntersects ( {
angle : 4.14 ,
intersectTag : 'a' ,
offset : 9
} , % )
| > tangentialArcTo ( [ 3.14 + 13 , 3.14 ] , % )
`
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-06-04 08:32:24 -04:00
await page . waitForTimeout ( 500 )
2024-05-24 12:32:15 -07:00
2024-05-24 20:54:42 +10:00
await page . getByText ( 'xLineTo(9 - 5, %)' ) . click ( )
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 13 )
const clickUnconstrained = _clickUnconstrained ( page )
const clickConstrained = _clickConstrained ( page )
2024-06-04 08:32:24 -04:00
let ang = 0
2024-05-24 20:54:42 +10:00
const yLine = await u . getBoundingBox ( ` [data-overlay-index="6"] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="6"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'yline1' )
await clickConstrained ( {
hoverPos : { x : yLine.x , y : yLine.y + 20 } ,
constraintType : 'yRelative' ,
expectBeforeUnconstrained : 'yLine(21.14 + 0, %)' ,
expectAfterUnconstrained : 'yLine(21.14, %)' ,
expectFinal : 'yLine(yRel001, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
const angledLineOfXLength = await u . getBoundingBox (
` [data-overlay-index="7"] `
)
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="7"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'angledLineOfXLength1' )
await clickConstrained ( {
hoverPos : { x : angledLineOfXLength.x + 20 , y : angledLineOfXLength.y } ,
constraintType : 'angle' ,
expectBeforeUnconstrained :
'angledLineOfXLength({ angle: 181 + 0, length: 23.14 }, %)' ,
expectAfterUnconstrained :
'angledLineOfXLength({ angle: -179, length: 23.14 }, %)' ,
expectFinal :
'angledLineOfXLength({ angle: angle001, length: 23.14 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
console . log ( 'angledLineOfXLength2' )
await clickUnconstrained ( {
hoverPos : { x : angledLineOfXLength.x + 25 , y : angledLineOfXLength.y } ,
constraintType : 'xRelative' ,
expectBeforeUnconstrained :
'angledLineOfXLength({ angle: angle001, length: 23.14 }, %)' ,
expectAfterUnconstrained :
'angledLineOfXLength({ angle: angle001, length: xRel001 }, %)' ,
expectFinal :
'angledLineOfXLength({ angle: angle001, length: 23.14 }, %)' ,
steps : 7 ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
const angledLineOfYLength = await u . getBoundingBox (
` [data-overlay-index="8"] `
)
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="8"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'angledLineOfYLength1' )
await clickUnconstrained ( {
hoverPos : { x : angledLineOfYLength.x , y : angledLineOfYLength.y - 20 } ,
constraintType : 'angle' ,
expectBeforeUnconstrained :
'angledLineOfYLength({ angle: -91, length: 19 + 0 }, %)' ,
expectAfterUnconstrained :
'angledLineOfYLength({ angle: angle002, length: 19 + 0 }, %)' ,
expectFinal : 'angledLineOfYLength({ angle: -91, length: 19 + 0 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
steps : 6 ,
} )
console . log ( 'angledLineOfYLength2' )
await clickConstrained ( {
hoverPos : { x : angledLineOfYLength.x , y : angledLineOfYLength.y - 20 } ,
constraintType : 'yRelative' ,
expectBeforeUnconstrained :
'angledLineOfYLength({ angle: -91, length: 19 + 0 }, %)' ,
expectAfterUnconstrained :
'angledLineOfYLength({ angle: -91, length: 19 }, %)' ,
expectFinal : 'angledLineOfYLength({ angle: -91, length: yRel002 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
steps : 7 ,
} )
} )
test ( 'for segments [angledLineToX, angledLineToY, angledLineThatIntersects]' , async ( {
page ,
} ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const part001 = startSketchOn('XZ')
| > startProfileAt ( [ 0 , 0 ] , % )
| > line ( [ 0.5 , - 14 + 0 ] , % )
| > angledLine ( { angle : 3 + 0 , length : 32 + 0 } , % )
| > lineTo ( [ 33 , 11.5 + 0 ] , % )
| > xLineTo ( 9 - 5 , % )
| > yLineTo ( - 10.77 , % , 'a' )
| > xLine ( 26.04 , % )
| > yLine ( 21.14 + 0 , % )
| > angledLineOfXLength ( { angle : 181 + 0 , length : 23.14 } , % )
| > angledLineOfYLength ( { angle : - 91 , length : 19 + 0 } , % )
| > angledLineToX ( { angle : 3 + 0 , to : 26 } , % )
| > angledLineToY ( { angle : 89 , to : 9.14 + 0 } , % )
| > angledLineThatIntersects ( {
angle : 4.14 ,
intersectTag : 'a' ,
offset : 9
} , % )
| > tangentialArcTo ( [ 3.14 + 13 , 1.14 ] , % )
`
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-24 20:54:42 +10:00
await page . getByText ( 'xLineTo(9 - 5, %)' ) . click ( )
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 13 )
const clickUnconstrained = _clickUnconstrained ( page )
const clickConstrained = _clickConstrained ( page )
2024-06-04 08:32:24 -04:00
let ang = 0
2024-05-24 20:54:42 +10:00
const angledLineToX = await u . getBoundingBox ( ` [data-overlay-index="9"] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="9"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'angledLineToX' )
await clickConstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : angledLineToX.x , y : angledLineToX.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'angle' ,
expectBeforeUnconstrained : 'angledLineToX({ angle: 3 + 0, to: 26 }, %)' ,
expectAfterUnconstrained : 'angledLineToX({ angle: 3, to: 26 }, %)' ,
expectFinal : 'angledLineToX({ angle: angle001, to: 26 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
console . log ( 'angledLineToX2' )
await clickUnconstrained ( {
hoverPos : { x : angledLineToX.x - 20 , y : angledLineToX.y } ,
constraintType : 'xAbsolute' ,
expectBeforeUnconstrained :
'angledLineToX({ angle: angle001, to: 26 }, %)' ,
expectAfterUnconstrained :
'angledLineToX({ angle: angle001, to: xAbs001 }, %)' ,
expectFinal : 'angledLineToX({ angle: angle001, to: 26 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
const angledLineToY = await u . getBoundingBox ( ` [data-overlay-index="10"] ` )
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="10"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'angledLineToY' )
await clickUnconstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : angledLineToY.x , y : angledLineToY.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'angle' ,
expectBeforeUnconstrained :
'angledLineToY({ angle: 89, to: 9.14 + 0 }, %)' ,
expectAfterUnconstrained :
'angledLineToY({ angle: angle002, to: 9.14 + 0 }, %)' ,
expectFinal : 'angledLineToY({ angle: 89, to: 9.14 + 0 }, %)' ,
steps : process.platform === 'darwin' ? 8 : 9 ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
console . log ( 'angledLineToY2' )
await clickConstrained ( {
hoverPos : { x : angledLineToY.x , y : angledLineToY.y + 20 } ,
constraintType : 'yAbsolute' ,
expectBeforeUnconstrained :
'angledLineToY({ angle: 89, to: 9.14 + 0 }, %)' ,
expectAfterUnconstrained : 'angledLineToY({ angle: 89, to: 9.14 }, %)' ,
expectFinal : 'angledLineToY({ angle: 89, to: yAbs001 }, %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
const angledLineThatIntersects = await u . getBoundingBox (
` [data-overlay-index="11"] `
)
2024-06-04 08:32:24 -04:00
ang = await u . getAngle ( ` [data-overlay-index="11"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'angledLineThatIntersects' )
await clickUnconstrained ( {
hoverPos : {
x : angledLineThatIntersects.x + 20 ,
y : angledLineThatIntersects.y ,
} ,
constraintType : 'angle' ,
expectBeforeUnconstrained : ` angledLineThatIntersects({
angle : 4.14 ,
intersectTag : 'a' ,
offset : 9
} , % ) ` ,
expectAfterUnconstrained : ` angledLineThatIntersects({
angle : angle003 ,
intersectTag : 'a' ,
offset : 9
} , % ) ` ,
expectFinal : ` angledLineThatIntersects({
angle : - 176 ,
offset : 9 ,
intersectTag : 'a'
} , % ) ` ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
console . log ( 'angledLineThatIntersects2' )
await clickUnconstrained ( {
hoverPos : {
x : angledLineThatIntersects.x + 20 ,
y : angledLineThatIntersects.y ,
} ,
constraintType : 'intersectionOffset' ,
expectBeforeUnconstrained : ` angledLineThatIntersects({
angle : - 176 ,
offset : 9 ,
intersectTag : 'a'
} , % ) ` ,
expectAfterUnconstrained : ` angledLineThatIntersects({
angle : - 176 ,
offset : perpDist001 ,
intersectTag : 'a'
} , % ) ` ,
expectFinal : ` angledLineThatIntersects({
angle : - 176 ,
offset : 9 ,
intersectTag : 'a'
} , % ) ` ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
} )
} )
test ( 'for segment [tangentialArcTo]' , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const part001 = startSketchOn('XZ')
| > startProfileAt ( [ 0 , 0 ] , % )
| > line ( [ 0.5 , - 14 + 0 ] , % )
| > angledLine ( { angle : 3 + 0 , length : 32 + 0 } , % )
| > lineTo ( [ 33 , 11.5 + 0 ] , % )
| > xLineTo ( 9 - 5 , % )
| > yLineTo ( - 10.77 , % , 'a' )
| > xLine ( 26.04 , % )
| > yLine ( 21.14 + 0 , % )
| > angledLineOfXLength ( { angle : 181 + 0 , length : 23.14 } , % )
| > angledLineOfYLength ( { angle : - 91 , length : 19 + 0 } , % )
| > angledLineToX ( { angle : 3 + 0 , to : 26 } , % )
| > angledLineToY ( { angle : 89 , to : 9.14 + 0 } , % )
| > angledLineThatIntersects ( {
angle : 4.14 ,
intersectTag : 'a' ,
offset : 9
} , % )
| > tangentialArcTo ( [ 3.14 + 13 , - 3.14 ] , % )
`
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-24 20:54:42 +10:00
await page . getByText ( 'xLineTo(9 - 5, %)' ) . click ( )
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 13 )
const clickUnconstrained = _clickUnconstrained ( page )
const clickConstrained = _clickConstrained ( page )
const tangentialArcTo = await u . getBoundingBox (
` [data-overlay-index="12"] `
)
2024-06-04 08:32:24 -04:00
let ang = await u . getAngle ( ` [data-overlay-index="12"] ` )
2024-05-24 20:54:42 +10:00
console . log ( 'tangentialArcTo' )
await clickConstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : tangentialArcTo.x , y : tangentialArcTo.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'xAbsolute' ,
expectBeforeUnconstrained : 'tangentialArcTo([3.14 + 13, -3.14], %)' ,
expectAfterUnconstrained : 'tangentialArcTo([16.14, -3.14], %)' ,
expectFinal : 'tangentialArcTo([xAbs001, -3.14], %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
steps : 6 ,
} )
console . log ( 'tangentialArcTo2' )
await clickUnconstrained ( {
2024-06-04 08:32:24 -04:00
hoverPos : { x : tangentialArcTo.x , y : tangentialArcTo.y } ,
2024-05-24 20:54:42 +10:00
constraintType : 'yAbsolute' ,
expectBeforeUnconstrained : 'tangentialArcTo([xAbs001, -3.14], %)' ,
expectAfterUnconstrained : 'tangentialArcTo([xAbs001, yAbs001], %)' ,
expectFinal : 'tangentialArcTo([xAbs001, -3.14], %)' ,
2024-06-04 08:32:24 -04:00
ang : ang + 180 ,
2024-05-24 20:54:42 +10:00
steps : 10 ,
} )
} )
} )
test . describe ( 'Testing deleting a segment' , ( ) = > {
const _deleteSegmentSequence =
( page : Page ) = >
async ( {
hoverPos ,
codeToBeDeleted ,
stdLibFnName ,
ang = 45 ,
steps = 6 ,
} : {
hoverPos : { x : number ; y : number }
codeToBeDeleted : string
stdLibFnName : string
ang? : number
steps? : number
} ) = > {
await expect ( page . getByText ( 'Added variable' ) ) . not . toBeVisible ( )
const [ x , y ] = [
Math . cos ( ( ang * Math . PI ) / 180 ) * 45 ,
Math . sin ( ( ang * Math . PI ) / 180 ) * 45 ,
]
await page . mouse . move ( hoverPos . x + x , hoverPos . y + y )
await page . mouse . move ( hoverPos . x , hoverPos . y , { steps } )
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( codeToBeDeleted )
await page . locator ( ` [data-stdlib-fn-name=" ${ stdLibFnName } "] ` ) . click ( )
await page . getByText ( 'Delete Segment' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . not . toContainText (
codeToBeDeleted
)
}
test ( 'all segment types' , async ( { page } ) = > {
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'persistCode' ,
` const part001 = startSketchOn('XZ')
| > startProfileAt ( [ 0 , 0 ] , % )
| > line ( [ 0.5 , - 14 + 0 ] , % )
| > angledLine ( { angle : 3 + 0 , length : 32 + 0 } , % )
| > lineTo ( [ 33 , 11.5 + 0 ] , % )
| > xLineTo ( 9 - 5 , % )
| > yLineTo ( - 10.77 , % , 'a' )
| > xLine ( 26.04 , % )
| > yLine ( 21.14 + 0 , % )
| > angledLineOfXLength ( { angle : 181 + 0 , length : 23.14 } , % )
| > angledLineOfYLength ( { angle : - 91 , length : 19 + 0 } , % )
| > angledLineToX ( { angle : 3 + 0 , to : 26 } , % )
| > angledLineToY ( { angle : 89 , to : 9.14 + 0 } , % )
| > angledLineThatIntersects ( {
angle : 4.14 ,
intersectTag : 'a' ,
offset : 9
} , % )
| > tangentialArcTo ( [ 3.14 + 13 , 1.14 ] , % )
`
)
} )
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-05-24 12:32:15 -07:00
// wait for execution done
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
2024-05-24 20:54:42 +10:00
await page . getByText ( 'xLineTo(9 - 5, %)' ) . click ( )
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 13 )
const deleteSegmentSequence = _deleteSegmentSequence ( page )
let segmentToDelete
const getOverlayByIndex = ( index : number ) = >
u . getBoundingBox ( ` [data-overlay-index=" ${ index } "] ` )
segmentToDelete = await getOverlayByIndex ( 12 )
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x - 10 , y : segmentToDelete.y + 20 } ,
codeToBeDeleted : 'tangentialArcTo([3.14 + 13, 1.14], %)' ,
stdLibFnName : 'tangentialArcTo' ,
ang : - 45 ,
steps : 6 ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 11 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x + 10 , y : segmentToDelete.y } ,
codeToBeDeleted : ` angledLineThatIntersects({
angle : 4.14 ,
intersectTag : 'a' ,
offset : 9
} , % ) ` ,
stdLibFnName : 'angledLineThatIntersects' ,
ang : - 45 ,
steps : 7 ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 10 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x + 10 , y : segmentToDelete.y } ,
codeToBeDeleted : 'angledLineToY({ angle: 89, to: 9.14 + 0 }, %)' ,
stdLibFnName : 'angledLineToY' ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 9 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x - 10 , y : segmentToDelete.y } ,
codeToBeDeleted : 'angledLineToX({ angle: 3 + 0, to: 26 }, %)' ,
stdLibFnName : 'angledLineToX' ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 8 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x , y : segmentToDelete.y - 10 } ,
codeToBeDeleted :
'angledLineOfYLength({ angle: -91, length: 19 + 0 }, %)' ,
stdLibFnName : 'angledLineOfYLength' ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 7 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x + 10 , y : segmentToDelete.y } ,
codeToBeDeleted :
'angledLineOfXLength({ angle: 181 + 0, length: 23.14 }, %)' ,
stdLibFnName : 'angledLineOfXLength' ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 6 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x , y : segmentToDelete.y + 10 } ,
codeToBeDeleted : 'yLine(21.14 + 0, %)' ,
stdLibFnName : 'yLine' ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 5 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x - 10 , y : segmentToDelete.y } ,
codeToBeDeleted : 'xLine(26.04, %)' ,
stdLibFnName : 'xLine' ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 4 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x , y : segmentToDelete.y - 10 } ,
codeToBeDeleted : "yLineTo(-10.77, %, 'a')" ,
stdLibFnName : 'yLineTo' ,
} )
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 3 )
2024-05-24 20:54:42 +10:00
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x + 10 , y : segmentToDelete.y } ,
codeToBeDeleted : 'xLineTo(9 - 5, %)' ,
stdLibFnName : 'xLineTo' ,
} )
2024-06-04 08:32:24 -04:00
// Not sure why this is diff. from the others - Kurt, ideas?
segmentToDelete = await getOverlayByIndex ( 2 )
2024-05-24 20:54:42 +10:00
const hoverPos = { x : segmentToDelete.x - 10 , y : segmentToDelete.y + 10 }
await expect ( page . getByText ( 'Added variable' ) ) . not . toBeVisible ( )
const [ x , y ] = [
Math . cos ( ( 45 * Math . PI ) / 180 ) * 45 ,
Math . sin ( ( 45 * Math . PI ) / 180 ) * 45 ,
]
await page . mouse . move ( hoverPos . x + x , hoverPos . y + y )
await page . mouse . move ( hoverPos . x , hoverPos . y , { steps : 5 } )
const codeToBeDeleted = 'lineTo([33, 11.5 + 0], %)'
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( codeToBeDeleted )
await page . getByTestId ( 'overlay-menu' ) . click ( )
await page . getByText ( 'Delete Segment' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . not . toContainText (
codeToBeDeleted
)
2024-06-04 08:32:24 -04:00
segmentToDelete = await getOverlayByIndex ( 1 )
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x - 20 , y : segmentToDelete.y } ,
codeToBeDeleted : 'angledLine({ angle: 3 + 0, length: 32 + 0 }, %)' ,
stdLibFnName : 'angledLine' ,
ang : 135 ,
} )
segmentToDelete = await getOverlayByIndex ( 0 )
await deleteSegmentSequence ( {
hoverPos : { x : segmentToDelete.x , y : segmentToDelete.y - 20 } ,
codeToBeDeleted : 'line([0.5, -14 + 0], %)' ,
stdLibFnName : 'line' ,
ang : - 45 ,
} )
await page . waitForTimeout ( 200 )
2024-05-24 20:54:42 +10:00
} )
} )
test . describe ( 'Testing delete with dependent segments' , ( ) = > {
const cases = [
"line([22, 2], %, 'seg01')" ,
"angledLine([5, 23.03], %, 'seg01')" ,
"xLine(23, %, 'seg01')" ,
"yLine(-8, %, 'seg01')" ,
"xLineTo(30, %, 'seg01')" ,
"yLineTo(-4, %, 'seg01')" ,
"angledLineOfXLength([3, 30], %, 'seg01')" ,
"angledLineOfXLength({ angle: 3, length: 30 }, %, 'seg01')" ,
"angledLineOfYLength([3, 1.5], %, 'seg01')" ,
"angledLineOfYLength({ angle: 3, length: 1.5 }, %, 'seg01')" ,
"angledLineToX([3, 30], %, 'seg01')" ,
"angledLineToX({ angle: 3, to: 30 }, %, 'seg01')" ,
"angledLineToY([3, 7], %, 'seg01')" ,
"angledLineToY({ angle: 3, to: 7 }, %, 'seg01')" ,
]
for ( const doesHaveTagOutsideSketch of [ true , false ] ) {
for ( const lineOfInterest of cases ) {
const isObj = lineOfInterest . includes ( '{ angle: 3,' )
test ( ` ${ lineOfInterest . split ( '(' ) [ 0 ] } ${ isObj ? '-[obj-input]' : '' } ${
doesHaveTagOutsideSketch ? '-[tagOutsideSketch]' : ''
} ` , async ({ page }) => {
await page . addInitScript (
async ( { lineToBeDeleted , extraLine } ) = > {
localStorage . setItem (
'persistCode' ,
` const part001 = startSketchOn('XZ')
| > startProfileAt ( [ 5 , 6 ] , % )
| > $ { lineToBeDeleted }
| > line ( [ - 10 , - 15 ] , % )
| > angledLine ( [ - 176 , segLen ( 'seg01' , % ) ] , % )
$ { extraLine ? "const myVar = segLen('seg01', part001)" : '' } `
)
} ,
{
lineToBeDeleted : lineOfInterest ,
extraLine : doesHaveTagOutsideSketch ,
}
)
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await page . waitForTimeout ( 300 )
await page . getByText ( lineOfInterest ) . click ( )
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 3 )
const segmentToDelete = await u . getBoundingBox (
` [data-overlay-index="0"] `
)
const isYLine = lineOfInterest . toLowerCase ( ) . includes ( 'yline' )
const hoverPos = {
x : segmentToDelete.x + ( isYLine ? 0 : - 20 ) ,
y : segmentToDelete.y + ( isYLine ? - 20 : 0 ) ,
}
await expect ( page . getByText ( 'Added variable' ) ) . not . toBeVisible ( )
const ang = isYLine ? 45 : - 45
const [ x , y ] = [
Math . cos ( ( ang * Math . PI ) / 180 ) * 45 ,
Math . sin ( ( ang * Math . PI ) / 180 ) * 45 ,
]
await page . mouse . move ( hoverPos . x + x , hoverPos . y + y )
await page . mouse . move ( hoverPos . x , hoverPos . y , { steps : 5 } )
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
lineOfInterest
)
await page . getByTestId ( 'overlay-menu' ) . click ( )
await page . getByText ( 'Delete Segment' ) . click ( )
await page . getByText ( 'Cancel' ) . click ( )
await page . mouse . move ( hoverPos . x + x , hoverPos . y + y )
await page . mouse . move ( hoverPos . x , hoverPos . y , { steps : 5 } )
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
lineOfInterest
)
await page . getByTestId ( 'overlay-menu' ) . click ( )
await page . getByText ( 'Delete Segment' ) . click ( )
await page . getByText ( 'Continue and unconstrain' ) . last ( ) . click ( )
if ( doesHaveTagOutsideSketch ) {
// eslint-disable-next-line jest/no-conditional-expect
await expect (
page . getByText (
'Segment tag used outside of current Sketch. Could not delete.'
)
) . toBeTruthy ( )
// eslint-disable-next-line jest/no-conditional-expect
await expect ( page . locator ( '.cm-content' ) ) . toContainText (
lineOfInterest
)
} else {
// eslint-disable-next-line jest/no-conditional-expect
await expect ( page . locator ( '.cm-content' ) ) . not . toContainText (
lineOfInterest
)
// eslint-disable-next-line jest/no-conditional-expect
await expect ( page . locator ( '.cm-content' ) ) . not . toContainText ( 'seg01' )
}
} )
}
}
} )
2024-06-04 16:29:20 +10:00
test . describe ( 'Testing remove constraints segments' , ( ) = > {
const cases = [
{
before : ` line([22 + 0, 2 + 0], %, 'seg01') ` ,
after : ` line([22, 2], %, 'seg01') ` ,
} ,
{
before : ` angledLine([5 + 0, 23.03 + 0], %, 'seg01') ` ,
after : ` line([22.94, 2.01], %, 'seg01') ` ,
} ,
{
before : ` xLine(23 + 0, %, 'seg01') ` ,
after : ` line([23, 0], %, 'seg01') ` ,
} ,
{
before : ` yLine(-8 + 0, %, 'seg01') ` ,
after : ` line([0, -8], %, 'seg01') ` ,
} ,
{
before : ` xLineTo(30 + 0, %, 'seg01') ` ,
after : ` line([25, 0], %, 'seg01') ` ,
} ,
{
before : ` yLineTo(-4 + 0, %, 'seg01') ` ,
after : ` line([0, -10], %, 'seg01') ` ,
} ,
{
before : ` angledLineOfXLength([3 + 0, 30 + 0], %, 'seg01') ` ,
after : ` line([30, 1.57], %, 'seg01') ` ,
} ,
{
before : ` angledLineOfYLength([3 + 0, 1.5 + 0], %, 'seg01') ` ,
after : ` line([28.62, 1.5], %, 'seg01') ` ,
} ,
{
before : ` angledLineToX([3 + 0, 30 + 0], %, 'seg01') ` ,
after : ` line([25, 1.31], %, 'seg01') ` ,
} ,
{
before : ` angledLineToY([3 + 0, 7 + 0], %, 'seg01') ` ,
after : ` line([19.08, 1], %, 'seg01') ` ,
} ,
{
before : ` angledLineOfXLength({ angle: 3 + 0, length: 30 + 0 }, %, 'seg01') ` ,
after : ` line([30, 1.57], %, 'seg01') ` ,
} ,
{
before : ` angledLineOfYLength({ angle: 3 + 0, length: 1.5 + 0 }, %, 'seg01') ` ,
after : ` line([28.62, 1.5], %, 'seg01') ` ,
} ,
{
before : ` angledLineToX({ angle: 3 + 0, to: 30 + 0 }, %, 'seg01') ` ,
after : ` line([25, 1.31], %, 'seg01') ` ,
} ,
{
before : ` angledLineToY({ angle: 3 + 0, to: 7 + 0 }, %, 'seg01') ` ,
after : ` line([19.08, 1], %, 'seg01') ` ,
} ,
]
for ( const { before , after } of cases ) {
const isObj = before . includes ( '{ angle: 3' )
test ( ` ${ before . split ( '(' ) [ 0 ] } ${ isObj ? '-[obj-input]' : '' } ` , async ( {
page ,
} ) = > {
await page . addInitScript (
async ( { lineToBeDeleted } ) = > {
localStorage . setItem (
'persistCode' ,
` const part001 = startSketchOn('XZ')
| > startProfileAt ( [ 5 , 6 ] , % )
| > $ { lineToBeDeleted }
| > line ( [ - 10 , - 15 ] , % )
| > angledLine ( [ - 176 , segLen ( 'seg01' , % ) ] , % ) `
)
} ,
{
lineToBeDeleted : before ,
}
)
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await page . waitForTimeout ( 300 )
await page . getByText ( before ) . click ( )
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Edit Sketch' } ) . click ( )
await page . waitForTimeout ( 500 )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 3 )
const segmentToDelete = await u . getBoundingBox (
` [data-overlay-index="0"] `
)
const isYLine = before . toLowerCase ( ) . includes ( 'yline' )
const hoverPos = {
x : segmentToDelete.x + ( isYLine ? 0 : - 20 ) ,
y : segmentToDelete.y + ( isYLine ? - 20 : 0 ) ,
}
await expect ( page . getByText ( 'Added variable' ) ) . not . toBeVisible ( )
const ang = isYLine ? 45 : - 45
const [ x , y ] = [
Math . cos ( ( ang * Math . PI ) / 180 ) * 45 ,
Math . sin ( ( ang * Math . PI ) / 180 ) * 45 ,
]
await page . mouse . move ( hoverPos . x + x , hoverPos . y + y )
await page . mouse . move ( hoverPos . x , hoverPos . y , { steps : 5 } )
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( before )
await page . getByTestId ( 'overlay-menu' ) . click ( )
await page . getByText ( 'Remove constraints' ) . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( after )
// check the cursor was left in the correct place after transform
await expect ( page . locator ( '.cm-activeLine' ) ) . toHaveText ( '|> ' + after )
await expect ( page . getByTestId ( 'segment-overlay' ) ) . toHaveCount ( 3 )
} )
}
} )
2024-05-24 20:54:42 +10:00
} )
2024-05-23 17:23:15 -07:00
test ( 'First escape in tool pops you out of tool, second exits sketch mode' , async ( {
page ,
} ) = > {
// Wait for the app to be ready for use
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
const lineButton = page . getByRole ( 'button' , { name : 'Line' } )
const arcButton = page . getByRole ( 'button' , { name : 'Tangential Arc' } )
// Test these hotkeys perform actions when
// focus is on the canvas
await page . mouse . move ( 600 , 250 )
await page . mouse . click ( 600 , 250 )
// Start a sketch
await page . keyboard . press ( 's' )
await page . mouse . move ( 800 , 300 )
await page . mouse . click ( 800 , 300 )
await page . waitForTimeout ( 1000 )
await expect ( lineButton ) . toHaveAttribute ( 'aria-pressed' , 'true' )
// Draw a line
await page . mouse . move ( 700 , 200 , { steps : 5 } )
await page . mouse . click ( 700 , 200 )
await page . mouse . move ( 800 , 250 , { steps : 5 } )
await page . mouse . click ( 800 , 250 )
// 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 ( lineButton ) . not . toHaveAttribute ( 'aria-pressed' , 'true' )
// Equip arc tool
await page . keyboard . press ( 'a' )
await expect ( arcButton ) . toHaveAttribute ( 'aria-pressed' , 'true' )
await page . mouse . move ( 1000 , 100 , { steps : 5 } )
await page . mouse . click ( 1000 , 100 )
await page . keyboard . press ( 'Escape' )
await page . keyboard . press ( 'l' )
await expect ( lineButton ) . toHaveAttribute ( 'aria-pressed' , 'true' )
// Do not close the sketch.
// On close it will exit sketch mode.
// Unequip line tool
await page . keyboard . press ( 'Escape' )
await expect ( lineButton ) . toHaveAttribute ( 'aria-pressed' , 'false' )
await expect ( arcButton ) . toHaveAttribute ( 'aria-pressed' , 'false' )
// Make sure we didn't pop out of sketch mode.
await expect ( page . getByRole ( 'button' , { name : 'Exit Sketch' } ) ) . toBeVisible ( )
// Exit sketch
await page . keyboard . press ( 'Escape' )
await expect (
page . getByRole ( 'button' , { name : 'Exit Sketch' } )
) . not . toBeVisible ( )
} )
2024-05-22 11:07:02 -04:00
test ( 'Basic default modeling and sketch hotkeys work' , async ( { page } ) = > {
// This test can run long if it takes a little too long to load
// the engine.
test . setTimeout ( 90000 )
// This test has a weird bug on ubuntu
test . skip (
process . platform === 'linux' ,
'weird playwright bug on ubuntu https://github.com/KittyCAD/modeling-app/issues/2444'
)
// Load the app with the code pane open
await page . addInitScript ( async ( ) = > {
localStorage . setItem (
'store' ,
JSON . stringify ( {
state : {
openPanes : [ 'code' ] ,
} ,
version : 0 ,
} )
)
} )
// Wait for the app to be ready for use
2024-05-23 02:20:40 -07:00
const u = await getUtils ( page )
2024-05-22 11:07:02 -04:00
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . closeDebugPanel ( )
const codePane = page . getByRole ( 'textbox' ) . locator ( 'div' )
const codePaneButton = page . getByRole ( 'tab' , { name : 'KCL Code' } )
const lineButton = page . getByRole ( 'button' , { name : 'Line' } )
const arcButton = page . getByRole ( 'button' , { name : 'Tangential Arc' } )
const extrudeButton = page . getByRole ( 'button' , { name : 'Extrude' } )
// Test that the hotkeys do nothing when
// focus is on the code pane
await codePane . click ( )
await page . keyboard . press ( 's' )
await page . keyboard . press ( 'l' )
await page . keyboard . press ( 'a' )
await page . keyboard . press ( 'e' )
await expect ( page . locator ( '.cm-content' ) ) . toHaveText ( 'slae' )
await page . keyboard . press ( 'Meta+/' )
// Test these hotkeys perform actions when
// focus is on the canvas
await page . mouse . move ( 600 , 250 )
await page . mouse . click ( 600 , 250 )
// Start a sketch
await page . keyboard . press ( 's' )
await page . mouse . move ( 800 , 300 )
await page . mouse . click ( 800 , 300 )
await page . waitForTimeout ( 1000 )
await expect ( lineButton ) . toHaveAttribute ( 'aria-pressed' , 'true' )
/ * *
* TODO : There is a bug somewhere that causes this test to fail
* if you toggle the codePane closed before your trigger the
* start of the sketch .
2024-05-24 18:12:39 -04:00
* and a separate Safari - only bug that causes the test to fail
* if the pane is open the entire test . The maintainer of CodeMirror
* has pinpointed this to the unusual browser behavior :
* https : //discuss.codemirror.net/t/how-to-force-unfocus-of-the-codemirror-element-in-safari/8095/3
2024-05-22 11:07:02 -04:00
* /
await codePaneButton . click ( )
// Draw a line
await page . mouse . move ( 700 , 200 , { steps : 5 } )
await page . mouse . click ( 700 , 200 )
await page . mouse . move ( 800 , 250 , { steps : 5 } )
await page . mouse . click ( 800 , 250 )
// Unequip line tool
await page . keyboard . press ( 'l' )
await expect ( lineButton ) . not . toHaveAttribute ( 'aria-pressed' , 'true' )
// Equip arc tool
await page . keyboard . press ( 'a' )
await expect ( arcButton ) . toHaveAttribute ( 'aria-pressed' , 'true' )
await page . mouse . move ( 1000 , 100 , { steps : 5 } )
await page . mouse . click ( 1000 , 100 )
await page . keyboard . press ( 'Escape' )
await page . keyboard . press ( 'l' )
await expect ( lineButton ) . toHaveAttribute ( 'aria-pressed' , 'true' )
// Close profile
await page . mouse . move ( 700 , 200 , { steps : 5 } )
await page . mouse . click ( 700 , 200 )
2024-05-23 17:23:15 -07:00
// On close it will unequip the line tool.
await expect ( lineButton ) . toHaveAttribute ( 'aria-pressed' , 'false' )
2024-05-22 11:07:02 -04:00
// Exit sketch
await page . keyboard . press ( 'Escape' )
2024-05-23 17:23:15 -07:00
await expect (
page . getByRole ( 'button' , { name : 'Exit Sketch' } )
) . not . toBeVisible ( )
2024-05-22 11:07:02 -04:00
// Extrude
await page . mouse . click ( 750 , 150 )
await expect ( extrudeButton ) . not . toBeDisabled ( )
await page . keyboard . press ( 'e' )
2024-05-23 15:44:19 +10:00
await page . mouse . move ( 730 , 230 , { steps : 5 } )
await page . mouse . click ( 730 , 230 )
2024-05-22 11:07:02 -04:00
await page . waitForTimeout ( 100 )
await page . getByRole ( 'button' , { name : 'Continue' } ) . click ( )
await page . getByRole ( 'button' , { name : 'Submit command' } ) . click ( )
await codePaneButton . click ( )
await expect ( page . locator ( '.cm-content' ) ) . toContainText ( 'extrude(' )
} )
2024-05-23 02:20:40 -07:00
test ( 'simulate network down and network little widget' , async ( { page } ) = > {
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
2024-06-04 08:32:24 -04:00
// This is how we wait until the stream is online
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( { timeout : 15000 } )
2024-05-23 02:20:40 -07:00
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 ( )
2024-06-04 08:32:24 -04:00
// (First check) Expect the network to be up
2024-05-23 02:20:40 -07:00
await expect ( page . getByText ( 'Network Health (Connected)' ) ) . toBeVisible ( )
// 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 ( page . getByText ( 'Network Health (Offline)' ) ) . toBeVisible ( )
// Click the network widget
await networkWidget . click ( )
// Check the modal opened.
await expect ( networkPopover ) . toBeVisible ( )
// Click off the modal.
2024-06-04 08:32:24 -04:00
await page . mouse . click ( 0 , 0 )
2024-05-23 02:20:40 -07:00
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 ,
} )
2024-06-04 08:32:24 -04:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( { timeout : 15000 } )
// (Second check) expect the network to be up
2024-05-23 02:20:40 -07:00
await expect ( page . getByText ( 'Network Health (Connected)' ) ) . toBeVisible ( )
} )
2024-05-24 16:11:49 -07:00
test ( 'Engine disconnect & reconnect in sketch mode' , async ( { page } ) = > {
const u = await getUtils ( page )
await page . setViewportSize ( { width : 1200 , height : 500 } )
const PUR = 400 / 37.5 //pixeltoUnitRatio
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
2024-06-04 08:32:24 -04:00
) . not . toBeDisabled ( { timeout : 15000 } )
2024-05-24 16:11:49 -07:00
// 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 (
2024-06-04 13:57:01 -04:00
` const sketch001 = startSketchOn('XZ') `
2024-05-24 16:11:49 -07:00
)
await u . closeDebugPanel ( )
await page . waitForTimeout ( 300 ) // 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' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-05-24 16:11:49 -07:00
| > 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' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-05-24 16:11:49 -07:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % ) ` )
// Expect the network to be up
await expect ( page . getByText ( 'Network Health (Connected)' ) ) . toBeVisible ( )
// 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 ( page . getByText ( 'Network Health (Offline)' ) ) . toBeVisible ( )
// 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
2024-06-04 08:32:24 -04:00
await expect (
page . getByRole ( 'button' , { name : 'Start Sketch' } )
) . not . toBeDisabled ( { timeout : 15000 } )
2024-05-24 16:11:49 -07:00
// Expect the network to be up
await expect ( page . getByText ( 'Network Health (Connected)' ) ) . toBeVisible ( )
// 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' } ) . click ( )
await page . waitForTimeout ( 150 )
// Ensure we can continue sketching
await page . mouse . click ( startXPx + PUR * 20 , 500 - PUR * 20 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-05-24 16:11:49 -07:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % )
2024-06-04 08:32:24 -04:00
| > line ( [ - 11.64 , 11.11 ] , % ) ` )
2024-05-24 16:11:49 -07:00
await page . waitForTimeout ( 100 )
await page . mouse . click ( startXPx , 500 - PUR * 20 )
await expect ( page . locator ( '.cm-content' ) )
2024-06-04 13:57:01 -04:00
. toHaveText ( ` const sketch001 = startSketchOn('XZ')
2024-05-24 16:11:49 -07:00
| > startProfileAt ( $ { commonPoints . startAt } , % )
| > line ( [ $ { commonPoints . num1 } , 0 ] , % )
2024-06-04 08:32:24 -04:00
| > line ( [ - 11.64 , 11.11 ] , % )
| > line ( [ - 6.56 , 0 ] , % ) ` )
2024-05-24 16:11:49 -07:00
// 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' } ) ) . not . toHaveAttribute (
'aria-pressed' ,
'true'
)
// Exit sketch
await page . keyboard . press ( 'Escape' )
await expect (
page . getByRole ( 'button' , { name : 'Exit Sketch' } )
) . not . toBeVisible ( )
} )
2024-05-29 18:04:27 -04:00
test ( 'Successful export shows a success toast' , async ( { page } ) = > {
// FYI this test doesn't work with only engine running locally
// And you will need to have the KittyCAD CLI installed
const u = await getUtils ( page )
await page . addInitScript ( async ( ) = > {
; ( window as any ) . playwrightSkipFilePicker = true
localStorage . setItem (
'persistCode' ,
` const topAng = 25
const bottomAng = 35
const baseLen = 3.5
const baseHeight = 1
const totalHeightHalf = 2
const armThick = 0.5
const totalLen = 9.5
const part001 = startSketchOn ( '-XZ' )
| > startProfileAt ( [ 0 , 0 ] , % )
| > yLine ( baseHeight , % )
| > xLine ( baseLen , % )
| > angledLineToY ( {
angle : topAng ,
to : totalHeightHalf ,
} , % , 'seg04' )
| > xLineTo ( totalLen , % , 'seg03' )
| > yLine ( - armThick , % , 'seg01' )
| > angledLineThatIntersects ( {
angle : HALF_TURN ,
offset : - armThick ,
intersectTag : 'seg04'
} , % )
| > angledLineToY ( [ segAng ( 'seg04' , % ) + 180 , ZERO ] , % )
| > angledLineToY ( {
angle : - bottomAng ,
to : - totalHeightHalf - armThick ,
} , % , 'seg02' )
| > xLineTo ( segEndX ( 'seg03' , % ) + 0 , % )
| > yLine ( - segLen ( 'seg01' , % ) , % )
| > angledLineThatIntersects ( {
angle : HALF_TURN ,
offset : - armThick ,
intersectTag : 'seg02'
} , % )
| > angledLineToY ( [ segAng ( 'seg02' , % ) + 180 , - baseHeight ] , % )
| > xLineTo ( ZERO , % )
| > close ( % )
| > extrude ( 4 , % ) `
)
} )
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' )
await u . waitForAuthSkipAppStart ( )
await u . openDebugPanel ( )
await u . expectCmdLog ( '[data-message-type="execution-done"]' )
await u . waitForCmdReceive ( 'extrude' )
await page . waitForTimeout ( 1000 )
await u . clearAndCloseDebugPanel ( )
await doExport (
{
type : 'gltf' ,
storage : 'embedded' ,
presentation : 'pretty' ,
} ,
page
)
// This is the main thing we're testing,
// We test the export functionality across all
// file types in snapshot-tests.spec.ts
await expect ( page . getByText ( 'Exported successfully' ) ) . toBeVisible ( )
} )
2024-06-04 14:36:34 -04:00
test ( 'Paste should not work unless an input is focused' , async ( {
page ,
browserName ,
} ) = > {
// To run this test locally, uncomment Firefox in playwright.config.ts
test . skip (
browserName !== 'firefox' ,
"This bug is really Firefox-only, which we don't run in CI."
)
await page . setViewportSize ( { width : 1200 , height : 500 } )
await page . goto ( '/' , { waitUntil : 'domcontentloaded' } )
await page
. getByRole ( 'button' , { name : 'Start Sketch' } )
. waitFor ( { state : 'visible' } )
const codeEditorText = page . locator ( '.cm-content' )
const pasteContent = ` // was this pasted? `
const typeContent = ` // this should be typed `
// Load text into the clipboard
await page . evaluate ( ( t ) = > navigator . clipboard . writeText ( t ) , pasteContent )
// Focus the text editor
await codeEditorText . focus ( )
// Show that we can type into it
await page . keyboard . type ( typeContent )
await page . keyboard . press ( 'Enter' )
// Paste without the code pane focused
await codeEditorText . blur ( )
await page . keyboard . press ( ` ${ metaModifier } +KeyV ` )
// Show that the paste didn't work but typing did
await expect ( codeEditorText ) . not . toContainText ( pasteContent )
await expect ( codeEditorText ) . toContainText ( typeContent )
// Paste with the code editor focused
// Following this guidance: https://github.com/microsoft/playwright/issues/8114
await codeEditorText . focus ( )
await page . keyboard . press ( ` ${ metaModifier } +KeyV ` )
await expect (
await page . evaluate (
( ) = > document . querySelector ( '.cm-content' ) ? . textContent
)
) . toContain ( pasteContent )
} )