Compare commits

...

17 Commits

Author SHA1 Message Date
b5bcb8a5ff fmt tsc lint 2025-03-04 18:53:18 -05:00
5e72da5770 Give snapshotter a better chance of getting a good snapshot 2025-03-04 18:48:11 -05:00
00be11f6d6 Had the wrong name 2025-03-03 15:25:03 -05:00
4fd53d527f Use single quotes for string 2025-03-03 15:06:41 -05:00
0f75d945b1 Do not run tests on dep install failure 2025-03-03 14:52:04 -05:00
9cc956ddff Explicitly set shell to bash for retry action in CI 2025-03-03 14:18:59 -05:00
dec74f633b Bump @codemirror/search from 6.5.6 to 6.5.10 (#5596)
Bumps [@codemirror/search](https://github.com/codemirror/search) from 6.5.6 to 6.5.10.
- [Changelog](https://github.com/codemirror/search/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/search/compare/6.5.6...6.5.10)

---
updated-dependencies:
- dependency-name: "@codemirror/search"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 19:16:58 +00:00
dfcea282ec add export test so we dont break cli / kcl.py (#5553)
* add export test so we dont break cli / kcl.py

Signed-off-by: Jess Frazelle <github@jessfraz.com>

Overwrite created date (#5602)

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-03 18:26:01 +00:00
191dcf8bb0 Bump nick-fields/retry from 3.0.1 to 3.0.2 (#5589)
* Bump nick-fields/retry from 3.0.1 to 3.0.2

Bumps [nick-fields/retry](https://github.com/nick-fields/retry) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/nick-fields/retry/releases)
- [Changelog](https://github.com/nick-fields/retry/blob/master/.releaserc.js)
- [Commits](https://github.com/nick-fields/retry/compare/v3.0.1...v3.0.2)

---
updated-dependencies:
- dependency-name: nick-fields/retry
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-03 10:08:37 -08:00
cb1bbe4660 Bump tabled from 0.15.0 to 0.18.0 in /rust (#5593)
Bumps [tabled](https://github.com/zhiburt/tabled) from 0.15.0 to 0.18.0.
- [Changelog](https://github.com/zhiburt/tabled/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zhiburt/tabled/commits)

---
updated-dependencies:
- dependency-name: tabled
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 10:05:50 -08:00
ff66cb1deb Bump parse-display from 0.9.1 to 0.10.0 in /rust (#5595)
Bumps [parse-display](https://github.com/frozenlib/parse-display) from 0.9.1 to 0.10.0.
- [Changelog](https://github.com/frozenlib/parse-display/blob/master/CHANGELOG.md)
- [Commits](https://github.com/frozenlib/parse-display/compare/v0.9.1...v0.10.0)

---
updated-dependencies:
- dependency-name: parse-display
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 10:05:21 -08:00
ab46349d63 Bump @codemirror/autocomplete from 6.17.0 to 6.18.6 in /packages/codemirror-lsp-client (#5601)
* Bump @codemirror/autocomplete in /packages/codemirror-lsp-client

Bumps [@codemirror/autocomplete](https://github.com/codemirror/autocomplete) from 6.17.0 to 6.18.6.
- [Changelog](https://github.com/codemirror/autocomplete/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/autocomplete/compare/6.17.0...6.18.6)

---
updated-dependencies:
- dependency-name: "@codemirror/autocomplete"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-03 10:04:44 -08:00
cffad78bf7 Bump convert_case from 0.6.0 to 0.8.0 in /rust (#5591)
* Bump convert_case from 0.6.0 to 0.8.0 in /rust

Bumps [convert_case](https://github.com/rutrum/convert-case) from 0.6.0 to 0.8.0.
- [Commits](https://github.com/rutrum/convert-case/commits)

---
updated-dependencies:
- dependency-name: convert_case
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-03 10:03:47 -08:00
bfb81877d3 Bump husky from 9.1.5 to 9.1.7 (#5597)
Bumps [husky](https://github.com/typicode/husky) from 9.1.5 to 9.1.7.
- [Release notes](https://github.com/typicode/husky/releases)
- [Commits](https://github.com/typicode/husky/compare/v9.1.5...v9.1.7)

---
updated-dependencies:
- dependency-name: husky
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 10:03:15 -08:00
c56398db83 Bump @types/diff from 6.0.0 to 7.0.1 (#5599)
Bumps [@types/diff](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/diff) from 6.0.0 to 7.0.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/diff)

---
updated-dependencies:
- dependency-name: "@types/diff"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 10:02:57 -08:00
36e0d35968 Bump @codemirror/commands from 6.6.0 to 6.8.0 (#5600)
Bumps [@codemirror/commands](https://github.com/codemirror/commands) from 6.6.0 to 6.8.0.
- [Changelog](https://github.com/codemirror/commands/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/commands/compare/6.6.0...6.8.0)

---
updated-dependencies:
- dependency-name: "@codemirror/commands"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-03 10:02:09 -08:00
62bf7d8715 Pin Rust to 1.85 to fix CI (#5606)
* Make Rust 1.85 the default

* Less specific Rust ver

* Pin Rust 1.85 to -clippy and -fmt

* Pin Rust version

* Use Rust 1.85 in package.json
2025-03-03 09:57:31 -08:00
43 changed files with 411 additions and 298 deletions

View File

@ -132,8 +132,9 @@ jobs:
- name: yarn install
# Windows is picky sometimes and fails on fetch. Step takes about ~30s
uses: nick-fields/retry@v3.0.1
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 2
max_attempts: 3
command: yarn install
@ -183,8 +184,9 @@ jobs:
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.1
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 10
max_attempts: 3
command: yarn tronb:package:prod
@ -244,8 +246,9 @@ jobs:
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.1
uses: nick-fields/retry@v3.0.2
with:
shell: bash
timeout_minutes: 10
max_attempts: 3
command: yarn tronb:package:prod

View File

@ -22,8 +22,9 @@ jobs:
- name: Install latest rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
toolchain: 1.85
override: true
default: true
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1

View File

@ -29,8 +29,9 @@ jobs:
- name: Install latest rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
toolchain: 1.85
override: true
default: true
components: clippy
- name: Rust Cache

View File

@ -31,8 +31,9 @@ jobs:
- name: Install latest rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
toolchain: 1.85
override: true
default: true
components: rustfmt
- name: Rust Cache

View File

@ -19,8 +19,9 @@ jobs:
- name: Install latest rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
toolchain: 1.85
override: true
default: true
- name: Install vector
run: |
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh

View File

@ -51,6 +51,7 @@ jobs:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Install dependencies
id: deps-install
shell: bash
run: yarn
- name: Cache Playwright Browsers
@ -133,7 +134,7 @@ jobs:
# TODO: break this in its own job, for now it's not slowing down the overall execution as ubuntu is the quickest,
# but we could do better. This forces a large 1/1 shard of all 20 snapshot tests that runs in about 3 minutes.
run: |
PLATFORM=web yarn playwright test --config=playwright.config.ts --retries="3" --update-snapshots --grep=@snapshot --trace=on --shard=1/1
yarn test:snapshots
env:
CI: true
NODE_ENV: development
@ -193,9 +194,10 @@ jobs:
path: test-results/
- name: Run playwright/electron flow (with retries)
id: retry
if: ${{ !cancelled() && (success() || failure()) }}
uses: nick-fields/retry@v3.0.1
if: ${{ !cancelled() && steps.deps-install.outcome == 'success' }}
uses: nick-fields/retry@v3.0.2
with:
shell: bash
command: .github/ci-cd-scripts/playwright-electron.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{matrix.os}}
timeout_minutes: 30
max_attempts: 25

View File

@ -1,12 +1,14 @@
import type { Page, Locator } from '@playwright/test'
import { expect } from '@playwright/test'
import { expect } from '../zoo-test'
import { isArray, uuidv4 } from 'lib/utils'
import { CmdBarFixture } from './cmdBarFixture'
import {
closeDebugPanel,
doAndWaitForImageDiff,
getPixelRGBs,
openAndClearDebugPanel,
sendCustomCmd,
getUtils,
} from '../test-utils'
type MouseParams = {
@ -40,9 +42,13 @@ export class SceneFixture {
public page: Page
public streamWrapper!: Locator
public loadingIndicator!: Locator
public networkToggleConnected!: Locator
public startEditSketchBtn!: Locator
get exeIndicator() {
return this.page.getByTestId('model-state-indicator-execution-done')
return this.page
.getByTestId('model-state-indicator-execution-done')
.or(this.page.getByTestId('model-state-indicator-receive-reliable'))
}
constructor(page: Page) {
@ -70,7 +76,11 @@ export class SceneFixture {
this.page = page
this.streamWrapper = page.getByTestId('stream')
this.networkToggleConnected = page.getByTestId('network-toggle-ok')
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
this.startEditSketchBtn = page
.getByRole('button', { name: 'Start Sketch' })
.or(page.getByRole('button', { name: 'Edit Sketch' }))
}
makeMouseHelpers = (
@ -229,6 +239,27 @@ export class SceneFixture {
await expect(this.exeIndicator).toBeVisible({ timeout: 30000 })
}
connectionEstablished = async () => {
const timeout = 30000
await expect(this.networkToggleConnected).toBeVisible({ timeout })
}
settled = async (cmdBar: CmdBarFixture) => {
const u = await getUtils(this.page)
await cmdBar.openCmdBar()
await cmdBar.chooseCommand('Settings · app · show debug panel')
await cmdBar.selectOption({ name: 'on' }).click()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await this.waitForExecutionDone()
await expect(this.startEditSketchBtn).not.toBeDisabled()
await expect(this.startEditSketchBtn).toBeVisible()
}
expectPixelColor = async (
colour: [number, number, number] | [number, number, number][],
coords: { x: number; y: number },

View File

@ -1,4 +1,4 @@
import { test, expect } from '@playwright/test'
import { test, expect } from './zoo-test'
import { secrets } from './secrets'
import { Paths, doExport, getUtils } from './test-utils'
import { Models } from '@kittycad/lib'
@ -13,27 +13,10 @@ import {
TEST_SETTINGS_KEY,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { SceneFixture } from './fixtures/sceneFixture'
import { CmdBarFixture } from './fixtures/cmdBarFixture'
test.beforeEach(async ({ page }) => {
// reducedMotion kills animations, which speeds up tests and reduces flakiness
await page.emulateMedia({ reducedMotion: 'reduce' })
// set the default settings
await page.addInitScript(
async ({ token, settingsKey, settings, IS_PLAYWRIGHT_KEY }) => {
localStorage.setItem('TOKEN_PERSIST_KEY', token)
localStorage.setItem('persistCode', ``)
localStorage.setItem(settingsKey, settings)
localStorage.setItem(IS_PLAYWRIGHT_KEY, 'true')
},
{
token: secrets.token,
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({ settings: TEST_SETTINGS }),
IS_PLAYWRIGHT_KEY: IS_PLAYWRIGHT_KEY,
}
)
test.beforeEach(async ({ page, context }) => {
// Make the user avatar image always 404
// so we see the fallback menu icon for all snapshot tests
await page.route('https://lh3.googleusercontent.com/**', async (route) => {
@ -45,6 +28,14 @@ test.beforeEach(async ({ page }) => {
})
})
// Help engine-manager: tear shit down.
test.afterEach(async ({ page }) => {
await page.evaluate(() => {
// @ts-expect-error
window.tearDown()
})
})
test.setTimeout(60_000)
// We test this end to end already - getting this to work on web just to take
@ -54,7 +45,7 @@ test.setTimeout(60_000)
test.skip(
'exports of each format should work',
{ tag: ['@snapshot', '@skipWin', '@skipMacos'] },
async ({ page, context }) => {
async ({ page, context, scene, cmdBar }) => {
// 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)
@ -106,11 +97,8 @@ part001 = startSketchOn('-XZ')
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 scene.connectionEstablished()
await scene.settled(cmdBar)
const axisDirectionPair: Models['AxisDirectionPair_type'] = {
axis: 'z',
@ -313,8 +301,25 @@ part001 = startSketchOn('-XZ')
}
)
const extrudeDefaultPlane = async (context: any, page: any, plane: string) => {
await context.addInitScript(async () => {
const extrudeDefaultPlane = async (
context: any,
page: any,
cmdBar: CmdBarFixture,
scene: SceneFixture,
plane: string
) => {
const code = `part001 = startSketchOn('${plane}')
|> startProfileAt([7.00, 4.40], %)
|> line(end = [6.60, -0.20])
|> line(end = [2.80, 5.00])
|> line(end = [-5.60, 4.40])
|> line(end = [-5.40, -3.80])
|> close()
|> extrude(length = 10.00)
`
// This probably does absolutely nothing based on my trip through here.
await page.addInitScript(async () => {
localStorage.setItem(
'SETTINGS_PERSIST_KEY',
JSON.stringify({
@ -331,41 +336,17 @@ const extrudeDefaultPlane = async (context: any, page: any, plane: string) => {
)
})
const code = `part001 = startSketchOn('${plane}')
|> startProfileAt([7.00, 4.40], %)
|> line(end = [6.60, -0.20])
|> line(end = [2.80, 5.00])
|> line(end = [-5.60, 4.40])
|> line(end = [-5.40, -3.80])
|> close()
|> extrude(length = 10.00)
`
await page.addInitScript(async (code: string) => {
localStorage.setItem('persistCode', code)
})
}, code)
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await scene.connectionEstablished()
await scene.settled(cmdBar)
// wait for execution done
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await page.waitForTimeout(200)
// clear code
await u.removeCurrentCode()
await u.openAndClearDebugPanel()
await u.doAndWaitForImageDiff(
() => page.locator('.cm-content').fill(code),
200
)
// wait for execution done
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await u.closeKclCodePanel()
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
@ -380,28 +361,28 @@ test.describe(
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
test('XY', async ({ page, context }) => {
await extrudeDefaultPlane(context, page, 'XY')
test('XY', async ({ page, context, cmdBar, scene }) => {
await extrudeDefaultPlane(context, page, cmdBar, scene, 'XY')
})
test('XZ', async ({ page, context }) => {
await extrudeDefaultPlane(context, page, 'XZ')
test('XZ', async ({ page, context, cmdBar, scene }) => {
await extrudeDefaultPlane(context, page, cmdBar, scene, 'XZ')
})
test('YZ', async ({ page, context }) => {
await extrudeDefaultPlane(context, page, 'YZ')
test('YZ', async ({ page, context, cmdBar, scene }) => {
await extrudeDefaultPlane(context, page, cmdBar, scene, 'YZ')
})
test('-XY', async ({ page, context }) => {
await extrudeDefaultPlane(context, page, '-XY')
test('-XY', async ({ page, context, cmdBar, scene }) => {
await extrudeDefaultPlane(context, page, cmdBar, scene, '-XY')
})
test('-XZ', async ({ page, context }) => {
await extrudeDefaultPlane(context, page, '-XZ')
test('-XZ', async ({ page, context, cmdBar, scene }) => {
await extrudeDefaultPlane(context, page, cmdBar, scene, '-XZ')
})
test('-YZ', async ({ page, context }) => {
await extrudeDefaultPlane(context, page, '-YZ')
test('-YZ', async ({ page, context, cmdBar, scene }) => {
await extrudeDefaultPlane(context, page, cmdBar, scene, '-YZ')
})
}
)
@ -409,7 +390,7 @@ test.describe(
test(
'Draft segments should look right',
{ tag: '@snapshot' },
async ({ page, context }) => {
async ({ page, context, scene, cmdBar }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
@ -418,17 +399,9 @@ test(
const PUR = 400 / 37.5 //pixeltoUnitRatio
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
await scene.connectionEstablished()
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
@ -448,8 +421,9 @@ test(
await expect(page.locator('.cm-content')).toHaveText(code)
await page.waitForTimeout(100)
await u.closeDebugPanel()
await page.mouse.move(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(500)
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
@ -458,7 +432,7 @@ test(
const lineEndClick = () =>
page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await lineEndClick()
await page.waitForTimeout(100)
await page.waitForTimeout(500)
code += `
|> xLine(7.25, %)`
@ -469,18 +443,16 @@ test(
.click()
// click on the end of the profile to continue it
await page.waitForTimeout(300)
await page.waitForTimeout(500)
await lineEndClick()
await page.waitForTimeout(100)
await page.waitForTimeout(500)
// click to continue profile
await page.mouse.move(813, 392, { steps: 10 })
await page.waitForTimeout(100)
await page.waitForTimeout(500)
await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 })
await page.waitForTimeout(1000)
await expect(page).toHaveScreenshot({
maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
@ -491,7 +463,7 @@ test(
test(
'Draft rectangles should look right',
{ tag: '@snapshot' },
async ({ page, context }) => {
async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
@ -500,17 +472,10 @@ test(
const PUR = 400 / 37.5 //pixeltoUnitRatio
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
await scene.connectionEstablished()
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
@ -523,8 +488,8 @@ test(
`sketch001 = startSketchOn('XZ')`
)
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
await u.closeDebugPanel()
// Wait for camera animation
await page.waitForTimeout(2000)
const startXPx = 600
@ -548,7 +513,7 @@ test(
test(
'Draft circle should look right',
{ tag: '@snapshot' },
async ({ page, context }) => {
async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird.
// test.skip(process.platform === 'darwin', 'Skip on macos')
@ -557,17 +522,9 @@ test(
const PUR = 400 / 37.5 //pixeltoUnitRatio
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
await scene.connectionEstablished()
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
@ -580,8 +537,8 @@ test(
`sketch001 = startSketchOn('XZ')`
)
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
await u.closeDebugPanel()
// Wait for camera animation
await page.waitForTimeout(2000)
const startXPx = 600
@ -611,23 +568,15 @@ test.describe(
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
test('Inch scale', async ({ page }) => {
test('Inch scale', async ({ page, cmdBar, scene }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
await scene.connectionEstablished()
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
@ -639,7 +588,8 @@ test.describe(
let code = `sketch001 = startSketchOn('XZ')`
await expect(page.locator('.cm-content')).toHaveText(code)
await page.waitForTimeout(600) // TODO detect animation ending, or disable animation
// Wait for camera animation
await page.waitForTimeout(2000)
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
@ -647,8 +597,6 @@ test.describe(
await expect(u.codeLocator).toHaveText(code)
await page.waitForTimeout(100)
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
@ -683,17 +631,12 @@ test.describe(
mask: [page.getByTestId('model-state-indicator')],
})
// exit sketch
await u.openAndClearDebugPanel()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Exit Sketch' }).click(),
200
)
// wait for execution done
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await page.waitForTimeout(300)
await scene.settled(cmdBar)
// second screen shot should look almost identical, i.e. scale should be the same.
await expect(page).toHaveScreenshot({
@ -702,8 +645,8 @@ test.describe(
})
})
test('Millimeter scale', async ({ page }) => {
await page.addInitScript(
test('Millimeter scale', async ({ page, context, cmdBar, scene }) => {
await context.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
},
@ -725,17 +668,10 @@ test.describe(
const PUR = 400 / 37.5 //pixeltoUnitRatio
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeVisible()
await scene.connectionEstablished()
await scene.settled(cmdBar)
// click on "Start Sketch" button
await u.clearCommandLogs()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
200
@ -747,7 +683,8 @@ test.describe(
let code = `sketch001 = startSketchOn('XZ')`
await expect(u.codeLocator).toHaveText(code)
await page.waitForTimeout(600) // TODO detect animation ending, or disable animation
// Wait for camera animation
await page.waitForTimeout(2000)
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
@ -755,8 +692,6 @@ test.describe(
await expect(u.codeLocator).toHaveText(code)
await page.waitForTimeout(100)
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
@ -790,16 +725,12 @@ test.describe(
})
// exit sketch
await u.openAndClearDebugPanel()
await u.doAndWaitForImageDiff(
() => page.getByRole('button', { name: 'Exit Sketch' }).click(),
200
)
// wait for execution done
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await page.waitForTimeout(300)
await scene.settled(cmdBar)
// second screen shot should look almost identical, i.e. scale should be the same.
await expect(page).toHaveScreenshot({
@ -812,7 +743,7 @@ test.describe(
test(
'Sketch on face with none z-up',
{ tag: '@snapshot' },
async ({ page, context }) => {
async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
@ -840,12 +771,8 @@ part002 = startSketchOn(part001, seg01)
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
// wait for execution done
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(1, { timeout: 10_000 })
await u.closeDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
// Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished
@ -877,7 +804,7 @@ part002 = startSketchOn(part001, seg01)
test(
'Zoom to fit on load - solid 2d',
{ tag: '@snapshot' },
async ({ page, context }) => {
async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
@ -899,12 +826,8 @@ test(
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
// wait for execution done
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(1)
await u.closeDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
// Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished
@ -920,7 +843,7 @@ test(
test(
'Zoom to fit on load - solid 3d',
{ tag: '@snapshot' },
async ({ page, context }) => {
async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
@ -943,12 +866,8 @@ test(
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
// wait for execution done
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(1)
await u.closeDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
// Wait for the second extrusion to appear
// TODO: Find a way to truly know that the objects have finished
@ -965,7 +884,11 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
// FIXME: Skip on macos its being weird.
// test.skip(process.platform === 'darwin', 'Skip on macos')
test('Grid turned off to on via command bar', async ({ page }) => {
test('Grid turned off to on via command bar', async ({
page,
cmdBar,
scene,
}) => {
const u = await getUtils(page)
const stream = page.getByTestId('stream')
const mask = [
@ -978,12 +901,9 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
await page.goto('/')
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
// wait for execution done
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(1)
await u.closeDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await u.closeKclCodePanel()
// TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient.
@ -1033,7 +953,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
})
})
test('Grid turned off', async ({ page }) => {
test('Grid turned off', async ({ page, cmdBar, scene }) => {
const u = await getUtils(page)
const stream = page.getByTestId('stream')
const mask = [
@ -1046,12 +966,9 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
await page.goto('/')
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
// wait for execution done
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(1)
await u.closeDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await u.closeKclCodePanel()
// TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient.
@ -1063,8 +980,8 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
})
})
test('Grid turned on', async ({ page }) => {
await page.addInitScript(
test('Grid turned on', async ({ page, context, cmdBar, scene }) => {
await context.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
},
@ -1094,12 +1011,9 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
await page.goto('/')
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
// wait for execution done
await expect(
page.locator('[data-message-type="execution-done"]')
).toHaveCount(1)
await u.closeDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await u.closeKclCodePanel()
// TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient.
@ -1179,7 +1093,7 @@ test.fixme('theme persists', async ({ page, context }) => {
})
test.describe('code color goober', { tag: '@snapshot' }, () => {
test('code color goober', async ({ page, context }) => {
test('code color goober', async ({ page, context, scene, cmdBar }) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
@ -1213,19 +1127,22 @@ sweepSketch = startSketchOn('XY')
})
await page.setViewportSize({ width: 1200, height: 1000 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await expect(page, 'expect small color widget').toHaveScreenshot({
maxDiffPixels: 100,
})
})
test('code color goober opening window', async ({ page, context }) => {
test('code color goober opening window', async ({
page,
context,
scene,
cmdBar,
}) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
@ -1259,12 +1176,10 @@ sweepSketch = startSketchOn('XY')
})
await page.setViewportSize({ width: 1200, height: 1000 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.clearAndCloseDebugPanel()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await expect(page.locator('.cm-css-color-picker-wrapper')).toBeVisible()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -13,10 +13,10 @@
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.17.0",
"@codemirror/commands": "^6.6.0",
"@codemirror/commands": "^6.8.0",
"@codemirror/language": "^6.10.8",
"@codemirror/lint": "^6.8.4",
"@codemirror/search": "^6.5.6",
"@codemirror/search": "^6.5.10",
"@codemirror/state": "^6.4.1",
"@codemirror/theme-one-dark": "^6.1.2",
"@csstools/postcss-oklab-function": "^4.0.7",
@ -69,7 +69,7 @@
"yargs": "^17.7.2"
},
"scripts": {
"install:rust": "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y",
"install:rust": "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.85",
"install:rust:windows": "winget install Microsoft.VisualStudio.2022.Community --silent --override \"--wait --quiet --add ProductLang En-us --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended\" && winget install Rustlang.Rustup",
"install:wasm-pack:sh": ". $HOME/.cargo/env && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -y",
"install:wasm-pack:cargo": "cargo install wasm-pack",
@ -118,6 +118,7 @@
"tronb:package:prod": "yarn tronb:vite:prod && electron-builder --config electron-builder.yml --publish always",
"test-setup": "yarn install && yarn build:wasm",
"test": "vitest --mode development",
"test:snapshots": "PLATFORM=web NODE_ENV=development yarn playwright test --config=playwright.config.ts --update-snapshots --grep=@snapshot --trace=on --shard=1/1",
"test:unit": "vitest run --mode development --exclude **/kclSamples.test.ts",
"test:unit:kcl-samples": "vitest run --mode development ./src/lang/kclSamples.test.ts",
"test:playwright:electron": "playwright test --config=playwright.electron.config.ts --grep-invert='@snapshot'",
@ -164,7 +165,7 @@
"@playwright/test": "^1.49.0",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^15.0.2",
"@types/diff": "^6.0.0",
"@types/diff": "^7.0.1",
"@types/electron": "^1.6.10",
"@types/isomorphic-fetch": "^0.0.39",
"@types/minimist": "^1.2.5",
@ -197,7 +198,7 @@
"eslint-plugin-testing-library": "^7.1.1",
"happy-dom": "^16.3.0",
"http-server": "^14.1.1",
"husky": "^9.1.5",
"husky": "^9.1.7",
"kill-port": "^2.0.1",
"node-fetch": "^3.3.2",
"pixelmatch": "^5.3.0",

View File

@ -18,7 +18,7 @@
"license": "MIT",
"private": false,
"dependencies": {
"@codemirror/autocomplete": "6.17.0",
"@codemirror/autocomplete": "6.18.6",
"@codemirror/language": "^6.10.2",
"@codemirror/state": "^6.4.1",
"@lezer/highlight": "^1.2.0",

View File

@ -2,10 +2,10 @@
# yarn lockfile v1
"@codemirror/autocomplete@6.17.0":
version "6.17.0"
resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.17.0.tgz#24ff5fc37fd91f6439df6f4ff9c8e910cde1b053"
integrity sha512-fdfj6e6ZxZf8yrkMHUSJJir7OJkHkZKaOZGzLWIYp2PZ3jd+d+UjG8zVPqJF6d3bKxkhvXTPan/UZ1t7Bqm0gA==
"@codemirror/autocomplete@6.18.6":
version "6.18.6"
resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz#de26e864a1ec8192a1b241eb86addbb612964ddb"
integrity sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==
dependencies:
"@codemirror/language" "^6.0.0"
"@codemirror/state" "^6.0.0"

63
rust/Cargo.lock generated
View File

@ -472,7 +472,7 @@ version = "4.5.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c"
dependencies = [
"heck 0.5.0",
"heck",
"proc-macro2",
"quote",
"syn 2.0.96",
@ -525,9 +525,9 @@ dependencies = [
[[package]]
name = "convert_case"
version = "0.6.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
dependencies = [
"unicode-segmentation",
]
@ -1164,12 +1164,6 @@ version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
@ -1714,7 +1708,7 @@ dependencies = [
"measurements",
"miette",
"mime_guess",
"parse-display 0.9.1",
"parse-display 0.10.0",
"pretty_assertions",
"pyo3",
"regex",
@ -2212,13 +2206,13 @@ checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56"
[[package]]
name = "papergrid"
version = "0.11.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ad43c07024ef767f9160710b3a6773976194758c7919b17e63b863db0bdf7fb"
checksum = "b915f831b85d984193fdc3d3611505871dc139b2534530fa01c1a6a6707b6723"
dependencies = [
"bytecount",
"fnv",
"unicode-width 0.1.14",
"unicode-width 0.2.0",
]
[[package]]
@ -2475,30 +2469,6 @@ dependencies = [
"yansi",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro-error-attr2"
version = "2.0.0"
@ -2587,7 +2557,7 @@ version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe"
dependencies = [
"heck 0.5.0",
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
@ -3330,7 +3300,7 @@ version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck 0.5.0",
"heck",
"proc-macro2",
"quote",
"rustversion",
@ -3408,26 +3378,25 @@ dependencies = [
[[package]]
name = "tabled"
version = "0.15.0"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c998b0c8b921495196a48aabaf1901ff28be0760136e31604f7967b0792050e"
checksum = "121d8171ee5687a4978d1b244f7d99c43e7385a272185a2f1e1fa4dc0979d444"
dependencies = [
"papergrid",
"tabled_derive",
"unicode-width 0.1.14",
]
[[package]]
name = "tabled_derive"
version = "0.7.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c138f99377e5d653a371cdad263615634cfc8467685dfe8e73e2b8e98f44b17"
checksum = "52d9946811baad81710ec921809e2af67ad77719418673b2a3794932d57b7538"
dependencies = [
"heck 0.4.1",
"proc-macro-error",
"heck",
"proc-macro-error2",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.96",
]
[[package]]

View File

@ -13,7 +13,7 @@ proc-macro = true
[dependencies]
Inflector = "0.11.4"
convert_case = "0.6.0"
convert_case = "0.8.0"
once_cell = "1.20.2"
proc-macro2 = "1"
quote = "1"

View File

@ -20,7 +20,7 @@ clap = { version = "4.5.27", default-features = false, optional = true, features
"std",
"derive",
] }
convert_case = "0.6.0"
convert_case = "0.8.0"
dashmap = "6.1.0"
dhat = { version = "0.3", optional = true }
fnv = "1.0.7"
@ -39,7 +39,7 @@ lazy_static = "1.5.0"
measurements = "0.11.0"
miette = { workspace = true }
mime_guess = "2.0.5"
parse-display = "0.9.1"
parse-display = "0.10.0"
pyo3 = { workspace = true, optional = true }
regex = "1.11.1"
reqwest = { version = "0.12", default-features = false, features = [
@ -58,7 +58,7 @@ schemars = { version = "0.8.17", features = [
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = "0.10.8"
tabled = { version = "0.15.0", optional = true }
tabled = { version = "0.18.0", optional = true }
thiserror = "2.0.0"
toml = "0.8.19"
ts-rs = { version = "10.1.0", features = [

View File

@ -1,7 +1,7 @@
mod cache;
use kcl_lib::{
test_server::{execute_and_snapshot, execute_and_snapshot_no_auth},
test_server::{execute_and_export_step, execute_and_snapshot, execute_and_snapshot_no_auth},
ExecError, UnitLength,
};
@ -2081,3 +2081,17 @@ async fn kcl_test_ensure_nothing_left_in_batch_multi_file() {
assert!(ctx.engine.batch().read().await.is_empty());
assert!(ctx.engine.batch_end().read().await.is_empty());
}
#[tokio::test(flavor = "multi_thread")]
async fn kcl_test_exporting_step_file() {
// This tests export like how we do it in cli and kcl.py.
let code = kcl_input!("helix_defaults_negative_extrude");
let (_, _, files) = execute_and_export_step(code, UnitLength::Mm, None).await.unwrap();
for file in files {
expectorate::assert_contents(
format!("e2e/executor/outputs/helix_defaults_negative_extrude_{}", file.name),
std::str::from_utf8(&file.contents).unwrap(),
);
}
}

View File

@ -0,0 +1,80 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION((('zoo.dev export')), '2;1');
FILE_NAME('test.step', '2021-01-01T00:00:00Z', ('Test'), ('Zoo'), 'zoo.dev beta', 'zoo.dev', 'Test');
FILE_SCHEMA(('AP203_CONFIGURATION_CONTROLLED_3D_DESIGN_OF_MECHANICAL_PARTS_AND_ASSEMBLIES_MIM_LF'));
ENDSEC;
DATA;
#1 = (
LENGTH_UNIT()
NAMED_UNIT(*)
SI_UNIT($, .METRE.)
);
#2 = UNCERTAINTY_MEASURE_WITH_UNIT(0.00001, #1, 'DISTANCE_ACCURACY_VALUE', $);
#3 = (
GEOMETRIC_REPRESENTATION_CONTEXT(3)
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#2))
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1))
REPRESENTATION_CONTEXT('', '3D')
);
#4 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
#5 = VERTEX_POINT('NONE', #4);
#6 = CARTESIAN_POINT('NONE', (0.015, 0, -0.005));
#7 = VERTEX_POINT('NONE', #6);
#8 = DIRECTION('NONE', (1, 0, -0));
#9 = DIRECTION('NONE', (0, 1, 0));
#10 = CARTESIAN_POINT('NONE', (0.005, -0.01, -0.005));
#11 = AXIS2_PLACEMENT_3D('NONE', #10, #9, #8);
#12 = CIRCLE('NONE', #11, 0.01);
#13 = DIRECTION('NONE', (0, 1, 0));
#14 = VECTOR('NONE', #13, 1);
#15 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
#16 = LINE('NONE', #15, #14);
#17 = DIRECTION('NONE', (1, 0, -0));
#18 = DIRECTION('NONE', (0, 1, 0));
#19 = CARTESIAN_POINT('NONE', (0.005, 0, -0.005));
#20 = AXIS2_PLACEMENT_3D('NONE', #19, #18, #17);
#21 = CIRCLE('NONE', #20, 0.01);
#22 = EDGE_CURVE('NONE', #5, #5, #12, .T.);
#23 = EDGE_CURVE('NONE', #5, #7, #16, .T.);
#24 = EDGE_CURVE('NONE', #7, #7, #21, .T.);
#25 = CARTESIAN_POINT('NONE', (0.005, -0.005, -0.005));
#26 = DIRECTION('NONE', (0, 1, 0));
#27 = DIRECTION('NONE', (1, 0, -0));
#28 = AXIS2_PLACEMENT_3D('NONE', #25, #26, #27);
#29 = CYLINDRICAL_SURFACE('NONE', #28, 0.01);
#30 = CARTESIAN_POINT('NONE', (0, -0.01, -0));
#31 = DIRECTION('NONE', (0, 1, 0));
#32 = AXIS2_PLACEMENT_3D('NONE', #30, #31, $);
#33 = PLANE('NONE', #32);
#34 = CARTESIAN_POINT('NONE', (0, 0, -0));
#35 = DIRECTION('NONE', (0, 1, 0));
#36 = AXIS2_PLACEMENT_3D('NONE', #34, #35, $);
#37 = PLANE('NONE', #36);
#38 = ORIENTED_EDGE('NONE', *, *, #22, .T.);
#39 = ORIENTED_EDGE('NONE', *, *, #24, .F.);
#40 = EDGE_LOOP('NONE', (#38));
#41 = FACE_BOUND('NONE', #40, .T.);
#42 = EDGE_LOOP('NONE', (#39));
#43 = FACE_BOUND('NONE', #42, .T.);
#44 = ADVANCED_FACE('NONE', (#41, #43), #29, .T.);
#45 = ORIENTED_EDGE('NONE', *, *, #22, .F.);
#46 = EDGE_LOOP('NONE', (#45));
#47 = FACE_BOUND('NONE', #46, .T.);
#48 = ADVANCED_FACE('NONE', (#47), #33, .F.);
#49 = ORIENTED_EDGE('NONE', *, *, #24, .T.);
#50 = EDGE_LOOP('NONE', (#49));
#51 = FACE_BOUND('NONE', #50, .T.);
#52 = ADVANCED_FACE('NONE', (#51), #37, .T.);
#53 = CLOSED_SHELL('NONE', (#44, #48, #52));
#54 = MANIFOLD_SOLID_BREP('NONE', #53);
#55 = APPLICATION_CONTEXT('configuration controlled 3D design of mechanical parts and assemblies');
#56 = PRODUCT_DEFINITION_CONTEXT('part definition', #55, 'design');
#57 = PRODUCT('UNIDENTIFIED_PRODUCT', 'NONE', $, ());
#58 = PRODUCT_DEFINITION_FORMATION('', $, #57);
#59 = PRODUCT_DEFINITION('design', $, #58, #56);
#60 = PRODUCT_DEFINITION_SHAPE('NONE', $, #59);
#61 = ADVANCED_BREP_SHAPE_REPRESENTATION('NONE', (#54), #3);
#62 = SHAPE_DEFINITION_REPRESENTATION(#60, #61);
ENDSEC;
END-ISO-10303-21;

View File

@ -20,6 +20,8 @@ pub enum ExecError {
Connection(#[from] ConnectionError),
#[error("PNG snapshot could not be decoded: {0}")]
BadPng(String),
#[error("Bad export: {0}")]
BadExport(String),
}
impl From<KclErrorWithOutputs> for ExecError {

View File

@ -129,3 +129,88 @@ pub async fn new_context(
.map_err(ConnectionError::Establishing)?;
Ok(ctx)
}
pub async fn execute_and_export_step(
code: &str,
units: UnitLength,
current_file: Option<PathBuf>,
) -> Result<
(
ExecState,
EnvironmentRef,
Vec<kittycad_modeling_cmds::websocket::RawFile>,
),
ExecErrorWithState,
> {
let ctx = new_context(units, true, current_file).await?;
let mut exec_state = ExecState::new(&ctx.settings);
let program = Program::parse_no_errs(code)
.map_err(|err| ExecErrorWithState::new(KclErrorWithOutputs::no_outputs(err).into(), exec_state.clone()))?;
let result = ctx
.run_with_ui_outputs(&program, &mut exec_state)
.await
.map_err(|err| ExecErrorWithState::new(err.into(), exec_state.clone()))?;
for e in exec_state.errors() {
if e.severity.is_err() {
return Err(ExecErrorWithState::new(
KclErrorWithOutputs::no_outputs(KclError::Semantic(e.clone().into())).into(),
exec_state.clone(),
));
}
}
let resp = ctx
.engine
.send_modeling_cmd(
uuid::Uuid::new_v4(),
crate::SourceRange::default(),
&kittycad_modeling_cmds::ModelingCmd::Export(kittycad_modeling_cmds::Export {
entity_ids: vec![],
format: kittycad_modeling_cmds::format::OutputFormat3d::Step(
kittycad_modeling_cmds::format::step::export::Options {
coords: *kittycad_modeling_cmds::coord::KITTYCAD,
// We want all to have the same timestamp.
created: Some(
chrono::DateTime::parse_from_rfc3339("2021-01-01T00:00:00Z")
.unwrap()
.into(),
),
},
),
}),
)
.await
.map_err(|err| ExecErrorWithState::new(KclErrorWithOutputs::no_outputs(err).into(), exec_state.clone()))?;
let kittycad_modeling_cmds::websocket::OkWebSocketResponseData::Export { mut files } = resp else {
return Err(ExecErrorWithState::new(
ExecError::BadExport(format!("Expected export response, got: {:?}", resp)),
exec_state.clone(),
));
};
for kittycad_modeling_cmds::websocket::RawFile { contents, .. } in &mut files {
use std::fmt::Write;
let utf8 = std::str::from_utf8(contents).unwrap();
let mut postprocessed = String::new();
for line in utf8.lines() {
if line.starts_with("FILE_NAME") {
let name = "test.step";
let time = "2021-01-01T00:00:00Z";
let author = "Test";
let org = "Zoo";
let version = "zoo.dev beta";
let system = "zoo.dev";
let authorization = "Test";
writeln!(&mut postprocessed, "FILE_NAME('{name}', '{time}', ('{author}'), ('{org}'), '{version}', '{system}', '{authorization}');").unwrap();
} else {
writeln!(&mut postprocessed, "{line}").unwrap();
}
}
*contents = postprocessed.into_bytes();
}
ctx.close().await;
Ok((exec_state, result.0, files))
}

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "1.85.0"
channel = "1.85"
components = ["clippy", "rustfmt"]

View File

@ -19,21 +19,25 @@ export interface ActionIconProps extends React.PropsWithChildren {
bgClassName?: string
iconClassName?: string
size?: keyof typeof iconSizes
'data-testid'?: string
}
export const ActionIcon = ({
icon = faCircleExclamation,
className,
bgClassName,
iconClassName,
size = 'md',
children,
}: ActionIconProps) => {
export const ActionIcon = (props: ActionIconProps) => {
const {
icon = faCircleExclamation,
className,
bgClassName,
iconClassName,
size = 'md',
children,
} = props
const computedIconClassName = `h-auto text-inherit dark:text-current group-disabled:text-chalkboard-60 group-disabled:text-chalkboard-60 ${iconClassName}`
const computedBgClassName = `bg-chalkboard-20 dark:bg-chalkboard-80 group-disabled:bg-chalkboard-30 dark:group-disabled:bg-chalkboard-80 ${bgClassName}`
return (
<div
data-testid={props['data-testid']}
className={
`w-fit self-stretch inline-grid place-content-center ${className} ` +
computedBgClassName

View File

@ -99,6 +99,9 @@ export const NetworkHealthIndicator = () => {
>
<ActionIcon
icon={overallConnectionStateIcon[overallState]}
data-testid={`network-toggle-${
overallState == NetworkHealthState.Ok ? 'ok' : 'other'
}`}
className="p-1"
iconClassName={overallConnectionStateColor[overallState].icon}
bgClassName={

View File

@ -1040,10 +1040,10 @@
"@codemirror/view" "^6.17.0"
"@lezer/common" "^1.0.0"
"@codemirror/commands@^6.0.0", "@codemirror/commands@^6.6.0":
version "6.6.0"
resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.6.0.tgz#d308f143fe1b8896ca25fdb855f66acdaf019dd4"
integrity sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==
"@codemirror/commands@^6.0.0", "@codemirror/commands@^6.8.0":
version "6.8.0"
resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.8.0.tgz#92f200b66f852939bd6ebb90d48c2d9e9c813d64"
integrity sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==
dependencies:
"@codemirror/language" "^6.0.0"
"@codemirror/state" "^6.4.0"
@ -1071,10 +1071,10 @@
"@codemirror/view" "^6.35.0"
crelt "^1.0.5"
"@codemirror/search@^6.0.0", "@codemirror/search@^6.5.6":
version "6.5.6"
resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.6.tgz#8f858b9e678d675869112e475f082d1e8488db93"
integrity sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==
"@codemirror/search@^6.0.0", "@codemirror/search@^6.5.10":
version "6.5.10"
resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.10.tgz#7367bfc88094d078b91c752bc74140fb565b55ee"
integrity sha512-RMdPdmsrUf53pb2VwflKGHEe1XVM07hI7vV2ntgw1dmqhimpatSJKva4VA9h4TLUDOD4EIF02201oZurpnEFsg==
dependencies:
"@codemirror/state" "^6.0.0"
"@codemirror/view" "^6.0.0"
@ -2276,10 +2276,10 @@
dependencies:
"@types/ms" "*"
"@types/diff@^6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@types/diff/-/diff-6.0.0.tgz#031f27cf57564f3cce825f38fb19fdd4349ad07a"
integrity sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==
"@types/diff@^7.0.1":
version "7.0.1"
resolved "https://registry.yarnpkg.com/@types/diff/-/diff-7.0.1.tgz#acc505eb2e8337ca400503283a6ab44a59906d9f"
integrity sha512-R/BHQFripuhW6XPXy05hIvXJQdQ4540KnTvEFHSLjXfHYM41liOLKgIJEyYYiQe796xpaMHfe4Uj/p7Uvng2vA==
"@types/electron@^1.6.10":
version "1.6.10"
@ -5743,10 +5743,10 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
husky@^9.1.5:
version "9.1.5"
resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.5.tgz#2b6edede53ee1adbbd3a3da490628a23f5243b83"
integrity sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==
husky@^9.1.7:
version "9.1.7"
resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d"
integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==
iconv-corefoundation@^1.1.7:
version "1.1.7"