Part of #4600. PR: https://github.com/KittyCAD/modeling-app/pull/4826 # Changes to KCL stdlib - `line(point, sketch, tag)` and `lineTo(point, sketch, tag)` are combined into `line(@sketch, end?, endAbsolute?, tag?)` - `close(sketch, tag?)` is now `close(@sketch, tag?)` - `extrude(length, sketch)` is now `extrude(@sketch, length)` Note that if a parameter starts with `@` like `@sketch`, it doesn't have any label when called, so you call it like this: ``` sketch = startSketchAt([0, 0]) line(sketch, end = [3, 3], tag = $hi) ``` Note also that if you're using a `|>` pipeline, you can omit the `@` argument and it will be assumed to be the LHS of the `|>`. So the above could be written as ``` sketch = startSketchAt([0, 0]) |> line(end = [3, 3], tag = $hi) ``` Also changes frontend tests to use KittyCAD/kcl-samples#139 instead of its main The regex find-and-replace I use for migrating code (note these don't work with multi-line expressions) are: ``` line\(([^=]*), %\) line(end = $1) line\((.*), %, (.*)\) line(end = $1, tag = $2) lineTo\((.*), %\) line(endAbsolute = $1) lineTo\((.*), %, (.*)\) line(endAbsolute = $1, tag = $2) extrude\((.*), %\) extrude(length = $1) extrude\(([^=]*), ([a-zA-Z0-9]+)\) extrude($2, length = $1) close\(%, (.*)\) close(tag = $1) ``` # Selected notes from commits before I squash them all * Fix test 'yRelative to horizontal distance' Fixes: - Make a lineTo helper - Fix pathToNode to go through the labeled arg .arg property * Fix test by changing lookups into transformMap Parts of the code assumed that `line` is always a relative call. But actually now it might be absolute, if it's got an `endAbsolute` parameter. So, change whether to look up `line` or `lineTo` and the relevant absolute or relative line types based on that parameter. * Stop asserting on exact source ranges When I changed line to kwargs, all the source ranges we assert on became slightly different. I find these assertions to be very very low value. So I'm removing them. * Fix more tests: getConstraintType calls weren't checking if the 'line' fn was absolute or relative. * Fixed another queryAst test There were 2 problems: - Test was looking for the old style of `line` call to choose an offset for pathToNode - Test assumed that the `tag` param was always the third one, but in a kwarg call, you have to look it up by label * Fix test: traverse was not handling CallExpressionKw * Fix another test, addTagKw addTag helper was not aware of kw args. * Convert close from positional to kwargs If the close() call has 0 args, or a single unlabeled arg, the parser interprets it as a CallExpression (positional) not a CallExpressionKw. But then if a codemod wants to add a tag to it, it tries adding a kwarg called 'tag', which fails because the CallExpression doesn't need kwargs inserted into it. The fix is: change the node from CallExpression to CallExpressionKw, and update getNodeFromPath to take a 'replacement' arg, so we can replace the old node with the new node in the AST. * Fix the last test Test was looking for `lineTo` as a substring of the input KCL program. But there's no more lineTo function, so I changed it to look for line() with an endAbsolute arg, which is the new equivalent. Also changed the getConstraintInfo code to look up the lineTo if using line with endAbsolute. * Fix many bad regex find-replaces I wrote a regex find-and-replace which converted `line` calls from positional to keyword calls. But it was accidentally applied to more places than it should be, for example, angledLine, xLine and yLine calls. Fixes this. * Fixes test 'Basic sketch › code pane closed at start' Problem was, the getNodeFromPath call might not actually find a callExpressionKw, it might find a callExpression. So the `giveSketchFnCallTag` thought it was modifying a kwargs call, but it was actually modifying a positional call. This meant it tried to push a labeled argument in, rather than a normal arg, and a lot of other problems. Fixed by doing runtime typechecking. * Fix: Optional args given with wrong type were silently ignored Optional args don't have to be given. But if the user gives them, they should be the right type. Bug: if the KCL interpreter found an optional arg, which was given, but was the wrong type, it would ignore it and pretend the arg was never given at all. This was confusing for users. Fix: Now if you give an optional arg, but it's the wrong type, KCL will emit a type error just like it would for a mandatory argument. --------- Signed-off-by: Nick Cameron <nrc@ncameron.org> Co-authored-by: Nick Cameron <nrc@ncameron.org> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Frank Noirot <frank@kittycad.io> Co-authored-by: Kevin Nadro <kevin@zoo.dev> Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
1195 lines
38 KiB
TypeScript
1195 lines
38 KiB
TypeScript
import { test, expect } from './zoo-test'
|
|
import fsp from 'fs/promises'
|
|
import { uuidv4 } from 'lib/utils'
|
|
import {
|
|
darkModeBgColor,
|
|
darkModePlaneColorXZ,
|
|
executorInputPath,
|
|
getUtils,
|
|
} from './test-utils'
|
|
|
|
import { join } from 'path'
|
|
|
|
test.describe('Editor tests', () => {
|
|
test('can comment out code with ctrl+/', async ({ page, homePage }) => {
|
|
const u = await getUtils(page)
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
|
|
await page.keyboard.down('ControlOrMeta')
|
|
await page.keyboard.press('/')
|
|
await page.keyboard.up('ControlOrMeta')
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
// |> close()`)
|
|
|
|
// uncomment the code
|
|
await page.keyboard.down('ControlOrMeta')
|
|
await page.keyboard.press('/')
|
|
await page.keyboard.up('ControlOrMeta')
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
})
|
|
|
|
test('ensure we use the cache, and do not re-execute', async ({
|
|
homePage,
|
|
page,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
await u.waitForPageLoad()
|
|
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
|
|
// Ensure we execute the first time.
|
|
await u.openDebugPanel()
|
|
await expect(
|
|
page.locator('[data-receive-command-type="scene_clear_all"]')
|
|
).toHaveCount(1)
|
|
await expect(
|
|
page.locator('[data-message-type="execution-done"]')
|
|
).toHaveCount(2)
|
|
|
|
// Add whitespace to the end of the code.
|
|
await u.codeLocator.click()
|
|
await page.keyboard.press('ArrowUp')
|
|
await page.keyboard.press('ArrowUp')
|
|
await page.keyboard.press('ArrowUp')
|
|
await page.keyboard.press('ArrowUp')
|
|
await page.keyboard.press('Home')
|
|
await page.keyboard.type(' ')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.type(' ')
|
|
|
|
// Ensure we don't execute the second time.
|
|
await u.openDebugPanel()
|
|
// Make sure we didn't clear the scene.
|
|
await expect(
|
|
page.locator('[data-message-type="execution-done"]')
|
|
).toHaveCount(3)
|
|
await expect(
|
|
page.locator('[data-receive-command-type="scene_clear_all"]')
|
|
).toHaveCount(1)
|
|
})
|
|
|
|
test('ensure we use the cache, and do not clear on append', async ({
|
|
homePage,
|
|
page,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
await u.waitForPageLoad()
|
|
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
|
|
// Ensure we execute the first time.
|
|
await u.openDebugPanel()
|
|
await expect(
|
|
page.locator('[data-receive-command-type="scene_clear_all"]')
|
|
).toHaveCount(1)
|
|
await expect(
|
|
page.locator('[data-message-type="execution-done"]')
|
|
).toHaveCount(2)
|
|
|
|
// Add whitespace to the end of the code.
|
|
await u.codeLocator.click()
|
|
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('End')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.type('const x = 1')
|
|
await page.keyboard.press('Enter')
|
|
|
|
await u.openDebugPanel()
|
|
await expect(
|
|
page.locator('[data-message-type="execution-done"]')
|
|
).toHaveCount(3)
|
|
await expect(
|
|
page.locator('[data-receive-command-type="scene_clear_all"]')
|
|
).toHaveCount(1)
|
|
})
|
|
|
|
test('if you click the format button it formats your code', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
await page.locator('#code-pane button:first-child').click()
|
|
await page.locator('button:has-text("Format code")').click()
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
})
|
|
|
|
test('if you click the format button it formats your code and executes so lints are still there', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type(`sketch_001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
|
|
await u.openDebugPanel()
|
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
await u.closeDebugPanel()
|
|
|
|
// error in guter
|
|
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
|
|
|
// error text on hover
|
|
await page.hover('.cm-lint-marker-info')
|
|
await expect(
|
|
page.getByText('Identifiers must be lowerCamelCase').first()
|
|
).toBeVisible()
|
|
|
|
await page.locator('#code-pane button:first-child').click()
|
|
await page.locator('button:has-text("Format code")').click()
|
|
|
|
await u.openDebugPanel()
|
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
await u.closeDebugPanel()
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch_001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
|
|
// error in guter
|
|
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
|
|
|
// error text on hover
|
|
await page.hover('.cm-lint-marker-info')
|
|
await expect(
|
|
page.getByText('Identifiers must be lowerCamelCase').first()
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('fold gutters work', async ({ page, homePage }) => {
|
|
const fullCode = `sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`
|
|
await page.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`
|
|
)
|
|
})
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// TODO: Jess needs to fix this but you have to mod the code to get them to show
|
|
// up, its an annoying codemirror thing.
|
|
await page.locator('.cm-content').click()
|
|
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')
|
|
|
|
const foldGutterFoldLine = page.locator('[title="Fold line"]')
|
|
const foldGutterUnfoldLine = page.locator('[title="Unfold line"]')
|
|
|
|
await expect(page.locator('.cm-content')).toHaveText(fullCode)
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
// Make sure we have a fold gutter
|
|
await expect(foldGutterFoldLine).toBeVisible()
|
|
await expect(foldGutterUnfoldLine).not.toBeVisible()
|
|
|
|
// Collapse the code
|
|
await foldGutterFoldLine.click()
|
|
|
|
await expect(page.locator('.cm-content')).toHaveText(
|
|
`sketch001 = startSketchOn('XY')… `
|
|
)
|
|
await expect(page.locator('.cm-content')).not.toHaveText(fullCode)
|
|
await expect(foldGutterFoldLine).not.toBeVisible()
|
|
await expect(foldGutterUnfoldLine.nth(1)).toBeVisible()
|
|
|
|
// Expand the code
|
|
await foldGutterUnfoldLine.nth(1).click()
|
|
await expect(page.locator('.cm-content')).toHaveText(fullCode)
|
|
|
|
// Delete all the code.
|
|
await page.locator('.cm-content').click()
|
|
// Select all
|
|
await page.keyboard.press('ControlOrMeta+A')
|
|
await page.keyboard.press('Backspace')
|
|
|
|
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
await expect(page.locator('.cm-content')).not.toHaveText(fullCode)
|
|
|
|
await expect(foldGutterUnfoldLine).not.toBeVisible()
|
|
await expect(foldGutterFoldLine).not.toBeVisible()
|
|
})
|
|
|
|
test('hover over functions shows function description', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`
|
|
)
|
|
})
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
await u.openDebugPanel()
|
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
await u.closeDebugPanel()
|
|
|
|
// focus the editor
|
|
await u.codeLocator.click()
|
|
|
|
// Hover over the startSketchOn function
|
|
await page.getByText('startSketchOn').hover()
|
|
await expect(page.locator('.hover-tooltip')).toBeVisible()
|
|
await expect(
|
|
page.getByText(
|
|
'Start a new 2-dimensional sketch on a specific plane or face'
|
|
)
|
|
).toBeVisible()
|
|
|
|
// Hover over the line function
|
|
await page.getByText('line').first().hover()
|
|
await expect(page.locator('.hover-tooltip')).toBeVisible()
|
|
await expect(
|
|
page.getByText('Extend the current sketch with a new straight line.')
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('if you use the format keyboard binding it formats your code', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`
|
|
)
|
|
localStorage.setItem('disableAxis', 'true')
|
|
})
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
await u.openDebugPanel()
|
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
await u.closeDebugPanel()
|
|
|
|
// focus the editor
|
|
await u.codeLocator.click()
|
|
|
|
// Hit alt+shift+f to format the code
|
|
await page.keyboard.press('Alt+Shift+KeyF')
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
})
|
|
|
|
test('if you use the format keyboard binding it formats your code and executes so lints are shown', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`sketch_001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`
|
|
)
|
|
localStorage.setItem('disableAxis', 'true')
|
|
})
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
await u.openDebugPanel()
|
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
await u.closeDebugPanel()
|
|
|
|
// error in guter
|
|
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
|
|
|
// error text on hover
|
|
await page.hover('.cm-lint-marker-info')
|
|
await expect(
|
|
page.getByText('Identifiers must be lowerCamelCase').first()
|
|
).toBeVisible()
|
|
|
|
// focus the editor
|
|
await u.codeLocator.click()
|
|
|
|
// Hit alt+shift+f to format the code
|
|
await page.keyboard.press('Alt+Shift+KeyF')
|
|
|
|
await u.openDebugPanel()
|
|
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
await u.closeDebugPanel()
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch_001 = startSketchOn('XY')
|
|
|> startProfileAt([-10, -10], %)
|
|
|> line(end = [20, 0])
|
|
|> line(end = [0, 20])
|
|
|> line(end = [-20, 0])
|
|
|> close()`)
|
|
|
|
// error in guter
|
|
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
|
|
|
// error text on hover
|
|
await page.hover('.cm-lint-marker-info')
|
|
await expect(
|
|
page.getByText('Identifiers must be lowerCamelCase').first()
|
|
).toBeVisible()
|
|
})
|
|
|
|
test('if you write kcl with lint errors you get lints', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible()
|
|
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type('my_snake_case_var = 5')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.type('myCamelCaseVar = 5')
|
|
await page.keyboard.press('Enter')
|
|
|
|
// press arrows to clear autocomplete
|
|
await page.keyboard.press('ArrowLeft')
|
|
await page.keyboard.press('ArrowRight')
|
|
|
|
// error in guter
|
|
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
|
|
|
// error text on hover
|
|
await page.hover('.cm-lint-marker-info')
|
|
await expect(
|
|
page.getByText('Identifiers must be lowerCamelCase').first()
|
|
).toBeVisible()
|
|
|
|
// select the line that's causing the error and delete it
|
|
await page.getByText('my_snake_case_var = 5').click()
|
|
await page.keyboard.press('End')
|
|
await page.keyboard.down('Shift')
|
|
await page.keyboard.press('Home')
|
|
await page.keyboard.up('Shift')
|
|
await page.keyboard.press('Backspace')
|
|
|
|
// wait for .cm-lint-marker-info not to be visible
|
|
await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible()
|
|
})
|
|
|
|
test('if you fixup kcl errors you clear lints', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([3.29, 7.86], %)
|
|
|> line(end = [2.48, 2.44])
|
|
|> line(end = [2.66, 1.17])
|
|
|> close()
|
|
`
|
|
)
|
|
})
|
|
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
await u.codeLocator.click()
|
|
|
|
await page.getByText(' |> line(end = [2.48, 2.44])').click()
|
|
|
|
await expect(
|
|
page.locator('.cm-lint-marker-error').first()
|
|
).not.toBeVisible()
|
|
await page.keyboard.press('End')
|
|
await page.keyboard.press('Backspace')
|
|
|
|
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
|
|
await page.keyboard.type(')')
|
|
await expect(
|
|
page.locator('.cm-lint-marker-error').first()
|
|
).not.toBeVisible()
|
|
})
|
|
|
|
test('if you write invalid kcl you get inlined errors', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// check no error to begin with
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
/* add the following code to the editor (~ error is not a valid line)
|
|
* the old check here used $ but this is for tags so it changed meaning.
|
|
* hopefully ~ doesn't change meaning
|
|
~ error
|
|
const topAng = 30
|
|
const bottomAng = 25
|
|
*/
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type('~ error')
|
|
|
|
// press arrows to clear autocomplete
|
|
await page.keyboard.press('ArrowLeft')
|
|
await page.keyboard.press('ArrowRight')
|
|
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.type('topAng = 30')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.type('bottomAng = 25')
|
|
await page.keyboard.press('Enter')
|
|
|
|
// error in guter
|
|
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
|
|
// error text on hover
|
|
await page.hover('.cm-lint-marker-error')
|
|
await expect(
|
|
page.getByText("found unknown token '~'").first()
|
|
).toBeVisible()
|
|
|
|
// select the line that's causing the error and delete it
|
|
await page.getByText('~ error').click()
|
|
await page.keyboard.press('End')
|
|
await page.keyboard.down('Shift')
|
|
await page.keyboard.press('Home')
|
|
await page.keyboard.up('Shift')
|
|
await page.keyboard.press('Backspace')
|
|
|
|
// wait for .cm-lint-marker-error not to be visible
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
|
|
// let's check we get an error when defining the same variable twice
|
|
await page.getByText('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('topAng = 42')
|
|
await page.keyboard.press('ArrowLeft')
|
|
|
|
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
await expect(
|
|
page.locator('.cm-lint-marker.cm-lint-marker-error')
|
|
).toBeVisible()
|
|
|
|
await page.locator('.cm-lint-marker.cm-lint-marker-error').hover()
|
|
await expect(page.locator('.cm-diagnosticText').first()).toBeVisible()
|
|
await expect(
|
|
page.getByText('Cannot redefine `topAng`').first()
|
|
).toBeVisible()
|
|
|
|
const secondTopAng = page.getByText('topAng').first()
|
|
await secondTopAng?.dblclick()
|
|
await page.keyboard.type('otherAng')
|
|
|
|
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
})
|
|
|
|
test.fixme(
|
|
'error with 2 source ranges gets 2 diagnostics',
|
|
async ({ page, homePage }) => {
|
|
const u = await getUtils(page)
|
|
await page.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`length = .750
|
|
width = 0.500
|
|
height = 0.500
|
|
dia = 4
|
|
|
|
fn squareHole = (l, w) => {
|
|
squareHoleSketch = startSketchOn('XY')
|
|
|> startProfileAt([-width / 2, -length / 2], %)
|
|
|> line(endAbsolute = [width / 2, -length / 2])
|
|
|> line(endAbsolute = [width / 2, length / 2])
|
|
|> line(endAbsolute = [-width / 2, length / 2])
|
|
|> close()
|
|
return squareHoleSketch
|
|
}
|
|
`
|
|
)
|
|
})
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
await u.waitForPageLoad()
|
|
await page.waitForTimeout(1000)
|
|
|
|
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 u.codeLocator.click()
|
|
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(`extrusion = startSketchOn('XY')
|
|
|> circle({ center: [0, 0], radius: dia/2 }, %)
|
|
|> hole(squareHole(length, width, height), %)
|
|
|> extrude(length = 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').first()
|
|
).toBeVisible()
|
|
|
|
// Make sure there are two diagnostics
|
|
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2)
|
|
}
|
|
)
|
|
test('if your kcl gets an error from the engine it is inlined', async ({
|
|
context,
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
await context.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`box = startSketchOn('XY')
|
|
|> startProfileAt([0, 0], %)
|
|
|> line(end = [0, 10])
|
|
|> line(end = [10, 0])
|
|
|> line(end = [0, -10], tag = $revolveAxis)
|
|
|> close()
|
|
|> extrude(length = 10)
|
|
|
|
sketch001 = startSketchOn(box, revolveAxis)
|
|
|> startProfileAt([5, 10], %)
|
|
|> line(end = [0, -10])
|
|
|> line(end = [2, 0])
|
|
|> line(end = [0, -10])
|
|
|> close()
|
|
|> revolve({
|
|
axis: revolveAxis,
|
|
angle: 90
|
|
}, %)
|
|
`
|
|
)
|
|
})
|
|
|
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
|
|
// error text on hover
|
|
await page.hover('.cm-lint-marker-error')
|
|
const searchText =
|
|
'sketch profile must lie entirely on one side of the revolution axis'
|
|
await expect(page.getByText(searchText)).toBeVisible()
|
|
})
|
|
test.describe('Autocomplete works', () => {
|
|
test('with enter/click to accept the completion', async ({
|
|
page,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// tests clicking on an option, selection the first option
|
|
// and arrowing down to an option
|
|
|
|
await u.codeLocator.click()
|
|
await page.keyboard.type('sketch001 = start')
|
|
|
|
// expect there to be some auto complete options
|
|
// exact number depends on the KCL stdlib, so let's just check it's > 0 for now.
|
|
await expect(async () => {
|
|
const children = await page.locator('.cm-completionLabel').count()
|
|
expect(children).toBeGreaterThan(0)
|
|
}).toPass()
|
|
// this makes sure we can accept a completion with click
|
|
await page.getByText('startSketchOn').click()
|
|
await page.keyboard.type("'XZ'")
|
|
await page.keyboard.press('Tab')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.type(' |> startProfi')
|
|
// expect there be a single auto complete option that we can just hit enter on
|
|
await expect(page.locator('.cm-completionLabel')).toBeVisible()
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Enter') // accepting the auto complete, not a new line
|
|
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.type('12')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Enter')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.type(' |> lin')
|
|
|
|
await expect(page.locator('.cm-tooltip-autocomplete')).toBeVisible()
|
|
await page.waitForTimeout(100)
|
|
// press arrow down then enter to accept xLine
|
|
await page.keyboard.press('ArrowDown')
|
|
await page.keyboard.press('Enter')
|
|
// finish line with comment
|
|
await page.keyboard.type('5')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
|
|
await page.keyboard.type(' // ')
|
|
// Since we need to parse the ast to know we are in a comment we gotta hang tight.
|
|
await page.waitForTimeout(700)
|
|
await page.keyboard.type('lin ')
|
|
await page.waitForTimeout(200)
|
|
// there shouldn't be any auto complete options for 'lin' in the comment
|
|
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([3.14, 12], %)
|
|
|> xLine(5, %) // lin`)
|
|
|
|
// expect there to be no KCL errors
|
|
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0)
|
|
})
|
|
|
|
test('with tab to accept the completion', async ({ page, homePage }) => {
|
|
const u = await getUtils(page)
|
|
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
|
|
// 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 u.codeLocator.click()
|
|
await page.keyboard.type('sketch001 = startSketchO')
|
|
await page.waitForTimeout(100)
|
|
|
|
// Make sure just hitting tab will take the only one left
|
|
await expect(page.locator('.cm-completionLabel')).toHaveCount(1)
|
|
await page.waitForTimeout(500)
|
|
await page.keyboard.press('ArrowDown')
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(500)
|
|
await page.keyboard.type("'XZ'")
|
|
await page.keyboard.press('Tab')
|
|
await page.keyboard.press('Enter')
|
|
await page.keyboard.type(' |> startProfi')
|
|
// expect there be a single auto complete option that we can just hit enter on
|
|
await expect(page.locator('.cm-completionLabel')).toBeVisible()
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab') // accepting the auto complete, not a new line
|
|
|
|
await page.keyboard.press('Tab')
|
|
await page.keyboard.type('12')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Enter')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.type(' |> lin')
|
|
|
|
await expect(page.locator('.cm-tooltip-autocomplete')).toBeVisible()
|
|
await page.waitForTimeout(100)
|
|
// press arrow down then tab to accept xLine
|
|
await page.keyboard.press('ArrowDown')
|
|
await page.keyboard.press('Tab')
|
|
// finish line with comment
|
|
await page.keyboard.type('5')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
await page.waitForTimeout(100)
|
|
await page.keyboard.press('Tab')
|
|
|
|
await page.keyboard.type(' // ')
|
|
// Since we need to parse the ast to know we are in a comment we gotta hang tight.
|
|
await page.waitForTimeout(700)
|
|
await page.keyboard.type('lin ')
|
|
await page.waitForTimeout(200)
|
|
// there shouldn't be any auto complete options for 'lin' in the comment
|
|
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([3.14, 12], %)
|
|
|> xLine(5, %) // lin`)
|
|
})
|
|
})
|
|
test('Can undo a click and point extrude with ctrl+z', async ({
|
|
page,
|
|
context,
|
|
homePage,
|
|
}) => {
|
|
const u = await getUtils(page)
|
|
await context.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([4.61, -14.01], %)
|
|
|> line(end = [12.73, -0.09])
|
|
|> tangentialArcTo([24.95, -5.38], %)
|
|
|> close()`
|
|
)
|
|
})
|
|
|
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
await expect(
|
|
page.getByRole('button', { name: 'Start Sketch' })
|
|
).not.toBeDisabled()
|
|
|
|
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)
|
|
|
|
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
|
|
await expect(page.getByRole('button', { name: 'Extrude' })).toBeVisible()
|
|
await page.getByRole('button', { name: 'Extrude' }).click()
|
|
|
|
await expect(page.getByTestId('command-bar')).toBeVisible()
|
|
await page.waitForTimeout(100)
|
|
|
|
await page.getByRole('button', { name: 'arrow right Continue' }).click()
|
|
await page.waitForTimeout(100)
|
|
await expect(page.getByText('Confirm Extrude')).toBeVisible()
|
|
await page.getByRole('button', { name: 'checkmark Submit command' }).click()
|
|
await page.waitForTimeout(100)
|
|
|
|
// expect the code to have changed
|
|
await expect(page.locator('.cm-content')).toHaveText(
|
|
`sketch001 = startSketchOn('XZ') |> startProfileAt([4.61, -14.01], %) |> line(end = [12.73, -0.09]) |> tangentialArcTo([24.95, -5.38], %) |> close()extrude001 = extrude(sketch001, length = 5)`
|
|
)
|
|
|
|
// Now hit undo
|
|
await page.keyboard.down('Control')
|
|
await page.keyboard.press('KeyZ')
|
|
await page.keyboard.up('Control')
|
|
|
|
await page.waitForTimeout(100)
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([4.61, -14.01], %)
|
|
|> line(end = [12.73, -0.09])
|
|
|> tangentialArcTo([24.95, -5.38], %)
|
|
|> close()`)
|
|
})
|
|
|
|
test(
|
|
'Can undo a sketch modification with ctrl+z',
|
|
{ tag: ['@skipWin'] },
|
|
async ({ page, homePage }) => {
|
|
const u = await getUtils(page)
|
|
await page.addInitScript(async () => {
|
|
localStorage.setItem(
|
|
'persistCode',
|
|
`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([4.61, -10.01], %)
|
|
|> line(end = [12.73, -0.09])
|
|
|> tangentialArcTo([24.95, -0.38], %)
|
|
|> close()
|
|
|> extrude(length = 5)`
|
|
)
|
|
})
|
|
|
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
|
|
|
await homePage.goToModelingScene()
|
|
await expect(
|
|
page.getByRole('button', { name: 'Start Sketch' })
|
|
).not.toBeDisabled()
|
|
|
|
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)
|
|
|
|
const startPX = [1200 / 2, 500 / 2]
|
|
|
|
const dragPX = 40
|
|
|
|
await page.getByText('startProfileAt([4.61, -10.01], %)').click()
|
|
await expect(
|
|
page.getByRole('button', { name: 'Edit Sketch' })
|
|
).toBeVisible()
|
|
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
|
await page.waitForTimeout(400)
|
|
let prevContent = await page.locator('.cm-content').innerText()
|
|
|
|
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
|
|
|
|
// drag startProfileAt handle
|
|
await page.dragAndDrop('#stream', '#stream', {
|
|
sourcePosition: { x: startPX[0] + 68, y: startPX[1] + 147 },
|
|
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
|
|
})
|
|
await page.waitForTimeout(100)
|
|
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
|
prevContent = await page.locator('.cm-content').innerText()
|
|
|
|
// drag line handle
|
|
// we wait so it saves the code
|
|
await page.waitForTimeout(800)
|
|
|
|
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
|
|
await page.waitForTimeout(100)
|
|
await page.dragAndDrop('#stream', '#stream', {
|
|
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
|
|
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
|
|
})
|
|
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
|
prevContent = await page.locator('.cm-content').innerText()
|
|
|
|
// we wait so it saves the code
|
|
await page.waitForTimeout(800)
|
|
|
|
// drag tangentialArcTo handle
|
|
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
|
await page.dragAndDrop('#stream', '#stream', {
|
|
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
|
|
targetPosition: {
|
|
x: tangentEnd.x + dragPX,
|
|
y: tangentEnd.y + dragPX,
|
|
},
|
|
})
|
|
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'))
|
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([2.71, -2.71], %)
|
|
|> line(end = [15.4, -2.78])
|
|
|> tangentialArcTo([27.6, -3.05], %)
|
|
|> close()
|
|
|> extrude(length = 5)
|
|
`)
|
|
|
|
// Hit undo
|
|
await page.keyboard.down('Control')
|
|
await page.keyboard.press('KeyZ')
|
|
await page.keyboard.up('Control')
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([2.71, -2.71], %)
|
|
|> line(end = [15.4, -2.78])
|
|
|> tangentialArcTo([24.95, -0.38], %)
|
|
|> close()
|
|
|> extrude(length = 5)`)
|
|
|
|
// Hit undo again.
|
|
await page.keyboard.down('Control')
|
|
await page.keyboard.press('KeyZ')
|
|
await page.keyboard.up('Control')
|
|
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([2.71, -2.71], %)
|
|
|> line(end = [12.73, -0.09])
|
|
|> tangentialArcTo([24.95, -0.38], %)
|
|
|> close()
|
|
|> extrude(length = 5)
|
|
`)
|
|
|
|
// Hit undo again.
|
|
await page.keyboard.down('Control')
|
|
await page.keyboard.press('KeyZ')
|
|
await page.keyboard.up('Control')
|
|
|
|
await page.waitForTimeout(100)
|
|
await expect(page.locator('.cm-content'))
|
|
.toHaveText(`sketch001 = startSketchOn('XZ')
|
|
|> startProfileAt([4.61, -10.01], %)
|
|
|> line(end = [12.73, -0.09])
|
|
|> tangentialArcTo([24.95, -0.38], %)
|
|
|> close()
|
|
|> extrude(length = 5)`)
|
|
}
|
|
)
|
|
|
|
test.fixme(
|
|
`Can use the import stdlib function on a local OBJ file`,
|
|
{ tag: '@electron' },
|
|
async ({ page, context }, testInfo) => {
|
|
await context.folderSetupFn(async (dir) => {
|
|
const bracketDir = join(dir, 'cube')
|
|
await fsp.mkdir(bracketDir, { recursive: true })
|
|
await fsp.copyFile(
|
|
executorInputPath('cube.obj'),
|
|
join(bracketDir, 'cube.obj')
|
|
)
|
|
await fsp.writeFile(join(bracketDir, 'main.kcl'), '')
|
|
})
|
|
|
|
const viewportSize = { width: 1200, height: 500 }
|
|
await page.setBodyDimensions(viewportSize)
|
|
|
|
// Locators and constants
|
|
const u = await getUtils(page)
|
|
const projectLink = page.getByRole('link', { name: 'cube' })
|
|
const gizmo = page.locator('[aria-label*=gizmo]')
|
|
const resetCameraButton = page.getByRole('button', { name: 'Reset view' })
|
|
const locationToHavColor = async (
|
|
position: { x: number; y: number },
|
|
color: [number, number, number]
|
|
) => {
|
|
return u.getGreatestPixDiff(position, color)
|
|
}
|
|
const notTheOrigin = {
|
|
x: viewportSize.width * 0.55,
|
|
y: viewportSize.height * 0.3,
|
|
}
|
|
const origin = { x: viewportSize.width / 2, y: viewportSize.height / 2 }
|
|
const errorIndicators = page.locator('.cm-lint-marker-error')
|
|
|
|
await test.step(`Open the empty file, see the default planes`, async () => {
|
|
await projectLink.click()
|
|
await u.waitForPageLoad()
|
|
await expect
|
|
.poll(
|
|
async () => locationToHavColor(notTheOrigin, darkModePlaneColorXZ),
|
|
{
|
|
timeout: 5000,
|
|
message: 'XZ plane color is visible',
|
|
}
|
|
)
|
|
.toBeLessThan(15)
|
|
})
|
|
await test.step(`Write the import function line`, async () => {
|
|
await u.codeLocator.fill(`import('cube.obj')`)
|
|
await page.waitForTimeout(800)
|
|
})
|
|
await test.step(`Reset the camera before checking`, async () => {
|
|
await u.doAndWaitForCmd(async () => {
|
|
await gizmo.click({ button: 'right' })
|
|
await resetCameraButton.click()
|
|
}, 'zoom_to_fit')
|
|
})
|
|
await test.step(`Verify that we see the imported geometry and no errors`, async () => {
|
|
await expect(errorIndicators).toHaveCount(0)
|
|
await expect
|
|
.poll(async () => locationToHavColor(origin, darkModePlaneColorXZ), {
|
|
timeout: 3000,
|
|
message: 'Plane color should not be visible',
|
|
})
|
|
.toBeGreaterThan(15)
|
|
await expect
|
|
.poll(async () => locationToHavColor(origin, darkModeBgColor), {
|
|
timeout: 3000,
|
|
message: 'Background color should not be visible',
|
|
})
|
|
.toBeGreaterThan(15)
|
|
})
|
|
}
|
|
)
|
|
})
|