Compare commits

...

274 Commits

Author SHA1 Message Date
f8f44743fa Bug fix: open project command lists project names (#5176)
* Amend project open test to show failing case

* Fix command config to use live context value

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

* Update src/lib/commandBarConfigs/projectsCommandConfig.ts

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

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

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-01-31 16:04:34 +00:00
f262eda12a Turn off snapshot commit bot (#5197)
Our team is actively investigating a recent spike in flaky WebRTC
connection behavior, which has impacted the web-only Playwright snapshot
tests particularly hard. The bot squashes other GH Actions in it's wake,
so I think we should turn it off so we can see the other E2E tests more
clearly
2025-01-31 10:57:52 -05:00
9e1136195a Fix: Center rectangle now works again, works with new LiteralValue structure (#5172)
* fix: new Literal data structure update

* fix: updated the LiteralValue dereferencing and added some type narrowing helpers

* fix: updating formatting

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

* fix: implementing a safer dereference method until we update createLiteraly()

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

* why is this fallback here

* fix: updating the type narrowing function

* fix: restore this... see if snapshots trigger again

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

* bump

* bump

* Add number with units formatting as KCL (#5195)

* Add number with units formatting as KCL

* Change type assertion helper to check what we need

* Fix rectangle unit test

* fix: adding a wait for execution to prevent clicking before lines are rendered

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-01-31 09:45:39 -06:00
4ff07ddaee Fix: Clearing sketch DOM elements after redirecting to the home page (#4965)
* fix: clear the previous DOM elements after page redirect

* fix: removed await delay since it can take awhile to destroy the sketch

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

* fix: added E2E test which actually caught a logic bug, moved the logic to the correct location

* fix: removing unused import

* fix: push main back...

* fix: restoring code to old state

* fix: moved cleanup code

* 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)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-31 07:01:51 -06:00
1e565379a7 allow setting units in subfiles/ turn on execution in modules (#5178)
* allow setting units in subfiles

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

* updates

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

* turn on execution in modules

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

* updates to tests

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

* updates

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

* cleanup bad snaps

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

* updates

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

* change some snapshots;

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

* fix tests

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-30 00:26:49 +00:00
76e34ac4da Ignore cloned kcl-samples (#5179) 2025-01-29 17:20:03 -05:00
4cd427bf91 fix: Remove link from code editor docs (#5170)
Remove link from the stdlib import() docs
2025-01-29 16:00:00 -05:00
f321ecdff0 add more unit names/abreevs (#5173)
* add more unit names

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

* typo

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-29 12:09:27 +11:00
d114ab798c fix subdirs (opening kcl-samples from kcl-samples dir) (#5171)
* WIP: Add the KCL file path into the executor

* reuse the stuff that works with settings.project_directory

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

* fixes on both sides

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

* fixes on both sides

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

* helper method

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

* fixes

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

* update kcl-samples tests to not change dirs

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

* update kcl-samples tests to not change dirs

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

* fmt

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-01-28 23:43:39 +00:00
69fec37107 prepare change in fillet api (#5168)
* updates

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

* bump version

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

* updates

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

* more snaps

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-28 22:22:19 +00:00
8ca8c49cc3 Fix to not error when using imported whole modules (#5161)
* Fix to not error when using imported whole modules

* Add TODO about adding a warning
2025-01-28 20:17:27 +00:00
b25fc302fd Support using import statements for non-KCL files (#5122)
* Improve checking of import paths

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Import path kinds in AST

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Use import statement for foreign files

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-01-29 08:28:32 +13:00
648b37c1dd Bump clap from 4.5.23 to 4.5.27 in /src/wasm-lib (#5152)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.23 to 4.5.27.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.23...clap_complete-v4.5.27)

---
updated-dependencies:
- dependency-name: clap
  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-01-27 21:29:09 +00:00
18e5da5ca4 bump modeling commands (#5145)
* add length unit

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

* new images

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-27 11:36:00 -08:00
46524cda10 Bump vite from 5.4.11 to 5.4.14 in /packages/codemirror-lang-kcl (#5128)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.11 to 5.4.14.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.14/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.14/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-27 17:22:19 +00:00
max
4585671a5d Refactor getNodePathFromSourceRange (#5139)
* Refactor getNodePathFromSourceRange

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

* Trigger CI

* 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)

* Trigger CI

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

* Trigger CI

* 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)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-27 08:24:28 -05:00
e7203b9e7a export ast visitor stubs (#5141) 2025-01-24 12:50:23 -05:00
ab375f4b92 Add in a Node::ptr_eq helper (#5140)
Add in a Node::ptr_eq helper

This looks a bit gross (I get it), but it's helpful when walking the
tree. It means we can construct nodes (via `into`) of borrows, and later
check to see if it's the same borrow later on if we need to walk the
tree multiple times or otherwise maintainer a pointer to a specific AST
entry.

The idea here is you could collect nodes, then traverse the tree again,
and know when you've reached the exact same node again.
2025-01-24 12:49:59 -05:00
04ed6f52ee Add ability to create and open URLs to create files (#4166)
* Rename `homeMachine` and accessories to `projectsMachine`

* Separate out `/home` route from `projectsMachine`

* Add logic to navigate out from deleted or renamed project

* Show a warning in the command palette for deleting a project

* Make it navigate when you create a project

* Update "New project" button to use command bar flow
Closes #2585

* More explicit warning message text

* Make projects watching code not run in web

* Tests first version: nested loops

* Tests second version: flattened

* Remove console logs

* Fix tsc

* @jtran feedback, use the type guard util

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Fix tests that relied on one-click, no-navigation project creation

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 7545b61b49.

* Revert "A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)"

This reverts commit 3d2e48732c.

* Add a mask to the state indicator to client-side scale test

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Fix lint

* Fix tsc

* Add menu item to share link to file

* Forward query params while redirecting to /home or /file

* Add (broken) event logic and command triggering logic

* Fix a couple stray tests that still relied on the old way of creating projects

* De-flake another text that could be thrown off by toast-based selectors

* FMT

* Dumb test error because I was rushing

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Ahhh more flaky toasts, they're everywhere!

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* Side quest: Only register commands once, power their disabled status while selecting commands via optional actor

* Get query-triggered command working in browser too

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* Tests always run on localhost, don't expect the prod origin

* rerun CI

* wip

* wip

* Everything's pretty much done but url.zoo.dev has been broken and we need to think about how to test reliably

* Merge branch 'main' into franknoirot/4088/create-file-url

* Add useCreateFileLinkQuery on Home page

* Get primary user flow working on desktop

* Rework to open browser app first, then send along to the desktop app if asked

* Styling updates to OpenInDesktopAppHandler

* Clean up unecessary file

* Merge branch 'main' into franknoirot/4088/create-file-url

* Separate creating `createFileUrl` and shortlink so it is unit testable

* Add E2E test for importing file from URL

* Add a couple component tests for OpenInDesktopAppHandler

* Fix the "existing project" user flow

* Add E2E test for "add to existing project" user flow

* Undo mistaken or unecessary changes

* Lints, fmt, tsc

* Fix unit test

* Fix broken rename and delete project commands
Something about the `optionsFromContext` config no longer works with file I/O-related commands. I suspect this has to do with our read/write loop patching

* Fix unit test, use kebab-case for url query param

* Use dev urls everywhere when configured that way

I think we were just using some constants that ended up returning bad
values for dev, it seemed to return a working shortlink when I went
through the flow.

* Clean up unneeded PROD_TOKEN

* Fix browser command flow, because we had made the projectMachine desktop-only on main

* Make the test executor a bit more patient (#5004)

* Fix so that all artifact commands are returned regardless of caching (#5005)

* Fix so that all artifact commands are returned regardless of caching

* Add some more docs and fix up old ones

* Add new lint to disallow use of confusing isNaN (#4999)

* Point-and-click Sweep (first PR) (#4989)

* Refactor 'Delete selection' as actor
Will fix #4662

* WIP logging

* WIP: working Solid3dGetExtrusionFaceInfo for loft

* Working wall deletion of loft

* Add offset plane deletion

* Add feature tree deletion of shell

* Clean up

* Revert "Clean up"

This reverts commit 214763cc2b.

* Clean up rust changes, taking the sketch with the most paths

* Working cap selection and deletion

* Clean up

* Add test for loft and offset plane deletion via selection

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

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

* Set reenter: false as it was originally

* Passing test

* Add shell deletion via feature tree test

* Revert the migration to promise actor

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

* Use cmd.id as solid_id after latest engine merge

* Add feature tree deletion of offset plane and fix lint

* Add feature tree deletion of loft

* Clean up

* Better comment

* Lint fix

* Remove sketch sorting

* WIP: sweep point-and-click

* Working sweep

* Add test

* Make sweep a development command

* Fix tsc error

* Clean up for review

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Upgrade typescript-eslint from 5.62.0 to 8.19.1 and remove eslint-config-react-app (#5006)

* Fix lost lints and add new ones (#5011)

* Add eslint-plugin-jsx-a11y dependency

* Add jsx-a11y lint

* Add eslint-plugin-react-hooks dependency

* Add react hooks lints

* Ignore new react hooks lint in tests

* Add eslint-plugin-testing-library dependency

* Add testing-library lint

* Fix yarn lint to use all files recursively

* Developer workflow: added auto generated workspace file from vitest extension in vscode (#4997)

* chore: added auto generated workspace file from vitest extension in vscode

* fix: auto fmt fixes

* Change Dependabot PRs to always be made on Mondays (#5025)

* Add packages to Dependabot updates (#5024)

* Bump @lezer/generator from 1.7.1 to 1.7.2 (#5018)

Bumps [@lezer/generator](https://github.com/lezer-parser/generator) from 1.7.1 to 1.7.2.
- [Changelog](https://github.com/lezer-parser/generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lezer-parser/generator/compare/1.7.1...1.7.2)

---
updated-dependencies:
- dependency-name: "@lezer/generator"
  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>

* Bump handlebars from 6.2.0 to 6.3.0 in /src/wasm-lib (#5012)

Bumps [handlebars](https://github.com/sunng87/handlebars-rust) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/sunng87/handlebars-rust/releases)
- [Changelog](https://github.com/sunng87/handlebars-rust/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sunng87/handlebars-rust/compare/v6.2.0...v6.3.0)

---
updated-dependencies:
- dependency-name: handlebars
  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>

* Bump syn from 2.0.95 to 2.0.96 in /src/wasm-lib (#5015)

Bumps [syn](https://github.com/dtolnay/syn) from 2.0.95 to 2.0.96.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.95...2.0.96)

---
updated-dependencies:
- dependency-name: syn
  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>

* Fix artifact types to be more accurate (#5022)

* Fix Cargo.lock to not have changes (#5034)

* Upgrade all wasm-bindgen dependencies together (#5037)

* Disable auto-updater on non-versioned builds (#5042)

* turns on helix from edge (#5036)

* updates for new lib

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

* autocomplete

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

* bump version

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

* bump all the things

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

* new samples

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

* docs

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

---------

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

* ci: Add yarn test of packages/codemirror-lang-kcl (#5035)

* ci: Add yarn test of packages/codemirror-lang-kcl

* Fix CI error running tests

* Fix postcss config error

* Bump xstate from 5.17.4 to 5.19.2 (#5027)

* Hook up chamfer UI with AST-mod (#4694)

* button

* config

* hook up with ast

* cmd bar test

* button states fix and test

* little naming fix

* xState action to actor

* remove button state test updates

* fixture-based approach

* nightly

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Update src/lib/toolbar.ts

Co-authored-by: Frank Noirot <frank@zoo.dev>

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>

* Remove Redundant Fillet Button State Test (#5009)

delete obsolete test

* Bump @types/node from 20.14.9 to 22.10.6 in /packages/codemirror-lsp-client (#5041)

* custom axis and origin example for helix (#5057)

* custom axis and origin for helix

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

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

* empty

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump typescript from 5.7.2 to 5.7.3 (#5021)

Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.7.2 to 5.7.3.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.2...v5.7.3)

---
updated-dependencies:
- dependency-name: typescript
  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>

* Refactor: break out `copyFileShareLink` into standalone function

* Add "Share file" to command palette

* Update dumb use of site URL instead of prod app URL

* fmt

* @lf94 nit

* @pierremtb spinner feedback

* Hide share link command and disable menu item for now

* Just comment out the command config for now

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: 49lf <ircsurfer33@gmail.com>
Co-authored-by: Adam Sunderland <iterion@gmail.com>
Co-authored-by: Adam Sunderland <adam@kittycad.io>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Kevin Nadro <nadr0@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: max <margorskyi@gmail.com>
2025-01-24 00:18:27 +00:00
2332338ca1 Show "No results found" for empty search results in command palette (#5143) 2025-01-23 18:49:50 -05:00
41b97de3d1 Fix: Badge indicator is now placed over the respective button in the sidebar (#4979)
* fix: positioning of the badge for the sidebar buttons

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

* bump since image is wrong

* bump since image is wrong

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

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-23 14:20:41 -06:00
8ef31a0be1 Refactor: decouple command palette actor from React (#5108)
* Convert commandBarMachine to standalone actor

* Switch all uses of CommandBarProvider pattern to use actor and selector snapshots directly
2025-01-23 10:25:21 -05:00
3adb42b5f2 Supress stdio logs on e2e tests in CI (#5132)
* WIP: pw log error only

* Force tests to run on branch

* Remove all page.on('console', console.log)

* Remove context.console too

* Add --quiet flag

* Revert useless changes

* Supress stdio logs on e2e tests in CI
2025-01-23 16:13:49 +01:00
20016b101e Fix: Properly setting selection range when KCL editor is not mounted. (#4960)
* fix: fixed selection range issue when doing a constraint when the KCL editor is closed

* fix: linter and tsc errors

* fix: trying to reuse logic instead?

* fix: removed console log
2025-01-23 09:45:45 -05:00
8d9dbf36c3 Bump vite from 5.4.6 to 5.4.12 (#5129)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.6 to 5.4.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-22 20:58:53 -05:00
440704ed9f Remove extra margin on some code editor menu items (#5094)
* Extra padding on 'Load a sample model' menu item
Fixes #5047

* Update src/components/ModelingSidebar/ModelingPanes/KclEditorMenu.module.css

Co-authored-by: Frank Noirot <frank@zoo.dev>

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>
2025-01-22 16:57:27 +01:00
2261217a5d Rename debug pane label for artifact graph (#5092)
* Rename debug pane label for artifact graph

* Rename component
2025-01-22 15:37:51 +00:00
10da986649 Add dry-run validation for Sweep (#5097)
* Add dry-run validation for Sweep
Fixes #5095

* Add sweep test failing validation

* Make naming more consistent with engine

* Fix tests after big rename

* Fix tsc after main merge
2025-01-22 15:59:47 +01:00
10789d9c3c set scene units based on a module's default units (#5127)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-01-22 15:23:55 +13:00
67cc4f5835 Tweaks to clarify tooltips from tool dropdown menus (#5123)
* Separate content from ToolbarItemTooltip, make simple and "rich" versions

* Add support for dropdown-arrow-only tooltip

* Add toolbar-wide hover timeouts and clears to switch between simple and rich tooltips

* Fix the dropdown arrow button hover styling now that they're separate

* Add missing doc links to rich toolbar tooltips

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

* Re-run CI after snapshots

* fix codespell

* fmt

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-21 18:32:56 -05:00
2692f2b73a Add units to geometry structs (#5075)
* Make all geometry KclValue variants into struct variants

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Add units to geometry types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-01-21 20:42:09 +00:00
965cb18059 Parse units on numeric literals and keep them in the AST (#5061)
* Code changes

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* test changes

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Frontend changes

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Refactor asNum

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-01-22 08:29:30 +13:00
a022b8ef6c Fix suggestion for updating function decl syntax for anon functions (#5088)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-01-22 07:10:07 +13:00
4d24bf7c94 Add API Call ID log for debugging (#5107) 2025-01-20 19:49:02 +00:00
9a537da183 Show toolbar tooltips on hover only, hide when dropdowns are open (#5109)
* Show toolbar tooltips on hover only, hide when dropdowns are open

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

* Re-run CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-18 05:22:22 -05:00
df81b76b8b Bug fix follow-up for create project (#5105)
* fix dumb mistake in command flow for #5083

* Add e2e test for creating projects with the default interpolated name

* Drop that number to 12 ain't got all day

* Why do I have a kcl-samples submodule hanging around?

* Empty commit to remove the submodule
2025-01-17 23:10:28 +00:00
ac3f7ab712 Rust: Remove iai benchmark tests (#5102)
We don't get much value from these, we can always run criterion or valgrind locally.

If we want to measure instruction counts, we should be using codspeed.io instead because
they support visualizing and tracking over time.

If we want to track performance over time we should be using Kevin's perf monitor machine.
2025-01-17 15:42:51 -06:00
dac91d3b79 Add uniqueness check to "Create project" command (#5100)
* Add failing playwright test

* Make create generate a unique name if the given one collides

* Add a new consolidated getUniqueProjectName function with tests

* Use getUniqueProjectName

* Replace "New project" button text with "Create project"
cc @pierremtb

* Extend the e2e test to show the incrementing behavior
cc @lf94
2025-01-17 19:46:52 +00:00
0698432abf Rust artifact graph (#5068)
* Start porting artifact graph creation to Rust

* Add most of artifact graph creation

* Add handling loft command from recent PR

* Refactor artifact merge code so that it errors when a new artifact type is added

* Add sweep subtype

* Finish implementation of build artifact graph

* Fix wasm.ts to use new combined generated ts-rs file

* Fix Rust lints

* Fix lints

* Fix up replacement code

* Add artifact graph to WASM outcome

* Add artifact graph to simulation test output

* Add new artifact graph output snapshots

* Fix wall field and reduce unreachable code

* Change field order for subtype

* Change subtype to be determined from the request, like the TS

* Fix plane sweep_id

* Condense code

* Change ID types to be properly optional

* Change to favor the new ID, the same as TS

* Fix to make error impossible

* Rename artifact type tag values to match TS

* Fix name of field on Cap

* Update outputs

* Change to use Rust source range

* Update output snapshots

* Add conversion to mermaid mind map and add to snapshot tests

* Add new mermaid mind map output

* Add flowchart

* Remove raw artifact graph from tests

* Remove JSON artifact graph output

* Update output file with header

* Update output after adding flowchart

* Fix flowchart to not have duplicate edges, one in each direction

* Fix not not output duplicate edges in flowcharts

* Change flowchart edge style to be more obvious when a direction is missing

* Update output after deduplication of edges

* Fix not not skip sketch-on-face artifacts

* Add docs

* Fix edge iteration order to be stable

* Update output after fixing order

* Port TS artifactGraph.test.ts tests to simulation tests

* Add grouping segments and solid2ds with their path

* Update output flowcharts since grouping paths

* Remove TS artifactGraph tests

* Remove unused d3 dependencies

* Fix to track loft ID on paths

* Add command ID to error messages

* Move artifact graph test code to a separate file since it's a large file

* Reduce function visibility

* Remove TS artifact graph code

* Fix spelling error with serde

* Add TODO for edge cut consumed ID

* Add comment about mermaid edge rank

* Fix mermaid flowchart edge cuts to appear as children of their edges

* Update output since fixing flowchart order

* Fix to always build the artifact graph even when there's a KCL error

* Add artifact graph to error output

* Change optional ID merge to match TS

* Remove redundant SourceRange definition

* Remove Rust-flavored default source range function

* Add helper for source range creation

* Update doc comment for the website

* Update docs after doc comment change

* Fix to save engine responses in execution cache

* Remove unused import

* Fix to not call WASM function before beforeAll callback is run

* Remove more unused imports
2025-01-17 14:34:36 -05:00
0592d3b5da Selection dry-run validation for Shell (#4775)
* WIP: mess with shell selection validation
Will eventually fix #4711

* Update from main

* WIP: not working yet

* Working loft dry run validator

* Clean up shell (still not working)

* Bump kittycad-modeling-cmds

* Clean up

* Add logging

* Add proper object_id and face_id mapping, still not working for shell

* Fix faceId

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Working validation after engine merge; Clean up

* Fix codespell

* Add pw test

* More clean up

* Back to basics

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

* Trigger CI

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

* Trigger CI

* Clean up

* Fix tests

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

* Trigger CI

* Remove kcl-samples

---------

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-17 10:16:18 -05:00
max
31e4d60045 Refactor Fillet Playwright Test to the new Fixture-based Approach (#4909)
* add locator

* new test

* remove old test

* separation of setup steps

* improved click reliability

* fix ubuntu

* ubuntu fix 2

* ubuntu fix 3

* flaky cmdbar ubuntu

* ubuntu fix second yellow

* ubuntu update

* enable test for windows

* step(Initial test setup)

* extra await, just in case

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

* Trigger CI

* 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)

* Trigger CI

* screenshot

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-17 10:21:55 +01:00
c0817b00e4 Auto retry on yarn install as it sometimes fail on windows (#5077) 2025-01-16 18:03:31 -05:00
4ea1d16fb6 Loft command prompt focus fix (#5080) 2025-01-16 18:03:01 -05:00
d049bf33e8 Return key to go through Onboarding steps (#5086)
Fixes #5049
2025-01-16 17:45:59 -05:00
7b11047d07 Fix helix sweep, you can make springs! (#5089)
* fix dumb mistake

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

* updates for springs!

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

* update docs

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

* update known issues

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-16 13:50:13 -08:00
412e9568f2 Per-file units (use per-file settings for conversion functions) (#5064)
* Use the project default units for the per-file unit default values

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Use per-file units in conversion functions

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-01-17 07:55:01 +13:00
9be208e5e1 Fix wasm bundle upload (upload-artifact@v4) (#5084) 2025-01-16 13:33:14 -05:00
842ef5ede9 Feature: Allow orbit in sketch mode via setting (#4990)
* feat: enable/disable free camera aka allow orbit in sketch mode mvp

* fix: removing comments

* fix: logic for enabling and disabling in and out of sketch mode

* fix: fmt, linter, tsc fixes

* fix: added comment

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

* fix: current,prev check to no op the useeffect if the values are the same

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-16 11:48:13 -06:00
3f855d7bad Make commands disable, not unregister, based on their machineActor (#5070)
* Make "Find and select command" global to commandBarMachine

* Make commands not removed based on their actor state, only disabled

* Sort commands better in CommandComboBox

* Break out sort logic, add a few unit tests

* Fix missed name change

* Needed to make one more change from source branch:
since `optionsFromContext` now only gets fired once, I/O-based options need to use the `options` config instead.

---------

Co-authored-by: 49fl <ircsurfer33@gmail.com>
2025-01-16 12:08:48 -05:00
0a1a6e50cf 3-point circle interactive component (#4982)
* Add dragging behavior to 3 point circle

Uses our talked about technique of calling Rust functions to calculate new
geometry coordinates and parameters. It works very well!

Need to have the modeling app show "edit sketch" still.

* Cargo fmt

* cargo fmt

* Address Jon's comments

* Fix clippy

* Dont use isNaN

* Make points easier to select (enlarge)

* Fix circle button not being activated

* Ensure efficiency of updating editor vs execution

* Make cargo clippy happy
2025-01-16 11:10:36 -05:00
d4e955289c Add helix icon and start of toolbar/feature tree impl (#5062)
* Add icon

* Add to stdLibMap

* Add to toolbar as "kcl-only"

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

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
2025-01-16 14:22:19 +00:00
c147a219f4 Minor bits and pieces (#5066)
* Use std deprecation for int rather than a hack in the parser

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Don't allow an epsilon when converting floats to ints for property access

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Fixup tests

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-01-16 14:00:32 +13:00
38513a1e25 Fix broken golden standard tests caused by changes to kcl-samples (#5065)
* Fix our golden standard tests (broken by new assemblies kcl-samples)

* Finally use the right combination of env vars

* Fix the manifest

* Continue to fix multiple file kcl-samples

* Fix loading in desktop app

* Type narrow for tsc

* fmt

---------

Co-authored-by: Frank Noirot <frank@kittycad.io>
2025-01-15 23:30:20 +00:00
c0c5c790ca Bump typescript from 5.7.2 to 5.7.3 (#5021)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.7.2 to 5.7.3.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.7.2...v5.7.3)

---
updated-dependencies:
- dependency-name: typescript
  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-01-14 16:18:26 -05:00
8b60f75220 custom axis and origin example for helix (#5057)
* custom axis and origin for helix

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

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

* empty

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-14 12:05:36 -08:00
f91ad4331f Bump @types/node from 20.14.9 to 22.10.6 in /packages/codemirror-lsp-client (#5041) 2025-01-14 17:36:46 +00:00
max
59103a2118 Remove Redundant Fillet Button State Test (#5009)
delete obsolete test
2025-01-14 12:09:29 -05:00
max
9737c2550a Hook up chamfer UI with AST-mod (#4694)
* button

* config

* hook up with ast

* cmd bar test

* button states fix and test

* little naming fix

* xState action to actor

* remove button state test updates

* fixture-based approach

* nightly

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Update src/lib/toolbar.ts

Co-authored-by: Frank Noirot <frank@zoo.dev>

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2025-01-14 12:08:32 -05:00
bf9d01a8dd Bump xstate from 5.17.4 to 5.19.2 (#5027) 2025-01-14 15:39:05 +00:00
702e322f90 ci: Add yarn test of packages/codemirror-lang-kcl (#5035)
* ci: Add yarn test of packages/codemirror-lang-kcl

* Fix CI error running tests

* Fix postcss config error
2025-01-14 09:30:08 -05:00
e82830754d turns on helix from edge (#5036)
* updates for new lib

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

* autocomplete

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

* bump version

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

* bump all the things

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

* new samples

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

* docs

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-13 23:34:43 +00:00
7806377a5a Disable auto-updater on non-versioned builds (#5042) 2025-01-13 17:40:51 -05:00
859afa2fd8 Upgrade all wasm-bindgen dependencies together (#5037) 2025-01-13 13:24:23 -08:00
0a5f3093fc Fix Cargo.lock to not have changes (#5034) 2025-01-13 15:38:24 -05:00
b65f7939f6 Fix artifact types to be more accurate (#5022) 2025-01-13 15:02:55 -05:00
c35dea5e07 Bump syn from 2.0.95 to 2.0.96 in /src/wasm-lib (#5015)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.95 to 2.0.96.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.95...2.0.96)

---
updated-dependencies:
- dependency-name: syn
  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-01-13 10:04:30 -08:00
fc66d4745f Bump handlebars from 6.2.0 to 6.3.0 in /src/wasm-lib (#5012)
Bumps [handlebars](https://github.com/sunng87/handlebars-rust) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/sunng87/handlebars-rust/releases)
- [Changelog](https://github.com/sunng87/handlebars-rust/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sunng87/handlebars-rust/compare/v6.2.0...v6.3.0)

---
updated-dependencies:
- dependency-name: handlebars
  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-01-13 13:03:34 -05:00
b313d26c2a Bump @lezer/generator from 1.7.1 to 1.7.2 (#5018)
Bumps [@lezer/generator](https://github.com/lezer-parser/generator) from 1.7.1 to 1.7.2.
- [Changelog](https://github.com/lezer-parser/generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lezer-parser/generator/compare/1.7.1...1.7.2)

---
updated-dependencies:
- dependency-name: "@lezer/generator"
  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-01-13 11:48:13 -05:00
00b94ead62 Add packages to Dependabot updates (#5024) 2025-01-13 11:29:00 -05:00
0531ea1ce9 Change Dependabot PRs to always be made on Mondays (#5025) 2025-01-13 15:30:33 +00:00
5f9a4887c1 Developer workflow: added auto generated workspace file from vitest extension in vscode (#4997)
* chore: added auto generated workspace file from vitest extension in vscode

* fix: auto fmt fixes
2025-01-13 09:57:12 -05:00
da7dfa16d8 Fix lost lints and add new ones (#5011)
* Add eslint-plugin-jsx-a11y dependency

* Add jsx-a11y lint

* Add eslint-plugin-react-hooks dependency

* Add react hooks lints

* Ignore new react hooks lint in tests

* Add eslint-plugin-testing-library dependency

* Add testing-library lint

* Fix yarn lint to use all files recursively
2025-01-13 09:30:14 -05:00
363ae10658 Upgrade typescript-eslint from 5.62.0 to 8.19.1 and remove eslint-config-react-app (#5006) 2025-01-11 09:59:09 -05:00
ac4a6c84cf Point-and-click Sweep (first PR) (#4989)
* Refactor 'Delete selection' as actor
Will fix #4662

* WIP logging

* WIP: working Solid3dGetExtrusionFaceInfo for loft

* Working wall deletion of loft

* Add offset plane deletion

* Add feature tree deletion of shell

* Clean up

* Revert "Clean up"

This reverts commit 214763cc2b.

* Clean up rust changes, taking the sketch with the most paths

* Working cap selection and deletion

* Clean up

* Add test for loft and offset plane deletion via selection

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

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

* Set reenter: false as it was originally

* Passing test

* Add shell deletion via feature tree test

* Revert the migration to promise actor

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

* Use cmd.id as solid_id after latest engine merge

* Add feature tree deletion of offset plane and fix lint

* Add feature tree deletion of loft

* Clean up

* Better comment

* Lint fix

* Remove sketch sorting

* WIP: sweep point-and-click

* Working sweep

* Add test

* Make sweep a development command

* Fix tsc error

* Clean up for review

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-11 08:20:49 -05:00
c6fad2e2dc Add new lint to disallow use of confusing isNaN (#4999) 2025-01-11 05:28:12 +00:00
013cb10961 Fix so that all artifact commands are returned regardless of caching (#5005)
* Fix so that all artifact commands are returned regardless of caching

* Add some more docs and fix up old ones
2025-01-10 22:33:05 -05:00
6261083cb1 Make the test executor a bit more patient (#5004) 2025-01-10 20:05:27 -05:00
2b0ba37ed0 Use Chromium instead of Chrome for Playwright Electron (#5001)
* Use Chromium instead of Chrome for Playwright Electron

* Remove channel
2025-01-10 13:37:26 -05:00
96174f3cf6 Increase playwright retries to 5 (#5000) 2025-01-10 13:34:27 -05:00
aed62ff912 Fix flaky playwright test 'Shell point-and-click sketch on face' (#5002)
Fixes #4998
2025-01-10 13:32:31 -05:00
9334d64608 Allow under-development commands in Nightly builds (#4995)
* Allow under-development commands in Nightly builds
Fixes #4994

* Fix warning

* Add back status: development to Revolve
2025-01-10 16:24:07 +00:00
4fa7d2d8c8 Feature: new axis and edge selection workflow for point and click revolve (#4939)
* feat: implemented axis or edge selection workflow in the commandbar

* fix: removing comment

* fix: removing console logs from testing

* fix: fixing lint and tsc errors

* fix: changed copy

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2025-01-10 08:52:04 -06:00
3e615dfdbc Update Katie's name reference and link in onboarding (#4967) 2025-01-09 22:07:40 -05:00
c9860af29f Fix Shell point-and-click picking the wrong face with piped extrudes (#4981)
* [BUG] Shell point and click references the wrong feature
Fixes #4961

* Add test for sketch on face based on extrudes in pipe

* Add no extrude in pipe case

* Lint

* Add scene.waitForExecutionDone()

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

* Trigger CI

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

* Trigger CI

* Update src/lang/modifyAst/addShell.ts

Co-authored-by: Frank Noirot <frank@zoo.dev>

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2025-01-10 01:20:07 +00:00
23a42f0195 Bump @kittycad/lib to v2.0.13 (#4988) 2025-01-09 16:02:05 -05:00
a77fa639f3 Point-and-click deletion of lofts, shells, and offset planes (#4898)
* Refactor 'Delete selection' as actor
Will fix #4662

* WIP logging

* WIP: working Solid3dGetExtrusionFaceInfo for loft

* Working wall deletion of loft

* Add offset plane deletion

* Add feature tree deletion of shell

* Clean up

* Revert "Clean up"

This reverts commit 214763cc2b.

* Clean up rust changes, taking the sketch with the most paths

* Working cap selection and deletion

* Clean up

* Add test for loft and offset plane deletion via selection

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

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

* Set reenter: false as it was originally

* Passing test

* Add shell deletion via feature tree test

* Revert the migration to promise actor

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

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

* Trigger CI

* Use cmd.id as solid_id after latest engine merge

* Add feature tree deletion of offset plane and fix lint

* Add feature tree deletion of loft

* Clean up

* Better comment

* Lint fix

* Remove sketch sorting

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-09 15:36:50 -05:00
0a5ad7c95b Show deprecated indicator in CodeMirror autocomplete (#4983) 2025-01-09 09:15:00 -05:00
4a654523d2 Prevent toSync from clobbering stack traces (#4980)
* Prevent toSync from clobbering stack traces

* Capture error on the outside of the toSync catch

* fmt

* Actually fix it 🤦
2025-01-09 03:40:42 +00:00
73a7e2bfd6 Return modeling commands from KCL execution (#4912)
* Add Rust side artifacts for startSketchOn face or plane

* Add Rust-generated artifacts to ExecOutcome

* Add output of artifact commands

* Add new output files

* Wire the artifact commands to the artifact graph creation

* Fix to use real PartialEq implemented in modeling commands

* Fix modeling commands with zero fields to work

* Fix missing artifactCommands field in errors

* Change artifact graph to be built from artifact commands

* Wire up ExecState artifacts, but not using them yet

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>

* Remove unneeded local var

* Fix test to fail with a helpful error message when command isn't found

* Rename and deprecate orderedCommands

* Update comment about borrowing

* Move ArtifactCommand tracking to the EngineManager trait

* Update artifact commands since tracking in the engine

* Upgrade kittycad-modeling-cmds from 0.2.85 to 0.2.86

* Remove unneeded JsonSchema derive to speed up build

* Fix to not fail on floating point differences in CI

* Update artifact commands output since truncating floating point numbers

* Fix to ensure artifact commands get cleared after a clear scene

* Update artifact commands snapshot after clearing them on clear scene

* Remove all remnants of OrderedCommands

* Update output for new simulation tests

---------

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2025-01-09 01:02:30 +00:00
eb0850fea9 Make codespell smooth when run locally (#4978)
* Skip the out/ directory produced by yarn tron:package

* Skip all dist/ dirs

Produced when building rollup packages like codemirror-lang-kcl.

* Skip typescript build info

* Fix typo instead of excluding file

---------

Co-authored-by: Matt Mundell <matt@mundell.me>
2025-01-08 10:36:37 -06:00
029f76f273 Nadro/4857/wasm panic catching errors (#4901)
* chore: skeleton code to initialize and detect the global WASM panic

* chore: implementing a reimport method to fix the wasm instance being bricked

* fix: cleaning up tsc/lint

* fix: renaming file to be more accurate

* fix: added toast message

* fix: types...

* fix: typed the functions with arg spreads
2025-01-08 15:58:41 +00:00
max
28b5f7080c Refactor Fillet AST Mod to Async Actor (#4803) 2025-01-08 16:05:24 +01:00
5b1dcfecd6 Open updater toast changelog links externally (#4970)
* fix: Hook into markdown-generated anchors to avoid e.g breaking the desktop app

* add comment

* Disable eslint on copied line from ts-stack

---------

Co-authored-by: marc2332 <mespinsanz@gmail.com>
2025-01-08 09:15:18 -05:00
f89d191425 add a test for foreign characters in project name (#4976)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-08 05:34:08 -05:00
2f4e4b62a8 Don't wait for !isExecuting to play the stream (#4971)
* Add failing test for current behavior

* Change stream behavior so that stream is played regardless of `isExecuting`

* Change expected pixel color

* Widen possible pixel color diff because local and CI produce slightly different colors
2025-01-08 04:34:57 -05:00
5ebd5c8dbb Enhance helixes (#4973)
* updates

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

* updates

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

* updates

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

* allow a helix to go into a sweep

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

* fix clippy

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

* updates

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

* udpates

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

* updates

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

* snapshots

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

* docs

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

* docs

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

* fix

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

* updates

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

* updates

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

* updates

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

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

* updates

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

* updates

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

* docs

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

* updates

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

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

* em,pty

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

* updates

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-08 03:10:53 +00:00
a9ceaf2678 fix: make error for missing a closing bracket clearer (#4974)
* fix: make error for missing a closing bracket clearer

* Fix test for error message

---------

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
2025-01-08 01:55:07 +00:00
c8afd3399b Dead code clean up (smol PR) (#4653)
* general clean up

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

* trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-08 01:46:05 +00:00
5dda4828c6 Bump react-modal from 3.16.1 to 3.16.3 (#4924)
Bumps [react-modal](https://github.com/reactjs/react-modal) from 3.16.1 to 3.16.3.
- [Release notes](https://github.com/reactjs/react-modal/releases)
- [Changelog](https://github.com/reactjs/react-modal/blob/master/CHANGELOG.md)
- [Commits](https://github.com/reactjs/react-modal/compare/v3.16.1...v3.16.3)

---
updated-dependencies:
- dependency-name: react-modal
  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-01-07 15:24:24 -08:00
72acab752c Bump async-trait from 0.1.83 to 0.1.85 in /src/wasm-lib (#4969)
Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.83 to 0.1.85.
- [Release notes](https://github.com/dtolnay/async-trait/releases)
- [Commits](https://github.com/dtolnay/async-trait/compare/0.1.83...0.1.85)

---
updated-dependencies:
- dependency-name: async-trait
  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-01-07 12:54:16 -08:00
81df38ad1c Bump happy-dom from 15.11.7 to 16.3.0 (#4925)
* Bump happy-dom from 15.11.7 to 16.3.0

Bumps [happy-dom](https://github.com/capricorn86/happy-dom) from 15.11.7 to 16.3.0.
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v15.11.7...v16.3.0)

---
updated-dependencies:
- dependency-name: happy-dom
  dependency-type: direct:development
  update-type: version-update:semver-major
...

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

* 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-01-07 20:51:15 +00:00
0576a2bef1 Bump react-hotkeys-hook from 4.5.1 to 4.6.1 (#4953)
Bumps [react-hotkeys-hook](https://github.com/JohannesKlauss/react-keymap-hook) from 4.5.1 to 4.6.1.
- [Release notes](https://github.com/JohannesKlauss/react-keymap-hook/releases)
- [Changelog](https://github.com/JohannesKlauss/react-hotkeys-hook/blob/main/CHANGELOG.md)
- [Commits](https://github.com/JohannesKlauss/react-keymap-hook/compare/v4.5.1...v4.6.1)

---
updated-dependencies:
- dependency-name: react-hotkeys-hook
  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-01-07 20:46:57 +00:00
4b2f6b4647 refactor: Remove unused UpdaterModal component (#4791) 2025-01-07 15:28:33 -05:00
69edaa4183 implementing array pop (#4806)
* implementing naive array pop

* multi-profile follow up. (#4802)

* multi-profile work

* fix enter sketch on cap

* fix coderef problem for walls and caps

* allow sketch mode entry from circle

* clean up

* update snapshot

* Look at this (photo)Graph *in the voice of Nickelback*

* trigger CI

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

* add test

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

* fix how expression index is corrected, to make compatible with offset planes

* another test

* tweak test

* more test tweaks

* break up test to fix it hopfully

* fix onboarding test

* remove bad comment

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* get ready to bump (kcl-lib and friends) world (#4794)

get ready to bump world

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

* Revert multi-profile (#4812)

* Revert "multi-profile follow up. (#4802)"

This reverts commit 2b2ed470c1.

* Revert "multi profile (#4532)"

This reverts commit 04e586d07b.

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

* Re-run CI after snapshots

* Re-run CI after snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Re-run CI after snapshots

* Add `fixme` to onboarding test

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Add tracking of operations for the feature tree (#4746)

* Add operations tracking for the timeline

* Change to only track certain stdlib functions as operations

* Update gen files

* Add operations to simulation snapshot tests

* Add tracking of positional function calls

* Fix generated field names to be camel case in TS

* Fix generated TS field names to match and better docs

* Fix order of ops with patternTransform

* Fix sweep to be included

* Add new expected test outputs

* Add tracking for startSketchOn

* Update ops output to include startSketchOn

* Fix serde field name

* Fix output field name

* Add tracking of operations that fail

* Add snapshots of operations even when there's a KCL execution error

* Add ops output for error executions

* Add operations output to executor error

* Update op source ranges

* Remove tracking of circle() and polygon() since they're not needed

* Update output without circle and polygon

* Fix to track patternCircular3d and patternLinear3d

* Remove tracking for mirror2d

* Update ops output

* Fix to track the correct source range of function definitions

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>

* Change KCL completion to use new object/record syntax (#4815)

* Reserve syntax for units of measure (#4783)

* Allow underscores but only for un-referenced names

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Support numeric suffixes for UoM types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* UoM type arguments

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* warnings -> non-fatal errors

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* type ascription

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Whole module imports (#4767)

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Support completions from import statements (#4768)

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Implements boolean logical and/or in kcl  (#4678)

* redoing bool logic impl on latest main

* adding snapshot tests (removing .new)

* removing accidental change smh:(

* accepting client side scene snapshot

* accepting png snapshot and triggering ci

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

* accepting png again?

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* accepting grid visibility snapshot

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* accepting png snapshot

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* accepting png snapshot

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

* accepting png snapshot

* rerunning simtest creation to get ops.snap files

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* Annotations syntax and per-file default units preparatory work (#4822)

* Parse annotations

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Propagate settings from annotations to exec_state

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* KCL: Unlabeled first param defaults to % (#4817)

Part of #4600

KCL functions can declare one special argument that doesn't require a label on its parameter when called.

This PR will default that arg to % (the current pipeline) if not given.

* Deprecate startSketchAt() stdlib function (#4819)

* Deprecate startSketchAt() stdlib function

* Remove uses of startSketchAt() from the doc tests

* Update docs

* Add dry-run validation for Loft (#4820)

* WIP: mess with shell selection validation
Will eventually fix #4711

* Update from main

* WIP: not working yet

* Working loft dry run validator

* Clean up shell (still not working)

* Bump kittycad-modeling-cmds

* Clean up

* Add logging

* Add proper object_id and face_id mapping, still not working for shell

* Fix faceId

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Add dry-run validation to Loft
Checks one box for #4711

* Add extra check for non solid2ds

---------

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Double click label on sketch to dimension  (#4816)

* feat: double click segment label to dimension length, POC, need to clean up code!

* fix: cleaning up the PR for review

* fix: cleaning for the PR. Adding more comments and moving some logic

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

* fix: mergining main, auto linter and tsc fixes. Need to make some more

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

* fix: tsc errors are resolved

* chore: added test for constraint

* fix: fixing overlay bug since length labels can now be clicked.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* KCL: Show beautiful Miette errors when a KCL example test fails (#4829)

* KCL: Show beautiful Miette errors when a KCL example test fails

Background: KCL example tests are generated from the stdlib KCL examples in the `#[stdlib]` macro in derive-docs.

Problem: When these tests fail, they output a really unhelpful error message like Kcl(Semantic(KclErrorDetails { source_ranges: [156, 160, 0], message: "Expected a sketch but found array" } )).

Solution: Use miette. Now the errors highlight the KCL code that failed and show exactly what went wrong, on which line, presenting nice diagnostics that look like cargo/rustc output.

* Update helix snapshots

* Move all tests over to electron (#4484)

* Move all tests over to electron

* Pass the correct param to playwright-electron.sh

* Add shebang to script and add macos-14-large as a target

* Get sketch-tests.spec.ts passing in electron

* Try out 4 workers

* Got testing-segment-overlays passing

* Pass testing-selections.spec.ts

* Go back to fix up sketch-tests test

* Pass various.spec.ts, by far the hardest one

* Pass can-sketch-on-all-planes... with ease

* Pass command bar tests

* fmt

* Completely fix code mirror text navigating for tests

* Pass debug pane tests

* Pass desktop export tests

* Pass editor tests

* Pass file tree tests

* Pass onboarding tests

* Corrected a fixme in file-tree.spec!

* Painfully fix hardcoded coordinates in point-click.spec

* Pass machine.spec tests

* Pass projects, fought hard with filechooser

* Pass regresion-tests.spec tests

* Pass network and connection tests

* Pass camera-movement.spec tests

* Extreme time eaten by gizmo test fixes. All passing now.

* Merge main (tests changed x_x) and pass all constraints.spec tests (pain)

* Pass another painful spec suite: testing-settings

* Pass perspective-toggle, interesting note

* Pass samples loading tests

* Pass app header tests

* Pass text-to-cad tests

* Pass segment-overlays (minor ache) and ability to switch to web if needed :)

* Fix a ton of syntax changes and deflake 2 more tests (pain)

* Correct all tsc errors

* Remove to-electron script

* Add an f-ton of shit because playwright doesnt want S P R E A D

* Try CI again

* Stop snapshots of exports (already test in e2e)

* Fix flake in double click editor

* Hopefully help CI flake

* Fixmes, fixmes everywhere

* One more fixme to settings

* Skip another code pane flake

* Port jess's projects.spec tests

* fixup

* Reuse electron window; difficult task

* Rebased and refixed

* Remove duplicate cases

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

* Reduce the workers to something CI can handle

* Lower it further, we need to think about the others

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Fix the last tests and tsc errors

* Timeout to 120 and windows-2022-16core

* Fix windows runner detection, enable concurrency temporarily

* Hopefully this time fix windows runner detection

* Comment out Vector, add back removed camera test code

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* Fix camera tests again

* Massively deflake a whole class of tests

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

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

* Try new CI and fix small onboarding test

* Derp

* No github tuning

* Try mac

* Add back all the OS

* Lord, hallow be thy name

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* One last try with window-16-cores

* Trigger CI

* Try AWS Windows runner

* Passing on windows locally with a few skips

* Skip more win tests, add back all three oses

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Add two more fixmes

* 2 more fixmes

* skip segment overlays on win32

* Another fixme

* Trigger CI

* Trigger CI

* Quick clean up

* Move all tests over to electron

* Pass the correct param to playwright-electron.sh

* Add shebang to script and add macos-14-large as a target

* Get sketch-tests.spec.ts passing in electron

* Try out 4 workers

* Got testing-segment-overlays passing

* Pass testing-selections.spec.ts

* Go back to fix up sketch-tests test

* Pass various.spec.ts, by far the hardest one

* Pass can-sketch-on-all-planes... with ease

* Pass command bar tests

* fmt

* Completely fix code mirror text navigating for tests

* Pass debug pane tests

* Pass desktop export tests

* Pass editor tests

* Pass file tree tests

* Pass onboarding tests

* Corrected a fixme in file-tree.spec!

* Painfully fix hardcoded coordinates in point-click.spec

* Pass machine.spec tests

* Pass projects, fought hard with filechooser

* Pass regresion-tests.spec tests

* Pass network and connection tests

* Pass camera-movement.spec tests

* Extreme time eaten by gizmo test fixes. All passing now.

* Merge main (tests changed x_x) and pass all constraints.spec tests (pain)

* Pass another painful spec suite: testing-settings

* Pass perspective-toggle, interesting note

* Pass samples loading tests

* Pass app header tests

* Pass text-to-cad tests

* Pass segment-overlays (minor ache) and ability to switch to web if needed :)

* Fix a ton of syntax changes and deflake 2 more tests (pain)

* Correct all tsc errors

* Remove to-electron script

* Add an f-ton of shit because playwright doesnt want S P R E A D

* Try CI again

* Stop snapshots of exports (already test in e2e)

* Fix flake in double click editor

* Hopefully help CI flake

* Fixmes, fixmes everywhere

* One more fixme to settings

* Skip another code pane flake

* Port jess's projects.spec tests

* fixup

* Reuse electron window; difficult task

* Rebased and refixed

* Remove duplicate cases

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

* Reduce the workers to something CI can handle

* Lower it further, we need to think about the others

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Fix the last tests and tsc errors

* Timeout to 120 and windows-2022-16core

* Fix windows runner detection, enable concurrency temporarily

* Hopefully this time fix windows runner detection

* Comment out Vector, add back removed camera test code

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* Fix camera tests again

* Massively deflake a whole class of tests

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* Try new CI and fix small onboarding test

* Derp

* No github tuning

* Try mac

* Add back all the OS

* Lord, hallow be thy name

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Try AWS Windows runner

* Passing on windows locally with a few skips

* Trigger CI

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

* fmt, tsc, lint

* Enable two fixmes again

* Fix lint, codespell, fmt

* Fix lint

* Don't run e2e on draft, add back concurrency, clean up

* One last windows skip

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>

* Add blank line to discord bot message (#4814)

* Add blank link to discord bot message

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Implement some basic cache program generation (#4840)

Implement some basic cache program generation

A bit ago, @jessfraz added the ability to control reexecution from the
executor. When we did this, it used the digest to determine if there
was a code change rather than a non-code change (whitespace, comment,
etc).

This allows the creation of a new program to be run without clearing the
scene. This, in conjunction with being able to delete Engine objects by
ID will allow us to do some clever stuff when incrementally executing
a program.

I'm still working on something a bit more advanced, but a good first
step to derisk some of the caching behavior here fully is to implement a
basic "changed program" stub.

This process the ast programs (old and new) if it doesn't exactly match.
This would have been a complete refresh before this commit.

 1) Check all overlapping top-level statements of the body of the new and
    old AST and ensure they all match.
      - If this is true, this means that one of the two AST programs has more
        elements then the other, and they all otherwise match (addition or
        deletion of the end of the program). We continue to #2 in this
        case.
      - If this is false, we have a meaingful difference in a section of
        overlapping code. This will result in a cache miss and rebuild
        the scene. We short-cut here and the scene is rebuilt.

 2) Check the lengths of the two bodies.
   - If they're the same, we shouldn't have even been called. We will
     short-cut with a noop cache return (no clear, no program).
   - if the old ast is longer, we've removed instructions from the
     program. We can't delete things now, so this will result in a cache
     miss and rebuild the scene. We short-cut here and the scene is
     rebuilt.
   - If the new ast is longer, we have an insertion of code at the end.

 3) construct a new program using only the new elements from the new
    ast, and return a `CacheResult` that *does not clear the scene*.
    This means nothing will be rebuilt, and only a new object will polp
    onto the scene. This is the first case where we diverge with
    existing behavior.

Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>

* Fix mac issue after electron test migration PR (#4842)

Fix mac issue after electron test migration pR

* Remove guards from modeling commands in the toolbar (#4800)

* Remove guards from modeling commands in the toolbar

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Remove the deprecated function, update doc comment for the one still in use

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Remove more selection check functions that are no longer used

* Update E2E tests that assumed the extrude button could be disabled due to selection

* Update a few fillet tests that expected the button to disable based on selection

* 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: windows-16-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-macos-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>

* Prompt to edit (#4830)

* initial plumbing for getting the new option into the cmd-bar

* start of prompt edit

* update AI poll

* add spinner

* more prompt engineering

* add success toast, allowing user's to reject code

* select code that changed in prompt to edit

* selection in scene should not disappear when opening prompt cmd

* tweak

* fmt

* add tests

* some clean up

* clean up

* fix tests

* Yeet telemetry to text to cad endpoint (#4847)

yeet telemetry to text to cad endpoint

* Tweak prompt wording (#4846)

tweak prompt wording

* update discord bot (#4837)

* Re-enable test 'code pane closed at start' after electron migration (#4841)

* Re-enable 'code pane closed at start'
Relates to #4838

* Enable test on current branch

* Revert "Enable test on current branch"

This reverts commit 0d970b9ad6.

* Add 3-point circle tool (#4832)

* Add 3-point circle tool

This adds a 1st pass for the 3-point circle tool.

There is disabled code to drag around the 3 points and redraw the circle and
a triangle created by those points. It will be enabled in a follow-up PR
when we have circle3Point in the stdlib.

For now, all it does is after the 3rd click, will insert circle center-radius
KCL code for users to modify.

* PR comments

* First draft of a feature tree pane (#4782)

* Fix e2e default planes tests to use mask on state indicator (#4849)

* Fix e2e default planes tests to use mask on state indicator

* 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: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* fix: don't error on failure to fetch privacy settings (#4799)

* fix: dont error on failure to fetch privacy settings

* Add console warning when we ignore it

---------

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>

* Match package license to LICENSE file (#4882)

* Remove the old Loft GitHub issue link in the toolbar (#4848)

Now that it's available, it shouldn't be there anymore.

* Fix fuzz crate lints and update deps (#4873)

* Fix fuzz to use new API

* Fix fuzz Cargo.toml lints and update lock

* Use app foreground color for focus outline button color so there's no hue collision (#4894)

Towards #4851

* Add support for float numbers in rem() arguments (#4858)

* Add support for float numbers in rem() arguments

* Update docs

* Rename to prevent name collision in docs

* Update docs after rename to NumberArg

* Fix parameter types to follow naming convention

* Change doc comment description to not refer to floating point

* Update docs after NumberArg doc change

* Change function to be more condensed

* Change to not try to preserve ints

* Update docs to use f64

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

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Add auto-retries to macOS build notarization (#4892)

* Add DEBUG=electron-notarize* to build-apps

* Force IS_RELEASE: true

* Temp: Disable version setting based on tag

* Remove deprecated notarize.teamId and add retry logic

* Revert "Remove deprecated notarize.teamId and add retry logic"

This reverts commit 6ff98d784d.

* Retry only on macOS

* Better retry logic for macOS

* Use nick-fields/retry

* Clean up Temp: commits for PR

* Clean up

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

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* Bump nanoid from 3.3.7 to 3.3.8 (#4731)

Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Enable enter for autocompletions in the command palette KCL input (#4896)

* Enable enter for autocompletions in the command palette KCL input

* Oops I commented out code for the variable name input
Thanks for the catch @pierremtb

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Bump rollup from 4.21.0 to 4.29.1 (#4888)

* Bump rollup from 4.21.0 to 4.29.1

Bumps [rollup](https://github.com/rollup/rollup) from 4.21.0 to 4.29.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.21.0...v4.29.1)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: indirect
...

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

* 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>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Louder Windows codesign errors (#4762)

* WIP: Silent failure in signWin.js
Fixes #4582

* Temp: force release build

* Fake throw

* Temp: another test

* Clean up for merge

* Add parsing keyword function calls inside pipelines (#4907)

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>

* Remove draft PR filter on e2e tests (#4908)

* Add three point circle stdlib function (#4893)

* Add parsing keyword function calls inside pipelines

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>

* Add three point circle stdlib function

* Generate new documentation

* Fix 20:20 for the circle three point test

* Convert to using keyword arguments

* Wtf yo

* Remove unused structure

* Use the new simulation tests

* Regenerate documentation

---------

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>

* Move the base CodeMirror KCL support to a local package (#4897)

* Move CodeMirror LRLanguage to new file

This separates the base language support from the LSP and color picker.

* Move the base CodeMirror KCL support to a local package

* Start CodeMirror grammar tests

* Exclude vitest config in tsconfig

* Add KCL path to tsconfig

* Remove stray import

* Drop extension from import

* Use __filename for commonjs compat

* Check exec return before access

* Build ES and CJS to dist

* Format

* Exclude all.test.ts from codespell

This is to work around "fileTests" imported from Lezer. Future codespell versions look
like they'll allow the code to be annotated, which would be nicer.

---------

Co-authored-by: Matt Mundell <matt@mundell.me>

* Fix typo in README (#3843)

Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>

* remove backwards compatibility for snake case in objects (#4920)

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

* CM KCL: Support `=` in record init (#4933)

Support `=` in record init

Co-authored-by: Matt Mundell <matt@mundell.me>

* Bump clap from 4.5.21 to 4.5.23 in /src/wasm-lib (#4928)

Bumps [clap](https://github.com/clap-rs/clap) from 4.5.21 to 4.5.23.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.21...clap_complete-v4.5.23)

---
updated-dependencies:
- dependency-name: clap
  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>

* Bump @kittycad/lib from 2.0.7 to 2.0.12 (#4922)

Bumps [@kittycad/lib](https://github.com/KittyCAD/kittycad.ts) from 2.0.7 to 2.0.12.
- [Release notes](https://github.com/KittyCAD/kittycad.ts/releases)
- [Commits](https://github.com/KittyCAD/kittycad.ts/compare/v2.0.7...v2.0.12)

---
updated-dependencies:
- dependency-name: "@kittycad/lib"
  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>

* Bump anyhow from 1.0.94 to 1.0.95 in /src/wasm-lib (#4929)

Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.94 to 1.0.95.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.94...1.0.95)

---
updated-dependencies:
- dependency-name: anyhow
  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>

* Bump url from 2.5.3 to 2.5.4 in /src/wasm-lib (#4930)

Bumps [url](https://github.com/servo/rust-url) from 2.5.3 to 2.5.4.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.5.3...v2.5.4)

---
updated-dependencies:
- dependency-name: url
  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>

* Bump wasm-streams from 0.4.1 to 0.4.2 in /src/wasm-lib (#4926)

Bumps [wasm-streams](https://github.com/MattiasBuelens/wasm-streams) from 0.4.1 to 0.4.2.
- [Release notes](https://github.com/MattiasBuelens/wasm-streams/releases)
- [Changelog](https://github.com/MattiasBuelens/wasm-streams/blob/main/CHANGELOG.md)
- [Commits](https://github.com/MattiasBuelens/wasm-streams/compare/v0.4.1...v0.4.2)

---
updated-dependencies:
- dependency-name: wasm-streams
  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>

* Bump @csstools/postcss-oklab-function from 4.0.2 to 4.0.7 (#4923)

Bumps [@csstools/postcss-oklab-function](https://github.com/csstools/postcss-plugins/tree/HEAD/plugins/postcss-oklab-function) from 4.0.2 to 4.0.7.
- [Changelog](https://github.com/csstools/postcss-plugins/blob/main/plugins/postcss-oklab-function/CHANGELOG.md)
- [Commits](https://github.com/csstools/postcss-plugins/commits/HEAD/plugins/postcss-oklab-function)

---
updated-dependencies:
- dependency-name: "@csstools/postcss-oklab-function"
  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>

* fix: writes to disk when the user accepts the prompt to edit (#4942)

* fix: writes to disk when the user accepts the prompt to edit

* fix: then catch

* Make circle3Point tool an actor (#4906)

* Reduce the amount of data sent to TS and make new fields opt-in (#4913)

* Reduce the amount of data sent back to JS/TS from WASM

* Remove unneeded derives since we shouldn't expose these types

* Alias type to be clearer

* Bump syn from 2.0.87 to 2.0.95 to be compatible with modeling-cmds 0.… (#4945)

Bump syn from 2.0.87 to 2.0.95 to be compatible with modeling-cmds 0.2.86

* fix out of range error (#4931)

* fix out of range error

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

* updates

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

* remove console logs

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

* add a regression test

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

---------

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

* Run chrome e2e snapshots only on linux (#4947)

* Run chrome e2e snapshots only on linux

* Wtf is this 1-indexed

* Force 1/1 sharding

* Add TODO

* Nadro/3079/screenshot improvements (#3917)

* chore: swapped screenshot to only use the video stream

* feat: video stream screenshot, native electron screenshot

* fix: auto tsc, fmt, xgen, lint

* fix: fixing tsc errors

* fix: removing debug console.log

* fix: renaming ScreenShot to Screenshot

* fix: deleting console log from debugging

* fix: bug with what source was referenced

* fix: using a productName

* fix: improving usage for native screenshots and detecthing support

* fix: fmt

* chore: updated rust test documentation

* fix: typo in readme

* fix: leaving package.json and yarn.lock the same as main??

* bump

* bump

* bump again

* bump again2

* feat: implemented zoom to fit on code change if previous AST was empty (#3925)

* feat: implemented zoom to fit on code change if previous AST was empty

* feat: implementing selectAll text logic to enable select all and copy and paste and zoom to fit will work

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* fix: clarifying comment in _isAstEmpty

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

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

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

* bump

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* bump again

* fix: fixing new type since this branch is old

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

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* bump

* 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)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: 49fl <ircsurfer33@gmail.com>

* Add dependabot group for all serde dependencies (#4944)

* Fix formatting of dependabot.yml

* Add dependabot group for all serde dependencies

* CM KCL: = and => are optional in fn declarations (#4941)

CM KCL: `=` and `=>` are optional in fn declarations

Co-authored-by: Matt Mundell <matt@mundell.me>

* Bump ts-rs from 10.0.0 to 10.1.0 (#4949)

* Add toolbar buttons for text-to-cad and prompt-to-edit (#4938)

* Add toolbar buttons for text-to-cad and prompt-to-edit
Resolves #4890

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-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)

* 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-macos-8-cores)

* `preventDefault` on <kbd>Enter</kbd> with textarea input so buttons aren't clicked as well

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>

* Bump quote from 1.0.37 to 1.0.38 in /src/wasm-lib (#4951)

Bumps [quote](https://github.com/dtolnay/quote) from 1.0.37 to 1.0.38.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.37...1.0.38)

---
updated-dependencies:
- dependency-name: quote
  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>

* array pop with unlabled kw arg

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Signed-off-by: Nick Cameron <nrc@ncameron.org>
Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Kevin Nadro <nadr0@users.noreply.github.com>
Co-authored-by: 49fl <ircsurfer33@gmail.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
Co-authored-by: Paul Tagliamonte <paul@zoo.dev>
Co-authored-by: Josh Gomez <114548659+jgomez720@users.noreply.github.com>
Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
Co-authored-by: Matt Mundell <32057441+mattmundell@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Matt Mundell <matt@mundell.me>
Co-authored-by: alteous <david@harvey-macaulay.com>
2025-01-07 20:24:24 +00:00
2eb7c382bf Bump @codemirror/lint from 6.8.1 to 6.8.4 (#4955)
Bumps [@codemirror/lint](https://github.com/codemirror/lint) from 6.8.1 to 6.8.4.
- [Changelog](https://github.com/codemirror/lint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/lint/compare/6.8.1...6.8.4)

---
updated-dependencies:
- dependency-name: "@codemirror/lint"
  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-01-07 20:23:07 +00:00
38913ecb98 Bump three and @types/three (#4956)
Bumps [three](https://github.com/mrdoob/three.js) and [@types/three](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/three). These dependencies needed to be updated together.

Updates `three` from 0.166.1 to 0.172.0
- [Release notes](https://github.com/mrdoob/three.js/releases)
- [Commits](https://github.com/mrdoob/three.js/commits)

Updates `@types/three` from 0.163.0 to 0.172.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/three)

---
updated-dependencies:
- dependency-name: three
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: "@types/three"
  dependency-type: direct:development
  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-01-07 20:19:58 +00:00
debd06129f CM KCL: numbers must have digits after dot (#4963)
Co-authored-by: Matt Mundell <matt@mundell.me>
2025-01-07 12:19:31 -08:00
d38bd342a0 Bump winnow from 0.6.20 to 0.6.22 in /src/wasm-lib (#4954)
Bumps [winnow](https://github.com/winnow-rs/winnow) from 0.6.20 to 0.6.22.
- [Changelog](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md)
- [Commits](https://github.com/winnow-rs/winnow/compare/v0.6.20...v0.6.22)

---
updated-dependencies:
- dependency-name: winnow
  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-01-07 20:16:56 +00:00
f026f10335 Bump zip from 2.2.0 to 2.2.2 in /src/wasm-lib (#4952)
Bumps [zip](https://github.com/zip-rs/zip2) from 2.2.0 to 2.2.2.
- [Release notes](https://github.com/zip-rs/zip2/releases)
- [Changelog](https://github.com/zip-rs/zip2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zip-rs/zip2/compare/v2.2.0...v2.2.2)

---
updated-dependencies:
- dependency-name: zip
  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-01-07 18:06:37 +00:00
895d7ebc6d Bump the serde-dependencies group in /src/wasm-lib with 2 updates (#4950)
Bumps the serde-dependencies group in /src/wasm-lib with 2 updates: [serde_json](https://github.com/serde-rs/json) and [serde](https://github.com/serde-rs/serde).


Updates `serde_json` from 1.0.133 to 1.0.135
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.133...v1.0.135)

Updates `serde` from 1.0.216 to 1.0.217
- [Release notes](https://github.com/serde-rs/serde/releases)
- [Commits](https://github.com/serde-rs/serde/compare/v1.0.216...v1.0.217)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: serde-dependencies
- dependency-name: serde
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: serde-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-07 17:55:33 +00:00
65edf17a44 Bump quote from 1.0.37 to 1.0.38 in /src/wasm-lib (#4951)
Bumps [quote](https://github.com/dtolnay/quote) from 1.0.37 to 1.0.38.
- [Release notes](https://github.com/dtolnay/quote/releases)
- [Commits](https://github.com/dtolnay/quote/compare/1.0.37...1.0.38)

---
updated-dependencies:
- dependency-name: quote
  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-01-07 09:14:32 -08:00
0c2a0a8c07 Add toolbar buttons for text-to-cad and prompt-to-edit (#4938)
* Add toolbar buttons for text-to-cad and prompt-to-edit
Resolves #4890

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-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)

* 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-macos-8-cores)

* `preventDefault` on <kbd>Enter</kbd> with textarea input so buttons aren't clicked as well

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
2025-01-07 16:45:30 +00:00
97cef4d16c Bump ts-rs from 10.0.0 to 10.1.0 (#4949) 2025-01-07 04:32:20 +00:00
9358278f7b CM KCL: = and => are optional in fn declarations (#4941)
CM KCL: `=` and `=>` are optional in fn declarations

Co-authored-by: Matt Mundell <matt@mundell.me>
2025-01-06 21:55:31 -06:00
a174e084d4 Add dependabot group for all serde dependencies (#4944)
* Fix formatting of dependabot.yml

* Add dependabot group for all serde dependencies
2025-01-07 03:33:06 +00:00
df7246897a feat: implemented zoom to fit on code change if previous AST was empty (#3925)
* feat: implemented zoom to fit on code change if previous AST was empty

* feat: implementing selectAll text logic to enable select all and copy and paste and zoom to fit will work

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* fix: clarifying comment in _isAstEmpty

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

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

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

* bump

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* bump again

* fix: fixing new type since this branch is old

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

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* bump

* 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)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: 49fl <ircsurfer33@gmail.com>
2025-01-07 02:53:20 +00:00
0c9f64dd7c Nadro/3079/screenshot improvements (#3917)
* chore: swapped screenshot to only use the video stream

* feat: video stream screenshot, native electron screenshot

* fix: auto tsc, fmt, xgen, lint

* fix: fixing tsc errors

* fix: removing debug console.log

* fix: renaming ScreenShot to Screenshot

* fix: deleting console log from debugging

* fix: bug with what source was referenced

* fix: using a productName

* fix: improving usage for native screenshots and detecthing support

* fix: fmt

* chore: updated rust test documentation

* fix: typo in readme

* fix: leaving package.json and yarn.lock the same as main??

* bump

* bump

* bump again

* bump again2
2025-01-07 02:13:06 +00:00
d2b9d3a058 Run chrome e2e snapshots only on linux (#4947)
* Run chrome e2e snapshots only on linux

* Wtf is this 1-indexed

* Force 1/1 sharding

* Add TODO
2025-01-06 17:32:47 -08:00
7e54f08778 fix out of range error (#4931)
* fix out of range error

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

* updates

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

* remove console logs

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

* add a regression test

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-07 01:18:58 +00:00
d9c2dd376e Bump syn from 2.0.87 to 2.0.95 to be compatible with modeling-cmds 0.… (#4945)
Bump syn from 2.0.87 to 2.0.95 to be compatible with modeling-cmds 0.2.86
2025-01-06 19:57:25 -05:00
275a2150e7 Reduce the amount of data sent to TS and make new fields opt-in (#4913)
* Reduce the amount of data sent back to JS/TS from WASM

* Remove unneeded derives since we shouldn't expose these types

* Alias type to be clearer
2025-01-06 21:55:59 +00:00
8b8feb8d68 Make circle3Point tool an actor (#4906) 2025-01-06 14:08:18 -05:00
e21ef3f122 fix: writes to disk when the user accepts the prompt to edit (#4942)
* fix: writes to disk when the user accepts the prompt to edit

* fix: then catch
2025-01-06 13:26:22 -05:00
66834931aa Bump @csstools/postcss-oklab-function from 4.0.2 to 4.0.7 (#4923)
Bumps [@csstools/postcss-oklab-function](https://github.com/csstools/postcss-plugins/tree/HEAD/plugins/postcss-oklab-function) from 4.0.2 to 4.0.7.
- [Changelog](https://github.com/csstools/postcss-plugins/blob/main/plugins/postcss-oklab-function/CHANGELOG.md)
- [Commits](https://github.com/csstools/postcss-plugins/commits/HEAD/plugins/postcss-oklab-function)

---
updated-dependencies:
- dependency-name: "@csstools/postcss-oklab-function"
  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-01-06 08:40:31 -08:00
06c1bcaf2e Bump wasm-streams from 0.4.1 to 0.4.2 in /src/wasm-lib (#4926)
Bumps [wasm-streams](https://github.com/MattiasBuelens/wasm-streams) from 0.4.1 to 0.4.2.
- [Release notes](https://github.com/MattiasBuelens/wasm-streams/releases)
- [Changelog](https://github.com/MattiasBuelens/wasm-streams/blob/main/CHANGELOG.md)
- [Commits](https://github.com/MattiasBuelens/wasm-streams/compare/v0.4.1...v0.4.2)

---
updated-dependencies:
- dependency-name: wasm-streams
  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-01-06 16:38:14 +00:00
fc7df7ecbe Bump url from 2.5.3 to 2.5.4 in /src/wasm-lib (#4930)
Bumps [url](https://github.com/servo/rust-url) from 2.5.3 to 2.5.4.
- [Release notes](https://github.com/servo/rust-url/releases)
- [Commits](https://github.com/servo/rust-url/compare/v2.5.3...v2.5.4)

---
updated-dependencies:
- dependency-name: url
  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-01-06 16:37:23 +00:00
67cb7b33bb Bump anyhow from 1.0.94 to 1.0.95 in /src/wasm-lib (#4929)
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.94 to 1.0.95.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.94...1.0.95)

---
updated-dependencies:
- dependency-name: anyhow
  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-01-06 16:35:04 +00:00
ea74b94fac Bump @kittycad/lib from 2.0.7 to 2.0.12 (#4922)
Bumps [@kittycad/lib](https://github.com/KittyCAD/kittycad.ts) from 2.0.7 to 2.0.12.
- [Release notes](https://github.com/KittyCAD/kittycad.ts/releases)
- [Commits](https://github.com/KittyCAD/kittycad.ts/compare/v2.0.7...v2.0.12)

---
updated-dependencies:
- dependency-name: "@kittycad/lib"
  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-01-06 11:10:11 -05:00
529833c63f Bump clap from 4.5.21 to 4.5.23 in /src/wasm-lib (#4928)
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.21 to 4.5.23.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.21...clap_complete-v4.5.23)

---
updated-dependencies:
- dependency-name: clap
  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-01-06 08:07:38 -08:00
92da86391a CM KCL: Support = in record init (#4933)
Support `=` in record init

Co-authored-by: Matt Mundell <matt@mundell.me>
2025-01-06 10:16:42 -05:00
e7cb390db4 remove backwards compatibility for snake case in objects (#4920)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-01-05 20:49:16 -05:00
8a66bbbdbd Fix typo in README (#3843)
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2025-01-06 01:11:05 +00:00
3c53babb50 Move the base CodeMirror KCL support to a local package (#4897)
* Move CodeMirror LRLanguage to new file

This separates the base language support from the LSP and color picker.

* Move the base CodeMirror KCL support to a local package

* Start CodeMirror grammar tests

* Exclude vitest config in tsconfig

* Add KCL path to tsconfig

* Remove stray import

* Drop extension from import

* Use __filename for commonjs compat

* Check exec return before access

* Build ES and CJS to dist

* Format

* Exclude all.test.ts from codespell

This is to work around "fileTests" imported from Lezer. Future codespell versions look
like they'll allow the code to be annotated, which would be nicer.

---------

Co-authored-by: Matt Mundell <matt@mundell.me>
2025-01-04 10:57:24 -08:00
474acb1c68 Add three point circle stdlib function (#4893)
* Add parsing keyword function calls inside pipelines

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>

* Add three point circle stdlib function

* Generate new documentation

* Fix 20:20 for the circle three point test

* Convert to using keyword arguments

* Wtf yo

* Remove unused structure

* Use the new simulation tests

* Regenerate documentation

---------

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
2025-01-04 12:18:29 -05:00
1c941112d7 Remove draft PR filter on e2e tests (#4908) 2025-01-03 16:14:51 -05:00
6f1d718097 Add parsing keyword function calls inside pipelines (#4907)
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
2025-01-03 19:56:23 +00:00
36957237c0 Louder Windows codesign errors (#4762)
* WIP: Silent failure in signWin.js
Fixes #4582

* Temp: force release build

* Fake throw

* Temp: another test

* Clean up for merge
2025-01-03 17:52:55 +00:00
da9cae98aa Bump rollup from 4.21.0 to 4.29.1 (#4888)
* Bump rollup from 4.21.0 to 4.29.1

Bumps [rollup](https://github.com/rollup/rollup) from 4.21.0 to 4.29.1.
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.21.0...v4.29.1)

---
updated-dependencies:
- dependency-name: rollup
  dependency-type: indirect
...

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

* 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>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-01-02 23:22:04 +00:00
9ae025dc56 Enable enter for autocompletions in the command palette KCL input (#4896)
* Enable enter for autocompletions in the command palette KCL input

* Oops I commented out code for the variable name input
Thanks for the catch @pierremtb

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-01-02 23:04:18 +00:00
579ab23d78 Bump nanoid from 3.3.7 to 3.3.8 (#4731)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-02 22:53:24 +00:00
4bef33e745 Add auto-retries to macOS build notarization (#4892)
* Add DEBUG=electron-notarize* to build-apps

* Force IS_RELEASE: true

* Temp: Disable version setting based on tag

* Remove deprecated notarize.teamId and add retry logic

* Revert "Remove deprecated notarize.teamId and add retry logic"

This reverts commit 6ff98d784d.

* Retry only on macOS

* Better retry logic for macOS

* Use nick-fields/retry

* Clean up Temp: commits for PR

* Clean up

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

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-02 22:17:08 +00:00
ac7bd28c5a Add support for float numbers in rem() arguments (#4858)
* Add support for float numbers in rem() arguments

* Update docs

* Rename to prevent name collision in docs

* Update docs after rename to NumberArg

* Fix parameter types to follow naming convention

* Change doc comment description to not refer to floating point

* Update docs after NumberArg doc change

* Change function to be more condensed

* Change to not try to preserve ints

* Update docs to use f64

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

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-02 21:52:01 +00:00
d478d81156 Use app foreground color for focus outline button color so there's no hue collision (#4894)
Towards #4851
2025-01-02 21:10:07 +00:00
3d27f0191b Fix fuzz crate lints and update deps (#4873)
* Fix fuzz to use new API

* Fix fuzz Cargo.toml lints and update lock
2025-01-02 13:05:46 -06:00
30c2acd18a Remove the old Loft GitHub issue link in the toolbar (#4848)
Now that it's available, it shouldn't be there anymore.
2025-01-02 11:34:35 -05:00
a83b4b2145 Match package license to LICENSE file (#4882) 2025-01-02 08:30:19 -05:00
70b8541038 fix: don't error on failure to fetch privacy settings (#4799)
* fix: dont error on failure to fetch privacy settings

* Add console warning when we ignore it

---------

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
2024-12-23 10:44:15 -06:00
bb51646738 Fix e2e default planes tests to use mask on state indicator (#4849)
* Fix e2e default planes tests to use mask on state indicator

* 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: windows-16-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-20 17:29:14 -05:00
c02e31a530 First draft of a feature tree pane (#4782) 2024-12-20 16:19:59 -05:00
1d06cc7845 Add 3-point circle tool (#4832)
* Add 3-point circle tool

This adds a 1st pass for the 3-point circle tool.

There is disabled code to drag around the 3 points and redraw the circle and
a triangle created by those points. It will be enabled in a follow-up PR
when we have circle3Point in the stdlib.

For now, all it does is after the 3rd click, will insert circle center-radius
KCL code for users to modify.

* PR comments
2024-12-20 19:30:37 +00:00
e0c07eecfe Re-enable test 'code pane closed at start' after electron migration (#4841)
* Re-enable 'code pane closed at start'
Relates to #4838

* Enable test on current branch

* Revert "Enable test on current branch"

This reverts commit 0d970b9ad6.
2024-12-20 10:04:03 -05:00
c5d42500fa update discord bot (#4837) 2024-12-20 09:31:21 -05:00
e6e47f77f0 Tweak prompt wording (#4846)
tweak prompt wording
2024-12-19 19:52:07 -08:00
662c2485ac Yeet telemetry to text to cad endpoint (#4847)
yeet telemetry to text to cad endpoint
2024-12-20 03:50:05 +00:00
9f891deebb Prompt to edit (#4830)
* initial plumbing for getting the new option into the cmd-bar

* start of prompt edit

* update AI poll

* add spinner

* more prompt engineering

* add success toast, allowing user's to reject code

* select code that changed in prompt to edit

* selection in scene should not disappear when opening prompt cmd

* tweak

* fmt

* add tests

* some clean up

* clean up

* fix tests
2024-12-20 13:39:06 +11:00
d08a07a1f8 Remove guards from modeling commands in the toolbar (#4800)
* Remove guards from modeling commands in the toolbar

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Remove the deprecated function, update doc comment for the one still in use

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Remove more selection check functions that are no longer used

* Update E2E tests that assumed the extrude button could be disabled due to selection

* Update a few fillet tests that expected the button to disable based on selection

* 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: windows-16-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-macos-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
2024-12-19 18:42:39 -05:00
872b196a86 Fix mac issue after electron test migration PR (#4842)
Fix mac issue after electron test migration pR
2024-12-19 21:27:00 +00:00
d535a2862d Implement some basic cache program generation (#4840)
Implement some basic cache program generation

A bit ago, @jessfraz added the ability to control reexecution from the
executor. When we did this, it used the digest to determine if there
was a code change rather than a non-code change (whitespace, comment,
etc).

This allows the creation of a new program to be run without clearing the
scene. This, in conjunction with being able to delete Engine objects by
ID will allow us to do some clever stuff when incrementally executing
a program.

I'm still working on something a bit more advanced, but a good first
step to derisk some of the caching behavior here fully is to implement a
basic "changed program" stub.

This process the ast programs (old and new) if it doesn't exactly match.
This would have been a complete refresh before this commit.

 1) Check all overlapping top-level statements of the body of the new and
    old AST and ensure they all match.
      - If this is true, this means that one of the two AST programs has more
        elements then the other, and they all otherwise match (addition or
        deletion of the end of the program). We continue to #2 in this
        case.
      - If this is false, we have a meaingful difference in a section of
        overlapping code. This will result in a cache miss and rebuild
        the scene. We short-cut here and the scene is rebuilt.

 2) Check the lengths of the two bodies.
   - If they're the same, we shouldn't have even been called. We will
     short-cut with a noop cache return (no clear, no program).
   - if the old ast is longer, we've removed instructions from the
     program. We can't delete things now, so this will result in a cache
     miss and rebuild the scene. We short-cut here and the scene is
     rebuilt.
   - If the new ast is longer, we have an insertion of code at the end.

 3) construct a new program using only the new elements from the new
    ast, and return a `CacheResult` that *does not clear the scene*.
    This means nothing will be rebuilt, and only a new object will polp
    onto the scene. This is the first case where we diverge with
    existing behavior.

Signed-off-by: Paul R. Tagliamonte <paul@zoo.dev>
2024-12-19 21:18:35 +00:00
63a3bc7bc6 Add blank line to discord bot message (#4814)
* Add blank link to discord bot message

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-19 05:11:29 -05:00
02055a8b31 Move all tests over to electron (#4484)
* Move all tests over to electron

* Pass the correct param to playwright-electron.sh

* Add shebang to script and add macos-14-large as a target

* Get sketch-tests.spec.ts passing in electron

* Try out 4 workers

* Got testing-segment-overlays passing

* Pass testing-selections.spec.ts

* Go back to fix up sketch-tests test

* Pass various.spec.ts, by far the hardest one

* Pass can-sketch-on-all-planes... with ease

* Pass command bar tests

* fmt

* Completely fix code mirror text navigating for tests

* Pass debug pane tests

* Pass desktop export tests

* Pass editor tests

* Pass file tree tests

* Pass onboarding tests

* Corrected a fixme in file-tree.spec!

* Painfully fix hardcoded coordinates in point-click.spec

* Pass machine.spec tests

* Pass projects, fought hard with filechooser

* Pass regresion-tests.spec tests

* Pass network and connection tests

* Pass camera-movement.spec tests

* Extreme time eaten by gizmo test fixes. All passing now.

* Merge main (tests changed x_x) and pass all constraints.spec tests (pain)

* Pass another painful spec suite: testing-settings

* Pass perspective-toggle, interesting note

* Pass samples loading tests

* Pass app header tests

* Pass text-to-cad tests

* Pass segment-overlays (minor ache) and ability to switch to web if needed :)

* Fix a ton of syntax changes and deflake 2 more tests (pain)

* Correct all tsc errors

* Remove to-electron script

* Add an f-ton of shit because playwright doesnt want S P R E A D

* Try CI again

* Stop snapshots of exports (already test in e2e)

* Fix flake in double click editor

* Hopefully help CI flake

* Fixmes, fixmes everywhere

* One more fixme to settings

* Skip another code pane flake

* Port jess's projects.spec tests

* fixup

* Reuse electron window; difficult task

* Rebased and refixed

* Remove duplicate cases

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

* Reduce the workers to something CI can handle

* Lower it further, we need to think about the others

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Fix the last tests and tsc errors

* Timeout to 120 and windows-2022-16core

* Fix windows runner detection, enable concurrency temporarily

* Hopefully this time fix windows runner detection

* Comment out Vector, add back removed camera test code

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* Fix camera tests again

* Massively deflake a whole class of tests

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

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

* Try new CI and fix small onboarding test

* Derp

* No github tuning

* Try mac

* Add back all the OS

* Lord, hallow be thy name

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* One last try with window-16-cores

* Trigger CI

* Try AWS Windows runner

* Passing on windows locally with a few skips

* Skip more win tests, add back all three oses

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-16-cores)

* Add two more fixmes

* 2 more fixmes

* skip segment overlays on win32

* Another fixme

* Trigger CI

* Trigger CI

* Quick clean up

* Move all tests over to electron

* Pass the correct param to playwright-electron.sh

* Add shebang to script and add macos-14-large as a target

* Get sketch-tests.spec.ts passing in electron

* Try out 4 workers

* Got testing-segment-overlays passing

* Pass testing-selections.spec.ts

* Go back to fix up sketch-tests test

* Pass various.spec.ts, by far the hardest one

* Pass can-sketch-on-all-planes... with ease

* Pass command bar tests

* fmt

* Completely fix code mirror text navigating for tests

* Pass debug pane tests

* Pass desktop export tests

* Pass editor tests

* Pass file tree tests

* Pass onboarding tests

* Corrected a fixme in file-tree.spec!

* Painfully fix hardcoded coordinates in point-click.spec

* Pass machine.spec tests

* Pass projects, fought hard with filechooser

* Pass regresion-tests.spec tests

* Pass network and connection tests

* Pass camera-movement.spec tests

* Extreme time eaten by gizmo test fixes. All passing now.

* Merge main (tests changed x_x) and pass all constraints.spec tests (pain)

* Pass another painful spec suite: testing-settings

* Pass perspective-toggle, interesting note

* Pass samples loading tests

* Pass app header tests

* Pass text-to-cad tests

* Pass segment-overlays (minor ache) and ability to switch to web if needed :)

* Fix a ton of syntax changes and deflake 2 more tests (pain)

* Correct all tsc errors

* Remove to-electron script

* Add an f-ton of shit because playwright doesnt want S P R E A D

* Try CI again

* Stop snapshots of exports (already test in e2e)

* Fix flake in double click editor

* Hopefully help CI flake

* Fixmes, fixmes everywhere

* One more fixme to settings

* Skip another code pane flake

* Port jess's projects.spec tests

* fixup

* Reuse electron window; difficult task

* Rebased and refixed

* Remove duplicate cases

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

* Reduce the workers to something CI can handle

* Lower it further, we need to think about the others

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Update package.json

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Fix the last tests and tsc errors

* Timeout to 120 and windows-2022-16core

* Fix windows runner detection, enable concurrency temporarily

* Hopefully this time fix windows runner detection

* Comment out Vector, add back removed camera test code

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* Fix camera tests again

* Massively deflake a whole class of tests

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: macos-14-large)

* Try new CI and fix small onboarding test

* Derp

* No github tuning

* Try mac

* Add back all the OS

* Lord, hallow be thy name

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Try AWS Windows runner

* Passing on windows locally with a few skips

* Trigger CI

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

* fmt, tsc, lint

* Enable two fixmes again

* Fix lint, codespell, fmt

* Fix lint

* Don't run e2e on draft, add back concurrency, clean up

* One last windows skip

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
2024-12-18 17:58:03 -05:00
93891422f7 KCL: Show beautiful Miette errors when a KCL example test fails (#4829)
* KCL: Show beautiful Miette errors when a KCL example test fails

Background: KCL example tests are generated from the stdlib KCL examples in the `#[stdlib]` macro in derive-docs.

Problem: When these tests fail, they output a really unhelpful error message like Kcl(Semantic(KclErrorDetails { source_ranges: [156, 160, 0], message: "Expected a sketch but found array" } )).

Solution: Use miette. Now the errors highlight the KCL code that failed and show exactly what went wrong, on which line, presenting nice diagnostics that look like cargo/rustc output.

* Update helix snapshots
2024-12-18 09:52:17 -05:00
7193b4110a Double click label on sketch to dimension (#4816)
* feat: double click segment label to dimension length, POC, need to clean up code!

* fix: cleaning up the PR for review

* fix: cleaning for the PR. Adding more comments and moving some logic

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

* fix: mergining main, auto linter and tsc fixes. Need to make some more

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

* fix: tsc errors are resolved

* chore: added test for constraint

* fix: fixing overlay bug since length labels can now be clicked.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-17 14:12:18 -06:00
76e7d80a55 Add dry-run validation for Loft (#4820)
* WIP: mess with shell selection validation
Will eventually fix #4711

* Update from main

* WIP: not working yet

* Working loft dry run validator

* Clean up shell (still not working)

* Bump kittycad-modeling-cmds

* Clean up

* Add logging

* Add proper object_id and face_id mapping, still not working for shell

* Fix faceId

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Add dry-run validation to Loft
Checks one box for #4711

* Add extra check for non solid2ds

---------

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-17 11:55:07 -05:00
b816df21d2 Deprecate startSketchAt() stdlib function (#4819)
* Deprecate startSketchAt() stdlib function

* Remove uses of startSketchAt() from the doc tests

* Update docs
2024-12-17 11:28:22 -05:00
3630696848 KCL: Unlabeled first param defaults to % (#4817)
Part of #4600

KCL functions can declare one special argument that doesn't require a label on its parameter when called.

This PR will default that arg to % (the current pipeline) if not given.
2024-12-16 21:01:23 -06:00
f165d19fda Annotations syntax and per-file default units preparatory work (#4822)
* Parse annotations

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Propagate settings from annotations to exec_state

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-17 15:23:00 +13:00
3dd98ae1d5 Implements boolean logical and/or in kcl (#4678)
* redoing bool logic impl on latest main

* adding snapshot tests (removing .new)

* removing accidental change smh:(

* accepting client side scene snapshot

* accepting png snapshot and triggering ci

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

* accepting png again?

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* accepting grid visibility snapshot

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* accepting png snapshot

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* accepting png snapshot

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

* accepting png snapshot

* rerunning simtest creation to get ops.snap files

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-12-16 17:33:08 -05:00
a46e0a0fe7 Support completions from import statements (#4768)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-17 10:48:38 +13:00
8f9dc06228 Whole module imports (#4767)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-16 20:38:32 +00:00
fa22c14723 Reserve syntax for units of measure (#4783)
* Allow underscores but only for un-referenced names

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Support numeric suffixes for UoM types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* UoM type arguments

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* warnings -> non-fatal errors

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* type ascription

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-17 09:01:51 +13:00
1d39983b08 Change KCL completion to use new object/record syntax (#4815) 2024-12-16 18:29:50 +00:00
da301ba862 Add tracking of operations for the feature tree (#4746)
* Add operations tracking for the timeline

* Change to only track certain stdlib functions as operations

* Update gen files

* Add operations to simulation snapshot tests

* Add tracking of positional function calls

* Fix generated field names to be camel case in TS

* Fix generated TS field names to match and better docs

* Fix order of ops with patternTransform

* Fix sweep to be included

* Add new expected test outputs

* Add tracking for startSketchOn

* Update ops output to include startSketchOn

* Fix serde field name

* Fix output field name

* Add tracking of operations that fail

* Add snapshots of operations even when there's a KCL execution error

* Add ops output for error executions

* Add operations output to executor error

* Update op source ranges

* Remove tracking of circle() and polygon() since they're not needed

* Update output without circle and polygon

* Fix to track patternCircular3d and patternLinear3d

* Remove tracking for mirror2d

* Update ops output

* Fix to track the correct source range of function definitions

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>
2024-12-16 13:10:31 -05:00
efe8089b08 Revert multi-profile (#4812)
* Revert "multi-profile follow up. (#4802)"

This reverts commit 2b2ed470c1.

* Revert "multi profile (#4532)"

This reverts commit 04e586d07b.

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

* Re-run CI after snapshots

* Re-run CI after snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Re-run CI after snapshots

* Add `fixme` to onboarding test

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-16 10:34:11 -05:00
49de3b0ac9 get ready to bump (kcl-lib and friends) world (#4794)
get ready to bump world

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-12-16 18:37:03 +11:00
2b2ed470c1 multi-profile follow up. (#4802)
* multi-profile work

* fix enter sketch on cap

* fix coderef problem for walls and caps

* allow sketch mode entry from circle

* clean up

* update snapshot

* Look at this (photo)Graph *in the voice of Nickelback*

* trigger CI

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

* add test

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

* fix how expression index is corrected, to make compatible with offset planes

* another test

* tweak test

* more test tweaks

* break up test to fix it hopfully

* fix onboarding test

* remove bad comment

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-16 18:36:48 +11:00
96652a0c48 Fix onboarding rendering (#4789)
* fix onboarding rendering

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

* updates

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

* updates

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

* empty string

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* updates

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

* updates

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

* updates

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

* updates

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

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

* empty

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

* empty

* can be off by 20

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

* can be off by 20

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-14 01:35:34 +00:00
04e586d07b multi profile (#4532)
* multi-profile work

* another test

* clean up

* cover a quirk with a test

* last of tests

* fix typos

* Fix source range in snap test

---------

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-12-13 17:57:33 -05:00
fe5f574a77 Revert "Fix so that tag declarators can be used as parameters (#4692)" (#4788)
This reverts commit e27840219b.
2024-12-13 21:39:40 +00:00
e787495ad0 add a test to make sure we cant shebang in a fn (#4781)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-12-13 20:10:33 +00:00
8bb9be7a5e Bump kittycad-modeling-cmds (#4777) 2024-12-13 19:42:41 +00:00
00892464e8 Always run cargo test in CI so that it can be required (#4786) 2024-12-13 14:34:23 -05:00
05ed2a3367 Loft uses kw arguments (#4757)
Part of #4600
2024-12-13 13:07:52 -06:00
10cc5bce59 Fix SourceRange values in OrderedCommands to match the TS type (#4785)
* Fix SourceRange type to match WASM commands

* Update artifact graph test snap

* Update artifact graph test
2024-12-13 19:03:24 +00:00
a32f150fc1 KCL tests: Update engine API snapshot (#4784)
When engine merged their big extrude ID bugfix,
they changed the response for extrudes on face.

Basically there's no longer a start face for
something you extrude from a face, because there
just isn't. There's a hole in a previous face,
it's just a gap.

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-12-13 11:24:29 -06:00
ac60082e67 Fix ids for kurt so front end re-uses same ones on executions (#4780)
* updates

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

* updates

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

* working test;

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

* fix tests

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

* Update src/wasm-lib/tests/executor/main.rs

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* Update src/wasm-lib/tests/executor/main.rs

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* fix race condition

* fix whoopsie

* fix tsc

* for some dumb ass reason the model executes twice on load

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
2024-12-13 02:06:26 +00:00
d44dc1b21a Bump wasm-bindgen from 0.2.91 to 0.2.99 and wasm-bindgen-futures from… (#4732)
* Bump wasm-bindgen from 0.2.91 to 0.2.99 and wasm-bindgen-futures from 0.4.44 to 0.4.49

* Upgrade in the kcl crate also

* Update web-sys version constraint to match lock
2024-12-12 15:37:50 -06:00
813962ea4c Revert "warn on unneccessary brackets (#4769)" (#4776)
This reverts commit 4b6bbbe2c5 (PR #4769) because these tests are failing:

        FAIL [   0.013s] kcl-lib parsing::parser::tests::assign_brackets
        FAIL [   0.012s] kcl-lib parsing::parser::tests::test_arg
2024-12-12 15:37:37 -06:00
738443a6ab add test that ensures we use the cache, from playwright (#4721)
add test that ensures we use the cache;

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-12-12 15:37:23 -06:00
4b6bbbe2c5 warn on unneccessary brackets (#4769)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-13 08:20:57 +13:00
6ff8addc8b Remove non code from Digests (#4772)
Remove non code from Digests

@jessfraz and I talked it over; for the time being we're going to remove
comments from the AST digest. We already exclude source position, so
this is just increasing the degree to which we're going to ignore things
that are not germane to execution.

Before, we'd digest *some* but not all of the comments in the AST.
Silly, I know, right?

So, this code:

```
firstSketch = startSketchOn('XY')
  |> startProfileAt([-12, 12], %)
  |> line([-24, 0], %) // my thing
  |> close(%)
  |> extrude(6, %)
```

Would digest differently than:

```
firstSketch = startSketchOn('XY')
  |> startProfileAt([-12, 12], %)
  |> line([-24, 0], %)
  |> close(%)
  |> extrude(6, %)
```

Which is wrong. We've fully divested of hashing code comments, so this
will now hash to be the same. Hooray.
2024-12-12 18:55:09 +00:00
da05c38b9e KCL stdlib: Add atan2 function (#4771)
At Lee's request
2024-12-12 18:11:07 +00:00
191b9b71fd KCL: Keyword fn args like "x = 1" not like "x: 1" (#4770)
Aligns with how we're doing objects.
2024-12-12 17:53:35 +00:00
05163fdded Fix KCL warnings in doc comments from let, const, and new fn syntax (#4756)
* Fix KCL warnings in doc comments from let, const, and new fn syntax

* Update docs
2024-12-12 11:33:37 -05:00
7ed26e21c6 More Walk cleanup (#4738)
* More Walk cleanup

 - The `Node` type contained two enums by mistake. Those have been
   removed.

 - Export the `Visitor` and `Visitable` traits, as I start to migrate
   stuff to them.

 - Add a wrapper to pull the `digest` off the node without doing a
   `match` elsewhere.
2024-12-12 01:49:18 +00:00
c668d40efc make pipe have a hole (#4766)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-12-12 01:07:14 +00:00
f38c6b90b7 Color picker in the code pane (#4761)
* add color plugin

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

* fixes

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

* fmt

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

* snapshot test goober

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

* updates

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

* updates

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-12 00:45:39 +00:00
7bc8bae0ec Update Camera Controls to Zoo (#4755)
* update camera controls to Zoo

* update e2e and initial settings

* update types and camera controls ts

* update mod.rs test

* update test, test locally
2024-12-11 15:03:51 -08:00
3804aca27e Bump codecov/codecov-action from 4 to 5 (#4498)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  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>
2024-12-11 14:19:43 -08:00
b127680f2f Remove type coercion (#4759)
remove type coercion
2024-12-11 22:04:36 +00:00
b7de8e60cf Sweep in kcl (#4754)
* updates

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

* updates

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

* updates

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

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

* updates

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

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

* empty

* Update src/wasm-lib/kcl/src/docs/mod.rs

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* updates

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

* updates

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

* updates

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-12-11 20:59:02 +00:00
058fccb5e1 Add a right-click menu to the stream, but only when not dragging (#4745)
* Refactor ContextMenu to be able to take a guard and other event types

* refactor: break out ViewControlMenu into its own component

* Add ViewControlMenu to Stream, but only on right-click non-drag mouseup

* Fix lints

* Don't use `useCallback` for contextmenu guard

* Update context menu position on subsequent right-clicks
2024-12-11 17:57:38 +00:00
00e97257ae Set disableDifferentialDownload to true for the auto updater (#4742)
Fixes #4120
2024-12-11 09:04:02 -06:00
aeb656d176 Remove flags we had for code sign on Cut Release PRs (#4728) 2024-12-11 09:03:12 -06:00
ac49ebd6e0 Revert "chore: implemented multiple instances instead of multiple appications?" (#4750)
Revert "chore: implemented multiple instances instead of multiple appications…"

This reverts commit 548c664db0.
2024-12-11 08:58:42 -06:00
b40f03ad25 Fix wasm init deprecation warning (#4747)
See `__wbg_init()` in `src/wasm-lib/pkg/wasm_lib.js`.
2024-12-11 04:54:20 -05:00
a8ad86e645 Add some comments to new API in wasm.ts (#4712)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-11 21:37:03 +13:00
87f50cd5e9 Implement as aliases for sub-expressions (#4723)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-11 21:26:42 +13:00
0400e6228e Add a "current" marker to UnitsMenu (#4744) 2024-12-11 06:00:19 +00:00
26f150fd6c Change diagnostic action button to primary color (#4737) 2024-12-11 00:25:43 -05:00
3049f405f5 Reapply "More aggressive using of cache on engine settings changes" (#4736)
* Reapply "More aggressive using of cache on engine settings changes (#4691)" (#4729)

This reverts commit 3f1f40eeba.

* Add a utility to get all the current values from the settings object

* Use an XState selector to get the latest settings snapshot for WASM

---------

Co-authored-by: Frank Noirot <frank@kittycad.io>
2024-12-11 02:50:22 +00:00
53d40301dc start of Appearance function (#4743)
* initial commit

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

* updates

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

* updates

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

* updates

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

* fix docs

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

* updates

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

* updates

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

* add more samples

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

* updates

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

* updatres

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

* regenerate docs

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

* updates

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

* patterns and appearance samples

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

* updates

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

* updates

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

* fmt

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-12-11 01:51:51 +00:00
671c01e36f More consistent GitHub links (#4741)
Fixes #4726
Tested locally with regular and nightly (`yarn files:flip-to-nightly`) configs.
2024-12-10 15:52:57 -06:00
e80151979b Pin electron versions and remove unused packages (#4708)
* Remove forge dependencies for packaging
Fixes #4628

* More clean up and pin current electron versions
2024-12-10 16:37:08 -05:00
668e2afb99 Fix race condition in wasm test (#4740) 2024-12-10 20:38:51 +00:00
548c664db0 chore: implemented multiple instances instead of multiple appications? (#4733) 2024-12-10 18:51:24 +00:00
d3a3f4410c Fix to not have browser tooltip on top of CodeMirror tooltips (#4730)
* Fix to not have browser tooltip on top of LSP tooltips

* Switch title to aria-label
2024-12-10 12:15:55 -05:00
22eb343171 Add more Rust lints (#4698)
Add more lints
2024-12-10 12:14:03 -05:00
f2cfa4d5cf Adding point and click revolve workflow for sketch and axis selection (#4687)
* selection stuff

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest)

* trigger CI

* fix bugs

* some edge cut stuff

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

* trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* fix sketch mode issues

* fix more tests, selection in sketch related

* more test fixing

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger ci

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger ci

* more sketch mode selection fixes

* fix unit tests

* rename function

* remove .only

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* lint

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* fix bad pathToNode issue

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* fix sketch on face

* migrate a more selections types

* migrate a more selections types

* fix code selection of fillets

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* migrate a more selections types

* fix bad path to node, looks like a race

* migrate a more selections types

* migrate a more selections types

* fix cmd bar selections

* fix cmd bar selections

* fix display issues

* feat: implementing axis selection for point and click revolve

* feat: enforcing selection of 2 options for axis rotation

* feat: added negative rotations for the revolve

* fix: fmt, tsc fixes

* migrate a more selections types

* Revert "migrate a more selections types"

This reverts commit 0d0e453bbb.

* migrate a more selections types

* clean up1

* clean up 2

* chore: improving the copy after discussing with Frank

* fix: merge main fixes

* chore: was able to add a seg to a line. Does not check if one exists already

* saving off some code

* chore: moving revolveSketch into own file for readability, improving variable names instead of node1

* chore: renaming more variables for readability

* chore: more renaming

* fix: allows creating a custom rotation on axis

* fix: added opposite edge logic and adj, need to error handle still

* fix: use other import

* feat: point and click on edges, crude implementation

* feat: implemented toast message and returned error message from validation

* fix: auto linter

* fix: addressing tsc errors

* fix: fighting typescript

* fix: cleaning up PR

* fix: trying to resolve more typescript issues

* fix: save off tsc fixes

* fix: adding comments

* fix: resolving tsc errors

* fix: tsc errors

* fix: auto linter fixes and tsc fixes

* fix:??

* fix: revolve ast works with declaration

* fix: retry logic to make sure the disable dry run actually runs

* fix: codespell typo

---------

Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-10 11:11:01 -06:00
3f1f40eeba Revert "More aggressive using of cache on engine settings changes (#4691)" (#4729)
This reverts commit 943cf21d34.
2024-12-10 12:03:41 -05:00
ff2d161606 KCL parser: fns with optional keyword args can set defaults (#4727)
Part of #4600
2024-12-10 10:20:51 -06:00
210c78029d KCL keyword args: calling user-defined functions (#4722)
Part of https://github.com/KittyCAD/modeling-app/issues/4600

You can now call a user-defined function via keyword args. E.g.

```
fn increment(@x) {
  return x + 1
}

fn add(@x, delta) {
  return x + delta
}

two = increment(1)
three = add(1, delta: 2)
```
2024-12-10 04:11:16 +00:00
e27840219b Fix so that tag declarators can be used as parameters (#4692)
* Add test with tag parameter

* Fix to not define TagIdentifiers pointing to nothing

* Add fixed test output

* Rename function to be clearer

* Remove optional param so that unparse works

* Fix to not allow redefining tags

* Fix to only ever define tags in memory when used with stdlib functions

* Fix to not define local variables when non-literal tag declarator is used

* Add removing mutability

* Change function signature since it isn't falliable
2024-12-10 01:47:34 +00:00
c943a3f192 Refactor TokenStream (and some minor changes to Token) (#4695)
* Refactor TokenStream (and some minor changes to Token)

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Tidy up lexer tests

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-10 14:26:53 +13:00
6aa588f09f Bug: KCL formatter removes 'fn' from closures: (#4718)
# Problem

Before this PR, our formatter reformats
```
squares_out = reduce(arr, 0, fn (i, squares)  {
  return 1
})
```
to 
```
squares_out = reduce(arr, 0, (i, squares) {
  return 1
})
```
i.e. it removes the `fn` keyword from the closure. This keyword is required, so, our formatter turned working code into invalid code.

# Cause

When this closure parameter is formatted, the ExprContext is ::Decl, so `Expr::recast` skips adding the `fn` keyword. The reason it's ::Decl is because the `squares_out = ` declaration sets it, and no subsequent call sets the context to something else.

# Solution

When recasting a call expression, set the context for every argument to `ExprContext::Other`.
2024-12-09 19:13:49 -06:00
59a6333aad Fix nightly release page link in bottom bar (#4714)
* Fix nightly release page link in bottom bar
Fixes #4713

* Working now

* Cleaner

* Add IS_NIGHTLY var to make these checks more consistent

* Review from Kevin

* Update url for settings content too
2024-12-10 00:43:11 +00:00
403f1507ae Update snapshots (#4724) 2024-12-10 00:32:00 +00:00
eac7b83504 Rework the walk module a bit (#4707)
* start a rework of the walk module

I'd like to have the code explicitly recurse in the visitor rather than
implicitly. This allows the calling code to build up an idea of the
depth of each node, or skip parts of the AST entirely.

i'm going to rebuild this enough to get the old API to work before
looking to merge this.

I've also discovered a number of new AST types that were just papered
over and/or excluded entirely -- I'm going to have to go through and
make sure that both Digest and the walker are still current, or if we
silently added types or, more likely, fields getting ignored.
2024-12-10 00:23:53 +00:00
667500d1b9 Bug: Setting mouse controls to OnShape or AutoCAD resets to default (#4681)
* Bugfix: Setting mouse controls to OnShape resets to KittyCAD
Fixes #4639

* Revert "Bugfix: Setting mouse controls to OnShape resets to KittyCAD"

This reverts commit c95878d617.

* Add cases for values without underscores

* Fix lint

* Pass yarn tsc and yarn fmt-check
2024-12-09 19:16:29 -05:00
b15aac9f48 Move length and named value constraint flows into command palette (#4675)
* Extend KCL argument input

* Migrate length constraint to be a command

* Add ability for `kcl` arguments to provide an initial variable name

* Move named variable flow into command palette

* Fix one e2e test

* Remove unwanted `ZERO` behavior when length constraint has no `variableName`

* Fix issue with `getSelectionCountByType` with sketches not yet in artifactGraph

* Update broken constraint tests

* Look at this (photo)Graph *in the voice of Nickelback*

* Fix segment overlays tests, which had out-of-date selectors

* Return early from `useConvertToVariable` if no selectionRanges

* Fixup for review comment from #4677 (#4696)

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Invalidate nightly bucket files after publish (#4627)

* Invalidate nightly bucket files after publish

* Fix conflict resolution

* Add some more warnings (#4697)

* Add installation instructions for all platforms (#4592)

* Add installation instructions for all platforms
Fixes #4511

* Typo

* Typo2

* Improve linux instructions, thanks @TomPridham

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>

---------

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>

* Bump node to v22.12.0 (LTS) (#4706)

* Point-and-click Shell (#4666)

* WIP: experimenting with Loft UI
Relates to #4470

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Add selection guard

* Working loft for two sketches in the right hardcoded order

* First pass at handling more than 2 sketches

* WIP selections

* WIP selections

* More checks

* Appends the loft line after the 'last' sketch in the code

* Clean up

* Enable multiple selections after the button click

* First point-click loft test (not working locally, loft gets inserted at the wrong place)

* Lint

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

* Clean up and working pw test

* Add test for doesSceneHaveSweepableSketch with count = 2

* Clean up loftSketches function

* Add pw test for preselected sketches

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Move to fromPromise-based Actor

* Move error logic out of loftSketches, fix pw tests

* Remove comments

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Fix typo

* Revert snapshots

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* WIP: initial shell code addition

* Rollback pw values to pre cam change

* WIP: more additions

* WIP: closer

* WIP: first time working shell mod

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

* Add extrude lookup for more generic shell

* Handle walls

* Add pw tests for cap shell

* Add shell wall test

* Fix lint

* Add selection guard and clean up

* Lint fix

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

* WIP mutliple faces

* WIP circular dep

* Lint

* Look at this (photo)Graph *in the voice of Nickelback*

* Trigger CI

* Working multi-face shell across types

* Cap and wall pw test

* Apply suggestions from Frank's review

Co-authored-by: Frank Noirot <frank@zoo.dev>

* Fix test annotations

* Add unit tests for doesSceneHaveExtrudedSketch

* Manual resolution of snapshot conflicts

* Fix assertParse

* Updated pathToNode construct

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>

* More aggressive using of cache on engine settings changes (#4691)

* move around the files for cache to better localtions

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

* updates

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

* cleanup

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

* updates

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

* updates

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

* updates

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

* updates

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

* udpates

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

* updates

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

* updates

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

* cleanup

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

* updates

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

* ensure we can change the grid setting via the command bar

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

* pass thru all setttings

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

* updates

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

* updates

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

* updates

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

* updates

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

* updates

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

* updates

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

* fix playwright test

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* emoty

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>

* fix use of `as`

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
2024-12-09 21:43:58 +00:00
54153aa646 fix: replace whitespace with a - so that ids are valid and scroll to works (#4710)
Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
2024-12-09 16:10:33 -05:00
943cf21d34 More aggressive using of cache on engine settings changes (#4691)
* move around the files for cache to better localtions

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

* updates

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

* cleanup

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

* updates

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

* updates

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

* updates

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

* updates

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

* udpates

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

* updates

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

* updates

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

* cleanup

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

* updates

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

* ensure we can change the grid setting via the command bar

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

* pass thru all setttings

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

* updates

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

* updates

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

* updates

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

* updates

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

* updates

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

* updates

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

* fix playwright test

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* emoty

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-09 21:06:53 +00:00
5a6728c45a Point-and-click Shell (#4666)
* WIP: experimenting with Loft UI
Relates to #4470

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Add selection guard

* Working loft for two sketches in the right hardcoded order

* First pass at handling more than 2 sketches

* WIP selections

* WIP selections

* More checks

* Appends the loft line after the 'last' sketch in the code

* Clean up

* Enable multiple selections after the button click

* First point-click loft test (not working locally, loft gets inserted at the wrong place)

* Lint

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

* Clean up and working pw test

* Add test for doesSceneHaveSweepableSketch with count = 2

* Clean up loftSketches function

* Add pw test for preselected sketches

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Move to fromPromise-based Actor

* Move error logic out of loftSketches, fix pw tests

* Remove comments

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Fix typo

* Revert snapshots

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

* WIP: initial shell code addition

* Rollback pw values to pre cam change

* WIP: more additions

* WIP: closer

* WIP: first time working shell mod

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

* Add extrude lookup for more generic shell

* Handle walls

* Add pw tests for cap shell

* Add shell wall test

* Fix lint

* Add selection guard and clean up

* Lint fix

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

* WIP mutliple faces

* WIP circular dep

* Lint

* Look at this (photo)Graph *in the voice of Nickelback*

* Trigger CI

* Working multi-face shell across types

* Cap and wall pw test

* Apply suggestions from Frank's review

Co-authored-by: Frank Noirot <frank@zoo.dev>

* Fix test annotations

* Add unit tests for doesSceneHaveExtrudedSketch

* Manual resolution of snapshot conflicts

* Fix assertParse

* Updated pathToNode construct

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2024-12-09 20:20:48 +00:00
ff2103d493 Bump node to v22.12.0 (LTS) (#4706) 2024-12-09 13:37:01 -05:00
2dfa8f2176 Add installation instructions for all platforms (#4592)
* Add installation instructions for all platforms
Fixes #4511

* Typo

* Typo2

* Improve linux instructions, thanks @TomPridham

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>

---------

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
2024-12-09 12:30:24 -05:00
29ed330326 Add some more warnings (#4697) 2024-12-10 06:27:04 +13:00
ca2cc825a6 Invalidate nightly bucket files after publish (#4627)
* Invalidate nightly bucket files after publish

* Fix conflict resolution
2024-12-09 11:45:32 -05:00
83fe1b7ce0 Fixup for review comment from #4677 (#4696)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-09 10:42:03 -05:00
157b76cc78 KCL refactor: combine two fields into one struct (#4689) 2024-12-06 19:11:31 -06:00
cf957d880e KCL refactor: Fix argument names (#4690)
Does not change behaviour. It just clarifies whether JS is passing a string containing KCL source code, or containing a JSON-stringified KCL AST.
2024-12-06 17:20:06 -06:00
dfc3d19677 remove clearScene from TS side (#4684)
* updates

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

* fix lint

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

* add failing tests

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

* more tests

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

* the scene is cleared

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

* create new clear scene and bust cache function from rust side

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

* pull thru

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

* set that we switched files

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

* updates

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

* updates

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

* updates

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

* fix two dirties

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

* fix

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-12-06 22:56:53 +00:00
dd370a9365 AST: Allow unlabeled kw args (#4686)
When declaring a function, its first parameter is allowed to be prefixed with `@`. This means that when users call this function, they don't have to label this argument.

Only the first parameter is allowed this prefix, no others.

Part of https://github.com/KittyCAD/modeling-app/issues/4600
2024-12-06 15:44:39 -06:00
2274d6459c Bump @types/react-dom from 18.3.0 to 18.3.1 (#4411)
Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 18.3.0 to 18.3.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react-dom"
  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>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
2024-12-06 15:21:28 -06:00
32ce857119 Update bracket KCL variable syntax in onboarding (#4685) 2024-12-06 16:04:17 -05:00
88b51da417 Run external contributor branch through CI (#4679)
* fix: make variable declaration errors Cut instead of Backtrace

* fix: clippy, move comma to empty case and add test

* fix: add missing TokenType case

* fix: incorrect fn args after merge

* fix: clippy lint

* fix: update error message being looked for in e2e test

---------

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-12-06 14:12:20 -05:00
30d365aeb3 Module/import upgrades (#4677)
* Parse more import syntax

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Remove unnecessary Vec from VariableDeclaration

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Parse export import

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Factor out an execution module

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* imports: constants, globs, export import

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* test fixups

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-06 13:16:04 -05:00
7af62399ac Change vite-plugin-eslint to maintained package (#4645)
* Change vite-plugin-eslint to maintained package

* Add .eslintcache to ignores
2024-12-06 12:28:58 -05:00
441d957228 start of cache: don't re-execute on whitespace / top level code comment changes (#4663)
* start

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

working for whitespace

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

pull thru

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

fix wasm

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

pull thru to js start

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

actually use the cache in ts

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

rust owns clearing the scene

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

fixes

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

empty

stupid log

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

updates

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

* updates

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

fix tests

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

updatez

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

updates

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

save the state

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

save the state

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

updates

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

use the old memory

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

cleanup to use the old exec state

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

fices

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

updates;

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

fixes

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

fmt

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

updates

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

fixes

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

updates

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

cleanup

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

fixes

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

* rebase and compile

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

* Look at this (photo)Graph *in the voice of Nickelback*

* fix the lsp to use the cache

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

* add comment

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

* use a global static instead;

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

* fix rust test

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

* cleanup more

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

* cleanups

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

* cleanup the api even more

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

* updates

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

* updates

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

* Look at this (photo)Graph *in the voice of Nickelback*

* bust the cache on unit changes

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

* updates

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

* updates

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

* updates

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

* Look at this (photo)Graph *in the voice of Nickelback*

* stupid codespell

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-06 03:51:06 +00:00
9e57034873 AST: Allow KCL fn params to have defaults and labels (#4676)
Pure refactor, should not change any behaviour.

Previously, optional parameters in KCL function calls always set the parameter to KclNone. 

As of this PR, they can be set to KCL literals in addition to KCL none. However the parser does not actually ever use this (that'll be in a follow-up PR).

Also adds a `labeled: bool` to all parameters, which is always true. But it lays the groundwork for the unlabeled first parameter in a follow-up PR.
2024-12-06 03:04:40 +00:00
eb96d6539c Surface warnings to frontend and LSP (#4603)
* Send multiple errors and warnings to the frontend and LSP

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Refactor the parser to use CompilationError for parsing errors rather than KclError

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Refactoring: move CompilationError, etc.

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Integrate compilation errors with the frontend and CodeMirror

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Fix tests

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Review comments

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Fix module id/source range stuff

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* More test fixups

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-06 13:57:31 +13:00
513c76ecc8 KCL: Remove stdlib written in KCL (#4673)
We don't have any of these, and I don't think it's
worth the complexity. The goal was to let us write
KCL stdlib functions in KCL not Rust. But who cares
really. We can always put this back if we need it.
2024-12-05 23:59:37 +00:00
51d9449280 Fix broken test from previous PR (#4674)
* Fix broken test from previous PR

* Look at this (photo)Graph *in the voice of Nickelback*

* void

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-05 23:39:40 +00:00
6366bc4766 KCL: Keyword function calls for stdlib (#4647)
Part of https://github.com/KittyCAD/modeling-app/issues/4600

Adds support for keyword arguments to the stdlib, and calling stdlib functions with keyword arguments.

So far, I've changed one function: `rem`. Previously you would have used `rem(7, 2)` but now it's `rem(7, divisor: 2)`.

This is a proof-of-concept. If it's approved, we will:

1. Support closures with keyword arguments, and calling them
2. Move the rest of the stdlib to use kw arguments
2024-12-05 14:27:51 -06:00
7a21918223 Cleaner nightly release notes (#4668)
* Bump: Improve and fix nightly release notes

* Clean up after manual push

* Consistency tweak
2024-12-05 15:14:58 -05:00
8072f1db63 Add support for line comments in playwright-secrets.env (#4671) 2024-12-05 19:45:33 +00:00
18e1855fa9 Bump indexmap from 2.6.0 to 2.7.0 in /src/wasm-lib (#4622)
Bumps [indexmap](https://github.com/indexmap-rs/indexmap) from 2.6.0 to 2.7.0.
- [Changelog](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md)
- [Commits](https://github.com/indexmap-rs/indexmap/compare/2.6.0...2.7.0)

---
updated-dependencies:
- dependency-name: indexmap
  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>
2024-12-05 17:44:35 +00:00
7be53c7d4a Bump KCL, KCL test server, derive-docs (#4670) 2024-12-05 17:34:43 +00:00
2bf20988ef Fix to never have undefined iteration order and lint against it (#4665) 2024-12-05 17:09:35 +00:00
1495cc6d18 Fix default planes to be created in deterministic order (#4664)
* Fix default planes to be created in deterministic order

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

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-05 16:04:04 +00:00
f876e6ca3c Bump and release kcl-lib 0.2.28 (#4669)
bump kcl version
2024-12-05 15:03:55 +00:00
60a0c811ab Move parsing files around (#4626)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-05 17:56:49 +13:00
cab0c1e6a1 Add list of commits as changelog between nightly builds (#4654) 2024-12-04 19:06:17 -05:00
417d720b22 Point-and-click Loft (#4605)
* WIP: experimenting with Loft UI
Relates to #4470

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Add selection guard

* Working loft for two sketches in the right hardcoded order

* First pass at handling more than 2 sketches

* WIP selections

* WIP selections

* More checks

* Appends the loft line after the 'last' sketch in the code

* Clean up

* Enable multiple selections after the button click

* First point-click loft test (not working locally, loft gets inserted at the wrong place)

* Lint

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

* Clean up and working pw test

* Add test for doesSceneHaveSweepableSketch with count = 2

* Clean up loftSketches function

* Add pw test for preselected sketches

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Move to fromPromise-based Actor

* Move error logic out of loftSketches, fix pw tests

* Remove comments

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Fix typo

* Revert snapshots

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

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

* A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest-8-cores)

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-04 22:24:16 +00:00
77293952c0 fix: upon entering sketch mode, axis do not rotate. (#4572)
* fix: upon entering sketch mode, axis do not rotate.

* fix: camera settings has the up vector to set, this should now work
2024-12-04 15:57:17 -06:00
ea3d604b73 Allow standard planes to appear in the artifact graph (#4594) 2024-12-04 21:06:02 +00:00
023a659491 Make some fields of lint::Discovered public again; update kittycad (#4658)
* Make some fields of lint::Discovered public again; update kittycad

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Empty commit to try to unstick CI

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2024-12-05 10:05:23 +13:00
dd3a2b14f9 Bump hashbrown from 0.15.0 to 0.15.2 (#4659) 2024-12-04 20:40:46 +00:00
424b409cc1 Bump and release kcl-lib 0.2.27 (#4643)
* bump and release kcl-lib

* update snapshot

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

* empty commit

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-03 17:58:21 -05:00
82a58e69c2 Bump wasm-pack from 0.13.0 to 0.13.1 (#4630) 2024-12-03 16:27:16 -06:00
max
776b420031 Rename addFillet files to addEdgeTreatment (#4644)
* rename

* update references
2024-12-04 08:30:02 +11:00
1087d4223b Bump happy-dom from 15.10.2 to 15.11.7 (#4625)
Bumps [happy-dom](https://github.com/capricorn86/happy-dom) from 15.10.2 to 15.11.7.
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v15.10.2...v15.11.7)

---
updated-dependencies:
- dependency-name: happy-dom
  dependency-type: direct:development
  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>
2024-12-03 15:40:35 -05:00
089d6df889 Update fn syntax in module docs (#4641) 2024-12-03 15:14:32 -05:00
efb067af58 Update fn syntax in module docs (#4641) 2024-12-03 19:47:21 +00:00
2aa27eab01 Bump happy-dom from 15.10.2 to 15.11.7 (#4625)
Bumps [happy-dom](https://github.com/capricorn86/happy-dom) from 15.10.2 to 15.11.7.
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v15.10.2...v15.11.7)

---
updated-dependencies:
- dependency-name: happy-dom
  dependency-type: direct:development
  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>
2024-12-03 19:40:36 +00:00
9c47ac5b57 Update fn syntax in KCL Types doc (#4640)
* update fn syntax

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

* Trigger CI

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2024-12-03 18:17:02 +00:00
1303 changed files with 432461 additions and 195253 deletions

View File

@ -1,3 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue,afterall ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser
skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock,./openapi/*.json,./src/lib/machine-api.d.ts skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,tsconfig.tsbuildinfo

View File

@ -5,16 +5,32 @@
}, },
"plugins": [ "plugins": [
"css-modules", "css-modules",
"jest",
"jsx-a11y",
"react",
"react-hooks",
"suggest-no-throw", "suggest-no-throw",
"testing-library",
"@typescript-eslint"
], ],
"extends": [ "extends": [
"react-app", "plugin:css-modules/recommended",
"react-app/jest", "plugin:jsx-a11y/recommended",
"plugin:css-modules/recommended" "plugin:react-hooks/recommended"
], ],
"rules": { "rules": {
"@typescript-eslint/no-floating-promises": "error", "@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error", "@typescript-eslint/no-misused-promises": "error",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",
"no-restricted-globals": [
"error",
{
"name": "isNaN",
"message": "Use Number.isNaN() instead."
}
],
"semi": [ "semi": [
"error", "error",
"never" "never"
@ -25,6 +41,9 @@
"overrides": [ "overrides": [
{ {
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure "files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"extends": [
"plugin:testing-library/react"
],
"rules": { "rules": {
"suggest-no-throw/suggest-no-throw": "off", "suggest-no-throw/suggest-no-throw": "off",
"testing-library/prefer-screen-queries": "off", "testing-library/prefer-screen-queries": "off",
@ -33,6 +52,9 @@
}, },
{ {
"files": ["src/**/*.test.ts"], "files": ["src/**/*.test.ts"],
"extends": [
"plugin:testing-library/react"
],
"rules": { "rules": {
"suggest-no-throw/suggest-no-throw": "off", "suggest-no-throw/suggest-no-throw": "off",
} }

View File

@ -1,59 +0,0 @@
# bash strict mode
set -euo pipefail
if [[ ! -f "test-results/.last-run.json" ]]; then
# if no last run artifact, than run plawright normally
echo "run playwright normally"
if [[ "$3" == ubuntu-latest* ]]; then
yarn test:playwright:browser:chrome:ubuntu -- --shard=$1/$2 || true
elif [[ "$3" == windows-latest* ]]; then
yarn test:playwright:browser:chrome:windows -- --shard=$1/$2 || true
else
echo "Do not run playwright. Unable to detect os runtime."
exit 1
fi
# # send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
fi
retry=1
max_retrys=4
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
while [[ $retry -le $max_retrys ]]; do
if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then
echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry"
if [[ "$3" == ubuntu-latest* ]]; then
yarn test:playwright:browser:chrome:ubuntu -- --last-failed || true
elif [[ "$3" == windows-latest* ]]; then
yarn test:playwright:browser:chrome:windows -- --last-failed || true
else
echo "Do not run playwright. Unable to detect os runtime."
exit 1
fi
# send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
retry=$((retry + 1))
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
else
echo "retried=false" >>$GITHUB_OUTPUT
exit 0
fi
done
echo "retried=false" >>$GITHUB_OUTPUT
if [[ -f "test-results/.last-run.json" ]]; then
failed_tests=$(jq '.failedTests | length' test-results/.last-run.json)
if [[ $failed_tests -gt 0 ]]; then
# if it still fails after 3 retrys, then fail the job
exit 1
fi
fi
exit 0

View File

@ -1,15 +1,17 @@
#!/bin/bash
# bash strict mode # bash strict mode
set -euo pipefail set -euo pipefail
if [[ ! -f "test-results/.last-run.json" ]]; then if [[ ! -f "test-results/.last-run.json" ]]; then
# if no last run artifact, than run plawright normally # if no last run artifact, than run plawright normally
echo "run playwright normally" echo "run playwright normally"
if [[ "$1" == ubuntu-latest* ]]; then if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu || true xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --shard=$1/$2 || true
elif [[ "$1" == windows-latest* ]]; then elif [[ "$3" == *windows* ]]; then
yarn test:playwright:electron:windows || true yarn test:playwright:electron:windows -- --shard=$1/$2 || true
elif [[ "$1" == macos-14* ]]; then elif [[ "$3" == *macos* ]]; then
yarn test:playwright:electron:macos || true yarn test:playwright:electron:macos -- --shard=$1/$2 || true
else else
echo "Do not run playwright. Unable to detect os runtime." echo "Do not run playwright. Unable to detect os runtime."
exit 1 exit 1
@ -19,7 +21,7 @@ if [[ ! -f "test-results/.last-run.json" ]]; then
fi fi
retry=1 retry=1
max_retrys=4 max_retrys=5
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues # retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
while [[ $retry -le $max_retrys ]]; do while [[ $retry -le $max_retrys ]]; do
@ -28,11 +30,11 @@ while [[ $retry -le $max_retrys ]]; do
if [[ $failed_tests -gt 0 ]]; then if [[ $failed_tests -gt 0 ]]; then
echo "retried=true" >>$GITHUB_OUTPUT echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry" echo "run playwright with last failed tests and retry $retry"
if [[ "$1" == ubuntu-latest* ]]; then if [[ "$3" == *ubuntu* ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --last-failed || true xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:playwright:electron:ubuntu -- --last-failed || true
elif [[ "$1" == windows-latest* ]]; then elif [[ "$3" == *windows* ]]; then
yarn test:playwright:electron:windows -- --last-failed || true yarn test:playwright:electron:windows -- --last-failed || true
elif [[ "$1" == macos-14* ]]; then elif [[ "$3" == *macos* ]]; then
yarn test:playwright:electron:macos -- --last-failed || true yarn test:playwright:electron:macos -- --last-failed || true
else else
echo "Do not run playwright. Unable to detect os runtime." echo "Do not run playwright. Unable to detect os runtime."

View File

@ -5,24 +5,37 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: 'npm' # See documentation for possible values - package-ecosystem: 'npm' # See documentation for possible values
directory: '/' # Location of package manifests directories:
schedule: - '/'
interval: 'weekly' - '/packages/codemirror-lang-kcl/'
reviewers: - '/packages/codemirror-lsp-client/'
- franknoirot schedule:
- irev-dev interval: weekly
- package-ecosystem: 'github-actions' # See documentation for possible values day: monday
directory: '/' # Location of package manifests reviewers:
schedule: - franknoirot
interval: 'weekly' - irev-dev
reviewers: - package-ecosystem: 'github-actions' # See documentation for possible values
- adamchalmers directory: '/' # Location of package manifests
- jessfraz schedule:
- package-ecosystem: 'cargo' # See documentation for possible values interval: weekly
directory: '/src/wasm-lib/' # Location of package manifests day: monday
schedule: reviewers:
interval: 'weekly' - adamchalmers
reviewers: - jessfraz
- adamchalmers - package-ecosystem: 'cargo' # See documentation for possible values
- jessfraz directory: '/src/wasm-lib/' # Location of package manifests
schedule:
interval: weekly
day: monday
reviewers:
- adamchalmers
- jessfraz
groups:
serde-dependencies:
patterns:
- "serde*"
wasm-bindgen-deps:
patterns:
- "wasm-bindgen*"

View File

@ -27,7 +27,7 @@ jobs:
# Upload the WASM bundle as an artifact # Upload the WASM bundle as an artifact
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v4
with: with:
name: wasm-bundle name: wasm-bundle
path: src/wasm-lib/pkg path: src/wasm-lib/pkg

View File

@ -126,7 +126,13 @@ jobs:
node-version-file: '.nvmrc' node-version-file: '.nvmrc'
cache: 'yarn' # Set this to npm, yarn or pnpm. cache: 'yarn' # Set this to npm, yarn or pnpm.
- run: yarn install - name: yarn install
# Windows is picky sometimes and fails on fetch. Step takes about ~30s
uses: nick-fields/retry@v3.0.0
with:
timeout_minutes: 2
max_attempts: 3
command: yarn install
- run: yarn tronb:vite - run: yarn tronb:vite
@ -165,7 +171,6 @@ jobs:
- name: Build the app (release) - name: Build the app (release)
if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }} if: ${{ env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true' }}
env: env:
PUBLISH_FOR_PULL_REQUEST: true
APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
@ -173,9 +178,14 @@ jobs:
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }} CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }} CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
CSC_FOR_PULL_REQUEST: true
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }} WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
run: yarn electron-builder --config --publish always DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.0
with:
timeout_minutes: 10
max_attempts: 3
command: yarn electron-builder --config --publish always
- name: List artifacts in out/ - name: List artifacts in out/
run: ls -R out run: ls -R out
@ -229,9 +239,14 @@ jobs:
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }} CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }} CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
CSC_FOR_PULL_REQUEST: true
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }} WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
run: yarn electron-builder --config --publish always DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.0
with:
timeout_minutes: 10
max_attempts: 3
command: yarn electron-builder --config --publish always
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }} if: ${{ env.IS_RELEASE == 'true' }}
@ -362,6 +377,17 @@ jobs:
- name: List artifacts - name: List artifacts
run: "ls -R out" run: "ls -R out"
- name: Set more complete nightly release notes
if: ${{ env.IS_NIGHTLY == 'true' }}
run: |
# Note: preferred going this way instead of a full clone in the checkout step,
# see https://github.com/actions/checkout/issues/1471
git fetch --prune --unshallow --tags
export TAG="nightly-${VERSION}"
export PREVIOUS_TAG=$(git describe --tags --match="nightly-v[0-9]*" --abbrev=0)
export NOTES=$(./scripts/get-nightly-changelog.sh)
yarn files:set-notes
- name: Authenticate to Google Cloud - name: Authenticate to Google Cloud
if: ${{ env.IS_NIGHTLY == 'true' }} if: ${{ env.IS_NIGHTLY == 'true' }}
uses: 'google-github-actions/auth@v2.1.7' uses: 'google-github-actions/auth@v2.1.7'
@ -382,3 +408,18 @@ jobs:
glob: '*' glob: '*'
parent: false parent: false
destination: 'dl.kittycad.io/releases/modeling-app/nightly' destination: 'dl.kittycad.io/releases/modeling-app/nightly'
- name: Invalidate bucket cache on latest*.yml and last_download.json files
if: ${{ env.IS_NIGHTLY == 'true' }}
run: yarn files:invalidate-bucket:nightly
- name: Tag nightly commit
if: ${{ env.IS_NIGHTLY == 'true' }}
uses: actions/github-script@v7
with:
script: |
const { VERSION } = process.env
const { owner, repo } = context.repo
const { sha } = context
const ref = `refs/tags/nightly-${VERSION}`
github.rest.git.createRef({ owner, repo, sha, ref })

View File

@ -1,44 +0,0 @@
on:
push:
branches:
- main
paths:
- '**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-bench.yml
pull_request:
paths:
- '**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-bench.yml
workflow_dispatch:
permissions: read-all
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
name: cargo bench
jobs:
cargo-bench:
name: Benchmark with iai
runs-on: ubuntu-latest-8-cores
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
cargo install cargo-criterion
sudo apt update
sudo apt install -y valgrind
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: Benchmark kcl library
shell: bash
run: |-
cd src/wasm-lib/kcl; cargo bench --all-features -- iai
env:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}

View File

@ -2,28 +2,8 @@ on:
push: push:
branches: branches:
- main - main
paths:
- 'src/wasm-lib/**.rs'
- 'src/wasm-lib/**.hbs'
- 'src/wasm-lib/**.gen'
- 'src/wasm-lib/**.snap'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'src/wasm-lib/**.kcl'
- .github/workflows/cargo-test.yml
pull_request: pull_request:
paths:
- 'src/wasm-lib/**.rs'
- 'src/wasm-lib/**.hbs'
- 'src/wasm-lib/**.gen'
- 'src/wasm-lib/**.snap'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'src/wasm-lib/**.kcl'
- .github/workflows/cargo-test.yml
workflow_dispatch: workflow_dispatch:
permissions: read-all permissions: read-all
concurrency: concurrency:
@ -71,7 +51,7 @@ jobs:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}} KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
RUST_MIN_STACK: 10485760000 RUST_MIN_STACK: 10485760000
- name: Upload to codecov.io - name: Upload to codecov.io
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v5
with: with:
token: ${{secrets.CODECOV_TOKEN}} token: ${{secrets.CODECOV_TOKEN}}
fail_ci_if_error: true fail_ci_if_error: true

View File

@ -0,0 +1,32 @@
name: CodeMirror Lang KCL
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
yarn-unit-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
working-directory: packages/codemirror-lang-kcl
- run: yarn tsc
working-directory: packages/codemirror-lang-kcl
- name: run unit tests
run: yarn test
working-directory: packages/codemirror-lang-kcl

View File

@ -33,20 +33,19 @@ jobs:
rust: rust:
- 'src/wasm-lib/**' - 'src/wasm-lib/**'
browser: electron:
timeout-minutes: ${{ matrix.os == 'macos-14' && 60 || 50 }} timeout-minutes: 60
name: playwright:browser:${{ matrix.os }} ${{ matrix.shardIndex }} ${{ matrix.shardTotal }} name: playwright:electron:${{ matrix.os }} ${{ matrix.shardIndex }} ${{ matrix.shardTotal }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest-8-cores, windows-latest-8-cores] # TODO: enable self-hosted-windows-8-cores once available
os: [namespace-profile-ubuntu-8-cores, namespace-profile-macos-8-cores, windows-16-cores]
shardIndex: [1, 2, 3, 4] shardIndex: [1, 2, 3, 4]
shardTotal: [4] shardTotal: [4]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
needs: check-rust-changes needs: check-rust-changes
steps: steps:
- name: Tune GitHub-hosted runner network
uses: smorimoto/tune-github-hosted-runner-network@v1
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
@ -101,194 +100,8 @@ jobs:
echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
- name: Install vector - name: Install vector
shell: bash shell: bash
if: ${{ !startsWith(matrix.os, 'windows') }} # TODO: figure out what to do with this, it's failing
run: | if: false
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
chmod +x /tmp/vector.sh
/tmp/vector.sh -y -no-modify-path
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- name: Build Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
shell: bash
run: yarn build:wasm
- name: OR Build Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
shell: bash
run: yarn build:wasm
- name: build web
run: yarn build:local
shell: bash
- name: Run ubuntu/chrome snapshots
shell: bash
run: |
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --retries="3" --update-snapshots --grep=@snapshot --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
CI: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
with:
name: playwright-report-${{ matrix.os }}-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
overwrite: true
- name: Clean up test-results
if: ${{ !cancelled() && (success() || failure()) }}
continue-on-error: true
run: rm -r test-results
- name: check for changes
shell: bash
id: git-check
run: |
git add .
if git status | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes, if any
if: steps.git-check.outputs.modified == 'true'
shell: bash
run: |
git add .
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
git commit -am "A snapshot a day keeps the bugs away! 📷🐛 (OS: ${{matrix.os}})" || true
git push
git push origin ${{ github.head_ref }}
# only upload artifacts if there's actually changes
- uses: actions/upload-artifact@v4
if: steps.git-check.outputs.modified == 'true'
with:
name: playwright-report-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
- uses: actions/download-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
continue-on-error: true
with:
name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
- name: Run playwright/chrome flow (with retries)
id: retry
if: ${{ !cancelled() && (success() || failure()) }}
shell: bash
run: |
.github/ci-cd-scripts/playwright-browser-chrome.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{matrix.os}}
env:
CI: true
FAIL_ON_CONSOLE_ERRORS: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: send to axiom
if: always()
shell: bash
run: |
node playwrightProcess.mjs | tee /tmp/github-actions.log
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
include-hidden-files: true
retention-days: 30
overwrite: true
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
overwrite: true
electron:
name: playwright:electron:${{matrix.os}}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest-8-cores, windows-latest-8-cores, macos-14-large]
timeout-minutes: 60
runs-on: ${{ matrix.os }}
needs: check-rust-changes
steps:
- name: Tune GitHub-hosted runner network
uses: smorimoto/tune-github-hosted-runner-network@v1
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- uses: KittyCAD/action-install-cli@main
- name: Install dependencies
shell: bash
run: yarn
- name: Cache Playwright Browsers
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Browsers
shell: bash
run: yarn playwright install chromium --with-deps
- name: Download Wasm Cache
id: download-wasm
if: needs.check-rust-changes.outputs.rust-changed == 'false'
uses: dawidd6/action-download-artifact@v7
continue-on-error: true
with:
github_token: ${{secrets.GITHUB_TOKEN}}
name: wasm-bundle
workflow: build-and-store-wasm.yml
branch: main
path: src/wasm-lib/pkg
- name: copy wasm blob
if: needs.check-rust-changes.outputs.rust-changed == 'false'
shell: bash
run: cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
continue-on-error: true
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: OR Cache Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: install good sed
if: ${{ startsWith(matrix.os, 'macos') }}
shell: bash
run: |
brew install gnu-sed
echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
- name: Install vector
if: ${{ startsWith(matrix.os, 'ubuntu') }}
shell: bash
run: | run: |
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
chmod +x /tmp/vector.sh chmod +x /tmp/vector.sh
@ -313,44 +126,97 @@ jobs:
- name: build electron - name: build electron
shell: bash shell: bash
run: yarn tron:package run: yarn tron:package
# - name: Run ubuntu/chrome snapshots
# if: ${{ matrix.os == 'namespace-profile-ubuntu-8-cores' && matrix.shardIndex == 1 }}
# shell: bash
# # 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 --shard=1/1
# env:
# CI: true
# NODE_ENV: development
# VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
# VITE_KC_SKIP_AUTH: true
# token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
# snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
with:
name: playwright-report-${{ matrix.os }}-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
overwrite: true
- name: Clean up test-results
if: ${{ !cancelled() && (success() || failure()) }}
continue-on-error: true
run: rm -r test-results
- name: check for changes
if: ${{ matrix.os == 'namespace-profile-ubuntu-8-cores' && matrix.shardIndex == 1 }}
shell: bash
id: git-check
run: |
git add .
if git status | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
# - name: Commit changes, if any
# if: steps.git-check.outputs.modified == 'true'
# shell: bash
# run: |
# git add .
# git config --local user.email "github-actions[bot]@users.noreply.github.com"
# git config --local user.name "github-actions[bot]"
# git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
# git fetch origin
# echo ${{ github.head_ref }}
# git checkout ${{ github.head_ref }}
# git commit -am "A snapshot a day keeps the bugs away! 📷🐛 (OS: ${{matrix.os}})" || true
# git push
# git push origin ${{ github.head_ref }}
# only upload artifacts if there's actually changes
- uses: actions/upload-artifact@v4
if: steps.git-check.outputs.modified == 'true'
with:
name: playwright-report-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
include-hidden-files: true
retention-days: 30
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }} if: ${{ !cancelled() && (success() || failure()) }}
continue-on-error: true continue-on-error: true
with: with:
name: test-results-electron-${{ matrix.os }}-${{ github.sha }} name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/ path: test-results/
- name: Run electron tests (with retries) - name: Run playwright/electron flow (with retries)
id: retry id: retry
if: ${{ !cancelled() && (success() || failure()) }} if: ${{ !cancelled() && (success() || failure()) }}
shell: bash shell: bash
run: | run: |
.github/ci-cd-scripts/playwright-electron.sh ${{ matrix.os }} .github/ci-cd-scripts/playwright-electron.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{matrix.os}}
env: env:
CI: true CI: true
FAIL_ON_CONSOLE_ERRORS: true FAIL_ON_CONSOLE_ERRORS: true
NODE_ENV: development NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true VITE_KC_SKIP_AUTH: true
IS_UBUNTU: ${{ startsWith(matrix.os, 'ubuntu') && 'true' || 'false' }} token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
#DEBUG: 'pw:browser*'
- name: send to axiom
if: ${{ !cancelled() && (success() || failure()) && !startsWith(matrix.os, 'windows') }}
shell: bash
run: |
node playwrightProcess.mjs | tee /tmp/github-actions.log
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }} if: always()
with: with:
name: test-results-electron-${{ matrix.os }}-${{ github.sha }} name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/ path: test-results/
include-hidden-files: true include-hidden-files: true
retention-days: 30 retention-days: 30
overwrite: true overwrite: true
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }} if: always()
with: with:
name: playwright-report-electron-${{ matrix.os }}-${{ github.sha }} name: playwright-report-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/ path: playwright-report/
include-hidden-files: true include-hidden-files: true
retention-days: 30 retention-days: 30
overwrite: true overwrite: true

View File

@ -126,11 +126,7 @@ jobs:
destination: 'dl.kittycad.io/releases/modeling-app' destination: 'dl.kittycad.io/releases/modeling-app'
- name: Invalidate bucket cache on latest*.yml and last_download.json files - name: Invalidate bucket cache on latest*.yml and last_download.json files
run: | run: yarn files:invalidate-bucket
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/last_download.json" --async
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/latest-linux-arm64.yml" --async
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/latest-mac.yml" --async
gcloud compute url-maps invalidate-cdn-cache dl-url-map --path="/releases/modeling-app/latest.yml" --async
- name: Upload release files to Github - name: Upload release files to Github
if: ${{ github.event_name == 'release' }} if: ${{ github.event_name == 'release' }}

3
.gitignore vendored
View File

@ -44,7 +44,7 @@ e2e/playwright/temp3.png
e2e/playwright/export-snapshots/* e2e/playwright/export-snapshots/*
!e2e/playwright/export-snapshots/*.png !e2e/playwright/export-snapshots/*.png
/kcl-samples
/test-results/ /test-results/
/playwright-report/ /playwright-report/
/blob-report/ /blob-report/
@ -61,6 +61,7 @@ Mac_App_Distribution.provisionprofile
*.tsbuildinfo *.tsbuildinfo
src/wasm-lib/pkg src/wasm-lib/pkg
.eslintcache
venv venv
.vite/ .vite/

2
.nvmrc
View File

@ -1 +1 @@
v21.7.3 v22.12.0

43
INSTALL.md Normal file
View File

@ -0,0 +1,43 @@
# Setting Up Zoo Modeling App
Compared to other CAD software, getting Zoo Modeling App up and running is quick and straightforward across platforms. It's about 100MB to download and is quick to install.
## Windows
1. Download the [Zoo Modeling App installer](https://zoo.dev/modeling-app/download) for Windows and for your processor type.
2. Once downloaded, run the installer `Zoo Modeling App-{version}-{arch}-win.exe` which should take a few seconds.
3. The installation happens at `C:\Program Files\Zoo Modeling App`. A shortcut in the start menu is also created so you can run the app easily by clicking on it.
## macOS
1. Download the [Zoo Modeling App installer](https://zoo.dev/modeling-app/download) for macOS and for your processor type.
2. Once downloaded, open the disk image `Zoo Modeling App-{version}-{arch}-mac.dmg` and drag the applications to your `Applications` directory.
3. You can then open your `Applications` directory and double-click on `Zoo Modeling App` to open.
## Linux
1. Download the [Zoo Modeling App installer](https://zoo.dev/modeling-app/download) for Linux and for your processor type.
2. Install the dependencies needed to run the [AppImage format](https://appimage.org/).
- On Ubuntu, install the FUSE library with these commands in a terminal.
```bash
sudo apt update
sudo apt install libfuse2
```
- Optionally, follow [these steps](https://github.com/probonopd/go-appimage/blob/master/src/appimaged/README.md#initial-setup) to install `appimaged`. It is a daemon that makes interacting with AppImage files more seamless.
- Once installed, copy the downloaded `Zoo Modeling App-{version}-{arch}-linux.AppImage` to the directory of your choice, for instance `~/Applications`.
- `appimaged` should automatically find it and make it executable. If not, run:
```bash
chmod a+x ~/Applications/Zoo\ Modeling\ App-{version}-{arch}-linux.AppImage
```
3. You can double-click on the AppImage to run it, or in a terminal with this command:
```bash
~/Applications/Zoo\ Modeling\ App-{version}-{arch}-linux.AppImage
```

View File

@ -99,7 +99,7 @@ yarn tron:start
This will start the application and hot-reload on changes. This will start the application and hot-reload on changes.
Devtools can be opened with the usual Cmd/Ctrl-Shift-I. Devtools can be opened with the usual Cmd-Opt-I (Mac) or Ctrl-Shift-I (Linux and Windows).
To build, run `yarn tron:package`. To build, run `yarn tron:package`.
@ -337,13 +337,47 @@ For individual testing:
yarn test abstractSyntaxTree -t "unexpected closed curly brace" --silent=false yarn test abstractSyntaxTree -t "unexpected closed curly brace" --silent=false
``` ```
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro/) tests, in interactive mode by default. Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro) tests, in interactive mode by default.
### Rust tests ### Rust tests
```bash **Dependencies**
- `KITTYCAD_API_TOKEN`
- `cargo-nextest`
- `just`
#### Setting KITTYCAD_API_TOKEN
Use the production zoo.dev token, set this environment variable before running the tests
#### Installing cargonextest
```
cd src/wasm-lib cd src/wasm-lib
KITTYCAD_API_TOKEN=XXX cargo test -- --test-threads=1 cargo search cargo-nextest
cargo install cargo-nextest
```
#### just
install [`just`](https://github.com/casey/just?tab=readme-ov-file#pre-built-binaries)
#### Running the tests
```bash
# With just
# Make sure KITTYCAD_API_TOKEN=<prod zoo.dev token> is set
# Make sure you installed cargo-nextest
# Make sure you installed just
cd src/wasm-lib
just test
```
```bash
# Without just
# Make sure KITTYCAD_API_TOKEN=<prod zoo.dev token> is set
# Make sure you installed cargo-nextest
cd src/wasm-lib
export RUST_BRACKTRACE="full" && cargo nextest run --workspace --test-threads=1
``` ```
Where `XXX` is an API token from the production engine (NOT the dev environment). Where `XXX` is an API token from the production engine (NOT the dev environment).
@ -388,23 +422,6 @@ yarn test:unit:local
#### E2E Tests #### E2E Tests
**Playwright Browser**
These E2E tests run in a browser (without electron).
There are tests that are skipped if they are ran in a windows OS or Linux OS. We can use playwright tags to implement test skipping.
Breaking down the command `yarn test:playwright:browser:chrome:windows`
- The application is `playwright`
- The runtime is a `browser`
- The specific `browser` is `chrome`
- The test should run in a `windows` environment. It will skip tests that are broken or flaky in the windows OS.
```
yarn test:playwright:browser:chrome
yarn test:playwright:browser:chrome:windows
yarn test:playwright:browser:chrome:ubuntu
```
**Playwright Electron** **Playwright Electron**
These E2E tests run in electron. There are tests that are skipped if they are ran in a windows, linux, or macos environment. We can use playwright tags to implement test skipping. These E2E tests run in electron. There are tests that are skipped if they are ran in a windows, linux, or macos environment. We can use playwright tags to implement test skipping.

View File

@ -22,3 +22,5 @@ once fixed in engine will just start working here with no language changes.
- **Chamfers**: Chamfers cannot intersect, you will get an error. Only simple - **Chamfers**: Chamfers cannot intersect, you will get an error. Only simple
chamfer cases work currently. chamfer cases work currently.
- **Appearance**: Changing the appearance on a loft does not work.

239
docs/kcl/appearance.md Normal file

File diff suppressed because one or more lines are too long

49
docs/kcl/atan2.md Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -19,6 +19,7 @@ layout: manual
* [`angledLineThatIntersects`](kcl/angledLineThatIntersects) * [`angledLineThatIntersects`](kcl/angledLineThatIntersects)
* [`angledLineToX`](kcl/angledLineToX) * [`angledLineToX`](kcl/angledLineToX)
* [`angledLineToY`](kcl/angledLineToY) * [`angledLineToY`](kcl/angledLineToY)
* [`appearance`](kcl/appearance)
* [`arc`](kcl/arc) * [`arc`](kcl/arc)
* [`arcTo`](kcl/arcTo) * [`arcTo`](kcl/arcTo)
* [`asin`](kcl/asin) * [`asin`](kcl/asin)
@ -29,10 +30,12 @@ layout: manual
* [`assertLessThan`](kcl/assertLessThan) * [`assertLessThan`](kcl/assertLessThan)
* [`assertLessThanOrEq`](kcl/assertLessThanOrEq) * [`assertLessThanOrEq`](kcl/assertLessThanOrEq)
* [`atan`](kcl/atan) * [`atan`](kcl/atan)
* [`atan2`](kcl/atan2)
* [`bezierCurve`](kcl/bezierCurve) * [`bezierCurve`](kcl/bezierCurve)
* [`ceil`](kcl/ceil) * [`ceil`](kcl/ceil)
* [`chamfer`](kcl/chamfer) * [`chamfer`](kcl/chamfer)
* [`circle`](kcl/circle) * [`circle`](kcl/circle)
* [`circleThreePoint`](kcl/circleThreePoint)
* [`close`](kcl/close) * [`close`](kcl/close)
* [`cm`](kcl/cm) * [`cm`](kcl/cm)
* [`cos`](kcl/cos) * [`cos`](kcl/cos)
@ -45,11 +48,10 @@ layout: manual
* [`getOppositeEdge`](kcl/getOppositeEdge) * [`getOppositeEdge`](kcl/getOppositeEdge)
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge) * [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
* [`helix`](kcl/helix) * [`helix`](kcl/helix)
* [`helixRevolutions`](kcl/helixRevolutions)
* [`hole`](kcl/hole) * [`hole`](kcl/hole)
* [`hollow`](kcl/hollow) * [`hollow`](kcl/hollow)
* [`import`](kcl/import)
* [`inch`](kcl/inch) * [`inch`](kcl/inch)
* [`int`](kcl/int)
* [`lastSegX`](kcl/lastSegX) * [`lastSegX`](kcl/lastSegX)
* [`lastSegY`](kcl/lastSegY) * [`lastSegY`](kcl/lastSegY)
* [`legAngX`](kcl/legAngX) * [`legAngX`](kcl/legAngX)
@ -78,6 +80,7 @@ layout: manual
* [`pi`](kcl/pi) * [`pi`](kcl/pi)
* [`polar`](kcl/polar) * [`polar`](kcl/polar)
* [`polygon`](kcl/polygon) * [`polygon`](kcl/polygon)
* [`pop`](kcl/pop)
* [`pow`](kcl/pow) * [`pow`](kcl/pow)
* [`profileStart`](kcl/profileStart) * [`profileStart`](kcl/profileStart)
* [`profileStartX`](kcl/profileStartX) * [`profileStartX`](kcl/profileStartX)
@ -99,8 +102,8 @@ layout: manual
* [`sin`](kcl/sin) * [`sin`](kcl/sin)
* [`sqrt`](kcl/sqrt) * [`sqrt`](kcl/sqrt)
* [`startProfileAt`](kcl/startProfileAt) * [`startProfileAt`](kcl/startProfileAt)
* [`startSketchAt`](kcl/startSketchAt)
* [`startSketchOn`](kcl/startSketchOn) * [`startSketchOn`](kcl/startSketchOn)
* [`sweep`](kcl/sweep)
* [`tan`](kcl/tan) * [`tan`](kcl/tan)
* [`tangentToEnd`](kcl/tangentToEnd) * [`tangentToEnd`](kcl/tangentToEnd)
* [`tangentialArc`](kcl/tangentialArc) * [`tangentialArc`](kcl/tangentialArc)

View File

@ -4,6 +4,8 @@ excerpt: "Convert a number to an integer."
layout: manual layout: manual
--- ---
**WARNING:** This function is deprecated.
Convert a number to an integer. Convert a number to an integer.
DEPRECATED use floor(), ceil(), or round(). DEPRECATED use floor(), ceil(), or round().

File diff suppressed because one or more lines are too long

View File

@ -45,7 +45,7 @@ circles = map([1..3], drawCircle)
```js ```js
r = 10 // radius r = 10 // radius
// Call `map`, using an anonymous function instead of a named one. // Call `map`, using an anonymous function instead of a named one.
circles = map([1..3], (id) { circles = map([1..3], fn(id) {
return startSketchOn("XY") return startSketchOn("XY")
|> circle({ center = [id * 2 * r, 0], radius = r }, %) |> circle({ center = [id * 2 * r, 0], radius = r }, %)
}) })

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,7 @@ to other modules.
``` ```
// util.kcl // util.kcl
export fn increment = (x) => { export fn increment(x) {
return x + 1 return x + 1
} }
``` ```
@ -37,11 +37,11 @@ Multiple functions can be exported in a file.
``` ```
// util.kcl // util.kcl
export fn increment = (x) => { export fn increment(x) {
return x + 1 return x + 1
} }
export fn decrement = (x) => { export fn decrement(x) {
return x - 1 return x - 1
} }
``` ```

File diff suppressed because one or more lines are too long

View File

@ -35,7 +35,7 @@ The transform function returns a transform object. All properties of the object
- `rotation.origin` (either "local" i.e. rotate around its own center, "global" i.e. rotate around the scene's center, or a 3D point, defaults to "local") - `rotation.origin` (either "local" i.e. rotate around its own center, "global" i.e. rotate around the scene's center, or a 3D point, defaults to "local")
```js ```js
patternTransform(total_instances: u32, transform_function: FunctionParam, solid_set: SolidSet) -> [Solid] patternTransform(total_instances: integer, transform_function: FunctionParam, solid_set: SolidSet) -> [Solid]
``` ```
@ -43,7 +43,7 @@ patternTransform(total_instances: u32, transform_function: FunctionParam, solid_
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `total_instances` | `u32` | | Yes | | `total_instances` | `integer` | | Yes |
| `transform_function` | `FunctionParam` | | Yes | | `transform_function` | `FunctionParam` | | Yes |
| `solid_set` | [`SolidSet`](/docs/kcl/types/SolidSet) | A solid or a group of solids. | Yes | | `solid_set` | [`SolidSet`](/docs/kcl/types/SolidSet) | A solid or a group of solids. | Yes |
@ -95,7 +95,8 @@ fn cube(length, center) {
p2 = [l + x, l + y] p2 = [l + x, l + y]
p3 = [l + x, -l + y] p3 = [l + x, -l + y]
return startSketchAt(p0) return startSketchOn('XY')
|> startProfileAt(p0, %)
|> lineTo(p1, %) |> lineTo(p1, %)
|> lineTo(p2, %) |> lineTo(p2, %)
|> lineTo(p3, %) |> lineTo(p3, %)
@ -132,7 +133,8 @@ fn cube(length, center) {
p2 = [l + x, l + y] p2 = [l + x, l + y]
p3 = [l + x, -l + y] p3 = [l + x, -l + y]
return startSketchAt(p0) return startSketchOn('XY')
|> startProfileAt(p0, %)
|> lineTo(p1, %) |> lineTo(p1, %)
|> lineTo(p2, %) |> lineTo(p2, %)
|> lineTo(p3, %) |> lineTo(p3, %)
@ -195,7 +197,8 @@ fn transform(i) {
{ rotation = { angle = 45 * i } } { rotation = { angle = 45 * i } }
] ]
} }
startSketchAt([0, 0]) startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> polygon({ |> polygon({
radius = 10, radius = 10,
numSides = 4, numSides = 4,

View File

@ -9,7 +9,7 @@ Just like patternTransform, but works on 2D sketches not 3D solids.
```js ```js
patternTransform2d(total_instances: u32, transform_function: FunctionParam, solid_set: SketchSet) -> [Sketch] patternTransform2d(total_instances: integer, transform_function: FunctionParam, solid_set: SketchSet) -> [Sketch]
``` ```
@ -17,7 +17,7 @@ patternTransform2d(total_instances: u32, transform_function: FunctionParam, soli
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `total_instances` | `u32` | | Yes | | `total_instances` | `integer` | | Yes |
| `transform_function` | `FunctionParam` | | Yes | | `transform_function` | `FunctionParam` | | Yes |
| `solid_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes | | `solid_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |

39
docs/kcl/pop.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -43,7 +43,7 @@ fn sum(arr) {
/* The above is basically like this pseudo-code: /* The above is basically like this pseudo-code:
fn sum(arr): fn sum(arr):
let sumSoFar = 0 sumSoFar = 0
for i in arr: for i in arr:
sumSoFar = add(sumSoFar, i) sumSoFar = add(sumSoFar, i)
return sumSoFar */ return sumSoFar */
@ -61,7 +61,7 @@ assertEqual(sum([1, 2, 3]), 6, 0.00001, "1 + 2 + 3 summed is 6")
// an anonymous `add` function as its parameter, instead of declaring a // an anonymous `add` function as its parameter, instead of declaring a
// named function outside. // named function outside.
arr = [1, 2, 3] arr = [1, 2, 3]
sum = reduce(arr, 0, (i, result_so_far) { sum = reduce(arr, 0, fn(i, result_so_far) {
return i + result_so_far return i + result_so_far
}) })
@ -79,12 +79,13 @@ fn decagon(radius) {
stepAngle = 1 / 10 * tau() stepAngle = 1 / 10 * tau()
// Start the decagon sketch at this point. // Start the decagon sketch at this point.
startOfDecagonSketch = startSketchAt([cos(0) * radius, sin(0) * radius]) startOfDecagonSketch = startSketchOn('XY')
|> startProfileAt([cos(0) * radius, sin(0) * radius], %)
// Use a `reduce` to draw the remaining decagon sides. // Use a `reduce` to draw the remaining decagon sides.
// For each number in the array 1..10, run the given function, // For each number in the array 1..10, run the given function,
// which takes a partially-sketched decagon and adds one more edge to it. // which takes a partially-sketched decagon and adds one more edge to it.
fullDecagon = reduce([1..10], startOfDecagonSketch, (i, partialDecagon) { fullDecagon = reduce([1..10], startOfDecagonSketch, fn(i, partialDecagon) {
// Draw one edge of the decagon. // Draw one edge of the decagon.
x = cos(stepAngle * i) * radius x = cos(stepAngle * i) * radius
y = sin(stepAngle * i) * radius y = sin(stepAngle * i) * radius
@ -96,14 +97,15 @@ fn decagon(radius) {
/* The `decagon` above is basically like this pseudo-code: /* The `decagon` above is basically like this pseudo-code:
fn decagon(radius): fn decagon(radius):
let stepAngle = (1/10) * tau() stepAngle = (1/10) * tau()
let startOfDecagonSketch = startSketchAt([(cos(0)*radius), (sin(0) * radius)]) plane = startSketchOn('XY')
startOfDecagonSketch = startProfileAt([(cos(0)*radius), (sin(0) * radius)], plane)
// Here's the reduce part. // Here's the reduce part.
let partialDecagon = startOfDecagonSketch partialDecagon = startOfDecagonSketch
for i in [1..10]: for i in [1..10]:
let x = cos(stepAngle * i) * radius x = cos(stepAngle * i) * radius
let y = sin(stepAngle * i) * radius y = sin(stepAngle * i) * radius
partialDecagon = lineTo([x, y], partialDecagon) partialDecagon = lineTo([x, y], partialDecagon)
fullDecagon = partialDecagon // it's now full fullDecagon = partialDecagon // it's now full
return fullDecagon */ return fullDecagon */

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,8 @@ segEnd(tag: TagIdentifier) -> [number]
```js ```js
w = 15 w = 15
cube = startSketchAt([0, 0]) cube = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([w, 0], %, $line1) |> line([w, 0], %, $line1)
|> line([0, w], %, $line2) |> line([0, w], %, $line2)
|> line([-w, 0], %, $line3) |> line([-w, 0], %, $line3)
@ -37,7 +38,8 @@ cube = startSketchAt([0, 0])
|> extrude(5, %) |> extrude(5, %)
fn cylinder(radius, tag) { fn cylinder(radius, tag) {
return startSketchAt([0, 0]) return startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> circle({ |> circle({
radius = radius, radius = radius,
center = segEnd(tag) center = segEnd(tag)

View File

@ -28,7 +28,8 @@ segStart(tag: TagIdentifier) -> [number]
```js ```js
w = 15 w = 15
cube = startSketchAt([0, 0]) cube = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([w, 0], %, $line1) |> line([w, 0], %, $line1)
|> line([0, w], %, $line2) |> line([0, w], %, $line2)
|> line([-w, 0], %, $line3) |> line([-w, 0], %, $line3)
@ -37,7 +38,8 @@ cube = startSketchAt([0, 0])
|> extrude(5, %) |> extrude(5, %)
fn cylinder(radius, tag) { fn cylinder(radius, tag) {
return startSketchAt([0, 0]) return startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> circle({ |> circle({
radius = radius, radius = radius,
center = segStart(tag) center = segStart(tag)

View File

@ -4,6 +4,8 @@ excerpt: "Start a new 2-dimensional sketch at a given point on the 'XY' plane."
layout: manual layout: manual
--- ---
**WARNING:** This function is deprecated.
Start a new 2-dimensional sketch at a given point on the 'XY' plane. Start a new 2-dimensional sketch at a given point on the 'XY' plane.

File diff suppressed because it is too large Load Diff

77
docs/kcl/sweep.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -54,7 +54,7 @@ We also have support for defining your own functions. Functions can take in any
type of argument. Below is an example of the syntax: type of argument. Below is an example of the syntax:
``` ```
fn myFn = (x) => { fn myFn(x) {
return x return x
} }
``` ```
@ -118,7 +118,7 @@ use the tag `rectangleSegmentA001` in any function or expression in the file.
However if the code was written like this: However if the code was written like this:
``` ```
fn rect = (origin) => { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine([0, 191.26], %, $rectangleSegmentA001) |> angledLine([0, 191.26], %, $rectangleSegmentA001)
@ -146,7 +146,7 @@ Tags are accessible through the sketch group they are declared in.
For example the following code works. For example the following code works.
``` ```
fn rect = (origin) => { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine([0, 191.26], %, $rectangleSegmentA001) |> angledLine([0, 191.26], %, $rectangleSegmentA001)

View File

@ -13,13 +13,18 @@ Data to draw an angled line.
An angle and length with explicitly named parameters An angle and length with explicitly named parameters
[`PolarCoordsData`](/docs/kcl/types/PolarCoordsData) **Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `angle` |`number`| The angle of the line (in degrees). | No |
| `length` |`number`| The length of the line. | No |
---- ----

View File

@ -0,0 +1,23 @@
---
title: "AppearanceData"
excerpt: "Data for appearance."
layout: manual
---
Data for appearance.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `color` |`string`| Color of the new material, a hex string like "#ff0000". | No |
| `metalness` |`number` (**maximum:** 100.0)| Metalness of the new material, a percentage like 95.7. | No |
| `roughness` |`number` (**maximum:** 100.0)| Roughness of the new material, a percentage like 95.7. | No |

View File

@ -1,19 +1,19 @@
--- ---
title: "AxisOrEdgeReference" title: "Axis2dOrEdgeReference"
excerpt: "Axis or tagged edge." excerpt: "A 2D axis or tagged edge."
layout: manual layout: manual
--- ---
Axis or tagged edge. A 2D axis or tagged edge.
**This schema accepts any of the following:** **This schema accepts any of the following:**
Axis and origin. 2D axis and origin.
[`AxisAndOrigin`](/docs/kcl/types/AxisAndOrigin) [`AxisAndOrigin2d`](/docs/kcl/types/AxisAndOrigin2d)

View File

@ -0,0 +1,42 @@
---
title: "Axis3dOrEdgeReference"
excerpt: "A 3D axis or tagged edge."
layout: manual
---
A 3D axis or tagged edge.
**This schema accepts any of the following:**
3D axis and origin.
[`AxisAndOrigin3d`](/docs/kcl/types/AxisAndOrigin3d)
----
Tagged edge.
[`EdgeReference`](/docs/kcl/types/EdgeReference)
----

View File

@ -1,10 +1,10 @@
--- ---
title: "AxisAndOrigin" title: "AxisAndOrigin2d"
excerpt: "Axis and origin." excerpt: "A 2D axis and origin."
layout: manual layout: manual
--- ---
Axis and origin. A 2D axis and origin.

View File

@ -0,0 +1,105 @@
---
title: "AxisAndOrigin3d"
excerpt: "A 3D axis and origin."
layout: manual
---
A 3D axis and origin.
**This schema accepts exactly one of the following:**
X-axis.
**enum:** `X`
----
Y-axis.
**enum:** `Y`
----
Z-axis.
**enum:** `Z`
----
Flip the X-axis.
**enum:** `-X`
----
Flip the Y-axis.
**enum:** `-Y`
----
Flip the Z-axis.
**enum:** `-Z`
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `custom` |`object`| | No |
----

View File

@ -0,0 +1,23 @@
---
title: "CircleThreePointData"
excerpt: "Data for drawing a 3-point circle"
layout: manual
---
Data for drawing a 3-point circle
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `p1` |`[number, number]`| Point one for circle derivation. | No |
| `p2` |`[number, number]`| Point two for circle derivation. | No |
| `p3` |`[number, number]`| Point three for circle derivation. | No |

28
docs/kcl/types/Face.md Normal file
View File

@ -0,0 +1,28 @@
---
title: "Face"
excerpt: "A face."
layout: manual
---
A face.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `id` |`string`| The id of the face. | No |
| `value` |`string`| The tag of the face. | No |
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the faces X axis be? | No |
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the faces Y axis be? | No |
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
| `solid` |[`Solid`](/docs/kcl/types/Solid)| The solid the face is on. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A face. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

26
docs/kcl/types/Helix.md Normal file
View File

@ -0,0 +1,26 @@
---
title: "Helix"
excerpt: "A helix."
layout: manual
---
A helix.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `value` |`string`| The id of the helix. | No |
| `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A helix. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -1,10 +1,10 @@
--- ---
title: "HelixData" title: "HelixData"
excerpt: "Data for helices." excerpt: "Data for a helix."
layout: manual layout: manual
--- ---
Data for helices. Data for a helix.
**Type:** `object` **Type:** `object`
@ -19,6 +19,8 @@ Data for helices.
| `revolutions` |`number`| Number of revolutions. | No | | `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No | | `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? The default is `false`. | No | | `ccw` |`boolean`| Is the helix rotation counter clockwise? The default is `false`. | No |
| `length` |`number`| Length of the helix. If this argument is not provided, the height of the solid is used. | No | | `length` |`number`| Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used. | No |
| `radius` |`number`| Radius of the helix. | No |
| `axis` |[`Axis3dOrEdgeReference`](/docs/kcl/types/Axis3dOrEdgeReference)| Axis to use as mirror. | No |

View File

@ -0,0 +1,24 @@
---
title: "HelixRevolutionsData"
excerpt: "Data for helix revolutions."
layout: manual
---
Data for helix revolutions.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? The default is `false`. | No |
| `length` |`number`| Length of the helix. If this argument is not provided, the height of the solid is used. | No |

View File

@ -0,0 +1,26 @@
---
title: "HelixValue"
excerpt: "A helix."
layout: manual
---
A helix.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `value` |`string`| The id of the helix. | No |
| `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A helix. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -12,5 +12,10 @@ KCL value for an optional parameter which was not given an argument. (remember,
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `digest` |`[, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`, `integer`]`| | No |

View File

@ -168,7 +168,6 @@ Any KCL value.
---- ----
A plane.
**Type:** `object` **Type:** `object`
@ -181,17 +180,10 @@ A plane.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`Plane`](/docs/kcl/types/Plane)| | No | | `type` |enum: [`Plane`](/docs/kcl/types/Plane)| | No |
| `id` |`string`| The id of the plane. | No | | `value` |[`Plane`](/docs/kcl/types/Plane)| Any KCL value. | No |
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| Any KCL value. | No |
| `origin` |[`Point3d`](/docs/kcl/types/Point3d)| Origin of the plane. | No |
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes X axis be? | No |
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes Y axis be? | No |
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
---- ----
A face.
**Type:** `object` **Type:** `object`
@ -203,14 +195,8 @@ A face.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: `Face`| | No | | `type` |enum: [`Face`](/docs/kcl/types/Face)| | No |
| `id` |`string`| The id of the face. | No | | `value` |[`Face`](/docs/kcl/types/Face)| Any KCL value. | No |
| `value` |`string`| The tag of the face. | No |
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the faces X axis be? | No |
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the faces Y axis be? | No |
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
| `solid` |[`Solid`](/docs/kcl/types/Solid)| The solid the face is on. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
---- ----
@ -246,7 +232,6 @@ A face.
---- ----
An solid is a collection of extrude surfaces.
**Type:** `object` **Type:** `object`
@ -259,14 +244,7 @@ An solid is a collection of extrude surfaces.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `type` |enum: [`Solid`](/docs/kcl/types/Solid)| | No | | `type` |enum: [`Solid`](/docs/kcl/types/Solid)| | No |
| `id` |`string`| The id of the solid. | No | | `value` |[`Solid`](/docs/kcl/types/Solid)| Any KCL value. | No |
| `value` |`[` [`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface) `]`| The extrude surfaces. | No |
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
| `height` |`number`| The height of the solid. | No |
| `startCapId` |`string`| The id of the extrusion start cap | No |
| `endCapId` |`string`| The id of the extrusion end cap | No |
| `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
---- ----
@ -285,6 +263,22 @@ An solid is a collection of extrude surfaces.
| `value` |`[` [`Solid`](/docs/kcl/types/Solid) `]`| | No | | `value` |`[` [`Solid`](/docs/kcl/types/Solid) `]`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: [`Helix`](/docs/kcl/types/Helix)| | No |
| `value` |[`Helix`](/docs/kcl/types/Helix)| Any KCL value. | No |
---- ----
Data for an imported geometry. Data for an imported geometry.
@ -329,6 +323,23 @@ Data for an imported geometry.
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Module`| | No |
| `value` |[`ModuleId`](/docs/kcl/types/ModuleId)| Any KCL value. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
----
**Type:** `object`
## Properties ## Properties
| Property | Type | Description | Required | | Property | Type | Description | Required |

View File

@ -16,6 +16,6 @@ Data for a mirror.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `axis` |[`AxisOrEdgeReference`](/docs/kcl/types/AxisOrEdgeReference)| Axis to use as mirror. | No | | `axis` |[`Axis2dOrEdgeReference`](/docs/kcl/types/Axis2dOrEdgeReference)| Axis to use as mirror. | No |

View File

@ -0,0 +1,16 @@
---
title: "ModuleId"
excerpt: "Identifier of a source file. Uses a u32 to keep the size small."
layout: manual
---
Identifier of a source file. Uses a u32 to keep the size small.
**Type:** `integer` (`uint32`)

View File

@ -22,6 +22,7 @@ A plane.
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes X axis be? | No | | `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes X axis be? | No |
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes Y axis be? | No | | `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes Y axis be? | No |
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No | | `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A plane. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -17,7 +17,7 @@ Data for revolution surfaces.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `angle` |`number` (**maximum:** 360.0) (**minimum:** -360.0)| Angle to revolve (in degrees). Default is 360. | No | | `angle` |`number` (**maximum:** 360.0) (**minimum:** -360.0)| Angle to revolve (in degrees). Default is 360. | No |
| `axis` |[`AxisOrEdgeReference`](/docs/kcl/types/AxisOrEdgeReference)| Axis of revolution. | No | | `axis` |[`Axis2dOrEdgeReference`](/docs/kcl/types/Axis2dOrEdgeReference)| Axis of revolution. | No |
| `tolerance` |`number`| Tolerance for the revolve operation. | No | | `tolerance` |`number`| Tolerance for the revolve operation. | No |

View File

@ -21,6 +21,7 @@ A sketch is a collection of paths.
| `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No | | `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No |
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No | | `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | No | | `tags` |`object`| Tag identifiers that have been declared in this sketch. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch is a collection of paths. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |

View File

@ -30,6 +30,7 @@ A sketch is a collection of paths.
| `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No | | `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No |
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No | | `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | No | | `tags` |`object`| Tag identifiers that have been declared in this sketch. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch or a group of sketches. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |

View File

@ -31,6 +31,7 @@ A plane.
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes X axis be? | No | | `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes X axis be? | No |
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes Y axis be? | No | | `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the planes Y axis be? | No |
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No | | `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch type. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
@ -54,6 +55,7 @@ A face.
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the faces Y axis be? | No | | `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the faces Y axis be? | No |
| `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No | | `zAxis` |[`Point3d`](/docs/kcl/types/Point3d)| The z-axis (normal). | No |
| `solid` |[`Solid`](/docs/kcl/types/Solid)| The solid the face is on. | No | | `solid` |[`Solid`](/docs/kcl/types/Solid)| The solid the face is on. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch type. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -23,6 +23,7 @@ An solid is a collection of extrude surfaces.
| `startCapId` |`string`| The id of the extrusion start cap | No | | `startCapId` |`string`| The id of the extrusion start cap | No |
| `endCapId` |`string`| The id of the extrusion end cap | No | | `endCapId` |`string`| The id of the extrusion end cap | No |
| `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No | | `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| An solid is a collection of extrude surfaces. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |

View File

@ -32,6 +32,7 @@ An solid is a collection of extrude surfaces.
| `startCapId` |`string`| The id of the extrusion start cap | No | | `startCapId` |`string`| The id of the extrusion start cap | No |
| `endCapId` |`string`| The id of the extrusion end cap | No | | `endCapId` |`string`| The id of the extrusion end cap | No |
| `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No | | `edgeCuts` |`[` [`EdgeCut`](/docs/kcl/types/EdgeCut) `]`| Chamfers or fillets on this solid. | No |
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A solid or a group of solids. | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No | | `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |

View File

@ -0,0 +1,23 @@
---
title: "SweepData"
excerpt: "Data for a sweep."
layout: manual
---
Data for a sweep.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `path` |[`SweepPath`](/docs/kcl/types/SweepPath)| The path to sweep along. | No |
| `sectional` |`boolean`| If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components. | No |
| `tolerance` |`number`| Tolerance for the sweep operation. | No |

View File

@ -0,0 +1,42 @@
---
title: "SweepPath"
excerpt: "A path to sweep along."
layout: manual
---
A path to sweep along.
**This schema accepts any of the following:**
A path to sweep along.
[`Sketch`](/docs/kcl/types/Sketch)
----
A path to sweep along.
[`Helix`](/docs/kcl/types/Helix)
----

107
docs/kcl/types/UnitLen.md Normal file
View File

@ -0,0 +1,107 @@
---
title: "UnitLen"
excerpt: ""
layout: manual
---
**This schema accepts exactly one of the following:**
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Mm`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Cm`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `M`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Inches`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Feet`| | No |
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Yards`| | No |
----

View File

@ -1,22 +1,11 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import { setupElectron, tearDown } from './test-utils'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Electron app header tests', () => { test.describe('Electron app header tests', () => {
test( test(
'Open Command Palette button has correct shortcut', 'Open Command Palette button has correct shortcut',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ page }, testInfo) => {
const { electronApp, page } = await setupElectron({ await page.setBodyDimensions({ width: 1200, height: 500 })
testInfo,
folderSetupFn: async () => {},
})
await page.setViewportSize({ width: 1200, height: 500 })
// No space before the shortcut since it checks textContent. // No space before the shortcut since it checks textContent.
let text let text
@ -34,21 +23,14 @@ test.describe('Electron app header tests', () => {
const commandsButton = page.getByRole('button', { name: 'Commands' }) const commandsButton = page.getByRole('button', { name: 'Commands' })
await expect(commandsButton).toBeVisible() await expect(commandsButton).toBeVisible()
await expect(commandsButton).toHaveText(text) await expect(commandsButton).toHaveText(text)
await electronApp.close()
} }
) )
test( test(
'User settings has correct shortcut', 'User settings has correct shortcut',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ page }, testInfo) => {
const { electronApp, page } = await setupElectron({ await page.setBodyDimensions({ width: 1200, height: 500 })
testInfo,
folderSetupFn: async () => {},
})
await page.setViewportSize({ width: 1200, height: 500 })
// Open the user sidebar menu. // Open the user sidebar menu.
await page.getByTestId('user-sidebar-toggle').click() await page.getByTestId('user-sidebar-toggle').click()
@ -59,8 +41,6 @@ test.describe('Electron app header tests', () => {
const userSettingsButton = page.getByTestId('user-settings') const userSettingsButton = page.getByTestId('user-settings')
await expect(userSettingsButton).toBeVisible() await expect(userSettingsButton).toBeVisible()
await expect(userSettingsButton).toHaveText(text) await expect(userSettingsButton).toHaveText(text)
await electronApp.close()
} }
) )
}) })

View File

@ -1,29 +1,26 @@
import { test, expect, Page } from '@playwright/test' import { test, expect, Page } from './zoo-test'
import { import {
getUtils, getUtils,
TEST_COLORS, TEST_COLORS,
setup,
tearDown,
commonPoints, commonPoints,
PERSIST_MODELING_CONTEXT, PERSIST_MODELING_CONTEXT,
} from './test-utils' } from './test-utils'
import { HomePageFixture } from './fixtures/homePageFixture'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.setTimeout(120000) test.setTimeout(120000)
async function doBasicSketch(page: Page, openPanes: string[]) { async function doBasicSketch(
page: Page,
homePage: HomePageFixture,
openPanes: string[]
) {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
await page.waitForTimeout(1000)
await u.openDebugPanel() await u.openDebugPanel()
// If we have the code pane open, we should see the code. // If we have the code pane open, we should see the code.
@ -148,13 +145,11 @@ async function doBasicSketch(page: Page, openPanes: string[]) {
} }
test.describe('Basic sketch', () => { test.describe('Basic sketch', () => {
test('code pane open at start', { tag: ['@skipWin'] }, async ({ page }) => { test.fixme('code pane open at start', async ({ page, homePage }) => {
// Skip on windows it is being weird. await doBasicSketch(page, homePage, ['code'])
test.skip(process.platform === 'win32', 'Skip on windows')
await doBasicSketch(page, ['code'])
}) })
test('code pane closed at start', async ({ page }) => { test('code pane closed at start', async ({ page, homePage }) => {
// Load the app with the code panes // Load the app with the code panes
await page.addInitScript(async (persistModelingContext) => { await page.addInitScript(async (persistModelingContext) => {
localStorage.setItem( localStorage.setItem(
@ -162,6 +157,6 @@ test.describe('Basic sketch', () => {
JSON.stringify({ openPanes: [] }) JSON.stringify({ openPanes: [] })
) )
}, PERSIST_MODELING_CONTEXT) }, PERSIST_MODELING_CONTEXT)
await doBasicSketch(page, []) await doBasicSketch(page, homePage, [])
}) })
}) })

View File

@ -1,27 +1,21 @@
import { test, expect } from '@playwright/test' import { test, expect, Page } from './zoo-test'
import { getUtils, setup, tearDown } from './test-utils' import { HomePageFixture } from './fixtures/homePageFixture'
import { getUtils } from './test-utils'
import { EngineCommand } from 'lang/std/artifactGraph' import { EngineCommand } from 'lang/std/artifactGraph'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Can create sketches on all planes and their back sides', () => { test.describe('Can create sketches on all planes and their back sides', () => {
const sketchOnPlaneAndBackSideTest = async ( const sketchOnPlaneAndBackSideTest = async (
page: any, page: Page,
homePage: HomePageFixture,
plane: string, plane: string,
clickCoords: { x: number; y: number } clickCoords: { x: number; y: number }
) => { ) => {
const u = await getUtils(page) const u = await getUtils(page)
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.openDebugPanel() await u.openDebugPanel()
const coord = const coord =
@ -83,32 +77,39 @@ test.describe('Can create sketches on all planes and their back sides', () => {
await u.clearCommandLogs() await u.clearCommandLogs()
await u.removeCurrentCode() await u.removeCurrentCode()
} }
test('XY', async ({ page }) => { test('XY', async ({ page, homePage }) => {
await sketchOnPlaneAndBackSideTest( await sketchOnPlaneAndBackSideTest(
page, page,
homePage,
'XY', 'XY',
{ x: 600, y: 388 } // red plane { x: 600, y: 388 } // red plane
// { x: 600, y: 400 }, // red plane // clicks grid helper and that causes problems, should fix so that these coords work too. // { x: 600, y: 400 }, // red plane // clicks grid helper and that causes problems, should fix so that these coords work too.
) )
}) })
test('YZ', async ({ page }) => { test('YZ', async ({ page, homePage }) => {
await sketchOnPlaneAndBackSideTest(page, 'YZ', { x: 700, y: 250 }) // green plane await sketchOnPlaneAndBackSideTest(page, homePage, 'YZ', { x: 700, y: 250 }) // green plane
}) })
test('XZ', async ({ page }) => { test('XZ', async ({ page, homePage }) => {
await sketchOnPlaneAndBackSideTest(page, '-XZ', { x: 700, y: 80 }) // blue plane await sketchOnPlaneAndBackSideTest(page, homePage, '-XZ', { x: 700, y: 80 }) // blue plane
}) })
test('-XY', async ({ page }) => { test('-XY', async ({ page, homePage }) => {
await sketchOnPlaneAndBackSideTest(page, '-XY', { x: 600, y: 118 }) // back of red plane await sketchOnPlaneAndBackSideTest(page, homePage, '-XY', {
x: 600,
y: 118,
}) // back of red plane
}) })
test('-YZ', async ({ page }) => { test('-YZ', async ({ page, homePage }) => {
await sketchOnPlaneAndBackSideTest(page, '-YZ', { x: 700, y: 219 }) // back of green plane await sketchOnPlaneAndBackSideTest(page, homePage, '-YZ', {
x: 700,
y: 219,
}) // back of green plan
}) })
test('-XZ', async ({ page }) => { test('-XZ', async ({ page, homePage }) => {
await sketchOnPlaneAndBackSideTest(page, 'XZ', { x: 700, y: 427 }) // back of blue plane await sketchOnPlaneAndBackSideTest(page, homePage, 'XZ', { x: 700, y: 427 }) // back of blue plane
}) })
}) })

View File

@ -1,28 +1,15 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import { import { getUtils, executorInputPath } from './test-utils'
getUtils,
setup,
setupElectron,
tearDown,
executorInputPath,
} from './test-utils'
import { join } from 'path' import { join } from 'path'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from './storageStates' import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from './storageStates'
import fsp from 'fs/promises' import fsp from 'fs/promises'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Code pane and errors', () => { test.describe('Code pane and errors', () => {
test('Typing KCL errors induces a badge on the code pane button', async ({ test('Typing KCL errors induces a badge on the code pane button', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
@ -31,18 +18,18 @@ test.describe('Code pane and errors', () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`// Extruded Triangle `// Extruded Triangle
sketch001 = startSketchOn('XZ') sketch001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line([10, 0], %) |> line([10, 0], %)
|> line([-5, 10], %) |> line([-5, 10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%) |> close(%)
extrude001 = extrude(5, sketch001)` extrude001 = extrude(5, sketch001)`
) )
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// wait for execution done // wait for execution done
await u.openDebugPanel() await u.openDebugPanel()
@ -62,11 +49,11 @@ extrude001 = extrude(5, sketch001)`
await expect(codePaneButtonHolder).toContainText('notification') await expect(codePaneButtonHolder).toContainText('notification')
}) })
test('Opening and closing the code pane will consistently show error diagnostics', async ({ test.skip('Opening and closing the code pane will consistently show error diagnostics', async ({
page, page,
homePage,
editor,
}) => { }) => {
await page.goto('http://localhost:3000')
const u = await getUtils(page) const u = await getUtils(page)
// Load the app with the working starter code // Load the app with the working starter code
@ -74,8 +61,8 @@ extrude001 = extrude(5, sketch001)`
localStorage.setItem('persistCode', code) localStorage.setItem('persistCode', code)
}, bracket) }, bracket)
await page.setViewportSize({ width: 1200, height: 900 }) await page.setBodyDimensions({ width: 1200, height: 900 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// wait for execution done // wait for execution done
await u.openDebugPanel() await u.openDebugPanel()
@ -91,8 +78,9 @@ extrude001 = extrude(5, sketch001)`
await expect(codePaneButtonHolder).not.toContainText('notification') await expect(codePaneButtonHolder).not.toContainText('notification')
// Delete a character to break the KCL // Delete a character to break the KCL
await u.openKclCodePanel() await editor.openPane()
await page.getByText('thickness, bracketLeg1Sketch)').click() await editor.scrollToText('thickness, bracketLeg1Sketch)')
await page.getByText('extrude(thickness, bracketLeg1Sketch)').click()
await page.keyboard.press('Backspace') await page.keyboard.press('Backspace')
// Ensure that a badge appears on the button // Ensure that a badge appears on the button
@ -116,7 +104,10 @@ extrude001 = extrude(5, sketch001)`
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// Open the code pane // Open the code pane
await u.openKclCodePanel() await editor.openPane()
// Go to our problematic code again (missing closing paren!)
await editor.scrollToText('extrude(thickness, bracketLeg1Sketch')
// Ensure that a badge appears on the button // Ensure that a badge appears on the button
await expect(codePaneButtonHolder).toContainText('notification') await expect(codePaneButtonHolder).toContainText('notification')
@ -129,59 +120,58 @@ extrude001 = extrude(5, sketch001)`
await expect(page.locator('.cm-tooltip').first()).toBeVisible() await expect(page.locator('.cm-tooltip').first()).toBeVisible()
}) })
test('When error is not in view you can click the badge to scroll to it', async ({ test.fixme(
page, 'When error is not in view you can click the badge to scroll to it',
}) => { async ({ page, homePage, context }) => {
const u = await getUtils(page) // Load the app with the working starter code
await context.addInitScript((code) => {
localStorage.setItem('persistCode', code)
}, TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW)
// Load the app with the working starter code await page.setBodyDimensions({ width: 1200, height: 500 })
await page.addInitScript((code) => { await homePage.goToModelingScene()
localStorage.setItem('persistCode', code)
}, TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW)
await page.setViewportSize({ width: 1200, height: 500 }) await page.waitForTimeout(1000)
await u.waitForAuthSkipAppStart()
await page.waitForTimeout(1000) // Ensure badge is present
const codePaneButtonHolder = page.locator('#code-button-holder')
await expect(codePaneButtonHolder).toContainText('notification')
// Ensure badge is present // Ensure we have no errors in the gutter, since error out of view.
const codePaneButtonHolder = page.locator('#code-button-holder') await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await expect(codePaneButtonHolder).toContainText('notification')
// Ensure we have no errors in the gutter, since error out of view. // Click the badge.
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() const badge = page.locator('#code-badge')
await expect(badge).toBeVisible()
await badge.click()
// Click the badge. // Ensure we have an error diagnostic.
const badge = page.locator('#code-badge') await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
await expect(badge).toBeVisible()
await badge.click()
// Ensure we have an error diagnostic. // Hover over the error to see the error message
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible() await page.hover('.cm-lint-marker-error')
await expect(
// Hover over the error to see the error message page
await page.hover('.cm-lint-marker-error') .getByText(
await expect( 'Modeling command failed: [ApiError { error_code: InternalEngine, message: "Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis" }]'
page )
.getByText( .first()
'sketch profile must lie entirely on one side of the revolution axis' ).toBeVisible()
) }
.first() )
).toBeVisible()
})
test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({ test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({
context,
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page)
// Load the app with the working starter code // Load the app with the working starter code
await page.addInitScript((code) => { await context.addInitScript((code) => {
localStorage.setItem('persistCode', code) localStorage.setItem('persistCode', code)
}, TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW) }, TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await page.waitForTimeout(1000) await page.waitForTimeout(1000)
@ -241,32 +231,29 @@ extrude001 = extrude(5, sketch001)`
test( test(
'Opening multiple panes persists when switching projects', 'Opening multiple panes persists when switching projects',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ context, page }, testInfo) => {
// Setup multiple projects. // Setup multiple projects.
const { electronApp, page } = await setupElectron({ await context.folderSetupFn(async (dir) => {
testInfo, const routerTemplateDir = join(dir, 'router-template-slate')
folderSetupFn: async (dir) => { const bracketDir = join(dir, 'bracket')
const routerTemplateDir = join(dir, 'router-template-slate') await Promise.all([
const bracketDir = join(dir, 'bracket') fsp.mkdir(routerTemplateDir, { recursive: true }),
await Promise.all([ fsp.mkdir(bracketDir, { recursive: true }),
fsp.mkdir(routerTemplateDir, { recursive: true }), ])
fsp.mkdir(bracketDir, { recursive: true }), await Promise.all([
]) fsp.copyFile(
await Promise.all([ executorInputPath('router-template-slate.kcl'),
fsp.copyFile( join(routerTemplateDir, 'main.kcl')
executorInputPath('router-template-slate.kcl'), ),
join(routerTemplateDir, 'main.kcl') fsp.copyFile(
), executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
fsp.copyFile( join(bracketDir, 'main.kcl')
executorInputPath('focusrite_scarlett_mounting_braket.kcl'), ),
join(bracketDir, 'main.kcl') ])
),
])
},
}) })
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await test.step('Opening the bracket project should load', async () => { await test.step('Opening the bracket project should load', async () => {
await expect(page.getByText('bracket')).toBeVisible() await expect(page.getByText('bracket')).toBeVisible()
@ -293,7 +280,7 @@ test(
await expect(page.getByRole('link', { name: 'bracket' })).toBeVisible() await expect(page.getByRole('link', { name: 'bracket' })).toBeVisible()
await expect(page.getByText('router-template-slate')).toBeVisible() await expect(page.getByText('router-template-slate')).toBeVisible()
await expect(page.getByText('New Project')).toBeVisible() await expect(page.getByText('Create project')).toBeVisible()
}) })
await test.step('Opening the router-template project should load', async () => { await test.step('Opening the router-template project should load', async () => {
@ -309,30 +296,21 @@ test(
await expect(page.locator('#variables-pane')).toBeVisible() await expect(page.locator('#variables-pane')).toBeVisible()
await expect(page.locator('#logs-pane')).toBeVisible() await expect(page.locator('#logs-pane')).toBeVisible()
}) })
await electronApp.close()
} }
) )
test( test(
'external change of file contents are reflected in editor', 'external change of file contents are reflected in editor',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ context, page }, testInfo) => {
const PROJECT_DIR_NAME = 'lee-was-here' const PROJECT_DIR_NAME = 'lee-was-here'
const { const { dir: projectsDir } = await context.folderSetupFn(async (dir) => {
electronApp, const aProjectDir = join(dir, PROJECT_DIR_NAME)
page, await fsp.mkdir(aProjectDir, { recursive: true })
dir: projectsDir,
} = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const aProjectDir = join(dir, PROJECT_DIR_NAME)
await fsp.mkdir(aProjectDir, { recursive: true })
},
}) })
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await test.step('Open the project', async () => { await test.step('Open the project', async () => {
await expect(page.getByText(PROJECT_DIR_NAME)).toBeVisible() await expect(page.getByText(PROJECT_DIR_NAME)).toBeVisible()
@ -351,7 +329,5 @@ test(
) )
await u.editorTextMatches(content) await u.editorTextMatches(content)
}) })
await electronApp.close()
} }
) )

View File

@ -1,37 +1,31 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import * as fsp from 'fs/promises'
import { getUtils, setup, tearDown } from './test-utils' import { executorInputPath, getUtils } from './test-utils'
import { KCL_DEFAULT_LENGTH } from 'lib/constants' import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import path from 'path'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Command bar tests', () => { test.describe('Command bar tests', () => {
test('Extrude from command bar selects extrude line after', async ({ test('Extrude from command bar selects extrude line after', async ({
page, page,
homePage,
}) => { }) => {
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XY') `sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> xLine(-20, %) |> xLine(-20, %)
|> close(%) |> close(%)
` `
) )
}) })
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.openDebugPanel() await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
@ -52,51 +46,12 @@ test.describe('Command bar tests', () => {
) )
}) })
test('Fillet from command bar', async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`sketch001 = startSketchOn('XY')
|> startProfileAt([-5, -5], %)
|> line([0, 10], %)
|> line([10, 0], %)
|> line([0, -10], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
extrude001 = extrude(-10, sketch001)`
)
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
const selectSegment = () => page.getByText(`line([0, -10], %)`).click()
await selectSegment()
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Fillet' }).click()
await page.waitForTimeout(100)
await page.keyboard.press('Enter') // skip selection
await page.waitForTimeout(100)
await page.keyboard.press('Enter') // accept default radius
await page.waitForTimeout(100)
await page.keyboard.press('Enter') // submit
await page.waitForTimeout(100)
await expect(page.locator('.cm-activeLine')).toContainText(
`fillet({ radius = ${KCL_DEFAULT_LENGTH}, tags = [seg01] }, %)`
)
})
test('Command bar can change a setting, and switch back and forth between arguments', async ({ test('Command bar can change a setting, and switch back and forth between arguments', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) await page.setBodyDimensions({ width: 1200, height: 500 })
await page.setViewportSize({ width: 1200, height: 500 }) await homePage.goToModelingScene()
await u.waitForAuthSkipAppStart()
const commandBarButton = page.getByRole('button', { name: 'Commands' }) const commandBarButton = page.getByRole('button', { name: 'Commands' })
const cmdSearchBar = page.getByPlaceholder('Search commands') const cmdSearchBar = page.getByPlaceholder('Search commands')
@ -153,7 +108,7 @@ extrude001 = extrude(-10, sketch001)`
// Check that the visibility changed // Check that the visibility changed
await expect(paneSelector).not.toBeVisible() await expect(paneSelector).not.toBeVisible()
commandOptionInput = page.getByPlaceholder('off') commandOptionInput = page.locator('[id="option-input"]')
// Test case for https://github.com/KittyCAD/modeling-app/issues/2882 // Test case for https://github.com/KittyCAD/modeling-app/issues/2882
await commandBarButton.click() await commandBarButton.click()
@ -174,10 +129,10 @@ extrude001 = extrude(-10, sketch001)`
test('Command bar keybinding works from code editor and can change a setting', async ({ test('Command bar keybinding works from code editor and can change a setting', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) await page.setBodyDimensions({ width: 1200, height: 500 })
await page.setViewportSize({ width: 1200, height: 500 }) await homePage.goToModelingScene()
await u.waitForAuthSkipAppStart()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
@ -221,25 +176,25 @@ extrude001 = extrude(-10, sketch001)`
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`) await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
}) })
test('Can extrude from the command bar', async ({ page }) => { test('Can extrude from the command bar', async ({ page, homePage }) => {
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`distance = sqrt(20) `distance = sqrt(20)
sketch001 = startSketchOn('XZ') sketch001 = startSketchOn('XZ')
|> startProfileAt([-6.95, 10.98], %) |> startProfileAt([-6.95, 10.98], %)
|> line([25.1, 0.41], %) |> line([25.1, 0.41], %)
|> line([0.73, -20.93], %) |> line([0.73, -20.93], %)
|> line([-23.44, 0.52], %) |> line([-23.44, 0.52], %)
|> close(%) |> close(%)
` `
) )
}) })
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// Make sure the stream is up // Make sure the stream is up
await u.openDebugPanel() await u.openDebugPanel()
@ -293,26 +248,19 @@ extrude001 = extrude(-10, sketch001)`
await continueButton.click() await continueButton.click()
await submitButton.click() await submitButton.click()
// Check that the code was updated
await u.waitForCmdReceive('extrude') await u.waitForCmdReceive('extrude')
// Unfortunately this indentation seems to matter for the test
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toContainText(
`distance = sqrt(20) 'extrude001 = extrude(distance001, sketch001)'
distance001 = ${KCL_DEFAULT_LENGTH}
sketch001 = startSketchOn('XZ')
|> startProfileAt([-6.95, 10.98], %)
|> line([25.1, 0.41], %)
|> line([0.73, -20.93], %)
|> line([-23.44, 0.52], %)
|> close(%)
extrude001 = extrude(distance001, sketch001)`.replace(/(\r\n|\n|\r)/gm, '') // remove newlines
) )
}) })
test('Can switch between sketch tools via command bar', async ({ page }) => { test('Can switch between sketch tools via command bar', async ({
const u = await getUtils(page) page,
await page.setViewportSize({ width: 1200, height: 500 }) homePage,
await u.waitForAuthSkipAppStart() }) => {
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
const sketchButton = page.getByRole('button', { name: 'Start Sketch' }) const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
const cmdBarButton = page.getByRole('button', { name: 'Commands' }) const cmdBarButton = page.getByRole('button', { name: 'Commands' })
@ -358,4 +306,132 @@ extrude001 = extrude(distance001, sketch001)`.replace(/(\r\n|\n|\r)/gm, '') // r
await arcToolCommand.click() await arcToolCommand.click()
await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true') await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true')
}) })
test(`Reacts to query param to open "import from URL" command`, async ({
page,
cmdBar,
editor,
homePage,
}) => {
await test.step(`Prepare and navigate to home page with query params`, async () => {
const targetURL = `?create-file&name=test&units=mm&code=ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D&ask-open-desktop`
await homePage.expectState({
projectCards: [],
sortBy: 'last-modified-desc',
})
await page.goto(page.url() + targetURL)
expect(page.url()).toContain(targetURL)
})
await test.step(`Submit the command`, async () => {
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Import file from URL',
currentArgKey: 'method',
currentArgValue: '',
headerArguments: {
Method: '',
Name: 'test',
Code: '1 line',
},
highlightedHeaderArg: 'method',
})
await cmdBar.selectOption({ name: 'New Project' }).click()
await cmdBar.expectState({
stage: 'review',
commandName: 'Import file from URL',
headerArguments: {
Method: 'New project',
Name: 'test',
Code: '1 line',
},
})
await cmdBar.progressCmdBar()
})
await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
await editor.expectEditor.toContain('extrusionDistance = 12')
})
})
test(`"import from URL" can add to existing project`, async ({
page,
cmdBar,
editor,
homePage,
toolbar,
context,
}) => {
await context.folderSetupFn(async (dir) => {
const testProjectDir = path.join(dir, 'testProjectDir')
await Promise.all([fsp.mkdir(testProjectDir, { recursive: true })])
await Promise.all([
fsp.copyFile(
executorInputPath('cylinder.kcl'),
path.join(testProjectDir, 'main.kcl')
),
])
})
await test.step(`Prepare and navigate to home page with query params`, async () => {
const targetURL = `?create-file&name=test&units=mm&code=ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D&ask-open-desktop`
await homePage.expectState({
projectCards: [
{
fileCount: 1,
title: 'testProjectDir',
},
],
sortBy: 'last-modified-desc',
})
await page.goto(page.url() + targetURL)
expect(page.url()).toContain(targetURL)
})
await test.step(`Submit the command`, async () => {
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Import file from URL',
currentArgKey: 'method',
currentArgValue: '',
headerArguments: {
Method: '',
Name: 'test',
Code: '1 line',
},
highlightedHeaderArg: 'method',
})
await cmdBar.selectOption({ name: 'Existing Project' }).click()
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Import file from URL',
currentArgKey: 'projectName',
currentArgValue: '',
headerArguments: {
Method: 'Existing project',
Name: 'test',
ProjectName: '',
Code: '1 line',
},
highlightedHeaderArg: 'projectName',
})
await cmdBar.selectOption({ name: 'testProjectDir' }).click()
await cmdBar.expectState({
stage: 'review',
commandName: 'Import file from URL',
headerArguments: {
Method: 'Existing project',
ProjectName: 'testProjectDir',
Name: 'test',
Code: '1 line',
},
})
await cmdBar.progressCmdBar()
})
await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
await editor.expectEditor.toContain('extrusionDistance = 12')
await toolbar.openPane('files')
await toolbar.expectFileTreeState(['main.kcl', 'test.kcl'])
})
})
}) })

View File

@ -1,23 +1,16 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import { getUtils, setup, tearDown } from './test-utils' import { getUtils } from './test-utils'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Copilot ghost text', () => { test.describe('Copilot ghost text', () => {
// eslint-disable-next-line jest/valid-title // eslint-disable-next-line jest/valid-title
test.skip(true, 'Needs to get covered again') test.skip(true, 'Needs to get covered again')
test('completes code in empty file', async ({ page }) => { test('completes code in empty file', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -52,12 +45,13 @@ test.describe('Copilot ghost text', () => {
test.skip('copilot disabled in sketch mode no select plane', async ({ test.skip('copilot disabled in sketch mode no select plane', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -101,12 +95,13 @@ test.describe('Copilot ghost text', () => {
test('copilot disabled in sketch mode after selecting plane', async ({ test('copilot disabled in sketch mode after selecting plane', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -184,12 +179,12 @@ test.describe('Copilot ghost text', () => {
await expect(page.locator('.cm-ghostText')).not.toBeVisible() await expect(page.locator('.cm-ghostText')).not.toBeVisible()
}) })
test('ArrowUp in code rejects the suggestion', async ({ page }) => { test('ArrowUp in code rejects the suggestion', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -212,12 +207,15 @@ test.describe('Copilot ghost text', () => {
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
}) })
test('ArrowDown in code rejects the suggestion', async ({ page }) => { test('ArrowDown in code rejects the suggestion', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -240,12 +238,15 @@ test.describe('Copilot ghost text', () => {
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
}) })
test('ArrowLeft in code rejects the suggestion', async ({ page }) => { test('ArrowLeft in code rejects the suggestion', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -268,12 +269,15 @@ test.describe('Copilot ghost text', () => {
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
}) })
test('ArrowRight in code rejects the suggestion', async ({ page }) => { test('ArrowRight in code rejects the suggestion', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -296,12 +300,12 @@ test.describe('Copilot ghost text', () => {
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
}) })
test('Enter in code scoots it down', async ({ page }) => { test('Enter in code scoots it down', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -326,12 +330,15 @@ test.describe('Copilot ghost text', () => {
) )
}) })
test('Ctrl+shift+z in code rejects the suggestion', async ({ page }) => { test('Ctrl+shift+z in code rejects the suggestion', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
@ -360,12 +367,13 @@ test.describe('Copilot ghost text', () => {
test('Ctrl+z in code rejects the suggestion and undos the last code', async ({ test('Ctrl+z in code rejects the suggestion and undos the last code', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await page.waitForTimeout(800) await page.waitForTimeout(800)
await u.codeLocator.click() await u.codeLocator.click()
@ -420,98 +428,107 @@ test.describe('Copilot ghost text', () => {
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible() await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
// TODO when we make codemirror a widget, we can test this. // TODO when we make codemirror a widget, we can test this.
//await expect(page.locator('.cm-content')).toHaveText(``) //await expect(page.locator('.cm-content')).toHaveText(``) })
})
test('delete in code rejects the suggestion', async ({ page }) => { test('delete in code rejects the suggestion', async ({
const u = await getUtils(page) page,
// const PUR = 400 / 37.5 //pixeltoUnitRatio homePage,
await page.setViewportSize({ width: 1200, height: 500 }) }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible() await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500) await page.waitForTimeout(500)
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible() await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)` `fn cube = (pos, scale) => { sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
) )
await expect(page.locator('.cm-ghostText').first()).toHaveText( await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {` `fn cube = (pos, scale) => {`
) )
// Going elsewhere in the code should hide the ghost text. // Going elsewhere in the code should hide the ghost text.
await page.keyboard.press('Delete') await page.keyboard.press('Delete')
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible() await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
}) })
test('backspace in code rejects the suggestion', async ({ page }) => { test('backspace in code rejects the suggestion', async ({
const u = await getUtils(page) page,
// const PUR = 400 / 37.5 //pixeltoUnitRatio homePage,
await page.setViewportSize({ width: 1200, height: 500 }) }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible() await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500) await page.waitForTimeout(500)
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible() await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)` `fn cube = (pos, scale) => { sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
) )
await expect(page.locator('.cm-ghostText').first()).toHaveText( await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {` `fn cube = (pos, scale) => {`
) )
// Going elsewhere in the code should hide the ghost text. // Going elsewhere in the code should hide the ghost text.
await page.keyboard.press('Backspace') await page.keyboard.press('Backspace')
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible() await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
}) })
test('focus outside code pane rejects the suggestion', async ({ page }) => { test('focus outside code pane rejects the suggestion', async ({
const u = await getUtils(page) page,
// const PUR = 400 / 37.5 //pixeltoUnitRatio homePage,
await page.setViewportSize({ width: 1200, height: 500 }) }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.codeLocator.click() await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible() await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500) await page.waitForTimeout(500)
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible() await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText( await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)` `fn cube = (pos, scale) => { sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
) )
await expect(page.locator('.cm-ghostText').first()).toHaveText( await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {` `fn cube = (pos, scale) => {`
) )
// Going outside the editor should hide the ghost text. // Going outside the editor should hide the ghost text.
await page.mouse.move(0, 0) await page.mouse.move(0, 0)
await page await page
.getByRole('button', { name: 'Start Sketch' }) .getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' }) .waitFor({ state: 'visible' })
await page.getByRole('button', { name: 'Start Sketch' }).click() await page.getByRole('button', { name: 'Start Sketch' }).click()
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible() await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(``) await expect(page.locator('.cm-content')).toHaveText(``)
})
}) })
}) })

View File

@ -1,14 +1,6 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import { getUtils, setup, tearDown } from './test-utils' import { getUtils } from './test-utils'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
function countNewlines(input: string): number { function countNewlines(input: string): number {
let count = 0 let count = 0
@ -24,13 +16,14 @@ test.describe('Debug pane', () => {
test('Artifact IDs in the artifact graph are stable across code edits', async ({ test('Artifact IDs in the artifact graph are stable across code edits', async ({
page, page,
context, context,
homePage,
}) => { }) => {
const code = `sketch001 = startSketchOn('XZ') const code = `sketch001 = startSketchOn('XZ')
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line([1, 1], %) |> line([1, 1], %)
` `
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
const tree = page.getByTestId('debug-feature-tree') const tree = page.getByTestId('debug-feature-tree')
const segment = tree.locator('li', { const segment = tree.locator('li', {
@ -39,20 +32,20 @@ test.describe('Debug pane', () => {
}) })
await test.step('Test setup', async () => { await test.step('Test setup', async () => {
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.openKclCodePanel() await u.openKclCodePanel()
await u.openDebugPanel() await u.openDebugPanel()
// Set the code in the code editor. // Set the code in the code editor.
await u.codeLocator.click() await u.codeLocator.click()
await page.keyboard.type(code, { delay: 0 }) await page.keyboard.type(code, { delay: 0 })
// Scroll to the feature tree. // Scroll to the artifact graph.
await tree.scrollIntoViewIfNeeded() await tree.scrollIntoViewIfNeeded()
// Expand the feature tree. // Expand the artifact graph.
await tree.getByText('Feature Tree').click() await tree.getByText('Artifact Graph').click()
// Just expanded the details, making the element taller, so scroll again. // Just expanded the details, making the element taller, so scroll again.
await tree.getByText('Plane').first().scrollIntoViewIfNeeded() await tree.getByText('Plane').first().scrollIntoViewIfNeeded()
}) })
// Extract the artifact IDs from the debug feature tree. // Extract the artifact IDs from the debug artifact graph.
const initialSegmentIds = await segment.innerText({ timeout: 5_000 }) const initialSegmentIds = await segment.innerText({ timeout: 5_000 })
// The artifact ID should include a UUID. // The artifact ID should include a UUID.
expect(initialSegmentIds).toMatch( expect(initialSegmentIds).toMatch(

View File

@ -1,39 +1,31 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import { join } from 'path' import path from 'path'
import { import {
getUtils, getUtils,
setupElectron,
tearDown,
executorInputPath, executorInputPath,
getPlaywrightDownloadDir,
} from './test-utils' } from './test-utils'
import fsp from 'fs/promises' import fsp from 'fs/promises'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test( test(
'export works on the first try', 'export works on the first try',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ page, context }, testInfo) => {
const { electronApp, page } = await setupElectron({ await context.folderSetupFn(async (dir) => {
testInfo, const bracketDir = path.join(dir, 'bracket')
folderSetupFn: async (dir) => { await Promise.all([fsp.mkdir(bracketDir, { recursive: true })])
const bracketDir = join(dir, 'bracket') await Promise.all([
await Promise.all([fsp.mkdir(bracketDir, { recursive: true })]) fsp.copyFile(
await Promise.all([ executorInputPath('router-template-slate.kcl'),
fsp.copyFile( path.join(bracketDir, 'other.kcl')
executorInputPath('router-template-slate.kcl'), ),
join(bracketDir, 'other.kcl') fsp.copyFile(
), executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
fsp.copyFile( path.join(bracketDir, 'main.kcl')
executorInputPath('focusrite_scarlett_mounting_braket.kcl'), ),
join(bracketDir, 'main.kcl') ])
),
])
},
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
page.on('console', console.log) page.on('console', console.log)
@ -93,12 +85,16 @@ test(
await expect(successToastMessage).toBeVisible() await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible() await expect(exportingToastMessage).not.toBeVisible()
const firstFileFullPath = path.resolve(
getPlaywrightDownloadDir(page),
exportFileName
)
await test.step('Check the export size', async () => { await test.step('Check the export size', async () => {
await expect await expect
.poll( .poll(
async () => { async () => {
try { try {
const outputGltf = await fsp.readFile(exportFileName) const outputGltf = await fsp.readFile(firstFileFullPath)
return outputGltf.byteLength return outputGltf.byteLength
} catch (e) { } catch (e) {
return 0 return 0
@ -107,9 +103,6 @@ test(
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBeGreaterThan(300_000) .toBeGreaterThan(300_000)
// clean up exported file
await fsp.rm(exportFileName)
}) })
}) })
@ -170,12 +163,16 @@ test(
expect(exportingToastMessage).not.toBeVisible(), expect(exportingToastMessage).not.toBeVisible(),
])) ]))
const secondFileFullPath = path.resolve(
getPlaywrightDownloadDir(page),
exportFileName
)
await test.step('Check the export size', async () => { await test.step('Check the export size', async () => {
await expect await expect
.poll( .poll(
async () => { async () => {
try { try {
const outputGltf = await fsp.readFile(exportFileName) const outputGltf = await fsp.readFile(secondFileFullPath)
return outputGltf.byteLength return outputGltf.byteLength
} catch (e) { } catch (e) {
return 0 return 0
@ -184,13 +181,7 @@ test(
{ timeout: 15_000 } { timeout: 15_000 }
) )
.toBeGreaterThan(100_000) .toBeGreaterThan(100_000)
// clean up exported file
await fsp.rm(exportFileName)
}) })
await electronApp.close()
}) })
await electronApp.close()
} }
) )

View File

@ -1,4 +1,4 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { uuidv4 } from 'lib/utils' import { uuidv4 } from 'lib/utils'
import { import {
@ -6,37 +6,27 @@ import {
darkModePlaneColorXZ, darkModePlaneColorXZ,
executorInputPath, executorInputPath,
getUtils, getUtils,
setup,
setupElectron,
tearDown,
} from './test-utils' } from './test-utils'
import { join } from 'path' import { join } from 'path'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Editor tests', () => { test.describe('Editor tests', () => {
test('can comment out code with ctrl+/', async ({ page }) => { test('can comment out code with ctrl+/', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// check no error to begin with // check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await u.codeLocator.click() await u.codeLocator.click()
await page.keyboard.type(`sketch001 = startSketchOn('XY') await page.keyboard.type(`sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> close(%)`)
await page.keyboard.down('ControlOrMeta') await page.keyboard.down('ControlOrMeta')
await page.keyboard.press('/') await page.keyboard.press('/')
@ -44,11 +34,11 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XY') .toHaveText(`sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
// |> close(%)`) // |> close(%)`)
// uncomment the code // uncomment the code
await page.keyboard.down('ControlOrMeta') await page.keyboard.down('ControlOrMeta')
@ -57,23 +47,22 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XY') .toHaveText(`sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> close(%)`)
}) })
test('if you click the format button it formats your code', async ({ test('ensure we use the cache, and do not re-execute', async ({
homePage,
page, page,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
// check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await u.codeLocator.click() await u.codeLocator.click()
await page.keyboard.type(`sketch001 = startSketchOn('XY') await page.keyboard.type(`sketch001 = startSketchOn('XY')
@ -82,36 +71,141 @@ test.describe('Editor tests', () => {
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> 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')) // Ensure we execute the first time.
.toHaveText(`sketch001 = startSketchOn('XY') 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([20, 0], %)
|> line([0, 20], %)
|> line([-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], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> 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([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)`)
}) })
test('if you click the format button it formats your code and executes so lints are still there', async ({ test('if you click the format button it formats your code and executes so lints are still there', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// check no error to begin with // check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await u.codeLocator.click() await u.codeLocator.click()
await page.keyboard.type(`sketch_001 = startSketchOn('XY') await page.keyboard.type(`sketch_001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> close(%)`)
await u.openDebugPanel() await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
@ -135,11 +229,11 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch_001 = startSketchOn('XY') .toHaveText(`sketch_001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> close(%)`)
// error in guter // error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible() await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
@ -151,29 +245,27 @@ test.describe('Editor tests', () => {
).toBeVisible() ).toBeVisible()
}) })
test('fold gutters work', async ({ page }) => { test('fold gutters work', async ({ page, homePage }) => {
const u = await getUtils(page)
const fullCode = `sketch001 = startSketchOn('XY') const fullCode = `sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)` |> close(%)`
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XY') `sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)` |> close(%)`
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// TODO: Jess needs to fix this but you have to mod the code to get them to show // TODO: Jess needs to fix this but you have to mod the code to get them to show
// up, its an annoying codemirror thing. // up, its an annoying codemirror thing.
@ -224,22 +316,25 @@ test.describe('Editor tests', () => {
await expect(foldGutterFoldLine).not.toBeVisible() await expect(foldGutterFoldLine).not.toBeVisible()
}) })
test('hover over functions shows function description', async ({ page }) => { test('hover over functions shows function description', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XY') `sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)` |> close(%)`
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// check no error to begin with // check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
@ -268,23 +363,24 @@ test.describe('Editor tests', () => {
test('if you use the format keyboard binding it formats your code', async ({ test('if you use the format keyboard binding it formats your code', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XY') `sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)` |> close(%)`
) )
localStorage.setItem('disableAxis', 'true') localStorage.setItem('disableAxis', 'true')
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// check no error to begin with // check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
@ -301,32 +397,33 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XY') .toHaveText(`sketch001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> close(%)`)
}) })
test('if you use the format keyboard binding it formats your code and executes so lints are shown', async ({ test('if you use the format keyboard binding it formats your code and executes so lints are shown', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch_001 = startSketchOn('XY') `sketch_001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)` |> close(%)`
) )
localStorage.setItem('disableAxis', 'true') localStorage.setItem('disableAxis', 'true')
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.openDebugPanel() await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
@ -353,11 +450,11 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch_001 = startSketchOn('XY') .toHaveText(`sketch_001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %) |> startProfileAt([-10, -10], %)
|> line([20, 0], %) |> line([20, 0], %)
|> line([0, 20], %) |> line([0, 20], %)
|> line([-20, 0], %) |> line([-20, 0], %)
|> close(%)`) |> close(%)`)
// error in guter // error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible() await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
@ -369,11 +466,14 @@ test.describe('Editor tests', () => {
).toBeVisible() ).toBeVisible()
}) })
test('if you write kcl with lint errors you get lints', async ({ page }) => { test('if you write kcl with lint errors you get lints', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// check no error to begin with // check no error to begin with
await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible()
@ -409,23 +509,26 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible()
}) })
test('if you fixup kcl errors you clear lints', async ({ page }) => { test('if you fixup kcl errors you clear lints', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XZ') `sketch001 = startSketchOn('XZ')
|> startProfileAt([3.29, 7.86], %) |> startProfileAt([3.29, 7.86], %)
|> line([2.48, 2.44], %) |> line([2.48, 2.44], %)
|> line([2.66, 1.17], %) |> line([2.66, 1.17], %)
|> close(%) |> close(%)
` `
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// check no error to begin with // check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
@ -447,22 +550,27 @@ test.describe('Editor tests', () => {
).not.toBeVisible() ).not.toBeVisible()
}) })
test('if you write invalid kcl you get inlined errors', async ({ page }) => { test('if you write invalid kcl you get inlined errors', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// check no error to begin with // check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
/* add the following code to the editor ($ error is not a valid line) /* add the following code to the editor (~ error is not a valid line)
$ error * the old check here used $ but this is for tags so it changed meaning.
const topAng = 30 * hopefully ~ doesn't change meaning
const bottomAng = 25 ~ error
*/ const topAng = 30
const bottomAng = 25
*/
await u.codeLocator.click() await u.codeLocator.click()
await page.keyboard.type('$ error') await page.keyboard.type('~ error')
// press arrows to clear autocomplete // press arrows to clear autocomplete
await page.keyboard.press('ArrowLeft') await page.keyboard.press('ArrowLeft')
@ -479,10 +587,12 @@ test.describe('Editor tests', () => {
// error text on hover // error text on hover
await page.hover('.cm-lint-marker-error') await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: $').first()).toBeVisible() await expect(
page.getByText("found unknown token '~'").first()
).toBeVisible()
// select the line that's causing the error and delete it // select the line that's causing the error and delete it
await page.getByText('$ error').click() await page.getByText('~ error').click()
await page.keyboard.press('End') await page.keyboard.press('End')
await page.keyboard.down('Shift') await page.keyboard.down('Shift')
await page.keyboard.press('Home') await page.keyboard.press('Home')
@ -518,103 +628,108 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
}) })
test('error with 2 source ranges gets 2 diagnostics', async ({ page }) => { test.fixme(
const u = await getUtils(page) 'error with 2 source ranges gets 2 diagnostics',
await page.addInitScript(async () => { async ({ page, homePage }) => {
localStorage.setItem( const u = await getUtils(page)
'persistCode', await page.addInitScript(async () => {
`length = .750 localStorage.setItem(
width = 0.500 'persistCode',
height = 0.500 `length = .750
dia = 4 width = 0.500
height = 0.500
dia = 4
fn squareHole = (l, w) => {
squareHoleSketch = startSketchOn('XY')
|> startProfileAt([-width / 2, -length / 2], %)
|> lineTo([width / 2, -length / 2], %)
|> lineTo([width / 2, length / 2], %)
|> lineTo([-width / 2, length / 2], %)
|> close(%)
return squareHoleSketch
}
`
)
})
await page.setBodyDimensions({ width: 1000, height: 500 })
fn squareHole = (l, w) => { await homePage.goToModelingScene()
squareHoleSketch = startSketchOn('XY') await u.waitForPageLoad()
|> startProfileAt([-width / 2, -length / 2], %) await page.waitForTimeout(1000)
|> lineTo([width / 2, -length / 2], %)
|> lineTo([width / 2, length / 2], %)
|> lineTo([-width / 2, length / 2], %)
|> close(%)
return squareHoleSketch
}
`
)
})
await page.setViewportSize({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
await u.openDebugPanel() // check no error to begin with
await u.expectCmdLog('[data-message-type="execution-done"]') await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await u.closeDebugPanel()
// check no error to begin with // Click on the bottom of the code editor to add a new line
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() 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(height, %)`)
// Click on the bottom of the code editor to add a new line // error in gutter
await u.codeLocator.click() await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
await page.keyboard.press('ArrowDown') await page.hover('.cm-lint-marker-error:first-child')
await page.keyboard.press('ArrowDown') await expect(
await page.keyboard.press('ArrowDown') page.getByText('Expected 2 arguments, got 3').first()
await page.keyboard.press('ArrowDown') ).toBeVisible()
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(height, %)`)
// error in gutter // Make sure there are two diagnostics
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible() await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2)
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 ({ test('if your kcl gets an error from the engine it is inlined', async ({
context,
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) await context.addInitScript(async () => {
await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`box = startSketchOn('XY') `box = startSketchOn('XY')
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line([0, 10], %) |> line([0, 10], %)
|> line([10, 0], %) |> line([10, 0], %)
|> line([0, -10], %, $revolveAxis) |> line([0, -10], %, $revolveAxis)
|> close(%) |> close(%)
|> extrude(10, %) |> extrude(10, %)
sketch001 = startSketchOn(box, revolveAxis) sketch001 = startSketchOn(box, revolveAxis)
|> startProfileAt([5, 10], %) |> startProfileAt([5, 10], %)
|> line([0, -10], %) |> line([0, -10], %)
|> line([2, 0], %) |> line([2, 0], %)
|> line([0, -10], %) |> line([0, -10], %)
|> close(%) |> close(%)
|> revolve({ |> revolve({
axis = revolveAxis, axis: revolveAxis,
angle = 90 angle: 90
}, %) }, %)
` `
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await page.goto('/') await homePage.goToModelingScene()
await u.waitForPageLoad()
await expect(page.locator('.cm-lint-marker-error')).toBeVisible() await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
@ -625,12 +740,15 @@ test.describe('Editor tests', () => {
await expect(page.getByText(searchText)).toBeVisible() await expect(page.getByText(searchText)).toBeVisible()
}) })
test.describe('Autocomplete works', () => { test.describe('Autocomplete works', () => {
test('with enter/click to accept the completion', async ({ page }) => { test('with enter/click to accept the completion', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// tests clicking on an option, selection the first option // tests clicking on an option, selection the first option
// and arrowing down to an option // and arrowing down to an option
@ -692,19 +810,19 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([3.14, 12], %) |> startProfileAt([3.14, 12], %)
|> xLine(5, %) // lin`) |> xLine(5, %) // lin`)
// expect there to be no KCL errors // expect there to be no KCL errors
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0) await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0)
}) })
test('with tab to accept the completion', async ({ page }) => { test('with tab to accept the completion', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
// this test might be brittle as we add and remove functions // this test might be brittle as we add and remove functions
// but should also be easy to update. // but should also be easy to update.
@ -766,26 +884,30 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([3.14, 12], %) |> startProfileAt([3.14, 12], %)
|> xLine(5, %) // lin`) |> xLine(5, %) // lin`)
}) })
}) })
test('Can undo a click and point extrude with ctrl+z', async ({ page }) => { test('Can undo a click and point extrude with ctrl+z', async ({
page,
context,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await context.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XZ') `sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], %)
|> close(%)` |> close(%)`
) )
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
@ -838,29 +960,32 @@ test.describe('Editor tests', () => {
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %) |> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %) |> tangentialArcTo([24.95, -5.38], %)
|> close(%)`) |> close(%)`)
}) })
test('Can undo a sketch modification with ctrl+z', async ({ page }) => { test('Can undo a sketch modification with ctrl+z', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('XZ') `sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
|> close(%) |> close(%)
|> extrude(5, %)` |> extrude(5, %)`
) )
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled() ).not.toBeDisabled()
@ -887,7 +1012,7 @@ test.describe('Editor tests', () => {
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
const startPX = [665, 397] const startPX = [1200 / 2, 500 / 2]
const dragPX = 40 const dragPX = 40
@ -901,9 +1026,9 @@ test.describe('Editor tests', () => {
await expect(page.getByTestId('segment-overlay')).toHaveCount(2) await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
// drag startProfieAt handle // drag startProfileAt handle
await page.dragAndDrop('#stream', '#stream', { await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: startPX[0], y: startPX[1] }, sourcePosition: { x: startPX[0] + 68, y: startPX[1] + 147 },
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX }, targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
}) })
await page.waitForTimeout(100) await page.waitForTimeout(100)
@ -941,12 +1066,12 @@ test.describe('Editor tests', () => {
// expect the code to have changed // expect the code to have changed
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %) |> startProfileAt([2.71, -2.71], %)
|> line([15.39, -2.78], %) |> line([15.4, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %) |> tangentialArcTo([27.6, -3.05], %)
|> close(%) |> close(%)
|> extrude(5, %) |> extrude(5, %)
`) `)
// Hit undo // Hit undo
await page.keyboard.down('Control') await page.keyboard.down('Control')
@ -955,11 +1080,11 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %) |> startProfileAt([2.71, -2.71], %)
|> line([15.39, -2.78], %) |> line([15.4, -2.78], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
// Hit undo again. // Hit undo again.
await page.keyboard.down('Control') await page.keyboard.down('Control')
@ -968,12 +1093,12 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %) |> startProfileAt([2.71, -2.71], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
|> close(%) |> close(%)
|> extrude(5, %) |> extrude(5, %)
`) `)
// Hit undo again. // Hit undo again.
await page.keyboard.down('Control') await page.keyboard.down('Control')
@ -983,31 +1108,29 @@ test.describe('Editor tests', () => {
await page.waitForTimeout(100) await page.waitForTimeout(100)
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn('XZ') .toHaveText(`sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %) |> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %) |> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %) |> tangentialArcTo([24.95, -0.38], %)
|> close(%) |> close(%)
|> extrude(5, %)`) |> extrude(5, %)`)
}) })
test.fixme( test.fixme(
`Can use the import stdlib function on a local OBJ file`, `Can use the import stdlib function on a local OBJ file`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ page, context }, testInfo) => {
const { electronApp, page } = await setupElectron({ await context.folderSetupFn(async (dir) => {
testInfo, const bracketDir = join(dir, 'cube')
folderSetupFn: async (dir) => { await fsp.mkdir(bracketDir, { recursive: true })
const bracketDir = join(dir, 'cube') await fsp.copyFile(
await fsp.mkdir(bracketDir, { recursive: true }) executorInputPath('cube.obj'),
await fsp.copyFile( join(bracketDir, 'cube.obj')
executorInputPath('cube.obj'), )
join(bracketDir, 'cube.obj') await fsp.writeFile(join(bracketDir, 'main.kcl'), '')
)
await fsp.writeFile(join(bracketDir, 'main.kcl'), '')
},
}) })
const viewportSize = { width: 1200, height: 500 } const viewportSize = { width: 1200, height: 500 }
await page.setViewportSize(viewportSize) await page.setBodyDimensions(viewportSize)
// Locators and constants // Locators and constants
const u = await getUtils(page) const u = await getUtils(page)
@ -1065,8 +1188,6 @@ test.describe('Editor tests', () => {
}) })
.toBeGreaterThan(15) .toBeGreaterThan(15)
}) })
await electronApp.close()
} }
) )
}) })

View File

@ -0,0 +1,127 @@
import { test, expect } from './zoo-test'
import * as fsp from 'fs/promises'
import { join } from 'path'
const FEATURE_TREE_EXAMPLE_CODE = `export fn timesFive(x) {
return 5 * x
}
export fn triangle() {
return startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> xLine(10, %)
|> line([-10, -5], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
}
length001 = timesFive(1) * 5
sketch001 = startSketchOn('XZ')
|> startProfileAt([20, 10], %)
|> line([10, 10], %)
|> angledLine([-45, length001], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
revolve001 = revolve({ axis = "X" }, sketch001)
triangle()
|> extrude(30, %)
plane001 = offsetPlane('XY', 10)
sketch002 = startSketchOn(plane001)
|> startProfileAt([-20, 0], %)
|> line([5, -15], %)
|> xLine(-10, %)
|> lineTo([-40, 0], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
extrude001 = extrude(10, sketch002)
`
test.describe('Feature Tree pane', () => {
test(
'User can go to definition and go to function definition',
{ tag: '@electron' },
async ({ context, homePage, scene, editor, toolbar }) => {
await context.folderSetupFn(async (dir) => {
const bracketDir = join(dir, 'test-sample')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.writeFile(
join(bracketDir, 'main.kcl'),
FEATURE_TREE_EXAMPLE_CODE,
'utf-8'
)
})
await test.step('setup test', async () => {
await homePage.expectState({
projectCards: [
{
title: 'test-sample',
fileCount: 1,
},
],
sortBy: 'last-modified-desc',
})
await homePage.openProject('test-sample')
await scene.waitForExecutionDone()
await editor.closePane()
await toolbar.openFeatureTreePane()
})
async function testViewSource({
operationName,
operationIndex,
expectedActiveLine,
}: {
operationName: string
operationIndex: number
expectedActiveLine: string
}) {
await test.step(`Go to definition of the ${operationName}`, async () => {
await toolbar.viewSourceOnOperation(operationName, operationIndex)
await editor.expectState({
highlightedCode: '',
diagnostics: [],
activeLines: [expectedActiveLine],
})
await expect(
editor.activeLine.first(),
`${operationName} code should be scrolled into view`
).toBeVisible()
})
}
await testViewSource({
operationName: 'Offset Plane',
operationIndex: 0,
expectedActiveLine: "plane001 = offsetPlane('XY', 10)",
})
await testViewSource({
operationName: 'Extrude',
operationIndex: 1,
expectedActiveLine: 'extrude001 = extrude(10, sketch002)',
})
await testViewSource({
operationName: 'Revolve',
operationIndex: 0,
expectedActiveLine: 'revolve001 = revolve({ axis = "X" }, sketch001)',
})
await testViewSource({
operationName: 'Triangle',
operationIndex: 0,
expectedActiveLine: 'triangle()',
})
await test.step('Go to definition on the triangle function', async () => {
await toolbar.goToDefinitionOnOperation('Triangle', 0)
await editor.expectState({
highlightedCode: '',
diagnostics: [],
activeLines: ['export fn triangle() {'],
})
await expect(
editor.activeLine.first(),
'Triangle function definition should be scrolled into view'
).toBeVisible()
})
}
)
})

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,9 @@
import type { Page } from '@playwright/test' import type { Page, Locator } from '@playwright/test'
import { expect } from '@playwright/test' import { expect } from '@playwright/test'
type CmdBarSerialised = type CmdBarSerialised =
| { | {
stage: 'commandBarClosed' stage: 'commandBarClosed'
// TODO no more properties needed but needs to be implemented in _serialiseCmdBar
} }
| { | {
stage: 'pickCommand' stage: 'pickCommand'
@ -26,15 +25,20 @@ type CmdBarSerialised =
export class CmdBarFixture { export class CmdBarFixture {
public page: Page public page: Page
cmdBarOpenBtn!: Locator
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
this.cmdBarOpenBtn = page.getByTestId('command-bar-open-button')
} }
reConstruct = (page: Page) => { reConstruct = (page: Page) => {
this.page = page this.page = page
} }
private _serialiseCmdBar = async (): Promise<CmdBarSerialised> => { private _serialiseCmdBar = async (): Promise<CmdBarSerialised> => {
if (!(await this.page.getByTestId('command-bar-wrapper').isVisible())) {
return { stage: 'commandBarClosed' }
}
const reviewForm = this.page.locator('#review-form') const reviewForm = this.page.locator('#review-form')
const getHeaderArgs = async () => { const getHeaderArgs = async () => {
const inputs = await this.page.getByTestId('cmd-bar-input-tab').all() const inputs = await this.page.getByTestId('cmd-bar-input-tab').all()
@ -116,4 +120,44 @@ export class CmdBarFixture {
await this.page.keyboard.press('Enter') await this.page.keyboard.press('Enter')
} }
} }
openCmdBar = async (selectCmd?: 'promptToEdit') => {
// TODO why does this button not work in electron tests?
// await this.cmdBarOpenBtn.click()
await this.page.keyboard.down('ControlOrMeta')
await this.page.keyboard.press('KeyK')
await this.page.keyboard.up('ControlOrMeta')
await expect(this.page.getByPlaceholder('Search commands')).toBeVisible()
if (selectCmd === 'promptToEdit') {
const promptEditCommand = this.page.getByText(
'Use Zoo AI to edit your kcl'
)
await expect(promptEditCommand.first()).toBeVisible()
await promptEditCommand.first().scrollIntoViewIfNeeded()
await promptEditCommand.first().click()
}
}
get cmdSearchInput() {
return this.page.getByTestId('cmd-bar-search')
}
get argumentInput() {
return this.page.getByTestId('cmd-bar-arg-value')
}
get cmdOptions() {
return this.page.getByTestId('cmd-bar-option')
}
chooseCommand = async (commandName: string) => {
await this.cmdOptions.getByText(commandName).click()
}
/**
* Select an option from the command bar
*/
selectOption = (options: Parameters<typeof this.page.getByRole>[1]) => {
return this.page.getByRole('option', options)
}
} }

View File

@ -20,7 +20,7 @@ export class EditorFixture {
private diagnosticsTooltip!: Locator private diagnosticsTooltip!: Locator
private diagnosticsGutterIcon!: Locator private diagnosticsGutterIcon!: Locator
private codeContent!: Locator private codeContent!: Locator
private activeLine!: Locator public activeLine!: Locator
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
@ -29,7 +29,7 @@ export class EditorFixture {
reConstruct = (page: Page) => { reConstruct = (page: Page) => {
this.page = page this.page = page
this.codeContent = page.locator('.cm-content') this.codeContent = page.locator('.cm-content[data-language="kcl"]')
this.diagnosticsTooltip = page.locator('.cm-tooltip-lint') this.diagnosticsTooltip = page.locator('.cm-tooltip-lint')
this.diagnosticsGutterIcon = page.locator('.cm-lint-marker-error') this.diagnosticsGutterIcon = page.locator('.cm-lint-marker-error')
this.activeLine = this.page.locator('.cm-activeLine') this.activeLine = this.page.locator('.cm-activeLine')
@ -54,13 +54,13 @@ export class EditorFixture {
} }
} }
if (!shouldNormalise) { if (!shouldNormalise) {
const expectStart = expect(this.codeContent) const expectStart = expect.poll(() => this.codeContent.textContent())
if (not) { if (not) {
const result = await expectStart.not.toContainText(code, { timeout }) const result = await expectStart.not.toContain(code)
await resetPane() await resetPane()
return result return result
} }
const result = await expectStart.toContainText(code, { timeout }) const result = await expectStart.toContain(code)
await resetPane() await resetPane()
return result return result
} }
@ -147,4 +147,28 @@ export class EditorFixture {
openPane() { openPane() {
return openPane(this.page, this.paneButtonTestId) return openPane(this.page, this.paneButtonTestId)
} }
scrollToText(text: string, placeCursor?: boolean) {
return this.page.evaluate(
(args: { text: string; placeCursor?: boolean }) => {
// error TS2339: Property 'docView' does not exist on type 'EditorView'.
// Except it does so :shrug:
// @ts-ignore
let index = window.editorManager._editorView?.docView.view.state.doc
.toString()
.indexOf(args.text)
window.editorManager._editorView?.focus()
window.editorManager._editorView?.dispatch({
selection: window.EditorSelection.create([
window.EditorSelection.cursor(index),
]),
effects: [
window.EditorView.scrollIntoView(
window.EditorSelection.range(index, index + 1)
),
],
})
},
{ text, placeCursor }
)
}
} }

View File

@ -1,11 +1,11 @@
import type { import type {
BrowserContext, BrowserContext,
ElectronApplication, ElectronApplication,
Page,
TestInfo, TestInfo,
Page,
} from '@playwright/test' } from '@playwright/test'
import { test as base } from '@playwright/test'
import { getUtils, setup, setupElectron, tearDown } from '../test-utils' import { getUtils, setup, setupElectron } from '../test-utils'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { join } from 'path' import { join } from 'path'
import { CmdBarFixture } from './cmdBarFixture' import { CmdBarFixture } from './cmdBarFixture'
@ -20,11 +20,13 @@ export class AuthenticatedApp {
public readonly page: Page public readonly page: Page
public readonly context: BrowserContext public readonly context: BrowserContext
public readonly testInfo: TestInfo public readonly testInfo: TestInfo
public readonly viewPortSize = { width: 1000, height: 500 } public readonly viewPortSize = { width: 1200, height: 500 }
public electronApp: undefined | ElectronApplication
public dir: string = ''
constructor(context: BrowserContext, page: Page, testInfo: TestInfo) { constructor(context: BrowserContext, page: Page, testInfo: TestInfo) {
this.page = page
this.context = context this.context = context
this.page = page
this.testInfo = testInfo this.testInfo = testInfo
} }
@ -49,9 +51,7 @@ export class AuthenticatedApp {
} }
} }
interface Fixtures { export interface Fixtures {
app: AuthenticatedApp
tronApp: AuthenticatedTronApp
cmdBar: CmdBarFixture cmdBar: CmdBarFixture
editor: EditorFixture editor: EditorFixture
toolbar: ToolbarFixture toolbar: ToolbarFixture
@ -61,9 +61,11 @@ interface Fixtures {
export class AuthenticatedTronApp { export class AuthenticatedTronApp {
public readonly _page: Page public readonly _page: Page
public page: Page public page: Page
public readonly context: BrowserContext public context: BrowserContext
public readonly testInfo: TestInfo public readonly testInfo: TestInfo
public electronApp?: ElectronApplication public electronApp: ElectronApplication | undefined
public readonly viewPortSize = { width: 1200, height: 500 }
public dir: string = ''
constructor(context: BrowserContext, page: Page, testInfo: TestInfo) { constructor(context: BrowserContext, page: Page, testInfo: TestInfo) {
this._page = page this._page = page
@ -79,15 +81,22 @@ export class AuthenticatedTronApp {
appSettings?: Partial<SaveSettingsPayload> appSettings?: Partial<SaveSettingsPayload>
} = { fixtures: {} } } = { fixtures: {} }
) { ) {
const { electronApp, page } = await setupElectron({ const { electronApp, page, context, dir } = await setupElectron({
testInfo: this.testInfo, testInfo: this.testInfo,
folderSetupFn: arg.folderSetupFn, folderSetupFn: arg.folderSetupFn,
cleanProjectDir: arg.cleanProjectDir, cleanProjectDir: arg.cleanProjectDir,
appSettings: arg.appSettings, appSettings: arg.appSettings,
}) })
this.page = page this.page = page
this.context = context
this.electronApp = electronApp this.electronApp = electronApp
await page.setViewportSize({ width: 1200, height: 500 }) this.dir = dir
// Easier to access throughout utils
this.page.dir = dir
// Setup localStorage, addCookies, reload
await setup(this.context, this.page, this.testInfo)
for (const key of unsafeTypedKeys(arg.fixtures)) { for (const key of unsafeTypedKeys(arg.fixtures)) {
const fixture = arg.fixtures[key] const fixture = arg.fixtures[key]
@ -110,32 +119,25 @@ export class AuthenticatedTronApp {
}) })
} }
export const test = base.extend<Fixtures>({ export const fixtures = {
app: async ({ page, context }, use, testInfo) => { cmdBar: async ({ page }: { page: Page }, use: any) => {
await use(new AuthenticatedApp(context, page, testInfo)) // eslint-disable-next-line react-hooks/rules-of-hooks
},
tronApp: async ({ page, context }, use, testInfo) => {
await use(new AuthenticatedTronApp(context, page, testInfo))
},
cmdBar: async ({ page }, use) => {
await use(new CmdBarFixture(page)) await use(new CmdBarFixture(page))
}, },
editor: async ({ page }, use) => { editor: async ({ page }: { page: Page }, use: any) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
await use(new EditorFixture(page)) await use(new EditorFixture(page))
}, },
toolbar: async ({ page }, use) => { toolbar: async ({ page }: { page: Page }, use: any) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
await use(new ToolbarFixture(page)) await use(new ToolbarFixture(page))
}, },
scene: async ({ page }, use) => { scene: async ({ page }: { page: Page }, use: any) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
await use(new SceneFixture(page)) await use(new SceneFixture(page))
}, },
homePage: async ({ page }, use) => { homePage: async ({ page }: { page: Page }, use: any) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
await use(new HomePageFixture(page)) await use(new HomePageFixture(page))
}, },
}) }
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
export { expect } from '@playwright/test'

View File

@ -14,10 +14,14 @@ interface HomePageState {
export class HomePageFixture { export class HomePageFixture {
public page: Page public page: Page
projectSection!: Locator
projectCard!: Locator projectCard!: Locator
projectCardTitle!: Locator projectCardTitle!: Locator
projectCardFile!: Locator projectCardFile!: Locator
projectCardFolder!: Locator projectCardFolder!: Locator
projectButtonNew!: Locator
projectButtonContinue!: Locator
projectTextName!: Locator
sortByDateBtn!: Locator sortByDateBtn!: Locator
sortByNameBtn!: Locator sortByNameBtn!: Locator
@ -28,11 +32,19 @@ export class HomePageFixture {
reConstruct = (page: Page) => { reConstruct = (page: Page) => {
this.page = page this.page = page
this.projectSection = this.page.getByTestId('home-section')
this.projectCard = this.page.getByTestId('project-link') this.projectCard = this.page.getByTestId('project-link')
this.projectCardTitle = this.page.getByTestId('project-title') this.projectCardTitle = this.page.getByTestId('project-title')
this.projectCardFile = this.page.getByTestId('project-file-count') this.projectCardFile = this.page.getByTestId('project-file-count')
this.projectCardFolder = this.page.getByTestId('project-folder-count') this.projectCardFolder = this.page.getByTestId('project-folder-count')
this.projectButtonNew = this.page.getByTestId('home-new-file')
this.projectTextName = this.page.getByTestId('cmd-bar-arg-value')
this.projectButtonContinue = this.page.getByRole('button', {
name: 'Continue',
})
this.sortByDateBtn = this.page.getByTestId('home-sort-by-modified') this.sortByDateBtn = this.page.getByTestId('home-sort-by-modified')
this.sortByNameBtn = this.page.getByTestId('home-sort-by-name') this.sortByNameBtn = this.page.getByTestId('home-sort-by-name')
} }
@ -91,10 +103,25 @@ export class HomePageFixture {
.toEqual(expectedState) .toEqual(expectedState)
} }
createAndGoToProject = async (projectTitle = 'project-$nnn') => {
await expect(this.projectSection).not.toHaveText('Loading your Projects...')
await this.projectButtonNew.click()
await this.projectTextName.click()
await this.projectTextName.fill(projectTitle)
await this.projectButtonContinue.click()
}
openProject = async (projectTitle: string) => { openProject = async (projectTitle: string) => {
const projectCard = this.projectCard.locator( const projectCard = this.projectCard.locator(
this.page.getByText(projectTitle) this.page.getByText(projectTitle)
) )
await projectCard.click() await projectCard.click()
} }
goToModelingScene = async (name: string = 'testDefault') => {
// On web this is a no-op. There is no project view.
if (process.env.PLATFORM === 'web') return
await this.createAndGoToProject(name)
}
} }

View File

@ -36,7 +36,8 @@ type DragFromHandler = (
export class SceneFixture { export class SceneFixture {
public page: Page public page: Page
public streamWrapper!: Locator
public loadingIndicator!: Locator
private exeIndicator!: Locator private exeIndicator!: Locator
constructor(page: Page) { constructor(page: Page) {
@ -53,8 +54,9 @@ export class SceneFixture {
expectState = async (expected: SceneSerialised) => { expectState = async (expected: SceneSerialised) => {
return expect return expect
.poll(() => this._serialiseScene(), { .poll(async () => await this._serialiseScene(), {
message: `Expected scene state to match`, intervals: [1_000, 2_000, 10_000],
timeout: 60000,
}) })
.toEqual(expected) .toEqual(expected)
} }
@ -63,6 +65,8 @@ export class SceneFixture {
this.page = page this.page = page
this.exeIndicator = page.getByTestId('model-state-indicator-execution-done') this.exeIndicator = page.getByTestId('model-state-indicator-execution-done')
this.streamWrapper = page.getByTestId('stream')
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
} }
makeMouseHelpers = ( makeMouseHelpers = (
@ -187,7 +191,10 @@ export class SceneFixture {
type: 'default_camera_get_settings', type: 'default_camera_get_settings',
}, },
}) })
await this.waitForExecutionDone() await this.page
.locator(`[data-receive-command-type="default_camera_get_settings"]`)
.first()
.waitFor()
const position = await Promise.all([ const position = await Promise.all([
this.page.getByTestId('cam-x-position').inputValue().then(Number), this.page.getByTestId('cam-x-position').inputValue().then(Number),
this.page.getByTestId('cam-y-position').inputValue().then(Number), this.page.getByTestId('cam-y-position').inputValue().then(Number),
@ -214,23 +221,7 @@ export class SceneFixture {
coords: { x: number; y: number }, coords: { x: number; y: number },
diff: number diff: number
) => { ) => {
let finalValue = colour await expectPixelColor(this.page, colour, coords, diff)
await expect
.poll(async () => {
const pixel = (await getPixelRGBs(this.page)(coords, 1))[0]
if (!pixel) return null
finalValue = pixel
return pixel.every(
(channel, index) => Math.abs(channel - colour[index]) < diff
)
})
.toBeTruthy()
.catch((cause) => {
throw new Error(
`ExpectPixelColor: expecting ${colour} got ${finalValue}`,
{ cause }
)
})
} }
get gizmo() { get gizmo() {
@ -238,6 +229,7 @@ export class SceneFixture {
} }
async clickGizmoMenuItem(name: string) { async clickGizmoMenuItem(name: string) {
await this.gizmo.hover()
await this.gizmo.click({ button: 'right' }) await this.gizmo.click({ button: 'right' })
const buttonToTest = this.page.getByRole('button', { const buttonToTest = this.page.getByRole('button', {
name: name, name: name,
@ -246,3 +238,28 @@ export class SceneFixture {
await buttonToTest.click() await buttonToTest.click()
} }
} }
export async function expectPixelColor(
page: Page,
colour: [number, number, number],
coords: { x: number; y: number },
diff: number
) {
let finalValue = colour
await expect
.poll(async () => {
const pixel = (await getPixelRGBs(page)(coords, 1))[0]
if (!pixel) return null
finalValue = pixel
return pixel.every(
(channel, index) => Math.abs(channel - colour[index]) < diff
)
})
.toBeTruthy()
.catch((cause) => {
throw new Error(
`ExpectPixelColor: expecting ${colour} got ${finalValue}`,
{ cause }
)
})
}

View File

@ -1,11 +1,23 @@
import type { Page, Locator } from '@playwright/test' import type { Page, Locator } from '@playwright/test'
import { expect } from './fixtureSetup' import { expect } from '../zoo-test'
import { doAndWaitForImageDiff } from '../test-utils' import {
checkIfPaneIsOpen,
closePane,
doAndWaitForImageDiff,
openPane,
} from '../test-utils'
import { SidebarType } from 'components/ModelingSidebar/ModelingPanes'
import { SIDEBAR_BUTTON_SUFFIX } from 'lib/constants'
export class ToolbarFixture { export class ToolbarFixture {
public page: Page public page: Page
extrudeButton!: Locator extrudeButton!: Locator
loftButton!: Locator
sweepButton!: Locator
filletButton!: Locator
chamferButton!: Locator
shellButton!: Locator
offsetPlaneButton!: Locator offsetPlaneButton!: Locator
startSketchBtn!: Locator startSketchBtn!: Locator
lineBtn!: Locator lineBtn!: Locator
@ -18,6 +30,10 @@ export class ToolbarFixture {
filePane!: Locator filePane!: Locator
exeIndicator!: Locator exeIndicator!: Locator
treeInputField!: Locator treeInputField!: Locator
/** The sidebar button for the Feature Tree pane */
featureTreeId = 'feature-tree' as const
/** The pane element for the Feature Tree */
featureTreePane!: Locator
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
@ -26,6 +42,11 @@ export class ToolbarFixture {
reConstruct = (page: Page) => { reConstruct = (page: Page) => {
this.page = page this.page = page
this.extrudeButton = page.getByTestId('extrude') this.extrudeButton = page.getByTestId('extrude')
this.loftButton = page.getByTestId('loft')
this.sweepButton = page.getByTestId('sweep')
this.filletButton = page.getByTestId('fillet3d')
this.chamferButton = page.getByTestId('chamfer3d')
this.shellButton = page.getByTestId('shell')
this.offsetPlaneButton = page.getByTestId('plane-offset') this.offsetPlaneButton = page.getByTestId('plane-offset')
this.startSketchBtn = page.getByTestId('sketch') this.startSketchBtn = page.getByTestId('sketch')
this.lineBtn = page.getByTestId('line') this.lineBtn = page.getByTestId('line')
@ -37,10 +58,15 @@ export class ToolbarFixture {
this.treeInputField = page.getByTestId('tree-input-field') this.treeInputField = page.getByTestId('tree-input-field')
this.filePane = page.locator('#files-pane') this.filePane = page.locator('#files-pane')
this.featureTreePane = page.locator('#feature-tree-pane')
this.fileCreateToast = page.getByText('Successfully created') this.fileCreateToast = page.getByText('Successfully created')
this.exeIndicator = page.getByTestId('model-state-indicator-execution-done') this.exeIndicator = page.getByTestId('model-state-indicator-execution-done')
} }
get logoLink() {
return this.page.getByTestId('app-logo')
}
startSketchPlaneSelection = async () => startSketchPlaneSelection = async () =>
doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500) doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500)
@ -87,4 +113,76 @@ export class ToolbarFixture {
await expect(this.exeIndicator).toBeVisible({ timeout: 15_000 }) await expect(this.exeIndicator).toBeVisible({ timeout: 15_000 })
} }
} }
async closePane(paneId: SidebarType) {
return closePane(this.page, paneId + SIDEBAR_BUTTON_SUFFIX)
}
async openPane(paneId: SidebarType) {
return openPane(this.page, paneId + SIDEBAR_BUTTON_SUFFIX)
}
async checkIfPaneIsOpen(paneId: SidebarType) {
return checkIfPaneIsOpen(this.page, paneId + SIDEBAR_BUTTON_SUFFIX)
}
async openFeatureTreePane() {
return this.openPane(this.featureTreeId)
}
async closeFeatureTreePane() {
await this.closePane(this.featureTreeId)
}
async checkIfFeatureTreePaneIsOpen() {
return this.checkIfPaneIsOpen(this.featureTreeId)
}
/**
* Get a specific operation button from the Feature Tree pane
*/
async getFeatureTreeOperation(operationName: string, operationIndex: number) {
await this.openFeatureTreePane()
await expect(this.featureTreePane).toBeVisible()
return this.featureTreePane
.getByRole('button', {
name: operationName,
})
.nth(operationIndex)
}
/**
* View source on a specific operation in the Feature Tree pane.
* @param operationName The name of the operation type
* @param operationIndex The index out of operations of this type
*/
async viewSourceOnOperation(operationName: string, operationIndex: number) {
const operationButton = await this.getFeatureTreeOperation(
operationName,
operationIndex
)
const viewSourceMenuButton = this.page.getByRole('button', {
name: 'View KCL source code',
})
await operationButton.click({ button: 'right' })
await expect(viewSourceMenuButton).toBeVisible()
await viewSourceMenuButton.click()
}
/**
* Go to definition on a specific operation in the Feature Tree pane
*/
async goToDefinitionOnOperation(
operationName: string,
operationIndex: number
) {
const operationButton = await this.getFeatureTreeOperation(
operationName,
operationIndex
)
const goToDefinitionMenuButton = this.page.getByRole('button', {
name: 'View function definition',
})
await operationButton.click({ button: 'right' })
await expect(goToDefinitionMenuButton).toBeVisible()
await goToDefinitionMenuButton.click()
}
} }

View File

@ -1,29 +1,22 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import { setupElectron, tearDown, executorInputPath } from './test-utils' import { executorInputPath } from './test-utils'
import { join } from 'path' import { join } from 'path'
import fsp from 'fs/promises' import fsp from 'fs/promises'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test( test(
'When machine-api server not found butt is disabled and shows the reason', 'When machine-api server not found butt is disabled and shows the reason',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ context, page }, testInfo) => {
const { electronApp, page } = await setupElectron({ await context.folderSetupFn(async (dir) => {
testInfo, const bracketDir = join(dir, 'bracket')
folderSetupFn: async (dir) => { await fsp.mkdir(bracketDir, { recursive: true })
const bracketDir = join(dir, 'bracket') await fsp.copyFile(
await fsp.mkdir(bracketDir, { recursive: true }) executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
await fsp.copyFile( join(bracketDir, 'main.kcl')
executorInputPath('focusrite_scarlett_mounting_braket.kcl'), )
join(bracketDir, 'main.kcl')
)
},
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await expect(page.getByText('bracket')).toBeVisible() await expect(page.getByText('bracket')).toBeVisible()
@ -47,28 +40,23 @@ test(
// that the machine-api server is not found // that the machine-api server is not found
await makeButton.hover() await makeButton.hover()
await expect(page.getByText(notFoundText).first()).toBeVisible() await expect(page.getByText(notFoundText).first()).toBeVisible()
await electronApp.close()
} }
) )
test( test(
'When machine-api server not found home screen & project status shows the reason', 'When machine-api server not found home screen & project status shows the reason',
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName }, testInfo) => { async ({ context, page }, testInfo) => {
const { electronApp, page } = await setupElectron({ await context.folderSetupFn(async (dir) => {
testInfo, const bracketDir = join(dir, 'bracket')
folderSetupFn: async (dir) => { await fsp.mkdir(bracketDir, { recursive: true })
const bracketDir = join(dir, 'bracket') await fsp.copyFile(
await fsp.mkdir(bracketDir, { recursive: true }) executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
await fsp.copyFile( join(bracketDir, 'main.kcl')
executorInputPath('focusrite_scarlett_mounting_braket.kcl'), )
join(bracketDir, 'main.kcl')
)
},
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
const notFoundText = 'Machine API server was not discovered' const notFoundText = 'Machine API server was not discovered'
@ -91,7 +79,5 @@ test(
await networkMachineToggle.hover() await networkMachineToggle.hover()
await expect(page.getByText(notFoundText).nth(1)).toBeVisible() await expect(page.getByText(notFoundText).nth(1)).toBeVisible()
await electronApp.close()
} }
) )

View File

@ -0,0 +1,12 @@
// These tests are meant to simply test starting and stopping the electron
// application, check it can make it to the project pane, and nothing more.
// It also tests our test wrappers are working.
// Additionally this serves as a nice minimal example.
import { test, expect } from './zoo-test'
test.describe('Open the application', () => {
test('see the project view', async ({ page, context }) => {
await expect(page.getByTestId('home-section')).toBeVisible()
})
})

View File

@ -1,79 +1,78 @@
import { test, expect } from '@playwright/test' import { test, expect } from './zoo-test'
import { join } from 'path' import { join } from 'path'
import fsp from 'fs/promises' import fsp from 'fs/promises'
import { import { getUtils, executorInputPath, createProject } from './test-utils'
getUtils,
setup,
setupElectron,
tearDown,
executorInputPath,
createProject,
} from './test-utils'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
import { onboardingPaths } from 'routes/Onboarding/paths' import { onboardingPaths } from 'routes/Onboarding/paths'
import { import {
TEST_SETTINGS_KEY, TEST_SETTINGS_KEY,
TEST_SETTINGS_ONBOARDING_START, TEST_SETTINGS_ONBOARDING_START,
TEST_SETTINGS_ONBOARDING_EXPORT, TEST_SETTINGS_ONBOARDING_EXPORT,
TEST_SETTINGS_ONBOARDING_PARAMETRIC_MODELING,
TEST_SETTINGS_ONBOARDING_USER_MENU, TEST_SETTINGS_ONBOARDING_USER_MENU,
} from './storageStates' } from './storageStates'
import * as TOML from '@iarna/toml' import * as TOML from '@iarna/toml'
import { expectPixelColor } from './fixtures/sceneFixture'
test.beforeEach(async ({ context, page }, testInfo) => { // Because onboarding relies on an app setting we need to set it as incompletel
if (testInfo.tags.includes('@electron')) { // for all these tests.
return
}
await setup(context, page)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Onboarding tests', () => { test.describe('Onboarding tests', () => {
test('Onboarding code is shown in the editor', async ({ page }) => { test(
const u = await getUtils(page) 'Onboarding code is shown in the editor',
{
// Override beforeEach test setup appSettings: {
await page.addInitScript( app: {
async ({ settingsKey }) => { onboardingStatus: 'incomplete',
// Give no initial code, so that the onboarding start is shown immediately },
localStorage.removeItem('persistCode')
localStorage.removeItem(settingsKey)
}, },
{ settingsKey: TEST_SETTINGS_KEY } cleanProjectDir: true,
) },
async ({ context, page, homePage }) => {
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await page.setViewportSize({ width: 1200, height: 500 }) // Test that the onboarding pane loaded
await expect(
page.getByText('Welcome to Modeling App! This')
).toBeVisible()
await u.waitForAuthSkipAppStart() // Test that the onboarding pane loaded
await expect(
page.getByText('Welcome to Modeling App! This')
).toBeVisible()
// Test that the onboarding pane loaded // *and* that the code is shown in the editor
await expect(page.getByText('Welcome to Modeling App! This')).toBeVisible() await expect(page.locator('.cm-content')).toContainText(
'// Shelf Bracket'
)
// *and* that the code is shown in the editor // Make sure the model loaded
await expect(page.locator('.cm-content')).toContainText('// Shelf Bracket') const XYPlanePoint = { x: 774, y: 116 } as const
}) const modelColor: [number, number, number] = [45, 45, 45]
await page.mouse.move(XYPlanePoint.x, XYPlanePoint.y)
expect(await u.getGreatestPixDiff(XYPlanePoint, modelColor)).toBeLessThan(
8
)
}
)
test( test(
'Desktop: fresh onboarding executes and loads', 'Desktop: fresh onboarding executes and loads',
{ tag: '@electron' }, {
async ({ browserName: _ }, testInfo) => { tag: '@electron',
const { electronApp, page } = await setupElectron({ appSettings: {
testInfo, app: {
appSettings: { onboardingStatus: 'incomplete',
app: {
onboardingStatus: 'incomplete',
},
}, },
cleanProjectDir: true, },
}) cleanProjectDir: true,
},
async ({ page, homePage }, testInfo) => {
const u = await getUtils(page) const u = await getUtils(page)
const viewportSize = { width: 1200, height: 500 } const viewportSize = { width: 1200, height: 500 }
await page.setViewportSize(viewportSize) await page.setBodyDimensions(viewportSize)
await test.step(`Create a project and open to the onboarding`, async () => { await test.step(`Create a project and open to the onboarding`, async () => {
await createProject({ name: 'project-link', page }) await createProject({ name: 'project-link', page })
@ -92,321 +91,370 @@ test.describe('Onboarding tests', () => {
await expect(page.locator('.cm-content')).toContainText( await expect(page.locator('.cm-content')).toContainText(
'// Shelf Bracket' '// Shelf Bracket'
) )
})
await electronApp.close() // TODO: jess make less shit
// Make sure the model loaded
//const XYPlanePoint = { x: 986, y: 522 } as const
//const modelColor: [number, number, number] = [76, 76, 76]
//await page.mouse.move(XYPlanePoint.x, XYPlanePoint.y)
//await expectPixelColor(page, modelColor, XYPlanePoint, 8)
})
} }
) )
test('Code resets after confirmation', async ({ page }) => { test(
const initialCode = `sketch001 = startSketchOn('XZ')` 'Code resets after confirmation',
{
// Load the page up with some code so we see the confirmation warning appSettings: {
// when we go to replay onboarding app: {
await page.addInitScript((code) => { onboardingStatus: 'incomplete',
localStorage.setItem('persistCode', code) },
}, initialCode)
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
// Replay the onboarding
await page.getByRole('link', { name: 'Settings' }).last().click()
const replayButton = page.getByRole('button', { name: 'Replay onboarding' })
await expect(replayButton).toBeVisible()
await replayButton.click()
// Ensure we see the warning, and that the code has not yet updated
await expect(
page.getByText('Replaying onboarding resets your code')
).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(initialCode)
const nextButton = page.getByTestId('onboarding-next')
await expect(nextButton).toBeVisible()
await nextButton.click()
// Ensure we see the introduction and that the code has been reset
await expect(page.getByText('Welcome to Modeling App!')).toBeVisible()
await expect(page.locator('.cm-content')).toContainText('// Shelf Bracket')
// Ensure we persisted the code to local storage.
// Playwright's addInitScript method unfortunately will reset
// this code if we try reloading the page as a test,
// so this is our best way to test persistence afaik.
expect(
await page.evaluate(() => {
return localStorage.getItem('persistCode')
})
).toContain('// Shelf Bracket')
})
test('Click through each onboarding step', async ({ page }) => {
const u = await getUtils(page)
// Override beforeEach test setup
await page.addInitScript(
async ({ settingsKey, settings }) => {
// Give no initial code, so that the onboarding start is shown immediately
localStorage.setItem('persistCode', '')
localStorage.setItem(settingsKey, settings)
}, },
{ cleanProjectDir: true,
settingsKey: TEST_SETTINGS_KEY, },
settings: TOML.stringify({ settings: TEST_SETTINGS_ONBOARDING_START }), async ({ context, page, homePage }) => {
} const initialCode = `sketch001 = startSketchOn('XZ')`
)
await page.setViewportSize({ width: 1200, height: 1080 }) // Load the page up with some code so we see the confirmation warning
// when we go to replay onboarding
await context.addInitScript((code) => {
localStorage.setItem('persistCode', code)
}, initialCode)
await u.waitForAuthSkipAppStart() await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// Test that the onboarding pane loaded // Replay the onboarding
await expect(page.getByText('Welcome to Modeling App! This')).toBeVisible() await page.getByRole('link', { name: 'Settings' }).last().click()
const replayButton = page.getByRole('button', {
name: 'Replay onboarding',
})
await expect(replayButton).toBeVisible()
await replayButton.click()
const nextButton = page.getByTestId('onboarding-next') // Ensure we see the warning, and that the code has not yet updated
await expect(page.getByText('Would you like to create')).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(initialCode)
while ((await nextButton.innerText()) !== 'Finish') { const nextButton = page.getByTestId('onboarding-next')
await expect(nextButton).toBeVisible() await nextButton.hover()
await nextButton.click() await nextButton.click()
// Ensure we see the introduction and that the code has been reset
await expect(page.getByText('Welcome to Modeling App!')).toBeVisible()
await expect(page.locator('.cm-content')).toContainText(
'// Shelf Bracket'
)
// There used to be old code here that checked if we stored the reset
// code into localStorage but that isn't the case on desktop. It gets
// saved to the file system, which we have other tests for.
} }
)
// Finish the onboarding test(
await expect(nextButton).toBeVisible() 'Click through each onboarding step',
await nextButton.click() {
appSettings: {
// Test that the onboarding pane is gone app: {
await expect(page.getByTestId('onboarding-content')).not.toBeVisible() onboardingStatus: 'incomplete',
await expect(page.url()).not.toContain('onboarding') },
})
test('Onboarding redirects and code updating', async ({ page }) => {
const u = await getUtils(page)
// Override beforeEach test setup
await page.addInitScript(
async ({ settingsKey, settings }) => {
// Give some initial code, so we can test that it's cleared
localStorage.setItem('persistCode', 'sigmaAllow = 15000')
localStorage.setItem(settingsKey, settings)
}, },
{ },
settingsKey: TEST_SETTINGS_KEY, async ({ context, page, homePage }) => {
settings: TOML.stringify({ settings: TEST_SETTINGS_ONBOARDING_EXPORT }), // Override beforeEach test setup
await context.addInitScript(
async ({ settingsKey, settings }) => {
// Give no initial code, so that the onboarding start is shown immediately
localStorage.setItem('persistCode', '')
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_START,
}),
}
)
await page.setBodyDimensions({ width: 1200, height: 1080 })
await homePage.goToModelingScene()
// Test that the onboarding pane loaded
await expect(
page.getByText('Welcome to Modeling App! This')
).toBeVisible()
const nextButton = page.getByTestId('onboarding-next')
while ((await nextButton.innerText()) !== 'Finish') {
await nextButton.hover()
await nextButton.click()
} }
)
await page.setViewportSize({ width: 1200, height: 500 }) // Finish the onboarding
await nextButton.hover()
await nextButton.click()
await u.waitForAuthSkipAppStart() // Test that the onboarding pane is gone
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
// Test that the redirect happened await expect.poll(() => page.url()).not.toContain('/onboarding')
await expect(page.url().split(':3000').slice(-1)[0]).toBe(
`/file/%2Fbrowser%2Fmain.kcl/onboarding/export`
)
// Test that you come back to this page when you refresh
await page.reload()
await expect(page.url().split(':3000').slice(-1)[0]).toBe(
`/file/%2Fbrowser%2Fmain.kcl/onboarding/export`
)
// Test that the onboarding pane loaded
const title = page.locator('[data-testid="onboarding-content"]')
await expect(title).toBeAttached()
// Test that the code changes when you advance to the next step
await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText('')
// Test that the code is not empty when you click on the next step
await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText(/.+/)
})
test('Onboarding code gets reset to demo on Interactive Numbers step', async ({
page,
}) => {
test.skip(
process.platform === 'darwin',
"Skip on macOS, because Playwright isn't behaving the same as the actual browser"
)
const u = await getUtils(page)
const badCode = `// This is bad code we shouldn't see`
// Override beforeEach test setup
await page.addInitScript(
async ({ settingsKey, settings, badCode }) => {
localStorage.setItem('persistCode', badCode)
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_PARAMETRIC_MODELING,
}),
badCode,
}
)
await page.setViewportSize({ width: 1200, height: 1080 })
await u.waitForAuthSkipAppStart()
await page.waitForURL('**' + onboardingPaths.PARAMETRIC_MODELING, {
waitUntil: 'domcontentloaded',
})
const bracketNoNewLines = bracket.replace(/\n/g, '')
// Check the code got reset on load
await expect(page.locator('#code-pane')).toBeVisible()
await expect(u.codeLocator).toHaveText(bracketNoNewLines, {
timeout: 10_000,
})
// Mess with the code again
await u.codeLocator.selectText()
await u.codeLocator.fill(badCode)
await expect(u.codeLocator).toHaveText(badCode)
// Click to the next step
await page.locator('[data-testid="onboarding-next"]').click()
await page.waitForURL('**' + onboardingPaths.INTERACTIVE_NUMBERS, {
waitUntil: 'domcontentloaded',
})
// Check that the code has been reset
await expect(u.codeLocator).toHaveText(bracketNoNewLines)
})
test('Avatar text updates depending on image load success', async ({
page,
}) => {
// Override beforeEach test setup
await page.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
}),
}
)
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await page.waitForURL('**/file/**', { waitUntil: 'domcontentloaded' })
// Test that the text in this step is correct
const avatarLocator = await page
.getByTestId('user-sidebar-toggle')
.locator('img')
const onboardingOverlayLocator = await page
.getByTestId('onboarding-content')
.locator('div')
.nth(1)
// Expect the avatar to be visible and for the text to reference it
await expect(avatarLocator).toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('your avatar')
// This is to force the avatar to 404.
// For our test image (only triggers locally. on CI, it's Kurt's /
// gravatar image )
await page.route('/cat.jpg', async (route) => {
await route.fulfill({
status: 404,
contentType: 'text/plain',
body: 'Not Found!',
})
})
// 404 the CI avatar image
await page.route('https://lh3.googleusercontent.com/**', async (route) => {
await route.fulfill({
status: 404,
contentType: 'text/plain',
body: 'Not Found!',
})
})
await page.reload({ waitUntil: 'domcontentloaded' })
// Now expect the text to be different
await expect(avatarLocator).not.toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('the menu button')
})
test("Avatar text doesn't mention avatar when no avatar", async ({
page,
}) => {
// Override beforeEach test setup
await page.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
localStorage.setItem('FORCE_NO_IMAGE', 'FORCE_NO_IMAGE')
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
}),
}
)
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await page.waitForURL('**/file/**', { waitUntil: 'domcontentloaded' })
// Test that the text in this step is correct
const sidebar = page.getByTestId('user-sidebar-toggle')
const avatar = sidebar.locator('img')
const onboardingOverlayLocator = page
.getByTestId('onboarding-content')
.locator('div')
.nth(1)
// Expect the avatar to be visible and for the text to reference it
await expect(avatar).not.toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('the menu button')
// Test we mention what else is in this menu for https://github.com/KittyCAD/modeling-app/issues/2939
// which doesn't deserver its own full test spun up
const userMenuFeatures = [
'manage your account',
'report a bug',
'request a feature',
'sign out',
]
for (const feature of userMenuFeatures) {
await expect(onboardingOverlayLocator).toContainText(feature)
} }
}) )
test(
'Onboarding redirects and code updating',
{
appSettings: {
app: {
onboardingStatus: '/export',
},
},
cleanProjectDir: true,
},
async ({ context, page, homePage }) => {
const originalCode = 'sigmaAllow = 15000'
// Override beforeEach test setup
await context.addInitScript(
async ({ settingsKey, settings }) => {
// Give some initial code, so we can test that it's cleared
localStorage.setItem('persistCode', originalCode)
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_EXPORT,
}),
}
)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// Test that the redirect happened
await expect.poll(() => page.url()).toContain('/onboarding/export')
// Test that you come back to this page when you refresh
await page.reload()
await expect.poll(() => page.url()).toContain('/onboarding/export')
// Test that the code changes when you advance to the next step
await page.getByTestId('onboarding-next').hover()
await page.getByTestId('onboarding-next').click()
// Test that the onboarding pane loaded
const title = page.locator('[data-testid="onboarding-content"]')
await expect(title).toBeAttached()
await expect(page.locator('.cm-content')).not.toHaveText(originalCode)
// Test that the code is not empty when you click on the next step
await page.locator('[data-testid="onboarding-next"]').hover()
await page.locator('[data-testid="onboarding-next"]').click()
await expect(page.locator('.cm-content')).toHaveText(/.+/)
}
)
test(
'Onboarding code gets reset to demo on Interactive Numbers step',
{
appSettings: {
app: {
onboardingStatus: '/parametric-modeling',
},
},
cleanProjectDir: true,
},
async ({ context, page, homePage }) => {
const u = await getUtils(page)
const badCode = `// This is bad code we shouldn't see`
await page.setBodyDimensions({ width: 1200, height: 1080 })
await homePage.goToModelingScene()
await expect
.poll(() => page.url())
.toContain(onboardingPaths.PARAMETRIC_MODELING)
const bracketNoNewLines = bracket.replace(/\n/g, '')
// Check the code got reset on load
await expect(page.locator('#code-pane')).toBeVisible()
await expect(u.codeLocator).toHaveText(bracketNoNewLines, {
timeout: 10_000,
})
// Mess with the code again
await u.codeLocator.selectText()
await u.codeLocator.fill(badCode)
await expect(u.codeLocator).toHaveText(badCode)
// Click to the next step
await page.locator('[data-testid="onboarding-next"]').hover()
await page.locator('[data-testid="onboarding-next"]').click()
await page.waitForURL('**' + onboardingPaths.INTERACTIVE_NUMBERS, {
waitUntil: 'domcontentloaded',
})
// Check that the code has been reset
await expect(u.codeLocator).toHaveText(bracketNoNewLines)
}
)
// (lee) The two avatar tests are weird because even on main, we don't have
// anything to do with the avatar inside the onboarding test. Due to the
// low impact of an avatar not showing I'm changing this to fixme.
test.fixme(
'Avatar text updates depending on image load success',
{
appSettings: {
app: {
onboardingStatus: 'incomplete',
},
},
cleanProjectDir: true,
},
async ({ context, page, homePage }) => {
// Override beforeEach test setup
await context.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
}),
}
)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// Test that the text in this step is correct
const avatarLocator = await page
.getByTestId('user-sidebar-toggle')
.locator('img')
const onboardingOverlayLocator = await page
.getByTestId('onboarding-content')
.locator('div')
.nth(1)
// Expect the avatar to be visible and for the text to reference it
await expect(avatarLocator).toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('your avatar')
// This is to force the avatar to 404.
// For our test image (only triggers locally. on CI, it's Kurt's /
// gravatar image )
await page.route('/cat.jpg', async (route) => {
await route.fulfill({
status: 404,
contentType: 'text/plain',
body: 'Not Found!',
})
})
// 404 the CI avatar image
await page.route(
'https://lh3.googleusercontent.com/**',
async (route) => {
await route.fulfill({
status: 404,
contentType: 'text/plain',
body: 'Not Found!',
})
}
)
await page.reload({ waitUntil: 'domcontentloaded' })
// Now expect the text to be different
await expect(avatarLocator).not.toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('the menu button')
}
)
test.fixme(
"Avatar text doesn't mention avatar when no avatar",
{
appSettings: {
app: {
onboardingStatus: 'incomplete',
},
},
cleanProjectDir: true,
},
async ({ context, page, homePage }) => {
// Override beforeEach test setup
await context.addInitScript(
async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings)
localStorage.setItem('FORCE_NO_IMAGE', 'FORCE_NO_IMAGE')
},
{
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({
settings: TEST_SETTINGS_ONBOARDING_USER_MENU,
}),
}
)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// Test that the text in this step is correct
const sidebar = page.getByTestId('user-sidebar-toggle')
const avatar = sidebar.locator('img')
const onboardingOverlayLocator = page
.getByTestId('onboarding-content')
.locator('div')
.nth(1)
// Expect the avatar to be visible and for the text to reference it
await expect(avatar).not.toBeVisible()
await expect(onboardingOverlayLocator).toBeVisible()
await expect(onboardingOverlayLocator).toContainText('the menu button')
// Test we mention what else is in this menu for https://github.com/KittyCAD/modeling-app/issues/2939
// which doesn't deserver its own full test spun up
const userMenuFeatures = [
'manage your account',
'report a bug',
'request a feature',
'sign out',
]
for (const feature of userMenuFeatures) {
await expect(onboardingOverlayLocator).toContainText(feature)
}
}
)
}) })
test( test.fixme(
'Restarting onboarding on desktop takes one attempt', 'Restarting onboarding on desktop takes one attempt',
{ tag: '@electron' }, {
async ({ browser: _ }, testInfo) => { appSettings: {
const { electronApp, page } = await setupElectron({ app: {
testInfo, onboardingStatus: 'dismissed',
folderSetupFn: async (dir) => {
const routerTemplateDir = join(dir, 'router-template-slate')
await fsp.mkdir(routerTemplateDir, { recursive: true })
await fsp.copyFile(
executorInputPath('router-template-slate.kcl'),
join(routerTemplateDir, 'main.kcl')
)
}, },
},
cleanProjectDir: true,
},
async ({ context, page, homePage }, testInfo) => {
await context.folderSetupFn(async (dir) => {
const routerTemplateDir = join(dir, 'router-template-slate')
await fsp.mkdir(routerTemplateDir, { recursive: true })
await fsp.copyFile(
executorInputPath('router-template-slate.kcl'),
join(routerTemplateDir, 'main.kcl')
)
}) })
// Our constants // Our constants
@ -418,9 +466,8 @@ test(
const restartOnboardingButton = page.getByRole('button', { const restartOnboardingButton = page.getByRole('button', {
name: 'Reset onboarding', name: 'Reset onboarding',
}) })
const restartConfirmationButton = page.getByRole('button', { const nextButton = page.getByTestId('onboarding-next')
name: 'Make a new project',
})
const tutorialProjectIndicator = page const tutorialProjectIndicator = page
.getByTestId('project-sidebar-toggle') .getByTestId('project-sidebar-toggle')
.filter({ hasText: 'Tutorial Project 00' }) .filter({ hasText: 'Tutorial Project 00' })
@ -439,7 +486,7 @@ test(
}) })
await test.step('Navigate into project', async () => { await test.step('Navigate into project', async () => {
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
page.on('console', console.log) page.on('console', console.log)
@ -455,14 +502,22 @@ test(
await helpMenuButton.click() await helpMenuButton.click()
await restartOnboardingButton.click() await restartOnboardingButton.click()
await expect(restartConfirmationButton).toBeVisible() await nextButton.hover()
await restartConfirmationButton.click() await nextButton.click()
}) })
await test.step('Confirm that the onboarding has restarted', async () => { await test.step('Confirm that the onboarding has restarted', async () => {
await expect(tutorialProjectIndicator).toBeVisible() await expect(tutorialProjectIndicator).toBeVisible()
await expect(tutorialModalText).toBeVisible() await expect(tutorialModalText).toBeVisible()
// Make sure the model loaded
const XYPlanePoint = { x: 988, y: 523 } as const
const modelColor: [number, number, number] = [76, 76, 76]
await page.mouse.move(XYPlanePoint.x, XYPlanePoint.y)
await expectPixelColor(page, modelColor, XYPlanePoint, 8)
await tutorialDismissButton.click() await tutorialDismissButton.click()
// Make sure model still there.
await expectPixelColor(page, modelColor, XYPlanePoint, 8)
}) })
await test.step('Clear code and restart onboarding from settings', async () => { await test.step('Clear code and restart onboarding from settings', async () => {
@ -480,11 +535,9 @@ test(
await restartOnboardingSettingsButton.click() await restartOnboardingSettingsButton.click()
// Since the code is empty, we should not see the confirmation dialog // Since the code is empty, we should not see the confirmation dialog
await expect(restartConfirmationButton).not.toBeVisible() await expect(nextButton).not.toBeVisible()
await expect(tutorialProjectIndicator).toBeVisible() await expect(tutorialProjectIndicator).toBeVisible()
await expect(tutorialModalText).toBeVisible() await expect(tutorialModalText).toBeVisible()
}) })
await electronApp.close()
} }
) )

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
import { test, expect } from './zoo-test'
/* eslint-disable jest/no-conditional-expect */
const file = `sketch001 = startSketchOn('XZ')
profile001 = startProfileAt([57.81, 250.51], sketch001)
|> line([121.13, 56.63], %, $seg02)
|> line([83.37, -34.61], %, $seg01)
|> line([19.66, -116.4], %)
|> line([-221.8, -41.69], %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
extrude001 = extrude(200, profile001)
sketch002 = startSketchOn('XZ')
|> startProfileAt([-73.64, -42.89], %)
|> xLine(173.71, %)
|> line([-22.12, -94.4], %)
|> xLine(-156.98, %)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
extrude002 = extrude(50, sketch002)
sketch003 = startSketchOn('XY')
|> startProfileAt([52.92, 157.81], %)
|> angledLine([0, 176.4], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001) - 90,
53.4
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)
extrude003 = extrude(20, sketch003)
`
test.describe('Check the happy path, for basic changing color', () => {
const cases = [
{
desc: 'User accepts change',
shouldReject: false,
},
{
desc: 'User rejects change',
shouldReject: true,
},
] as const
for (const { desc, shouldReject } of cases) {
test(`${desc}`, async ({
context,
homePage,
cmdBar,
editor,
page,
scene,
}) => {
await context.addInitScript((file) => {
localStorage.setItem('persistCode', file)
}, file)
await homePage.goToModelingScene()
const body1CapCoords = { x: 571, y: 351 }
const greenCheckCoords = { x: 565, y: 345 }
const body2WallCoords = { x: 609, y: 153 }
const [clickBody1Cap] = scene.makeMouseHelpers(
body1CapCoords.x,
body1CapCoords.y
)
const yellow: [number, number, number] = [179, 179, 131]
const green: [number, number, number] = [108, 152, 75]
const notGreen: [number, number, number] = [132, 132, 132]
const body2NotGreen: [number, number, number] = [88, 88, 88]
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
const successToast = page.getByText('Prompt to edit successful')
const acceptBtn = page.getByRole('button', { name: 'checkmark Accept' })
const rejectBtn = page.getByRole('button', { name: 'close Reject' })
await test.step('wait for scene to load select body and check selection came through', async () => {
await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15)
await clickBody1Cap()
await scene.expectPixelColor(yellow, body1CapCoords, 20)
await editor.expectState({
highlightedCode: '',
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],
diagnostics: [],
})
})
await test.step('fire off edit prompt', async () => {
await cmdBar.openCmdBar('promptToEdit')
// being specific about the color with a hex means asserting pixel color is more stable
await page
.getByTestId('cmd-bar-arg-value')
.fill('make this neon green please, use #39FF14')
await page.waitForTimeout(100)
await cmdBar.progressCmdBar()
await expect(submittingToast).toBeVisible()
await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000 }) // can take a while
await expect(successToast).toBeVisible()
})
await test.step('verify initial change', async () => {
await scene.expectPixelColor(green, greenCheckCoords, 15)
await scene.expectPixelColor(body2NotGreen, body2WallCoords, 15)
await editor.expectEditor.toContain('appearance({')
})
if (!shouldReject) {
await test.step('check accept works and can be "undo"ed', async () => {
await acceptBtn.click()
await expect(successToast).not.toBeVisible()
await scene.expectPixelColor(green, greenCheckCoords, 15)
await editor.expectEditor.toContain('appearance({')
// ctrl-z works after accepting
await page.keyboard.down('ControlOrMeta')
await page.keyboard.press('KeyZ')
await page.keyboard.up('ControlOrMeta')
await editor.expectEditor.not.toContain('appearance({')
await scene.expectPixelColor(notGreen, greenCheckCoords, 15)
})
} else {
await test.step('check reject works', async () => {
await rejectBtn.click()
await expect(successToast).not.toBeVisible()
await scene.expectPixelColor(notGreen, greenCheckCoords, 15)
await editor.expectEditor.not.toContain('appearance({')
})
}
})
}
})
test.describe('bad path', () => {
test(`bad edit prompt`, async ({
context,
homePage,
cmdBar,
editor,
toolbar,
page,
scene,
}) => {
await context.addInitScript((file) => {
localStorage.setItem('persistCode', file)
}, file)
await homePage.goToModelingScene()
const body1CapCoords = { x: 571, y: 351 }
const [clickBody1Cap] = scene.makeMouseHelpers(
body1CapCoords.x,
body1CapCoords.y
)
const yellow: [number, number, number] = [179, 179, 131]
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
const failToast = page.getByText(
'Failed to edit your KCL code, please try again with a different prompt or selection'
)
await test.step('wait for scene to load and select body', async () => {
await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15)
await clickBody1Cap()
await scene.expectPixelColor(yellow, body1CapCoords, 20)
await editor.expectState({
highlightedCode: '',
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],
diagnostics: [],
})
})
await test.step('fire of bad prompt', async () => {
await cmdBar.openCmdBar('promptToEdit')
await page
.getByTestId('cmd-bar-arg-value')
.fill('ansheusha asnthuatshoeuhtaoetuhthaeu laughs in dvorak')
await page.waitForTimeout(100)
await cmdBar.progressCmdBar()
await expect(submittingToast).toBeVisible()
})
await test.step('check fail toast appeared', async () => {
await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000 }) // can take a while
await expect(failToast).toBeVisible()
})
})
})

View File

@ -1,46 +1,37 @@
import { test, expect, Page } from '@playwright/test' import { test, expect, Page } from './zoo-test'
import { join } from 'path' import path from 'path'
import * as fsp from 'fs/promises' import * as fsp from 'fs/promises'
import { import { getUtils, executorInputPath } from './test-utils'
getUtils,
setup,
setupElectron,
tearDown,
executorInputPath,
} from './test-utils'
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates' import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Regression tests', () => { test.describe('Regression tests', () => {
// bugs we found that don't fit neatly into other categories // bugs we found that don't fit neatly into other categories
test('bad model has inline error #3251', async ({ page }) => { test('bad model has inline error #3251', async ({
context,
page,
homePage,
}) => {
// because the model has `line([0,0]..` it is valid code, but the model is invalid // because the model has `line([0,0]..` it is valid code, but the model is invalid
// regression test for https://github.com/KittyCAD/modeling-app/issues/3251 // regression test for https://github.com/KittyCAD/modeling-app/issues/3251
// Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics // Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await context.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch2 = startSketchOn("XY") `sketch2 = startSketchOn("XY")
sketch001 = startSketchAt([-0, -0]) sketch001 = startSketchAt([-0, -0])
|> line([0, 0], %) |> line([0, 0], %)
|> line([-4.84, -5.29], %) |> line([-4.84, -5.29], %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)` |> close(%)`
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
// error in guter // error in guter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible() await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
@ -56,6 +47,7 @@ sketch001 = startSketchAt([-0, -0])
}) })
test('user should not have to press down twice in cmdbar', async ({ test('user should not have to press down twice in cmdbar', async ({
page, page,
homePage,
}) => { }) => {
// because the model has `line([0,0]..` it is valid code, but the model is invalid // because the model has `line([0,0]..` it is valid code, but the model is invalid
// regression test for https://github.com/KittyCAD/modeling-app/issues/3251 // regression test for https://github.com/KittyCAD/modeling-app/issues/3251
@ -64,26 +56,38 @@ sketch001 = startSketchAt([-0, -0])
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch2 = startSketchOn("XY") `sketch001 = startSketchOn('XY')
sketch001 = startSketchAt([-0, -0]) |> startProfileAt([82.33, 238.21], %)
|> line([0, 0], %) |> angledLine([0, 288.63], %, $rectangleSegmentA001)
|> line([-4.84, -5.29], %) |> angledLine([
segAng(rectangleSegmentA001) - 90,
197.97
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)
|> close(%)` |> close(%)
extrude001 = extrude(50, sketch001)
`
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await page.goto('/') await homePage.goToModelingScene()
await u.waitForPageLoad() await u.waitForPageLoad()
await test.step('Check arrow down works', async () => { await test.step('Check arrow down works', async () => {
await page.getByTestId('command-bar-open-button').hover()
await page.getByTestId('command-bar-open-button').click() await page.getByTestId('command-bar-open-button').click()
await page const floppy = page.getByRole('option', {
.getByRole('option', { name: 'floppy disk arrow Export' }) name: 'floppy disk arrow Export',
.click() })
await floppy.click()
// press arrow down key twice // press arrow down key twice
await page.keyboard.press('ArrowDown') await page.keyboard.press('ArrowDown')
@ -115,21 +119,22 @@ sketch001 = startSketchAt([-0, -0])
) )
}) })
}) })
test('executes on load', async ({ page }) => { test('executes on load', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`sketch001 = startSketchOn('-XZ') `sketch001 = startSketchOn('-XZ')
|> startProfileAt([-6.95, 4.98], %) |> startProfileAt([-6.95, 4.98], %)
|> line([25.1, 0.41], %) |> line([25.1, 0.41], %)
|> line([0.73, -14.93], %) |> line([0.73, -14.93], %)
|> line([-23.44, 0.52], %)` |> line([-23.44, 0.52], %)`
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
// expand variables section // expand variables section
const variablesTabButton = page.getByTestId('variables-pane-button') const variablesTabButton = page.getByTestId('variables-pane-button')
@ -148,14 +153,15 @@ sketch001 = startSketchAt([-0, -0])
).toBeVisible() ).toBeVisible()
}) })
test('re-executes', async ({ page }) => { test('re-executes', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem('persistCode', `myVar = 5`) localStorage.setItem('persistCode', `myVar = 5`)
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
const variablesTabButton = page.getByTestId('variables-pane-button') const variablesTabButton = page.getByTestId('variables-pane-button')
await variablesTabButton.click() await variablesTabButton.click()
@ -174,32 +180,33 @@ sketch001 = startSketchAt([-0, -0])
page.locator('.pretty-json-container >> text=myVar:67') page.locator('.pretty-json-container >> text=myVar:67')
).toBeVisible() ).toBeVisible()
}) })
test('ProgramMemory can be serialised', async ({ page }) => { test('ProgramMemory can be serialised', async ({ page, homePage }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`part = startSketchOn('XY') `part = startSketchOn('XY')
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line([0, 1], %) |> line([0, 1], %)
|> line([1, 0], %) |> line([1, 0], %)
|> line([0, -1], %) |> line([0, -1], %)
|> close(%) |> close(%)
|> extrude(1, %) |> extrude(1, %)
|> patternLinear3d({ |> patternLinear3d({
axis: [1, 0, 1], axis: [1, 0, 1],
repetitions: 3, repetitions: 3,
distance: 6 distance: 6
}, %)` }, %)`
) )
}) })
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
const messages: string[] = [] const messages: string[] = []
// Listen for all console events and push the message text to an array // Listen for all console events and push the message text to an array
page.on('console', (message) => messages.push(message.text())) page.on('console', (message) => messages.push(message.text()))
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
// wait for execution done // wait for execution done
await u.openDebugPanel() await u.openDebugPanel()
@ -212,19 +219,26 @@ sketch001 = startSketchAt([-0, -0])
}) })
}) })
}) })
test('ensure the Zoo logo is not a link in browser app', async ({ page }) => {
// Not relevant to us anymore, or at least for the time being.
test.skip('ensure the Zoo logo is not a link in browser app', async ({
page,
homePage,
}) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
const zooLogo = page.locator('[data-testid="app-logo"]') const zooLogo = page.locator('[data-testid="app-logo"]')
// Make sure it's not a link // Make sure it's not a link
await expect(zooLogo).not.toHaveAttribute('href') await expect(zooLogo).not.toHaveAttribute('href')
}) })
test( test(
'Position _ Is Out Of Range... regression test', 'Position _ Is Out Of Range... regression test',
{ tag: ['@skipWin'] }, { tag: ['@skipWin'] },
async ({ page }) => { async ({ context, page, homePage }) => {
// SKip on windows, its being weird. // SKip on windows, its being weird.
test.skip( test.skip(
process.platform === 'win32', process.platform === 'win32',
@ -233,25 +247,26 @@ sketch001 = startSketchAt([-0, -0])
const u = await getUtils(page) const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio // const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await page.addInitScript(async () => { await context.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(
'persistCode', 'persistCode',
`exampleSketch = startSketchOn("XZ") `exampleSketch = startSketchOn("XZ")
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine({ angle: 50, length: 45 }, %) |> angledLine({ angle: 50, length: 45 }, %)
|> yLineTo(0, %) |> yLineTo(0, %)
|> close(%) |> close(%)
|> |>
example = extrude(5, exampleSketch) example = extrude(5, exampleSketch)
shell({ faces: ['end'], thickness: 0.25 }, exampleSketch)` shell({ faces: ['end'], thickness: 0.25 }, exampleSketch)`
) )
}) })
await expect(async () => { await expect(async () => {
await page.goto('/') await homePage.goToModelingScene()
await u.waitForPageLoad() await u.waitForPageLoad()
// error in guter // error in guter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible({ await expect(page.locator('.cm-lint-marker-error')).toBeVisible({
timeout: 1_000, timeout: 1_000,
@ -293,12 +308,12 @@ sketch001 = startSketchAt([-0, -0])
await expect(page.locator('.cm-content')) await expect(page.locator('.cm-content'))
.toContainText(`exampleSketch = startSketchOn("XZ") .toContainText(`exampleSketch = startSketchOn("XZ")
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine({ angle: 50, length: 45 }, %) |> angledLine({ angle: 50, length: 45 }, %)
|> yLineTo(0, %) |> yLineTo(0, %)
|> close(%) |> close(%)
thing: "blah"`) thing: "blah"`)
await expect(page.locator('.cm-lint-marker-error')).toBeVisible() await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
} }
@ -306,6 +321,7 @@ sketch001 = startSketchAt([-0, -0])
test('when engine fails export we handle the failure and alert the user', async ({ test('when engine fails export we handle the failure and alert the user', async ({
page, page,
homePage,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.addInitScript( await page.addInitScript(
@ -316,9 +332,10 @@ sketch001 = startSketchAt([-0, -0])
{ code: TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } { code: TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR }
) )
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
// wait for execution done // wait for execution done
await u.openDebugPanel() await u.openDebugPanel()
@ -374,7 +391,6 @@ sketch001 = startSketchAt([-0, -0])
// wait for execution done // wait for execution done
await u.openDebugPanel() await u.openDebugPanel()
await u.clearCommandLogs()
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel() await u.closeDebugPanel()
@ -408,7 +424,7 @@ sketch001 = startSketchAt([-0, -0])
test( test(
'ensure you can not export while an export is already going', 'ensure you can not export while an export is already going',
{ tag: ['@skipLinux', '@skipWin'] }, { tag: ['@skipLinux', '@skipWin'] },
async ({ page }) => { async ({ page, homePage }) => {
// This is being weird on ubuntu and windows. // This is being weird on ubuntu and windows.
test.skip( test.skip(
// eslint-disable-next-line jest/valid-title // eslint-disable-next-line jest/valid-title
@ -428,9 +444,10 @@ sketch001 = startSketchAt([-0, -0])
} }
) )
await page.setViewportSize({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
// wait for execution done // wait for execution done
await u.openDebugPanel() await u.openDebugPanel()
@ -500,20 +517,17 @@ sketch001 = startSketchAt([-0, -0])
test( test(
`Network health indicator only appears in modeling view`, `Network health indicator only appears in modeling view`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ browserName: _ }, testInfo) => { async ({ context, page }, testInfo) => {
const { electronApp, page } = await setupElectron({ await context.folderSetupFn(async (dir) => {
testInfo, const bracketDir = path.join(dir, 'bracket')
folderSetupFn: async (dir) => { await fsp.mkdir(bracketDir, { recursive: true })
const bracketDir = join(dir, 'bracket') await fsp.copyFile(
await fsp.mkdir(bracketDir, { recursive: true }) executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
await fsp.copyFile( path.join(bracketDir, 'main.kcl')
executorInputPath('focusrite_scarlett_mounting_braket.kcl'), )
join(bracketDir, 'main.kcl')
)
},
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
const u = await getUtils(page) const u = await getUtils(page)
// Locators // Locators
@ -539,14 +553,15 @@ sketch001 = startSketchAt([-0, -0])
await u.waitForPageLoad() await u.waitForPageLoad()
await expect(networkHealthIndicator).toContainText('Connected') await expect(networkHealthIndicator).toContainText('Connected')
}) })
await electronApp.close()
} }
) )
test(`View gizmo stays visible even when zoomed out all the way`, async ({ test(`View gizmo stays visible even when zoomed out all the way`, async ({
page, page,
homePage,
}) => { }) => {
// TODO: fix this test on windows after the electron migration
test.skip(process.platform === 'win32', 'Skip on windows')
const u = await getUtils(page) const u = await getUtils(page)
// Constants and locators // Constants and locators
@ -561,8 +576,9 @@ sketch001 = startSketchAt([-0, -0])
await page.addInitScript(async () => { await page.addInitScript(async () => {
localStorage.setItem('persistCode', '') localStorage.setItem('persistCode', '')
}) })
await page.setViewportSize({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart() await homePage.goToModelingScene()
await u.waitForPageLoad()
await u.closeKclCodePanel() await u.closeKclCodePanel()
}) })
@ -572,7 +588,7 @@ sketch001 = startSketchAt([-0, -0])
timeout: 5000, timeout: 5000,
message: 'Plane color is visible', message: 'Plane color is visible',
}) })
.toBeLessThan(15) .toBeLessThanOrEqual(15)
let maxZoomOuts = 10 let maxZoomOuts = 10
let middlePixelIsBackgroundColor = let middlePixelIsBackgroundColor =
@ -590,7 +606,7 @@ sketch001 = startSketchAt([-0, -0])
} }
expect(middlePixelIsBackgroundColor, { expect(middlePixelIsBackgroundColor, {
message: 'We no longer the default planes', message: 'We should not see the default planes',
}).toBeTruthy() }).toBeTruthy()
}) })
@ -598,6 +614,38 @@ sketch001 = startSketchAt([-0, -0])
await expect(gizmo).toBeVisible() await expect(gizmo).toBeVisible()
}) })
}) })
test(`Refreshing the app doesn't cause the stream to pause on long-executing files`, async ({
context,
homePage,
scene,
toolbar,
viewport,
}) => {
await context.folderSetupFn(async (dir) => {
const legoDir = path.join(dir, 'lego')
await fsp.mkdir(legoDir, { recursive: true })
await fsp.copyFile(
executorInputPath('lego.kcl'),
path.join(legoDir, 'main.kcl')
)
})
await test.step(`Test setup`, async () => {
await homePage.openProject('lego')
await toolbar.closePane('code')
})
await test.step(`Waiting for the loading spinner to disappear`, async () => {
await scene.loadingIndicator.waitFor({ state: 'detached' })
})
await test.step(`The part should start loading quickly, not waiting until execution is complete`, async () => {
await scene.expectPixelColor(
[143, 143, 143],
{ x: (viewport?.width ?? 1200) / 2, y: (viewport?.height ?? 500) / 2 },
15
)
})
})
}) })
async function clickExportButton(page: Page) { async function clickExportButton(page: Page) {

View File

@ -7,6 +7,8 @@ try {
.split('\n') .split('\n')
.filter((line) => line && line.length > 1) .filter((line) => line && line.length > 1)
.forEach((line) => { .forEach((line) => {
// Allow line comments.
if (line.trimStart().startsWith('#')) return
const [key, value] = line.split('=') const [key, value] = line.split('=')
// prefer env vars over secrets file // prefer env vars over secrets file
secrets[key] = process.env[key] || (value as any).replaceAll('"', '') secrets[key] = process.env[key] || (value as any).replaceAll('"', '')

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,11 @@ test.beforeEach(async ({ page }) => {
test.setTimeout(60_000) test.setTimeout(60_000)
test( // We test this end to end already - getting this to work on web just to take
// a snapshot of it feels weird. I'd rather our regular tests fail.
// The primary failure is doExport now relies on the filesystem. We can follow
// up with another PR if we want this back.
test.skip(
'exports of each format should work', 'exports of each format should work',
{ tag: ['@snapshot', '@skipWin', '@skipMacos'] }, { tag: ['@snapshot', '@skipWin', '@skipMacos'] },
async ({ page, context }) => { async ({ page, context }) => {
@ -371,6 +375,7 @@ const extrudeDefaultPlane = async (context: any, page: any, plane: string) => {
await u.closeKclCodePanel() await u.closeKclCodePanel()
await expect(page).toHaveScreenshot({ await expect(page).toHaveScreenshot({
maxDiffPixels: 100, maxDiffPixels: 100,
mask: [page.getByTestId('model-state-indicator')],
}) })
await u.openKclCodePanel() await u.openKclCodePanel()
} }
@ -950,7 +955,75 @@ test(
test.describe('Grid visibility', { tag: '@snapshot' }, () => { test.describe('Grid visibility', { tag: '@snapshot' }, () => {
// FIXME: Skip on macos its being weird. // FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos') // test.skip(process.platform === 'darwin', 'Skip on macos')
test('Grid turned off to on via command bar', async ({ page }) => {
const u = await getUtils(page)
const stream = page.getByTestId('stream')
const mask = [
page.locator('#app-header'),
page.locator('#sidebar-top-ribbon'),
page.locator('#sidebar-bottom-ribbon'),
]
await page.setViewportSize({ width: 1200, height: 500 })
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 u.closeKclCodePanel()
// TODO: Find a way to truly know that the objects have finished
// rendering, because an execution-done message is not sufficient.
await page.waitForTimeout(1000)
// Open the command bar.
await page
.getByRole('button', { name: 'Commands', exact: false })
.or(page.getByRole('button', { name: '⌘K' }))
.click()
const commandName = 'show scale grid'
const commandOption = page.getByRole('option', {
name: commandName,
exact: false,
})
const cmdSearchBar = page.getByPlaceholder('Search commands')
// This selector changes after we set the setting
await cmdSearchBar.fill(commandName)
await expect(commandOption).toBeVisible()
await commandOption.click()
const toggleInput = page.getByPlaceholder('Off')
await expect(toggleInput).toBeVisible()
await expect(toggleInput).toBeFocused()
// Select On
await page.keyboard.press('ArrowDown')
await expect(page.getByRole('option', { name: 'Off' })).toHaveAttribute(
'data-headlessui-state',
'active selected'
)
await page.keyboard.press('ArrowUp')
await expect(page.getByRole('option', { name: 'On' })).toHaveAttribute(
'data-headlessui-state',
'active'
)
await page.keyboard.press('Enter')
// Check the toast appeared
await expect(
page.getByText(`Set show scale grid to "true" as a user default`)
).toBeVisible()
await expect(stream).toHaveScreenshot({
maxDiffPixels: 100,
mask,
})
})
test('Grid turned off', async ({ page }) => { test('Grid turned off', async ({ page }) => {
const u = await getUtils(page) const u = await getUtils(page)
@ -1096,3 +1169,109 @@ test.fixme('theme persists', async ({ page, context }) => {
maxDiffPixels: 100, maxDiffPixels: 100,
}) })
}) })
test.describe('code color goober', { tag: '@snapshot' }, () => {
test('code color goober', async ({ page, context }) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`// Create a pipe using a sweep.
// Create a path for the sweep.
sweepPath = startSketchOn('XZ')
|> startProfileAt([0.05, 0.05], %)
|> line([0, 7], %)
|> tangentialArc({ offset = 90, radius = 5 }, %)
|> line([-3, 0], %)
|> tangentialArc({ offset = -90, radius = 5 }, %)
|> line([0, 7], %)
sweepSketch = startSketchOn('XY')
|> startProfileAt([2, 0], %)
|> arc({
angleEnd = 360,
angleStart = 0,
radius = 2
}, %)
|> sweep({
path = sweepPath,
}, %)
|> appearance({
color = "#bb00ff",
metalness = 90,
roughness = 90
}, %)
`
)
})
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 expect(page, 'expect small color widget').toHaveScreenshot({
maxDiffPixels: 100,
})
})
test('code color goober opening window', async ({ page, context }) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`// Create a pipe using a sweep.
// Create a path for the sweep.
sweepPath = startSketchOn('XZ')
|> startProfileAt([0.05, 0.05], %)
|> line([0, 7], %)
|> tangentialArc({ offset = 90, radius = 5 }, %)
|> line([-3, 0], %)
|> tangentialArc({ offset = -90, radius = 5 }, %)
|> line([0, 7], %)
sweepSketch = startSketchOn('XY')
|> startProfileAt([2, 0], %)
|> arc({
angleEnd = 360,
angleStart = 0,
radius = 2
}, %)
|> sweep({
path = sweepPath,
}, %)
|> appearance({
color = "#bb00ff",
metalness = 90,
roughness = 90
}, %)
`
)
})
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 expect(page.locator('.cm-css-color-picker-wrapper')).toBeVisible()
// Click the color widget
await page.locator('.cm-css-color-picker-wrapper input').click()
await expect(
page,
'expect small color widget to have window open'
).toHaveScreenshot({
maxDiffPixels: 100,
})
})
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Some files were not shown because too many files have changed in this diff Show More