Compare commits

..

40 Commits

Author SHA1 Message Date
f65a84b1dd updates
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 16:48:11 -07:00
f00a7059a2 fix source ranges
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 15:36:05 -07:00
0f9bed70a6 no printlns
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 15:20:23 -07:00
ff10275823 no printlns
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 15:20:03 -07:00
1da4667f5b cluppy
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 15:12:22 -07:00
1de64ea15c race w batch
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 15:05:09 -07:00
729ca08eef no extra executes
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 14:41:22 -07:00
cb2368dc17 updates
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 14:18:55 -07:00
e943303434 logs
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 10:20:35 -07:00
8ce175f006 clippy
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 09:48:45 -07:00
13aa178734 get rid of execution kind
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-05 09:44:18 -07:00
de137ff13b Merge remote-tracking branch 'origin/main' into jess/changes-import
* origin/main: (26 commits)
  attempt to import win-ca on windows (#6136)
  Upgrade e2e-tests windows runner from 4 cores to 8 (#6166)
  Follow-up fixes after bearing sample rename (#6164)
  Add test for #5799: "Only showing axis planes when there are no errors" (#6007)
  Wait for export button to make test more reliable (#6143)
  sketching on a mirror2d thats been extruded fixed! (#6149)
  Bump vite from 5.4.16 to 5.4.17 in /packages/codemirror-lang-kcl in the security group (#6150)
  Bump vite from 5.4.16 to 5.4.17 in the security group (#6151)
  Update all KCL-Samples to be more ME friendly (#6132)
  Shorten feedback cycle for legitimate failures (#6146)
  Remove the camera projection toggle from the UI (#6077)
  Use all available CPUs to run tests on CI (#6138)
  [fix] Get rid of risky useEffect in restart onboarding flow (#6133)
  Feature: Traditional menu actions in desktop application part II (#6030)
  [Bug] fix some UI friction from imports (#6139)
  Use scene fixture to make test more reliable on macOS (#6140)
  Fix: function composition during playwright setup created a massive page.reload loop (#6137)
  Alternative way to make appMachine spawned children type safe (#5890)
  [BUG] mutate ast to keep comments for pipe split ast-mod (#6128)
  Rename the app to Zoo Design Studio (#5974)
  ...
2025-04-05 09:33:50 -07:00
3504b9246f Merge remote-tracking branch 'origin/main' into paultag/import 2025-04-03 10:15:28 -04:00
a035f7879b Merge remote-tracking branch 'origin/main' into paultag/import 2025-04-02 11:36:59 -04:00
d122d7a224 fix rebase add feature flag
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-04-01 12:34:42 -07:00
198e7c4bd2 Merge remote-tracking branch 'origin/main' into paultag/import 2025-04-01 15:18:23 -04:00
14d8903acc man this is bad 2025-04-01 15:16:59 -04:00
275c23f294 chip away more 2025-04-01 13:35:50 -04:00
0ac9ac3896 Reapply "this was a bad idea"
This reverts commit fafdf41093.
2025-04-01 11:56:36 -04:00
0220d0f9de ok 2025-04-01 11:55:08 -04:00
4523dc209b Merge remote-tracking branch 'origin/main' into paultag/import 2025-04-01 11:55:02 -04:00
ea73eb011c :( 2025-03-31 16:51:46 -04:00
0aa2824c20 yike 2025-03-31 16:20:29 -04:00
e66893c5d0 poop 2025-03-31 16:17:35 -04:00
60274127df error 2025-03-31 15:57:13 -04:00
a0d1750829 prepare prelude before spawning 2025-03-31 15:54:35 -04:00
00ffa8c0bf Merge remote-tracking branch 'origin/main' into paultag/import 2025-03-31 15:46:26 -04:00
fafdf41093 Revert "this was a bad idea"
This reverts commit a2092e7ed6.
2025-03-28 17:07:29 -04:00
a2092e7ed6 this was a bad idea 2025-03-28 15:03:13 -04:00
aa103d299c Merge branch 'main' into paultag/import 2025-03-28 14:40:34 -04:00
aaaab495bc Merge remote-tracking branch 'origin' into paultag/import 2025-03-18 16:24:05 -04:00
364e38fda2 Merge remote-tracking branch 'origin' into paultag/import 2025-03-18 09:17:51 -04:00
b085af139b lock start things 2025-03-13 14:58:24 -04:00
ec537cd8dc Merge remote-tracking branch 'origin/main' into paultag/import 2025-03-13 11:17:34 -04:00
8debbc5241 wip 2025-03-13 11:17:22 -04:00
a590ed99cf Merge branch 'main' of github.com:KittyCAD/modeling-app into paultag/import 2025-03-12 12:00:46 -04:00
a002bb60a0 Merge remote-tracking branch 'origin/main' into paultag/import 2025-03-11 16:18:58 -04:00
6ba01b8dfa sketch a bit more; going to pull this out of tests next 2025-03-10 15:43:43 -04:00
ca9e6e0944 Merge remote-tracking branch 'origin/main' into paultag/import 2025-03-10 12:27:50 -04:00
e85e54215c wip 2025-03-10 12:27:47 -04:00
774 changed files with 114027 additions and 119181 deletions

View File

@ -1,3 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser
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,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo 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,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo

View File

@ -1,24 +0,0 @@
#!/bin/bash
set -euo pipefail
# Install vector
brew tap vectordotdev/brew && brew install vector
# Configure vector
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i '' "s#OS_NAME#${OS_NAME}#g" /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#${GH_ACTIONS_AXIOM_TOKEN}#g" /tmp/vector.toml
# Display settings
echo
echo 'Vector config:'
cat /tmp/vector.toml
echo
# Start in the background
$(brew --prefix)/opt/vector/bin/vector --config /tmp/vector.toml &

View File

@ -1,24 +0,0 @@
#!/bin/bash
set -euo pipefail
# Install vector
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev | bash -s -- -y
# Configure vector
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#OS_NAME#${OS_NAME}#g" /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#${GH_ACTIONS_AXIOM_TOKEN}#g" /tmp/vector.toml
# Display settings
echo
echo 'Vector config:'
cat /tmp/vector.toml
echo
# Start in background
${HOME}/.vector/bin/vector --config /tmp/vector.toml &

View File

@ -24,7 +24,7 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack
- name: Rust Cache - name: Rust Cache

View File

@ -10,8 +10,7 @@ on:
- 'nightly-v[0-9]+.[0-9]+.[0-9]+' - 'nightly-v[0-9]+.[0-9]+.[0-9]+'
env: env:
# IS_RELEASE: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }} IS_RELEASE: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }}
IS_RELEASE: true
IS_NIGHTLY: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'nightly-v') }} IS_NIGHTLY: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'nightly-v') }}
concurrency: concurrency:
@ -78,7 +77,7 @@ jobs:
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
with: with:
tool: wasm-pack tool: wasm-pack
@ -100,11 +99,11 @@ jobs:
yarn files:set-version yarn files:set-version
yarn files:flip-to-nightly yarn files:flip-to-nightly
# - name: Set release version - name: Set release version
# if: ${{ env.IS_RELEASE == 'true' }} if: ${{ env.IS_RELEASE == 'true' }}
# run: | run: |
# export VERSION=${GITHUB_REF_NAME#v} export VERSION=${GITHUB_REF_NAME#v}
# yarn files:set-version yarn files:set-version
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
@ -184,32 +183,30 @@ jobs:
max_attempts: 3 max_attempts: 3
command: yarn install command: yarn install
# Next steps are from Digicert docs at
# https://docs.digicert.com/en/digicert-keylocker/ci-cd-integrations/scripts/github/scripts-for-signing-using-ksp-library-on-github.html#ksp-signing-using-github-action-488726
- name: Prepare certificate and variables (Windows only) - name: Prepare certificate and variables (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }} if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
run: | run: |
CERTIFICATE_PATH=$RUNNER_TEMP/certificate.p12 echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
echo "$SM_CLIENT_CERT_FILE_B64" | base64 --decode > $CERTIFICATE_PATH cat /d/Certificate_pkcs12.p12
echo "SM_CLIENT_CERT_FILE=$CERTIFICATE_PATH" >> "$GITHUB_ENV" echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV" echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV" echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV" echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
echo "C:\Program Files\DigiCert\DigiCert Keylocker Tools" >> $GITHUB_PATH echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH
shell: bash shell: bash
- name: Setup certicate with SSM KSP (Windows only) - name: Setup certicate with SSM KSP (Windows only)
if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }} if: ${{ (env.IS_RELEASE == 'true' || env.IS_NIGHTLY == 'true') && matrix.os == 'windows-2022' }}
run: | run: |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/Keylockertools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o Keylockertools-windows-x64.msi curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi
msiexec /i Keylockertools-windows-x64.msi /quiet /qn msiexec /i smtools-windows-x64.msi /quiet /qn
smksp_registrar.exe list smksp_registrar.exe list
smctl.exe keypair ls smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe smksp_cert_sync.exe
smctl windows certsync
shell: cmd shell: cmd
- name: Build the app (debug) - name: Build the app (debug)
@ -228,8 +225,8 @@ 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 }}
# DEBUG: "electron-notarize*" WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
DEBUG: electron-builder DEBUG: "electron-notarize*"
# TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures # TODO: Fix electron-notarize flakes. The logs above should help gather more data on failures
uses: nick-fields/retry@v3.0.2 uses: nick-fields/retry@v3.0.2
with: with:

View File

@ -34,11 +34,20 @@ jobs:
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
cache: false # Configured below. cache: false # Configured below.
- name: Start Vector - name: Install vector
run: .github/ci-cd-scripts/start-vector-ubuntu.sh run: |
env: curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }} chmod +x /tmp/vector.sh
OS_NAME: ${{ env.OS_NAME }} /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 &
- uses: taiki-e/install-action@cargo-llvm-cov - uses: taiki-e/install-action@cargo-llvm-cov
- uses: taiki-e/install-action@nextest - uses: taiki-e/install-action@nextest
- name: Install just - name: Install just

View File

@ -140,7 +140,7 @@ jobs:
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }} if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
with: with:
tool: wasm-pack tool: wasm-pack
@ -339,12 +339,22 @@ jobs:
if: needs.conditions.outputs.should-run == 'true' if: needs.conditions.outputs.should-run == 'true'
run: yarn tronb:vite:dev run: yarn tronb:vite:dev
- name: Start Vector - name: Install vector
if: ${{ needs.conditions.outputs.should-run == 'true' && !contains(matrix.os, 'windows') }} if: ${{ needs.conditions.outputs.should-run == 'true' && contains(matrix.os, 'ubuntu') }}
run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh shell: bash
env: run: |
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }} curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
OS_NAME: ${{ env.OS_NAME }} 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 &
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }} if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}

View File

@ -51,7 +51,7 @@ jobs:
with: with:
cache: false # Configured below. cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack
@ -191,7 +191,7 @@ jobs:
cache: 'yarn' cache: 'yarn'
- run: yarn install - run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack
@ -236,7 +236,7 @@ jobs:
cache: 'yarn' cache: 'yarn'
- run: yarn install - run: yarn install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc - uses: taiki-e/install-action@37bdc826eaedac215f638a96472df572feab0f9b
with: with:
tool: wasm-pack tool: wasm-pack

View File

@ -8,7 +8,6 @@ include = ["/tmp/github-actions.log"]
type = "remap" type = "remap"
inputs = [ "github-actions-file" ] inputs = [ "github-actions-file" ]
source = ''' source = '''
.platform = "OS_NAME"
.action = "GITHUB_WORKFLOW" .action = "GITHUB_WORKFLOW"
.repo = "GITHUB_REPOSITORY" .repo = "GITHUB_REPOSITORY"
.sha = "GITHUB_SHA" .sha = "GITHUB_SHA"

View File

@ -5,15 +5,8 @@ all: install build check
# INSTALL # INSTALL
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
export WINDOWS := true CARGO ?= ~/.cargo/bin/cargo.exe
ifndef MSYSTEM WASM_PACK ?= ~/.cargo/bin/wasm-pack.exe
export POWERSHELL := true
endif
endif
ifdef WINDOWS
CARGO ?= $(USERPROFILE)/.cargo/bin/cargo.exe
WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe
else else
CARGO ?= ~/.cargo/bin/cargo CARGO ?= ~/.cargo/bin/cargo
WASM_PACK ?= ~/.cargo/bin/wasm-pack WASM_PACK ?= ~/.cargo/bin/wasm-pack
@ -24,21 +17,21 @@ install: node_modules/.yarn-integrity $(CARGO) $(WASM_PACK) ## Install dependenc
node_modules/.yarn-integrity: package.json yarn.lock node_modules/.yarn-integrity: package.json yarn.lock
yarn install yarn install
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
@ type nul > $@ @ type nul > $@
else else
@ touch $@ @ touch $@
endif endif
$(CARGO): $(CARGO):
ifdef WINDOWS ifeq ($(OS),Windows_NT)
yarn install:rust:windows yarn install:rust:windows
else else
yarn install:rust yarn install:rust
endif endif
$(WASM_PACK): $(WASM_PACK):
ifdef WINDOWS ifeq ($(OS),Windows_NT)
yarn install:wasm-pack:cargo yarn install:wasm-pack:cargo
else else
yarn install:wasm-pack:sh yarn install:wasm-pack:sh
@ -64,7 +57,7 @@ build-web: install public/kcl_wasm_lib_bg.wasm build/index.html
build-desktop: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js build-desktop: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES) public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES)
ifdef WINDOWS ifeq ($(OS),Windows_NT)
yarn build:wasm:dev:windows yarn build:wasm:dev:windows
else else
yarn build:wasm:dev yarn build:wasm:dev
@ -147,8 +140,8 @@ endif
.PHONY: clean .PHONY: clean
clean: ## Delete all artifacts clean: ## Delete all artifacts
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
git clean --force -d -x --exclude=.env* --exclude=**/*.env git clean --force -d -X
else else
rm -rf .vite/ build/ rm -rf .vite/ build/
rm -rf trace.zip playwright-report/ test-results/ rm -rf trace.zip playwright-report/ test-results/
@ -159,7 +152,7 @@ endif
.PHONY: help .PHONY: help
help: install help: install
ifdef POWERSHELL ifeq ($(OS),Windows_NT)
@ powershell -Command "Get-Content $(MAKEFILE_LIST) | Select-String -Pattern '^[^\s]+:.*##\s.*$$' | ForEach-Object { $$line = $$_.Line -split ':.*?##\s+'; Write-Host -NoNewline $$line[0].PadRight(30) -ForegroundColor Cyan; Write-Host $$line[1] }" @ powershell -Command "Get-Content $(MAKEFILE_LIST) | Select-String -Pattern '^[^\s]+:.*##\s.*$$' | ForEach-Object { $$line = $$_.Line -split ':.*?##\s+'; Write-Host -NoNewline $$line[0].PadRight(30) -ForegroundColor Cyan; Write-Host $$line[1] }"
else else
@ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@ -36,9 +36,9 @@ myAngle = -120
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [8, 0]) |> line(end = [8, 0])
|> angledLine(angle = abs(myAngle), length = 5) |> angledLine({ angle = abs(myAngle), length = 5 }, %)
|> line(end = [-5, 0]) |> line(end = [-5, 0])
|> angledLine(angle = myAngle, length = 5) |> angledLine({ angle = myAngle, length = 5 }, %)
|> close() |> close()
baseExtrusion = extrude(sketch001, length = 5) baseExtrusion = extrude(sketch001, length = 5)

View File

@ -33,7 +33,10 @@ acos(num: number): number
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(acos(0.5)), length = 10) |> angledLine({
angle = toDegrees(acos(0.5)),
length = 10
}, %)
|> line(end = [5, 0]) |> line(end = [5, 0])
|> line(endAbsolute = [12, 0]) |> line(endAbsolute = [12, 0])
|> close() |> close()

View File

@ -36,7 +36,7 @@ angleToMatchLengthX(
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [2, 5], tag = $seg01) |> line(end = [2, 5], tag = $seg01)
|> angledLine(angle = -angleToMatchLengthX(seg01, 7, %), endAbsoluteX = 10) |> angledLineToX([-angleToMatchLengthX(seg01, 7, %), 10], %)
|> close() |> close()
extrusion = extrude(sketch001, length = 5) extrusion = extrude(sketch001, length = 5)

View File

@ -36,7 +36,10 @@ angleToMatchLengthY(
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [1, 2], tag = $seg01) |> line(end = [1, 2], tag = $seg01)
|> angledLine(angle = angleToMatchLengthY(seg01, 15, %), length = 5) |> angledLine({
angle = angleToMatchLengthY(seg01, 15, %),
length = 5
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -10,13 +10,8 @@ Draw a line segment relative to the current origin using the polar measure of so
```js ```js
angledLine( angledLine(
data: AngledLineData,
sketch: Sketch, sketch: Sketch,
angle: number,
length?: number,
lengthX?: number,
lengthY?: number,
endAbsoluteX?: number,
endAbsoluteY?: number,
tag?: TagDeclarator, tag?: TagDeclarator,
): Sketch ): Sketch
``` ```
@ -26,14 +21,9 @@ angledLine(
| Name | Type | Description | Required | | Name | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | Which sketch should this path be added to? | Yes | | `data` | [`AngledLineData`](/docs/kcl/types/AngledLineData) | Data to draw an angled line. | Yes |
| `angle` | [`number`](/docs/kcl/types/number) | Which angle should the line be drawn at? | Yes | | `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | | Yes |
| `length` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the given angle. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No | | [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | | No |
| `lengthX` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the X axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `lengthY` | [`number`](/docs/kcl/types/number) | Draw the line this distance along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `endAbsoluteX` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the X axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| `endAbsoluteY` | [`number`](/docs/kcl/types/number) | Draw the line along the given angle until it reaches this point along the Y axis. Only one of `length`, `lengthX`, `lengthY`, `lengthAbsoluteEndX`, `lengthAbsoluteEndY` can be given. | No |
| [`tag`](/docs/kcl/types/tag) | [`TagDeclarator`](/docs/kcl/types#tag-declaration) | Create a new tag which refers to this line | No |
### Returns ### Returns
@ -46,7 +36,7 @@ angledLine(
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> yLine(endAbsolute = 15) |> yLine(endAbsolute = 15)
|> angledLine(angle = 30, length = 15) |> angledLine({ angle = 30, length = 15 }, %)
|> line(end = [8, -10]) |> line(end = [8, -10])
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

48
docs/kcl/angledLineToX.md Normal file

File diff suppressed because one or more lines are too long

48
docs/kcl/angledLineToY.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -33,7 +33,10 @@ asin(num: number): number
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(asin(0.5)), length = 20) |> angledLine({
angle = toDegrees(asin(0.5)),
length = 20
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -33,7 +33,10 @@ atan(num: number): number
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(atan(1.25)), length = 20) |> angledLine({
angle = toDegrees(atan(1.25)),
length = 20
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -37,7 +37,10 @@ atan2(
```js ```js
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = toDegrees(atan2(1.25, 2)), length = 20) |> angledLine({
angle = toDegrees(atan2(1.25, 2)),
length = 20
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -17,10 +17,10 @@ std::math::E: number = 2.71828182845904523536028747135266250_
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine( |> angledLine({
angle = 30, angle = 30,
length = 2 * E ^ 2, length = 2 * E ^ 2,
) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -30,7 +30,7 @@ e(): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 30, length = 2 * e() ^ 2) |> angledLine({ angle = 30, length = 2 * e() ^ 2 }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

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

@ -30,10 +30,10 @@ getNextAdjacentEdge(tag: TagIdentifier): Uuid
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [10, 0]) |> line(end = [10, 0])
|> angledLine(angle = 60, length = 10) |> angledLine({ angle = 60, length = 10 }, %)
|> angledLine(angle = 120, length = 10) |> angledLine({ angle = 120, length = 10 }, %)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> angledLine(angle = 240, length = 10, tag = $referenceEdge) |> angledLine({ angle = 240, length = 10 }, %, $referenceEdge)
|> close() |> close()
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)

View File

@ -30,10 +30,10 @@ getOppositeEdge(tag: TagIdentifier): Uuid
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [10, 0]) |> line(end = [10, 0])
|> angledLine(angle = 60, length = 10) |> angledLine({ angle = 60, length = 10 }, %)
|> angledLine(angle = 120, length = 10) |> angledLine({ angle = 120, length = 10 }, %)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> angledLine(angle = 240, length = 10, tag = $referenceEdge) |> angledLine({ angle = 240, length = 10 }, %, $referenceEdge)
|> close() |> close()
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)

View File

@ -30,10 +30,10 @@ getPreviousAdjacentEdge(tag: TagIdentifier): Uuid
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [10, 0]) |> line(end = [10, 0])
|> angledLine(angle = 60, length = 10) |> angledLine({ angle = 60, length = 10 }, %)
|> angledLine(angle = 120, length = 10) |> angledLine({ angle = 120, length = 10 }, %)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> angledLine(angle = 240, length = 10, tag = $referenceEdge) |> angledLine({ angle = 240, length = 10 }, %, $referenceEdge)
|> close() |> close()
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)

40
docs/kcl/inch.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -43,7 +43,11 @@ layout: manual
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX) * [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
* [`angleToMatchLengthY`](kcl/angleToMatchLengthY) * [`angleToMatchLengthY`](kcl/angleToMatchLengthY)
* [`angledLine`](kcl/angledLine) * [`angledLine`](kcl/angledLine)
* [`angledLineOfXLength`](kcl/angledLineOfXLength)
* [`angledLineOfYLength`](kcl/angledLineOfYLength)
* [`angledLineThatIntersects`](kcl/angledLineThatIntersects) * [`angledLineThatIntersects`](kcl/angledLineThatIntersects)
* [`angledLineToX`](kcl/angledLineToX)
* [`angledLineToY`](kcl/angledLineToY)
* [`appearance`](kcl/appearance) * [`appearance`](kcl/appearance)
* [`arc`](kcl/arc) * [`arc`](kcl/arc)
* [`arcTo`](kcl/arcTo) * [`arcTo`](kcl/arcTo)
@ -61,15 +65,11 @@ layout: manual
* [`chamfer`](kcl/chamfer) * [`chamfer`](kcl/chamfer)
* [`circleThreePoint`](kcl/circleThreePoint) * [`circleThreePoint`](kcl/circleThreePoint)
* [`close`](kcl/close) * [`close`](kcl/close)
* [`cm`](kcl/cm)
* [`extrude`](kcl/extrude) * [`extrude`](kcl/extrude)
* [`fillet`](kcl/fillet) * [`fillet`](kcl/fillet)
* [`floor`](kcl/floor) * [`floor`](kcl/floor)
* [`fromCm`](kcl/fromCm) * [`ft`](kcl/ft)
* [`fromFt`](kcl/fromFt)
* [`fromInches`](kcl/fromInches)
* [`fromM`](kcl/fromM)
* [`fromMm`](kcl/fromMm)
* [`fromYd`](kcl/fromYd)
* [`getCommonEdge`](kcl/getCommonEdge) * [`getCommonEdge`](kcl/getCommonEdge)
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge) * [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
* [`getOppositeEdge`](kcl/getOppositeEdge) * [`getOppositeEdge`](kcl/getOppositeEdge)
@ -77,6 +77,7 @@ layout: manual
* [`helix`](kcl/std-helix) * [`helix`](kcl/std-helix)
* [`hole`](kcl/hole) * [`hole`](kcl/hole)
* [`hollow`](kcl/hollow) * [`hollow`](kcl/hollow)
* [`inch`](kcl/inch)
* [`lastSegX`](kcl/lastSegX) * [`lastSegX`](kcl/lastSegX)
* [`lastSegY`](kcl/lastSegY) * [`lastSegY`](kcl/lastSegY)
* [`legAngX`](kcl/legAngX) * [`legAngX`](kcl/legAngX)
@ -88,9 +89,11 @@ layout: manual
* [`log`](kcl/log) * [`log`](kcl/log)
* [`log10`](kcl/log10) * [`log10`](kcl/log10)
* [`log2`](kcl/log2) * [`log2`](kcl/log2)
* [`m`](kcl/m)
* [`map`](kcl/map) * [`map`](kcl/map)
* [`max`](kcl/max) * [`max`](kcl/max)
* [`min`](kcl/min) * [`min`](kcl/min)
* [`mm`](kcl/mm)
* [`offsetPlane`](kcl/offsetPlane) * [`offsetPlane`](kcl/offsetPlane)
* [`patternCircular2d`](kcl/patternCircular2d) * [`patternCircular2d`](kcl/patternCircular2d)
* [`patternCircular3d`](kcl/patternCircular3d) * [`patternCircular3d`](kcl/patternCircular3d)
@ -98,6 +101,7 @@ layout: manual
* [`patternLinear3d`](kcl/patternLinear3d) * [`patternLinear3d`](kcl/patternLinear3d)
* [`patternTransform`](kcl/patternTransform) * [`patternTransform`](kcl/patternTransform)
* [`patternTransform2d`](kcl/patternTransform2d) * [`patternTransform2d`](kcl/patternTransform2d)
* [`polar`](kcl/polar)
* [`polygon`](kcl/polygon) * [`polygon`](kcl/polygon)
* [`pop`](kcl/pop) * [`pop`](kcl/pop)
* [`pow`](kcl/pow) * [`pow`](kcl/pow)
@ -133,12 +137,12 @@ layout: manual
* [`translate`](kcl/translate) * [`translate`](kcl/translate)
* [`xLine`](kcl/xLine) * [`xLine`](kcl/xLine)
* [`yLine`](kcl/yLine) * [`yLine`](kcl/yLine)
* [`yd`](kcl/yd)
* **std::math** * **std::math**
* [`E`](kcl/consts/std-math-E) * [`E`](kcl/consts/std-math-E)
* [`PI`](kcl/consts/std-math-PI) * [`PI`](kcl/consts/std-math-PI)
* [`TAU`](kcl/consts/std-math-TAU) * [`TAU`](kcl/consts/std-math-TAU)
* [`cos`](kcl/std-math-cos) * [`cos`](kcl/std-math-cos)
* [`polar`](kcl/std-math-polar)
* [`sin`](kcl/std-math-sin) * [`sin`](kcl/std-math-sin)
* [`tan`](kcl/std-math-tan) * [`tan`](kcl/std-math-tan)
* **std::sketch** * **std::sketch**

File diff suppressed because one or more lines are too long

View File

@ -33,7 +33,10 @@ max(args: [number]): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 70, length = max(15, 31, 4, 13, 22)) |> angledLine({
angle = 70,
length = max(15, 31, 4, 13, 22)
}, %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> close() |> close()

View File

@ -33,7 +33,10 @@ min(args: [number]): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 70, length = min(15, 31, 4, 13, 22)) |> angledLine({
angle = 70,
length = min(15, 31, 4, 13, 22)
}, %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> close() |> close()

File diff suppressed because one or more lines are too long

43
docs/kcl/polar.md Normal file

File diff suppressed because one or more lines are too long

View File

@ -37,7 +37,7 @@ pow(
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = pow(5, 2)) |> angledLine({ angle = 50, length = pow(5, 2) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -29,8 +29,11 @@ profileStart(sketch: Sketch): [number]
```js ```js
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
|> startProfileAt([5, 2], %) |> startProfileAt([5, 2], %)
|> angledLine(angle = 120, length = 50, tag = $seg01) |> angledLine({ angle = 120, length = 50 }, %, $seg01)
|> angledLine(angle = segAng(seg01) + 120, length = 50) |> angledLine({
angle = segAng(seg01) + 120,
length = 50
}, %)
|> line(end = profileStart(%)) |> line(end = profileStart(%))
|> close() |> close()
|> extrude(length = 20) |> extrude(length = 20)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -78,7 +78,7 @@ assertEqual(sum, 6, 0.00001, "1 + 2 + 3 summed is 6")
```js ```js
// Declare a function that sketches a decagon. // Declare a function that sketches a decagon.
fn decagon(radius) { fn decagon(radius) {
// Each side of the decagon is turned this many radians from the previous angle. // Each side of the decagon is turned this many degrees from the previous angle.
stepAngle = 1 / 10 * TAU stepAngle = 1 / 10 * TAU
// Start the decagon sketch at this point. // Start the decagon sketch at this point.

View File

@ -151,9 +151,15 @@ cube
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()

View File

@ -85,9 +85,15 @@ cube
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()

View File

@ -32,9 +32,9 @@ exampleSketch = startSketchOn(XZ)
|> line(end = [10, 0]) |> line(end = [10, 0])
|> line(end = [5, 10], tag = $seg01) |> line(end = [5, 10], tag = $seg01)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> angledLine(angle = segAng(seg01), length = 10) |> angledLine([segAng(seg01), 10], %)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> angledLine(angle = segAng(seg01), length = -15) |> angledLine([segAng(seg01), -15], %)
|> close() |> close()
example = extrude(exampleSketch, length = 4) example = extrude(exampleSketch, length = 4)

View File

@ -29,9 +29,9 @@ segLen(tag: TagIdentifier): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 60, length = 10, tag = $thing) |> angledLine({ angle = 60, length = 10 }, %, $thing)
|> tangentialArc({ offset = -120, radius = 5 }, %) |> tangentialArc({ offset = -120, radius = 5 }, %)
|> angledLine(angle = -60, length = segLen(thing)) |> angledLine({ angle = -60, length = segLen(thing) }, %)
|> close() |> close()
example = extrude(exampleSketch, length = 5) example = extrude(exampleSketch, length = 5)

View File

@ -6,7 +6,7 @@ layout: manual
# KCL Settings # KCL Settings
There are three levels of settings available in Zoo Design Studio: There are three levels of settings available in the KittyCAD Design Studiolication:
1. [User Settings](/docs/kcl/settings/user): Global settings that apply to all projects, stored in `user.toml` 1. [User Settings](/docs/kcl/settings/user): Global settings that apply to all projects, stored in `user.toml`
2. [Project Settings](/docs/kcl/settings/project): Settings specific to a project, stored in `project.toml` 2. [Project Settings](/docs/kcl/settings/project): Settings specific to a project, stored in `project.toml`
@ -14,7 +14,7 @@ There are three levels of settings available in Zoo Design Studio:
## Configuration Files ## Configuration Files
Zoo Design Studio uses TOML files for configuration: The KittyCAD Design Studio uses TOML files for configuration:
* **User Settings**: `user.toml` - See [complete documentation](/docs/kcl/settings/user) * **User Settings**: `user.toml` - See [complete documentation](/docs/kcl/settings/user)
* **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl/settings/project) * **Project Settings**: `project.toml` - See [complete documentation](/docs/kcl/settings/project)

View File

@ -96,7 +96,7 @@ Permanently dismiss the banner warning to download the desktop app. This setting
##### stream_idle_mode ##### stream_idle_mode
When the user is idle, teardown the stream after some time. When the user is idle, and this is true, the stream will be torn down.
**Default:** None **Default:** None

View File

@ -33,7 +33,7 @@ sqrt(num: number): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = sqrt(2500)) |> angledLine({ angle = 50, length = sqrt(2500) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -9,15 +9,7 @@ Create a helix.
```js ```js
helix( helix(revolutions: number(_), angleStart: number(deg), ccw?: bool, radius?: number(mm), axis?: Axis3d | Edge, length?: number(mm), cylinder?: Solid): Helix
revolutions: number(_),
angleStart: number(deg),
ccw?: bool,
radius?: number(mm),
axis?: Axis3d | Edge,
length?: number(mm),
cylinder?: Solid,
): Helix
``` ```

View File

@ -29,10 +29,10 @@ cos(@num: number(rad)): number(_)
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine( |> angledLine({
angle = 30, angle = 30,
length = 3 / cos(toRadians(30)), length = 3 / cos(toRadians(30)),
) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -29,10 +29,10 @@ tan(@num: number(rad)): number(_)
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine( |> angledLine({
angle = 50, angle = 50,
length = 50 * tan(1/2), length = 50 * tan(1/2),
) }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -6,16 +6,10 @@ layout: manual
Construct a 2-dimensional circle, of the specified radius, centered at Construct a 2-dimensional circle, of the specified radius, centered atthe provided (x, y) origin point.
the provided (x, y) origin point.
```js ```js
circle( circle(@sketch_or_surface: Sketch | Plane | Face, center: Point2d, radius: number, tag?: tag): Sketch
@sketch_or_surface: Sketch | Plane | Face,
center: Point2d,
radius: number,
tag?: tag,
): Sketch
``` ```

View File

@ -11,10 +11,7 @@ Only works on unclosed sketches for now.
Mirror occurs around a local sketch axis rather than a global axis. Mirror occurs around a local sketch axis rather than a global axis.
```js ```js
mirror2d( mirror2d(@sketches: [Sketch; 1+], axis: Axis2d | Edge): Sketch
@sketches: [Sketch; 1+],
axis: Axis2d | Edge,
): Sketch
``` ```

File diff suppressed because it is too large Load Diff

View File

@ -91,9 +91,15 @@ springSketch = startSketchOn(YZ)
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()

View File

@ -32,7 +32,10 @@ pillSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [20, 0]) |> line(end = [20, 0])
|> tangentialArcToRelative([0, 10], %, $arc1) |> tangentialArcToRelative([0, 10], %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine({
angle = tangentToEnd(arc1),
length = 20
}, %)
|> tangentialArcToRelative([0, -10], %) |> tangentialArcToRelative([0, -10], %)
|> close() |> close()
@ -47,7 +50,10 @@ pillSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [0, 20]) |> line(end = [0, 20])
|> tangentialArcTo([10, 20], %, $arc1) |> tangentialArcTo([10, 20], %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine({
angle = tangentToEnd(arc1),
length = 20
}, %)
|> tangentialArcToRelative([-10, 0], %) |> tangentialArcToRelative([-10, 0], %)
|> close() |> close()
@ -60,7 +66,10 @@ pillExtrude = extrude(pillSketch, length = 10)
rectangleSketch = startSketchOn(XZ) rectangleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> line(end = [10, 0], tag = $seg1) |> line(end = [10, 0], tag = $seg1)
|> angledLine(angle = tangentToEnd(seg1), length = 10) |> angledLine({
angle = tangentToEnd(seg1),
length = 10
}, %)
|> line(end = [0, 10]) |> line(end = [0, 10])
|> line(end = [-20, 0]) |> line(end = [-20, 0])
|> close() |> close()
@ -74,7 +83,7 @@ rectangleExtrude = extrude(rectangleSketch, length = 10)
bottom = startSketchOn(XY) bottom = startSketchOn(XY)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> arcTo({ end = [10, 10], interior = [5, 1] }, %, $arc1) |> arcTo({ end = [10, 10], interior = [5, 1] }, %, $arc1)
|> angledLine(angle = tangentToEnd(arc1), length = 20) |> angledLine([tangentToEnd(arc1), 20], %)
|> close() |> close()
``` ```
@ -86,7 +95,7 @@ circSketch = startSketchOn(XY)
triangleSketch = startSketchOn(XY) triangleSketch = startSketchOn(XY)
|> startProfileAt([-5, 0], %) |> startProfileAt([-5, 0], %)
|> angledLine(angle = tangentToEnd(circ), length = 10) |> angledLine([tangentToEnd(circ), 10], %)
|> line(end = [-15, 0]) |> line(end = [-15, 0])
|> close() |> close()
``` ```

View File

@ -35,9 +35,9 @@ tangentialArc(
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 60, length = 10) |> angledLine({ angle = 60, length = 10 }, %)
|> tangentialArc({ radius = 10, offset = -120 }, %) |> tangentialArc({ radius = 10, offset = -120 }, %)
|> angledLine(angle = -60, length = 10) |> angledLine({ angle = -60, length = 10 }, %)
|> close() |> close()
example = extrude(exampleSketch, length = 10) example = extrude(exampleSketch, length = 10)

View File

@ -35,7 +35,7 @@ tangentialArcTo(
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 60, length = 10) |> angledLine({ angle = 60, length = 10 }, %)
|> tangentialArcTo([15, 15], %) |> tangentialArcTo([15, 15], %)
|> line(end = [10, -15]) |> line(end = [10, -15])
|> close() |> close()

View File

@ -35,7 +35,7 @@ tangentialArcToRelative(
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 45, length = 10) |> angledLine({ angle = 45, length = 10 }, %)
|> tangentialArcToRelative([0, -10], %) |> tangentialArcToRelative([0, -10], %)
|> line(end = [-10, 0]) |> line(end = [-10, 0])
|> close() |> close()

View File

@ -30,7 +30,7 @@ tau(): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 10 * tau()) |> angledLine({ angle = 50, length = 10 * tau() }, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -33,7 +33,10 @@ toDegrees(num: number): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 70 * cos(toDegrees(pi() / 4))) |> angledLine({
angle = 50,
length = 70 * cos(toDegrees(pi() / 4))
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -33,7 +33,10 @@ toRadians(num: number): number
```js ```js
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 50, length = 70 * cos(toRadians(45))) |> angledLine({
angle = 50,
length = 70 * cos(toRadians(45))
}, %)
|> yLine(endAbsolute = 0) |> yLine(endAbsolute = 0)
|> close() |> close()

View File

@ -86,9 +86,15 @@ cube
sketch001 = startSketchOn(XY) sketch001 = startSketchOn(XY)
rectangleSketch = startProfileAt([-200, 23.86], sketch001) rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001) |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 50.61) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
50.61
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()

View File

@ -184,17 +184,15 @@ way:
```norun ```norun
startSketchOn('XZ') startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99,
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001), length = -segLen(rectangleSegmentA001),
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
``` ```
@ -219,17 +217,15 @@ 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(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001) length = -segLen(rectangleSegmentA001)
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }
@ -249,17 +245,15 @@ For example the following code works.
fn rect(origin) { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001) length = -segLen(rectangleSegmentA001)
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }

View File

@ -0,0 +1,22 @@
---
title: "PolarCoordsData"
excerpt: "Data for polar coordinates."
layout: manual
---
Data for polar coordinates.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `angle` |[`number`](/docs/kcl/types/number)| The angle of the line (in degrees). | No |
| `length` |[`number`](/docs/kcl/types/number)| The length of the line. | No |

View File

@ -14,17 +14,15 @@ way:
```js ```js
startSketchOn('XZ') startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99,
tag = $rectangleSegmentB001, }, %, $rectangleSegmentB001)
) |> angledLine({
|> angledLine(
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001), length = -segLen(rectangleSegmentA001),
tag = $rectangleSegmentC001, }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
``` ```
@ -48,16 +46,15 @@ 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(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99, length = 196.99
tag = $rectangleSegmentB001) }, %, $rectangleSegmentB001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)
tag = $rectangleSegmentC001 }, %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }
@ -77,15 +74,15 @@ For example the following code works.
fn rect(origin) { fn rect(origin) {
return startSketchOn('XZ') return startSketchOn('XZ')
|> startProfileAt(origin, %) |> startProfileAt(origin, %)
|> angledLine(angle = 0, length = 191.26, tag = $rectangleSegmentA001) |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001) - 90, angle = segAng(rectangleSegmentA001) - 90,
length = 196.99 length = 196.99
, %, $rectangleSegmentB001) }, %, $rectangleSegmentB001)
|> angledLine( |> angledLine({
angle = segAng(rectangleSegmentA001), angle = segAng(rectangleSegmentA001),
length = -segLen(rectangleSegmentA001) length = -segLen(rectangleSegmentA001)
, %, $rectangleSegmentC001) }, %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
} }

View File

@ -38,10 +38,10 @@ xLine(
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> xLine(length = 15) |> xLine(length = 15)
|> angledLine(angle = 80, length = 15) |> angledLine({ angle = 80, length = 15 }, %)
|> line(end = [8, -10]) |> line(end = [8, -10])
|> xLine(length = 10) |> xLine(length = 10)
|> angledLine(angle = 120, length = 30) |> angledLine({ angle = 120, length = 30 }, %)
|> xLine(length = -15) |> xLine(length = -15)
|> close() |> close()

View File

@ -38,7 +38,7 @@ yLine(
exampleSketch = startSketchOn(XZ) exampleSketch = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> yLine(length = 15) |> yLine(length = 15)
|> angledLine(angle = 30, length = 15) |> angledLine({ angle = 30, length = 15 }, %)
|> line(end = [8, -10]) |> line(end = [8, -10])
|> yLine(length = -5) |> yLine(length = -5)
|> close() |> close()

File diff suppressed because one or more lines are too long

View File

@ -137,7 +137,7 @@ async function doBasicSketch(
await page.waitForTimeout(100) await page.waitForTimeout(100)
} }
await page.getByRole('button', { name: 'constraints: open menu' }).click() await page.getByRole('button', { name: 'Length: open menu' }).click()
await page.getByRole('button', { name: 'Equal Length' }).click() await page.getByRole('button', { name: 'Equal Length' }).click()
// Open the code pane. // Open the code pane.

View File

@ -38,7 +38,7 @@ test.describe('Point and click for boolean workflows', () => {
path.resolve( path.resolve(
__dirname, __dirname,
'../../', '../../',
'./rust/kcl-lib/e2e/executor/inputs/boolean-setup-with-sketch-on-faces.kcl' './rust/kcl-lib/e2e/executor/inputs/boolean-setup-with'
), ),
'utf-8' 'utf-8'
) )
@ -46,6 +46,8 @@ test.describe('Point and click for boolean workflows', () => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.waitForExecutionDone()
await scene.settled(cmdBar) await scene.settled(cmdBar)
// Test coordinates for selection - these might need adjustment based on actual scene layout // Test coordinates for selection - these might need adjustment based on actual scene layout
@ -75,7 +77,6 @@ test.describe('Point and click for boolean workflows', () => {
// Select first object in the scene, expect there to be a pixel diff from the selection color change // Select first object in the scene, expect there to be a pixel diff from the selection color change
await clickFirstObject({ pixelDiff: 50 }) await clickFirstObject({ pixelDiff: 50 })
await page.waitForTimeout(1000)
// For subtract, we need to proceed to the next step before selecting the second object // For subtract, we need to proceed to the next step before selecting the second object
if (operationName !== 'subtract') { if (operationName !== 'subtract') {
@ -86,8 +87,6 @@ test.describe('Point and click for boolean workflows', () => {
// Select second object // Select second object
await clickSecondObject({ pixelDiff: 50 }) await clickSecondObject({ pixelDiff: 50 })
await page.waitForTimeout(1000)
// Confirm the operation in the command bar // Confirm the operation in the command bar
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()

View File

@ -4,7 +4,6 @@ import { uuidv4 } from '@src/lib/utils'
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture' import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture' import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import { getUtils } from '@e2e/playwright/test-utils' import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
@ -16,7 +15,6 @@ test.describe(
page: Page, page: Page,
homePage: HomePageFixture, homePage: HomePageFixture,
scene: SceneFixture, scene: SceneFixture,
toolbar: ToolbarFixture,
plane: string, plane: string,
clickCoords: { x: number; y: number } clickCoords: { x: number; y: number }
) => { ) => {
@ -61,12 +59,9 @@ test.describe(
await u.sendCustomCmd(updateCamCommand) await u.sendCustomCmd(updateCamCommand)
await u.closeDebugPanel() await u.closeDebugPanel()
await page.mouse.click(clickCoords.x, clickCoords.y) await page.mouse.click(clickCoords.x, clickCoords.y)
await page.waitForTimeout(600) // wait for animation await page.waitForTimeout(600) // wait for animation
await toolbar.waitUntilSketchingReady()
await expect( await expect(
page.getByRole('button', { name: 'line Line', exact: true }) page.getByRole('button', { name: 'line Line', exact: true })
).toBeVisible() ).toBeVisible()
@ -122,12 +117,11 @@ test.describe(
] ]
for (const config of planeConfigs) { for (const config of planeConfigs) {
test(config.plane, async ({ page, homePage, scene, toolbar }) => { test(config.plane, async ({ page, homePage, scene }) => {
await sketchOnPlaneAndBackSideTest( await sketchOnPlaneAndBackSideTest(
page, page,
homePage, homePage,
scene, scene,
toolbar,
config.plane, config.plane,
config.coords config.coords
) )

View File

@ -15,7 +15,6 @@ test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
page, page,
homePage, homePage,
scene, scene,
cmdBar,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
@ -37,7 +36,7 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// Ensure no badge is present // Ensure no badge is present
const codePaneButtonHolder = page.locator('#code-button-holder') const codePaneButtonHolder = page.locator('#code-button-holder')
@ -172,8 +171,6 @@ extrude001 = extrude(sketch001, length = 5)`
context, context,
page, page,
homePage, homePage,
scene,
cmdBar,
}) => { }) => {
// Load the app with the working starter code // Load the app with the working starter code
await context.addInitScript((code) => { await context.addInitScript((code) => {
@ -183,7 +180,9 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) // FIXME: await scene.waitForExecutionDone() does not work. It still fails.
// I needed to increase this timeout to get this to pass.
await page.waitForTimeout(10000)
// Ensure badge is present // Ensure badge is present
const codePaneButtonHolder = page.locator('#code-button-holder') const codePaneButtonHolder = page.locator('#code-button-holder')

View File

@ -317,13 +317,9 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
test('Can switch between sketch tools via command bar', async ({ test('Can switch between sketch tools via command bar', async ({
page, page,
homePage, homePage,
scene,
cmdBar,
toolbar,
}) => { }) => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar)
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' })
@ -347,9 +343,7 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
// Start a sketch // Start a sketch
await sketchButton.click() await sketchButton.click()
await page.mouse.click(700, 200) await page.mouse.click(700, 200)
await toolbar.waitUntilSketchingReady()
// Switch between sketch tools via the command bar // Switch between sketch tools via the command bar
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true') await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')

View File

@ -11,7 +11,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
test( test(
'export works on the first try', 'export works on the first try',
{ tag: ['@electron', '@skipLocalEngine'] }, { tag: ['@electron', '@skipLocalEngine'] },
async ({ page, context, scene, tronApp, cmdBar }, testInfo) => { async ({ page, context, scene, tronApp }, testInfo) => {
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -37,7 +37,8 @@ test(
const projectName = page.getByText(`bracket`) const projectName = page.getByText(`bracket`)
await expect(projectName).toBeVisible() await expect(projectName).toBeVisible()
await projectName.click() await projectName.click()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await page.waitForTimeout(1_000) // wait for panel buttons to be available
// Expect zero errors in gutter // Expect zero errors in gutter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
@ -46,9 +47,10 @@ test(
const exportButton = page.getByTestId('export-pane-button') const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible() await expect(exportButton).toBeVisible()
await exportButton.click() await exportButton.click()
await page.waitForTimeout(1_000) // wait for export options to be available
// Select the first format option // Select the first format option
const gltfOption = cmdBar.selectOption({ name: 'glTF' }) const gltfOption = page.getByText('glTF')
const exportFileName = `main.gltf` // source file is named `main.kcl` const exportFileName = `main.gltf` // source file is named `main.kcl`
await expect(gltfOption).toBeVisible() await expect(gltfOption).toBeVisible()
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
@ -56,6 +58,7 @@ test(
// Click the checkbox // Click the checkbox
const submitButton = page.getByText('Confirm Export') const submitButton = page.getByText('Confirm Export')
await expect(submitButton).toBeVisible() await expect(submitButton).toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
// Look out for the toast message // Look out for the toast message
@ -107,7 +110,8 @@ test(
// Close the file pane // Close the file pane
await u.closeFilePanel() await u.closeFilePanel()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await page.waitForTimeout(1_000) // wait for panel buttons to be available
// Expect zero errors in gutter // Expect zero errors in gutter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible() await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
@ -116,9 +120,10 @@ test(
const exportButton = page.getByTestId('export-pane-button') const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible() await expect(exportButton).toBeVisible()
await exportButton.click() await exportButton.click()
await page.waitForTimeout(1_000) // wait for export options to be available
// Select the first format option // Select the first format option
const gltfOption = cmdBar.selectOption({ name: 'glTF' }) const gltfOption = page.getByText('glTF')
const exportFileName = `other.gltf` // source file is named `other.kcl` const exportFileName = `other.gltf` // source file is named `other.kcl`
await expect(gltfOption).toBeVisible() await expect(gltfOption).toBeVisible()
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
@ -126,6 +131,7 @@ test(
// Click the checkbox // Click the checkbox
const submitButton = page.getByText('Confirm Export') const submitButton = page.getByText('Confirm Export')
await expect(submitButton).toBeVisible() await expect(submitButton).toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter') await page.keyboard.press('Enter')
// Look out for the toast message // Look out for the toast message

View File

@ -78,14 +78,12 @@ sketch001 = startSketchOn(XY)
// Ensure we execute the first time. // Ensure we execute the first time.
await u.openDebugPanel() await u.openDebugPanel()
await expect await expect(
.poll(() => page.locator('[data-receive-command-type="scene_clear_all"]')
page.locator('[data-receive-command-type="scene_clear_all"]').count() ).toHaveCount(1)
) await expect(
.toBe(1) page.locator('[data-message-type="execution-done"]')
await expect ).toHaveCount(2)
.poll(() => page.locator('[data-message-type="execution-done"]').count())
.toBe(2)
// Add whitespace to the end of the code. // Add whitespace to the end of the code.
await u.codeLocator.click() await u.codeLocator.click()
@ -112,14 +110,12 @@ sketch001 = startSketchOn(XY)
test('ensure we use the cache, and do not clear on append', async ({ test('ensure we use the cache, and do not clear on append', async ({
homePage, homePage,
page, page,
scene,
cmdBar,
}) => { }) => {
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await u.waitForPageLoad()
await u.codeLocator.click() await u.codeLocator.click()
await page.keyboard.type(`sketch001 = startSketchOn(XY) await page.keyboard.type(`sketch001 = startSketchOn(XY)
@ -503,7 +499,7 @@ sketch_001 = startSketchOn(XY)
await page.keyboard.press('ArrowLeft') await page.keyboard.press('ArrowLeft')
await page.keyboard.press('ArrowRight') await page.keyboard.press('ArrowRight')
await scene.connectionEstablished() await scene.waitForExecutionDone()
// 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()
@ -1353,51 +1349,4 @@ sketch001 = startSketchOn(XZ)
15 15
) )
}) })
test(`test-toolbar-buttons`, async ({
page,
homePage,
toolbar,
scene,
cmdBar,
}) => {
await test.step('Load an empty file', async () => {
await page.addInitScript(async () => {
localStorage.setItem('persistCode', '')
})
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// wait until scene is ready to be interacted with
await scene.connectionEstablished()
await scene.settled(cmdBar)
})
await test.step('Test toolbar button correct selection', async () => {
await toolbar.expectToolbarMode.toBe('modeling')
await toolbar.startSketchPlaneSelection()
// Click on a default plane
await page.mouse.click(700, 200)
// tools cannot be selected immediately, couldn't find an event to await instead.
await page.waitForTimeout(1000)
await toolbar.selectCenterRectangle()
await expect(page.getByTestId('center-rectangle')).toHaveAttribute(
'aria-pressed',
'true'
)
})
await test.step('Test Toolbar dropdown remembering last selection', async () => {
// Select another tool
await page.getByTestId('circle-center').click()
// center-rectangle should still be the active option in the rectangle dropdown
await expect(page.getByTestId('center-rectangle')).toBeVisible()
})
})
}) })

View File

@ -19,7 +19,7 @@ length001 = timesFive(1) * 5
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([20, 10], %) |> startProfileAt([20, 10], %)
|> line(end = [10, 10]) |> line(end = [10, 10])
|> angledLine(angle = -45, length = length001) |> angledLine([-45, length001], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
revolve001 = revolve(sketch001, axis = X) revolve001 = revolve(sketch001, axis = X)
@ -38,9 +38,15 @@ extrude001 = extrude(sketch002, length = 10)
const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn(XZ) const FEATURE_TREE_SKETCH_CODE = `sketch001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
|> angledLine(angle = 0, length = 4, tag = $rectangleSegmentA001) |> angledLine([0, 4], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 2, tag = $rectangleSegmentB001) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) segAng(rectangleSegmentA001) - 90,
2
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close(%) |> close(%)
extrude001 = extrude(sketch001, length = 10) extrude001 = extrude(sketch001, length = 10)
@ -58,7 +64,7 @@ test.describe('Feature Tree pane', () => {
test( test(
'User can go to definition and go to function definition', 'User can go to definition and go to function definition',
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, homePage, scene, editor, toolbar, cmdBar, page }) => { async ({ context, homePage, scene, editor, toolbar }) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = join(dir, 'test-sample') const bracketDir = join(dir, 'test-sample')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })
@ -80,13 +86,9 @@ test.describe('Feature Tree pane', () => {
sortBy: 'last-modified-desc', sortBy: 'last-modified-desc',
}) })
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.connectionEstablished() await scene.waitForExecutionDone()
await scene.settled(cmdBar) await editor.closePane()
await toolbar.openFeatureTreePane() await toolbar.openFeatureTreePane()
await expect
.poll(() => page.getByText('Feature tree').count())
.toBeGreaterThan(1)
}) })
async function testViewSource({ async function testViewSource({
@ -252,7 +254,7 @@ test.describe('Feature Tree pane', () => {
sortBy: 'last-modified-desc', sortBy: 'last-modified-desc',
}) })
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await toolbar.openFeatureTreePane() await toolbar.openFeatureTreePane()
}) })
@ -337,7 +339,7 @@ test.describe('Feature Tree pane', () => {
sortBy: 'last-modified-desc', sortBy: 'last-modified-desc',
}) })
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await toolbar.openFeatureTreePane() await toolbar.openFeatureTreePane()
}) })
@ -412,7 +414,8 @@ profile003 = startProfileAt([0, -4.93], sketch001)
const planeColor: [number, number, number] = [74, 74, 74] const planeColor: [number, number, number] = [74, 74, 74]
await homePage.openProject('test-sample') await homePage.openProject('test-sample')
await scene.settled(cmdBar) // FIXME: @lf94 has a better way to verify execution completion, in a PR rn
await scene.waitForExecutionDone()
await test.step(`Verify we see the sketch`, async () => { await test.step(`Verify we see the sketch`, async () => {
await scene.expectPixelColor(sketchColor, testPoint, 10) await scene.expectPixelColor(sketchColor, testPoint, 10)

View File

@ -47,7 +47,6 @@ test.describe('integrations tests', () => {
await scene.connectionEstablished() await scene.connectionEstablished()
await scene.settled(cmdBar) await scene.settled(cmdBar)
await clickObj() await clickObj()
await page.waitForTimeout(1000)
await scene.moveNoWhere() await scene.moveNoWhere()
await editor.expectState({ await editor.expectState({
activeLines: [ activeLines: [
@ -73,11 +72,11 @@ test.describe('integrations tests', () => {
}) })
await test.step('setup for next assertion', async () => { await test.step('setup for next assertion', async () => {
await toolbar.openFile('main.kcl') await toolbar.openFile('main.kcl')
await page.waitForTimeout(1000)
await scene.settled(cmdBar)
await clickObj() await clickObj()
await page.waitForTimeout(1000)
await scene.moveNoWhere() await scene.moveNoWhere()
await page.waitForTimeout(1000)
await editor.expectState({ await editor.expectState({
activeLines: [ activeLines: [
'|>startProfileAt([75.8,317.2],%)//[$startCapTag,$EndCapTag]', '|>startProfileAt([75.8,317.2],%)//[$startCapTag,$EndCapTag]',
@ -90,7 +89,7 @@ test.describe('integrations tests', () => {
await toolbar.expectFileTreeState(['main.kcl', fileName]) await toolbar.expectFileTreeState(['main.kcl', fileName])
}) })
await test.step('check sketch mode is exited when opening a different file', async () => { await test.step('check sketch mode is exited when opening a different file', async () => {
await toolbar.openFile(fileName) await toolbar.openFile(fileName, { wait: false })
// check we're out of sketch mode // check we're out of sketch mode
await expect(toolbar.exitSketchBtn).not.toBeVisible() await expect(toolbar.exitSketchBtn).not.toBeVisible()

View File

@ -112,7 +112,10 @@ export class CmdBarFixture {
* and assumes we are past the `pickCommand` step. * and assumes we are past the `pickCommand` step.
*/ */
progressCmdBar = async (shouldFuzzProgressMethod = true) => { progressCmdBar = async (shouldFuzzProgressMethod = true) => {
await this.page.waitForTimeout(2000) // FIXME: Progressing the command bar is a race condition. We have an async useEffect that reports the final state via useCalculateKclExpression. If this does not run quickly enough, it will not "fail" the continue because you can press continue if the state is not ready. E2E tests do not know this.
// Wait 1250ms to assume the await executeAst of the KCL input field is finished
await this.page.waitForTimeout(1250)
if (shouldFuzzProgressMethod || Math.random() > 0.5) {
const arrowButton = this.page.getByRole('button', { const arrowButton = this.page.getByRole('button', {
name: 'arrow right Continue', name: 'arrow right Continue',
}) })
@ -123,6 +126,9 @@ export class CmdBarFixture {
.getByRole('button', { name: 'checkmark Submit command' }) .getByRole('button', { name: 'checkmark Submit command' })
.click() .click()
} }
} else {
await this.page.keyboard.press('Enter')
}
} }
// Added data-testid to the command bar buttons // Added data-testid to the command bar buttons

View File

@ -39,8 +39,7 @@ export class AuthenticatedApp {
} }
async initialise(code = '') { async initialise(code = '') {
const testDir = this.testInfo.outputPath('electron-test-projects-dir') await setup(this.context, this.page, this.testInfo)
await setup(this.context, this.page, testDir, this.testInfo)
const u = await getUtils(this.page) const u = await getUtils(this.page)
await this.page.addInitScript(async (code) => { await this.page.addInitScript(async (code) => {
@ -103,11 +102,11 @@ export class ElectronZoo {
return resolve(undefined) return resolve(undefined)
} }
if (Date.now() - timeA > 3000) { if (Date.now() - timeA > 10000) {
return resolve(undefined) return resolve(undefined)
} }
setTimeout(checkDisconnected, 1) setTimeout(checkDisconnected, 0)
} }
checkDisconnected() checkDisconnected()
}) })
@ -129,9 +128,11 @@ export class ElectronZoo {
const that = this const that = this
const options = { const options = {
timeout: 120000,
args: ['.', '--no-sandbox'], args: ['.', '--no-sandbox'],
env: { env: {
...process.env, ...process.env,
TEST_SETTINGS_FILE_KEY: this.projectDirName,
IS_PLAYWRIGHT: 'true', IS_PLAYWRIGHT: 'true',
}, },
...(process.env.ELECTRON_OVERRIDE_DIST_PATH ...(process.env.ELECTRON_OVERRIDE_DIST_PATH
@ -199,14 +200,7 @@ export class ElectronZoo {
await this.context.tracing.startChunk() await this.context.tracing.startChunk()
// THIS IS ABSOLUTELY NECESSARY TO CHANGE THE PROJECT DIRECTORY BETWEEN await setup(this.context, this.page, testInfo)
// TESTS BECAUSE OF THE ELECTRON INSTANCE REUSE.
await this.electron?.evaluate(({ app }, projectDirName) => {
// @ts-ignore can't declaration merge see main.ts
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
}, this.projectDirName)
await setup(this.context, this.page, this.projectDirName, testInfo)
await this.cleanProjectDir() await this.cleanProjectDir()
@ -256,6 +250,11 @@ export class ElectronZoo {
// return app.reuseWindowForTest(); // return app.reuseWindowForTest();
// }); // });
await this.electron?.evaluate(({ app }, projectDirName) => {
// @ts-ignore can't declaration merge see main.ts
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
}, this.projectDirName)
// Always start at the root view // Always start at the root view
await this.page.goto(this.firstUrl) await this.page.goto(this.firstUrl)
@ -279,9 +278,8 @@ export class ElectronZoo {
// Not a problem if it already exists. // Not a problem if it already exists.
} }
const tempSettingsFilePath = path.resolve( const tempSettingsFilePath = path.join(
this.projectDirName, this.projectDirName,
'..',
SETTINGS_FILE_NAME SETTINGS_FILE_NAME
) )

View File

@ -43,15 +43,21 @@ type DragFromHandler = (
export class SceneFixture { export class SceneFixture {
public page: Page public page: Page
public streamWrapper!: Locator public streamWrapper!: Locator
public loadingIndicator!: Locator
public networkToggleConnected!: Locator public networkToggleConnected!: Locator
public startEditSketchBtn!: Locator public startEditSketchBtn!: Locator
get exeIndicator() {
return this.page
.getByTestId('model-state-indicator-execution-done')
.or(this.page.getByTestId('model-state-indicator-receive-reliable'))
}
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
this.streamWrapper = page.getByTestId('stream') this.streamWrapper = page.getByTestId('stream')
this.networkToggleConnected = page this.networkToggleConnected = page.getByTestId('network-toggle-ok')
.getByTestId('network-toggle-ok') this.loadingIndicator = this.streamWrapper.getByTestId('loading')
.or(page.getByTestId('network-toggle-other'))
this.startEditSketchBtn = page this.startEditSketchBtn = page
.getByRole('button', { name: 'Start Sketch' }) .getByRole('button', { name: 'Start Sketch' })
.or(page.getByRole('button', { name: 'Edit Sketch' })) .or(page.getByRole('button', { name: 'Edit Sketch' }))
@ -225,6 +231,10 @@ export class SceneFixture {
} }
} }
waitForExecutionDone = async () => {
await expect(this.exeIndicator).toBeVisible({ timeout: 30000 })
}
connectionEstablished = async () => { connectionEstablished = async () => {
const timeout = 30000 const timeout = 30000
await expect(this.networkToggleConnected).toBeVisible({ timeout }) await expect(this.networkToggleConnected).toBeVisible({ timeout })
@ -233,9 +243,6 @@ export class SceneFixture {
settled = async (cmdBar: CmdBarFixture) => { settled = async (cmdBar: CmdBarFixture) => {
const u = await getUtils(this.page) const u = await getUtils(this.page)
await expect(this.startEditSketchBtn).not.toBeDisabled()
await expect(this.startEditSketchBtn).toBeVisible()
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
await cmdBar.chooseCommand('Settings · app · show debug panel') await cmdBar.chooseCommand('Settings · app · show debug panel')
await cmdBar.selectOption({ name: 'on' }).click() await cmdBar.selectOption({ name: 'on' }).click()
@ -243,6 +250,10 @@ export class SceneFixture {
await u.openDebugPanel() await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]') await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel() await u.closeDebugPanel()
await this.waitForExecutionDone()
await expect(this.startEditSketchBtn).not.toBeDisabled()
await expect(this.startEditSketchBtn).toBeVisible()
} }
expectPixelColor = async ( expectPixelColor = async (

View File

@ -44,7 +44,6 @@ export class ToolbarFixture {
featureTreePane!: Locator featureTreePane!: Locator
gizmo!: Locator gizmo!: Locator
gizmoDisabled!: Locator gizmoDisabled!: Locator
insertButton!: Locator
constructor(page: Page) { constructor(page: Page) {
this.page = page this.page = page
@ -79,14 +78,18 @@ export class ToolbarFixture {
// element or two different elements can represent these states. // element or two different elements can represent these states.
this.gizmo = page.getByTestId('gizmo') this.gizmo = page.getByTestId('gizmo')
this.gizmoDisabled = page.getByTestId('gizmo-disabled') this.gizmoDisabled = page.getByTestId('gizmo-disabled')
this.insertButton = page.getByTestId('insert-pane-button')
} }
get logoLink() { get logoLink() {
return this.page.getByTestId('app-logo') return this.page.getByTestId('app-logo')
} }
get exeIndicator() {
return this.page
.getByTestId('model-state-indicator-receive-reliable')
.or(this.page.getByTestId('model-state-indicator-execution-done'))
}
startSketchPlaneSelection = async () => startSketchPlaneSelection = async () =>
doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500) doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500)
@ -162,14 +165,20 @@ export class ToolbarFixture {
} }
} }
/** /**
* Opens file by it's name * Opens file by it's name and waits for execution to finish
*/ */
openFile = async (fileName: string) => { openFile = async (
fileName: string,
{ wait }: { wait?: boolean } = { wait: true }
) => {
await this.filePane.getByText(fileName).click() await this.filePane.getByText(fileName).click()
if (wait) {
await expect(this.exeIndicator).toBeVisible({ timeout: 15_000 })
}
} }
selectCenterRectangle = async () => { selectCenterRectangle = async () => {
await this.page await this.page
.getByRole('button', { name: 'caret down rectangles:' }) .getByRole('button', { name: 'caret down Corner rectangle:' })
.click() .click()
await expect( await expect(
this.page.getByTestId('dropdown-center-rectangle') this.page.getByTestId('dropdown-center-rectangle')
@ -178,7 +187,7 @@ export class ToolbarFixture {
} }
selectBoolean = async (operation: 'union' | 'subtract' | 'intersect') => { selectBoolean = async (operation: 'union' | 'subtract' | 'intersect') => {
await this.page await this.page
.getByRole('button', { name: 'caret down booleans: open menu' }) .getByRole('button', { name: 'caret down Union: open menu' })
.click() .click()
const operationTestId = `dropdown-boolean-${operation}` const operationTestId = `dropdown-boolean-${operation}`
await expect(this.page.getByTestId(operationTestId)).toBeVisible() await expect(this.page.getByTestId(operationTestId)).toBeVisible()
@ -186,19 +195,25 @@ export class ToolbarFixture {
} }
selectCircleThreePoint = async () => { selectCircleThreePoint = async () => {
await this.page.getByRole('button', { name: 'caret down circles:' }).click() await this.page
.getByRole('button', { name: 'caret down Center circle:' })
.click()
await expect( await expect(
this.page.getByTestId('dropdown-circle-three-points') this.page.getByTestId('dropdown-circle-three-points')
).toBeVisible() ).toBeVisible()
await this.page.getByTestId('dropdown-circle-three-points').click() await this.page.getByTestId('dropdown-circle-three-points').click()
} }
selectArc = async () => { selectArc = async () => {
await this.page.getByRole('button', { name: 'caret down arcs:' }).click() await this.page
.getByRole('button', { name: 'caret down Tangential Arc:' })
.click()
await expect(this.page.getByTestId('dropdown-arc')).toBeVisible() await expect(this.page.getByTestId('dropdown-arc')).toBeVisible()
await this.page.getByTestId('dropdown-arc').click() await this.page.getByTestId('dropdown-arc').click()
} }
selectThreePointArc = async () => { selectThreePointArc = async () => {
await this.page.getByRole('button', { name: 'caret down arcs:' }).click() await this.page
.getByRole('button', { name: 'caret down Tangential Arc:' })
.click()
await expect( await expect(
this.page.getByTestId('dropdown-three-point-arc') this.page.getByTestId('dropdown-three-point-arc')
).toBeVisible() ).toBeVisible()

View File

@ -10,7 +10,6 @@ test.describe('Import UI tests', () => {
toolbar, toolbar,
scene, scene,
editor, editor,
cmdBar,
}) => { }) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const projectDir = path.join(dir, 'import-test') const projectDir = path.join(dir, 'import-test')
@ -21,9 +20,15 @@ test.describe('Import UI tests', () => {
path.join(projectDir, 'toBeImported.kcl'), path.join(projectDir, 'toBeImported.kcl'),
`sketch001 = startSketchOn(XZ) `sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([281.54, 305.81], sketch001) profile001 = startProfileAt([281.54, 305.81], sketch001)
|> angledLine(angle = 0, length = 123.43, tag = $rectangleSegmentA001) |> angledLine([0, 123.43], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 85.99) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) - 90,
85.99
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude(profile001, length = 100)` extrude(profile001, length = 100)`
@ -38,9 +43,15 @@ importedCube
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([-134.53, -56.17], sketch001) profile001 = startProfileAt([-134.53, -56.17], sketch001)
|> angledLine(angle = 0, length = 79.05, tag = $rectangleSegmentA001) |> angledLine([0, 79.05], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 76.28) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $seg01) segAng(rectangleSegmentA001) - 90,
76.28
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $seg01)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02) |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close() |> close()
extrude001 = extrude(profile001, length = 100) extrude001 = extrude(profile001, length = 100)
@ -50,7 +61,7 @@ sketch002 = startSketchOn(extrude001, seg01)`
}) })
await homePage.openProject('import-test') await homePage.openProject('import-test')
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await scene.moveCameraTo( await scene.moveCameraTo(
{ {

View File

@ -7,7 +7,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
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 ({ context, page, scene, cmdBar }, testInfo) => { async ({ context, page }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = join(dir, 'bracket') const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })
@ -23,7 +23,10 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
const notFoundText = 'Machine API server was not discovered' const notFoundText = 'Machine API server was not discovered'
await expect(page.getByText(notFoundText).first()).not.toBeVisible() await expect(page.getByText(notFoundText).first()).not.toBeVisible()
@ -44,7 +47,7 @@ test(
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 ({ context, page, scene, cmdBar }, testInfo) => { async ({ context, page }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = join(dir, 'bracket') const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })
@ -68,7 +71,10 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(page.getByText(notFoundText).nth(1)).not.toBeVisible() await expect(page.getByText(notFoundText).nth(1)).not.toBeVisible()

View File

@ -61,7 +61,6 @@ function tomlStringOverWriteNamedViewUuids(toml: string): string {
} }
test.describe('Named view tests', () => { test.describe('Named view tests', () => {
test.skip() // TODO: Jace is working on these
test('Verify project.toml is not created', async ({ page }, testInfo) => { test('Verify project.toml is not created', async ({ page }, testInfo) => {
// Create project and load it // Create project and load it
const projectName = 'named-views' const projectName = 'named-views'
@ -89,7 +88,7 @@ test.describe('Named view tests', () => {
// Create and load project // Create and load project
await createProject({ name: projectName, page }) await createProject({ name: projectName, page })
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// Create named view // Create named view
const projectDirName = testInfo.outputPath('electron-test-projects-dir') const projectDirName = testInfo.outputPath('electron-test-projects-dir')
@ -111,17 +110,14 @@ test.describe('Named view tests', () => {
expect(exists).toBe(true) expect(exists).toBe(true)
}).toPass() }).toPass()
await expect(async () => {
// Read project.toml into memory // Read project.toml into memory
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8') let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break // Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
tomlString = tomlStringOverWriteNamedViewUuids(tomlString) tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created') expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
}).toPass()
}) })
test('Verify named view gets deleted', async ({ test('Verify named view gets deleted', async ({
cmdBar, cmdBar,
@ -134,7 +130,7 @@ test.describe('Named view tests', () => {
// Create project and go into the project // Create project and go into the project
await createProject({ name: projectName, page }) await createProject({ name: projectName, page })
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// Create a new named view // Create a new named view
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
@ -156,7 +152,6 @@ test.describe('Named view tests', () => {
expect(exists).toBe(true) expect(exists).toBe(true)
}).toPass() }).toPass()
await expect(async () => {
// Read project.toml into memory // Read project.toml into memory
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8') let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break // Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
@ -165,7 +160,6 @@ test.describe('Named view tests', () => {
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created') expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
}).toPass()
// Delete a named view // Delete a named view
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
@ -173,16 +167,14 @@ test.describe('Named view tests', () => {
cmdBar.selectOption({ name: myNamedView2 }) cmdBar.selectOption({ name: myNamedView2 })
await cmdBar.progressCmdBar(false) await cmdBar.progressCmdBar(false)
await expect(async () => {
// Read project.toml into memory again since we deleted a named view // Read project.toml into memory again since we deleted a named view
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8') tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break // Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
tomlString = tomlStringOverWriteNamedViewUuids(tomlString) tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
// // Write the entire tomlString to a snapshot. // // Write the entire tomlString to a snapshot.
// // There are many key/value pairs to check this is a safer match. // // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted') expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted')
}).toPass()
}) })
test('Verify named view gets loaded', async ({ test('Verify named view gets loaded', async ({
cmdBar, cmdBar,
@ -194,7 +186,7 @@ test.describe('Named view tests', () => {
// Create project and go into the project // Create project and go into the project
await createProject({ name: projectName, page }) await createProject({ name: projectName, page })
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// Create a new named view // Create a new named view
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
@ -216,7 +208,6 @@ test.describe('Named view tests', () => {
expect(exists).toBe(true) expect(exists).toBe(true)
}).toPass() }).toPass()
await expect(async () => {
// Read project.toml into memory // Read project.toml into memory
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8') let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break // Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
@ -225,7 +216,6 @@ test.describe('Named view tests', () => {
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created') expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
}).toPass()
// Create a load a named view // Create a load a named view
await cmdBar.openCmdBar() await cmdBar.openCmdBar()
@ -249,7 +239,7 @@ test.describe('Named view tests', () => {
// Create and load project // Create and load project
await createProject({ name: projectName, page }) await createProject({ name: projectName, page })
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// Create named view // Create named view
const projectDirName = testInfo.outputPath('electron-test-projects-dir') const projectDirName = testInfo.outputPath('electron-test-projects-dir')
@ -292,7 +282,6 @@ test.describe('Named view tests', () => {
expect(exists).toBe(true) expect(exists).toBe(true)
}).toPass() }).toPass()
await expect(async () => {
// Read project.toml into memory // Read project.toml into memory
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8') let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break // Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
@ -301,6 +290,5 @@ test.describe('Named view tests', () => {
// Write the entire tomlString to a snapshot. // Write the entire tomlString to a snapshot.
// There are many key/value pairs to check this is a safer match. // There are many key/value pairs to check this is a safer match.
expect(tomlString).toMatchSnapshot('verify-two-named-view-gets-created') expect(tomlString).toMatchSnapshot('verify-two-named-view-gets-created')
}).toPass()
}) })
}) })

View File

@ -1,16 +0,0 @@
[settings]
modeling = { }
text_editor = { }
command_bar = { }
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
name = "uuid1"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 0, 0, 0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1

View File

@ -1,28 +0,0 @@
[settings]
modeling = { }
text_editor = { }
command_bar = { }
[settings.app.named_views.0656fb1a-9640-473e-b334-591dc70c0138]
name = "uuid1"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 0, 0, 0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1
[settings.app.named_views.c810cf04-c6cc-4a4a-8b11-17bf445dcab7]
name = "uuid2"
eye_offset = 1_378.0059
fov_y = 45
is_ortho = false
ortho_scale_enabled = true
ortho_scale_factor = 1.6
pivot_position = [ 1_826.5239, 0.0, 0.0 ]
pivot_rotation = [ 0.5380994, 0.0, 0.0, 0.8428814 ]
world_coord_system = "right_handed_up_z"
version = 1

View File

@ -1,5 +1,4 @@
import { throwTronAppMissing } from '@e2e/playwright/lib/electron-helpers' import { throwTronAppMissing } from '@e2e/playwright/lib/electron-helpers'
import { orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
/** /**
@ -7,28 +6,19 @@ import { expect, test } from '@e2e/playwright/zoo-test'
* Test file menu actions that trigger something in the frontend * Test file menu actions that trigger something in the frontend
*/ */
test.describe('Native file menu', { tag: ['@electron'] }, () => { test.describe('Native file menu', { tag: ['@electron'] }, () => {
test.skip() // TODO: Reimplement native file menu tests
test.describe('Home page', () => { test.describe('Home page', () => {
test.describe('File role', () => { test.describe('File role', () => {
test('Home.File.Create project', async ({ tronApp, cmdBar, page }) => { test('Home.File.Create project', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) fail()
return false
}
const newProject = const newProject =
app.applicationMenu.getMenuItemById('File.New project') app.applicationMenu.getMenuItemById('File.New project')
if (!newProject) return false if (!newProject) fail()
newProject.click() newProject.click()
return true
}) })
)
.toBe(true)
// Check that the command bar is opened // Check that the command bar is opened
await expect(cmdBar.cmdBarElement).toBeVisible() await expect(cmdBar.cmdBarElement).toBeVisible()
// Check the placeholder project name exists // Check the placeholder project name exists
@ -42,21 +32,13 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const openProject = const openProject =
app.applicationMenu.getMenuItemById('File.Open project') app.applicationMenu.getMenuItemById('File.Open project')
if (!openProject) { if (!openProject) fail()
return false
}
openProject.click() openProject.click()
return true
}) })
)
.toBe(true)
// Check that the command bar is opened // Check that the command bar is opened
await expect(cmdBar.cmdBarElement).toBeVisible() await expect(cmdBar.cmdBarElement).toBeVisible()
// Check the placeholder project name exists // Check the placeholder project name exists
@ -74,23 +56,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
console.log(app) if (!app || !app.applicationMenu) fail()
if (!app || !app.applicationMenu) {
return false
}
const userSettings = app.applicationMenu.getMenuItemById( const userSettings = app.applicationMenu.getMenuItemById(
'File.Preferences.User settings' 'File.Preferences.User settings'
) )
if (!userSettings) return false if (!userSettings) fail()
userSettings.click() userSettings.click()
return true
}) })
)
.toBe(true)
const settings = page.getByTestId('settings-dialog-panel') const settings = page.getByTestId('settings-dialog-panel')
await expect(settings).toBeVisible() await expect(settings).toBeVisible()
// You are viewing the user tab // You are viewing the user tab
@ -104,27 +77,17 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
cmdBar, cmdBar,
page, page,
}) => { }) => {
if (!tronApp) { if (!tronApp) fail()
fail()
}
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const keybindings = app.applicationMenu.getMenuItemById( const keybindings = app.applicationMenu.getMenuItemById(
'File.Preferences.Keybindings' 'File.Preferences.Keybindings'
) )
if (!keybindings) { if (!keybindings) fail()
return false
}
keybindings.click() keybindings.click()
return true
}) })
)
.toBe(true)
const settings = page.getByTestId('settings-dialog-panel') const settings = page.getByTestId('settings-dialog-panel')
await expect(settings).toBeVisible() await expect(settings).toBeVisible()
// You are viewing the keybindings tab // You are viewing the keybindings tab
@ -139,22 +102,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) fail()
return false
}
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'File.Preferences.User default units' 'File.Preferences.User default units'
) )
if (!menu) return false if (!menu) fail()
menu.click() menu.click()
return true
}) })
)
.toBe(true)
const settings = page.getByTestId('settings-dialog-panel') const settings = page.getByTestId('settings-dialog-panel')
await expect(settings).toBeVisible() await expect(settings).toBeVisible()
const defaultUnit = settings.locator('#defaultUnit') const defaultUnit = settings.locator('#defaultUnit')
@ -164,22 +119,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'File.Preferences.Theme' 'File.Preferences.Theme'
) )
if (!menu) { if (!menu) fail()
return false
}
menu.click() menu.click()
return true
}) })
)
.toBe(true)
// Check that the command bar is opened // Check that the command bar is opened
await expect(cmdBar.cmdBarElement).toBeVisible() await expect(cmdBar.cmdBarElement).toBeVisible()
// Check the placeholder project name exists // Check the placeholder project name exists
@ -197,22 +144,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) fail()
return false
}
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'File.Preferences.Theme color' 'File.Preferences.Theme color'
) )
if (!menu) return false if (!menu) fail()
menu.click() menu.click()
return true
}) })
)
.toBe(true)
const settings = page.getByTestId('settings-dialog-panel') const settings = page.getByTestId('settings-dialog-panel')
await expect(settings).toBeVisible() await expect(settings).toBeVisible()
const defaultUnit = settings.locator('#themeColor') const defaultUnit = settings.locator('#themeColor')
@ -226,22 +165,13 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const menu = const menu = app.applicationMenu.getMenuItemById('File.Sign out')
app.applicationMenu.getMenuItemById('File.Sign out') if (!menu) fail()
if (!menu) {
return false
}
// FIXME: Add back when you can actually sign out // FIXME: Add back when you can actually sign out
// menu.click() // menu.click()
return true
}) })
)
.toBe(true)
// FIXME: When signing out during E2E the page is not bound correctly. // FIXME: When signing out during E2E the page is not bound correctly.
// It cannot find the button // It cannot find the button
// const signIn = page.getByTestId('sign-in-button') // const signIn = page.getByTestId('sign-in-button')
@ -254,22 +184,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) fail()
return false
}
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Edit.Rename project' 'Edit.Rename project'
) )
if (!menu) return false if (!menu) fail()
menu.click() menu.click()
return true
}) })
)
.toBe(true)
// Check the placeholder project name exists // Check the placeholder project name exists
const actual = await cmdBar.cmdBarElement const actual = await cmdBar.cmdBarElement
.getByTestId('command-name') .getByTestId('command-name')
@ -281,27 +203,20 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Edit.Delete project' 'Edit.Delete project'
) )
if (!menu) { if (!menu) fail()
return false
}
menu.click() menu.click()
return true
}) })
)
.toBe(true)
// Check the placeholder project name exists // Check the placeholder project name exists
const actual = async () => const actual = await cmdBar.cmdBarElement
cmdBar.cmdBarElement.getByTestId('command-name').textContent() .getByTestId('command-name')
.textContent()
const expected = 'Delete project' const expected = 'Delete project'
await expect.poll(async () => await actual()).toBe(expected) expect(actual).toBe(expected)
}) })
test('Home.Edit.Change project directory', async ({ test('Home.Edit.Change project directory', async ({
tronApp, tronApp,
@ -311,22 +226,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) fail()
return false
}
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Edit.Change project directory' 'Edit.Change project directory'
) )
if (!menu) return false if (!menu) fail()
menu.click() menu.click()
return true
}) })
)
.toBe(true)
const settings = page.getByTestId('settings-dialog-panel') const settings = page.getByTestId('settings-dialog-panel')
await expect(settings).toBeVisible() await expect(settings).toBeVisible()
const projectDirectory = settings.locator('#projectDirectory') const projectDirectory = settings.locator('#projectDirectory')
@ -342,22 +249,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'View.Command Palette...' 'View.Command Palette...'
) )
if (!menu) { if (!menu) fail()
return false
}
menu.click() menu.click()
return true
}) })
)
.toBe(true)
// Check the placeholder project name exists // Check the placeholder project name exists
const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search') const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search')
await expect(actual).toBeVisible() await expect(actual).toBeVisible()
@ -368,22 +267,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) fail()
return false
}
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Help.Show all commands' 'Help.Show all commands'
) )
if (!menu) return false if (!menu) fail()
menu.click() menu.click()
return true
}) })
)
.toBe(true)
// Check the placeholder project name exists // Check the placeholder project name exists
const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search') const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search')
await expect(actual).toBeVisible() await expect(actual).toBeVisible()
@ -392,21 +283,13 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Help.KCL code samples' 'Help.KCL code samples'
) )
if (!menu) { if (!menu) fail()
return false
}
return true
}) })
)
.toBe(true)
}) })
test('Home.Help.Refresh and report a bug', async ({ test('Home.Help.Refresh and report a bug', async ({
tronApp, tronApp,
@ -416,22 +299,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) fail()
return false
}
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Help.Refresh and report a bug' 'Help.Refresh and report a bug'
) )
if (!menu) return false if (!menu) fail()
menu.click() menu.click()
return true
}) })
)
.toBe(true)
// Core dump and refresh magic number timeout // Core dump and refresh magic number timeout
await page.waitForTimeout(7000) await page.waitForTimeout(7000)
const actual = page.getByText( const actual = page.getByText(
@ -443,22 +318,14 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
if (!tronApp) fail() if (!tronApp) fail()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Help.Reset onboarding' 'Help.Reset onboarding'
) )
if (!menu) { if (!menu) fail()
return false
}
menu.click() menu.click()
return true
}) })
)
.toBe(true)
const actual = page.getByText( const actual = page.getByText(
`This is a hardware design tool that lets you edit visually, with code, or both. It's powered by the KittyCAD Design API, the first API created for anyone to build hardware design tools.` `This is a hardware design tool that lets you edit visually, with code, or both. It's powered by the KittyCAD Design API, the first API created for anyone to build hardware design tools.`
@ -478,7 +345,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
}) => { }) => {
if (!tronApp) fail() if (!tronApp) fail()
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -510,7 +377,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -546,7 +413,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -571,43 +438,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
const expected = 'Open sample' const expected = 'Open sample'
expect(actual).toBe(expected) expect(actual).toBe(expected)
}) })
test('Modeling.File.Insert from project file', async ({
tronApp,
cmdBar,
page,
homePage,
scene,
}) => {
if (!tronApp) {
throwTronAppMissing()
return
}
await homePage.goToModelingScene()
await scene.settled(cmdBar)
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) {
throw new Error('app or app.applicationMenu is missing')
}
const openProject = app.applicationMenu.getMenuItemById(
'File.Insert from project file'
)
if (!openProject) {
throw new Error('File.Insert from project file')
}
openProject.click()
})
// Check that the command bar is opened
await expect(cmdBar.cmdBarElement).toBeVisible()
// Check the placeholder project name exists
const actual = await cmdBar.cmdBarElement
.getByTestId('command-name')
.textContent()
const expected = 'Insert'
expect(actual).toBe(expected)
})
test('Modeling.File.Export current part', async ({ test('Modeling.File.Export current part', async ({
tronApp, tronApp,
cmdBar, cmdBar,
@ -620,7 +450,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -657,7 +487,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -693,7 +523,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -730,7 +560,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -766,7 +596,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -800,7 +630,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -833,7 +663,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -870,7 +700,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -903,28 +733,21 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) { if (!app || !app.applicationMenu) {
throw new Error('app or app.applicationMenu is missing') throw new Error('app or app.applicationMenu is missing')
} }
const menu = const menu = app.applicationMenu.getMenuItemById('File.Sign out')
app.applicationMenu.getMenuItemById('File.Sign out')
if (!menu) { if (!menu) {
throw new Error('File.Sign out') throw new Error('File.Sign out')
} }
// FIXME: Add back when you can actually sign out // FIXME: Add back when you can actually sign out
// menu.click() // menu.click()
return true
}) })
)
.toBe(true)
// FIXME: When signing out during E2E the page is not bound correctly. // FIXME: When signing out during E2E the page is not bound correctly.
// It cannot find the button // It cannot find the button
// const signIn = page.getByTestId('sign-in-button') // const signIn = page.getByTestId('sign-in-button')
@ -944,7 +767,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -979,7 +802,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1014,7 +837,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1044,7 +867,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1079,7 +902,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1114,7 +937,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
@ -1148,7 +971,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1180,7 +1003,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1216,7 +1039,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1252,7 +1075,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1289,7 +1112,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1318,7 +1141,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1347,7 +1170,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1376,7 +1199,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1405,7 +1228,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1434,7 +1257,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1463,7 +1286,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1492,7 +1315,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1521,7 +1344,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1558,7 +1381,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1595,7 +1418,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1632,7 +1455,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1665,7 +1488,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1698,7 +1521,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1731,7 +1554,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1764,7 +1587,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1798,7 +1621,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1835,7 +1658,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1872,7 +1695,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1910,7 +1733,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1947,7 +1770,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -1984,7 +1807,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2021,7 +1844,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2058,7 +1881,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2095,7 +1918,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2133,7 +1956,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2171,7 +1994,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2209,7 +2032,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2248,7 +2071,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2276,7 +2099,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
@ -2296,33 +2119,25 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
scene, scene,
toolbar, toolbar,
}) => { }) => {
// TODO: this test has been dead dead on the idle stream branch
test.fixme(orRunWhenFullSuiteEnabled())
if (!tronApp) { if (!tronApp) {
throwTronAppMissing() throwTronAppMissing()
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await expect
.poll(
async () =>
await tronApp.electron.evaluate(async ({ app }) => { await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) return false if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById( const menu = app.applicationMenu.getMenuItemById(
'Help.Refresh and report a bug' 'Help.Refresh and report a bug'
) )
if (!menu) return false if (!menu) fail()
menu.click() menu.click()
return true
}) })
)
.toBe(true)
// Core dump and refresh magic number timeout // Core dump and refresh magic number timeout
await scene.connectionEstablished() await scene.waitForExecutionDone()
await expect(toolbar.startSketchBtn).toBeVisible() await expect(toolbar.startSketchBtn).toBeVisible()
}) })
test('Modeling.Help.Reset onboarding', async ({ test('Modeling.Help.Reset onboarding', async ({
@ -2337,7 +2152,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
return return
} }
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// Run electron snippet to find the Menu! // Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run await page.waitForTimeout(100) // wait for createModelingPageMenu() to run

View File

@ -1,292 +0,0 @@
import * as fsp from 'fs/promises'
import path from 'path'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import {
executorInputPath,
getUtils,
testsInputPath,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import type { Page } from '@playwright/test'
async function insertPartIntoAssembly(
path: string,
alias: string,
toolbar: ToolbarFixture,
cmdBar: CmdBarFixture,
page: Page
) {
await toolbar.insertButton.click()
await cmdBar.selectOption({ name: path }).click()
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'localName',
currentArgValue: '',
headerArguments: { Path: path, LocalName: '' },
highlightedHeaderArg: 'localName',
commandName: 'Insert',
})
await page.keyboard.insertText(alias)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: { Path: path, LocalName: alias },
commandName: 'Insert',
})
await cmdBar.progressCmdBar()
}
// test file is for testing point an click code gen functionality that's assemblies related
test.describe('Point-and-click assemblies tests', () => {
test(
`Insert kcl parts into assembly as whole module import`,
{ tag: ['@electron'] },
async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
tronApp,
}) => {
if (!tronApp) {
fail()
}
const midPoint = { x: 500, y: 250 }
const partPoint = { x: midPoint.x + 30, y: midPoint.y - 30 } // mid point, just off top right
const defaultPlanesColor: [number, number, number] = [180, 220, 180]
const partColor: [number, number, number] = [100, 100, 100]
const tolerance = 50
const u = await getUtils(page)
const gizmo = page.locator('[aria-label*=gizmo]')
const resetCameraButton = page.getByRole('button', { name: 'Reset view' })
await test.step('Setup parts and expect empty assembly scene', async () => {
const projectName = 'assembly'
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, projectName)
await fsp.mkdir(bracketDir, { recursive: true })
await Promise.all([
fsp.copyFile(
executorInputPath('cylinder.kcl'),
path.join(bracketDir, 'cylinder.kcl')
),
fsp.copyFile(
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
path.join(bracketDir, 'bracket.kcl')
),
fsp.copyFile(
testsInputPath('cube.step'),
path.join(bracketDir, 'cube.step')
),
fsp.writeFile(path.join(bracketDir, 'main.kcl'), ''),
])
})
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.openProject(projectName)
await scene.settled(cmdBar)
await toolbar.closePane('code')
await scene.expectPixelColor(defaultPlanesColor, midPoint, tolerance)
})
await test.step('Insert kcl as first part as module', async () => {
await insertPartIntoAssembly(
'cylinder.kcl',
'cylinder',
toolbar,
cmdBar,
page
)
await toolbar.openPane('code')
await editor.expectEditor.toContain(
`
import "cylinder.kcl" as cylinder
cylinder
`,
{ shouldNormalise: true }
)
await scene.settled(cmdBar)
// Check scene for changes
await toolbar.closePane('code')
await u.doAndWaitForCmd(async () => {
await gizmo.click({ button: 'right' })
await resetCameraButton.click()
}, 'zoom_to_fit')
await toolbar.closePane('debug')
await scene.expectPixelColor(partColor, partPoint, tolerance)
await toolbar.openPane('code')
})
await test.step('Insert kcl second part as module', async () => {
await insertPartIntoAssembly(
'bracket.kcl',
'bracket',
toolbar,
cmdBar,
page
)
await editor.expectEditor.toContain(
`
import "cylinder.kcl" as cylinder
import "bracket.kcl" as bracket
cylinder
bracket
`,
{ shouldNormalise: true }
)
await scene.settled(cmdBar)
})
await test.step('Insert a second time and expect error', async () => {
// TODO: revisit once we have clone with #6209
await insertPartIntoAssembly(
'bracket.kcl',
'bracket',
toolbar,
cmdBar,
page
)
await editor.expectEditor.toContain(
`
import "cylinder.kcl" as cylinder
import "bracket.kcl" as bracket
import "bracket.kcl" as bracket
cylinder
bracket
bracket
`,
{ shouldNormalise: true }
)
await scene.settled(cmdBar)
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
})
}
)
test(
`Insert foreign parts into assembly as whole module import`,
{ tag: ['@electron'] },
async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
tronApp,
}) => {
if (!tronApp) {
fail()
}
const midPoint = { x: 500, y: 250 }
const partPoint = { x: midPoint.x + 30, y: midPoint.y - 30 } // mid point, just off top right
const defaultPlanesColor: [number, number, number] = [180, 220, 180]
const partColor: [number, number, number] = [150, 150, 150]
const tolerance = 50
const complexPlmFileName = 'cube_Complex-PLM_Name_-001.sldprt'
const camelCasedSolidworksFileName = 'cubeComplexPLMName001'
await test.step('Setup parts and expect empty assembly scene', async () => {
const projectName = 'assembly'
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, projectName)
await fsp.mkdir(bracketDir, { recursive: true })
await Promise.all([
fsp.copyFile(
testsInputPath('cube.step'),
path.join(bracketDir, 'cube.step')
),
fsp.copyFile(
testsInputPath('cube.sldprt'),
path.join(bracketDir, complexPlmFileName)
),
fsp.writeFile(path.join(bracketDir, 'main.kcl'), ''),
])
})
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.openProject(projectName)
await scene.settled(cmdBar)
await toolbar.closePane('code')
await scene.expectPixelColor(defaultPlanesColor, midPoint, tolerance)
})
await test.step('Insert step part as module', async () => {
await insertPartIntoAssembly('cube.step', 'cube', toolbar, cmdBar, page)
await toolbar.openPane('code')
await editor.expectEditor.toContain(
`
import "cube.step" as cube
cube
`,
{ shouldNormalise: true }
)
await scene.settled(cmdBar)
// TODO: remove this once #5780 is fixed
await page.reload()
await scene.settled(cmdBar)
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await toolbar.closePane('code')
await scene.expectPixelColor(partColor, partPoint, tolerance)
})
await test.step('Insert second step part by clicking', async () => {
await toolbar.openPane('files')
await toolbar.expectFileTreeState([
complexPlmFileName,
'cube.step',
'main.kcl',
])
await toolbar.openFile(complexPlmFileName)
// Go through the ToastInsert prompt
await page.getByText('Insert into my current file').click()
// Check getPathFilenameInVariableCase output
const parsedValueFromFile =
await cmdBar.currentArgumentInput.inputValue()
expect(parsedValueFromFile).toEqual(camelCasedSolidworksFileName)
// Continue on with the flow
await page.keyboard.insertText('cubeSw')
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: { Path: complexPlmFileName, LocalName: 'cubeSw' },
commandName: 'Insert',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('files')
await toolbar.openPane('code')
await editor.expectEditor.toContain(
`
import "cube.step" as cube
import "${complexPlmFileName}" as cubeSw
cube
cubeSw
`,
{ shouldNormalise: true }
)
await scene.settled(cmdBar)
// TODO: remove this once #5780 is fixed
await page.reload()
await scene.settled(cmdBar)
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
await toolbar.closePane('code')
await scene.expectPixelColor(partColor, partPoint, tolerance)
})
}
)
})

View File

@ -5,14 +5,13 @@ import path from 'node:path'
import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture' import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture' import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture' import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import { orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils' import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
// test file is for testing point an click code gen functionality that's not sketch mode related // test file is for testing point an click code gen functionality that's not sketch mode related
test.describe('Point-and-click tests', () => { test.describe('Point-and-click tests', () => {
test('verify extruding circle works', async ({ test('verify extruding circle works', async ({
page,
context, context,
homePage, homePage,
cmdBar, cmdBar,
@ -31,9 +30,8 @@ test.describe('Point-and-click tests', () => {
await context.addInitScript((file) => { await context.addInitScript((file) => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
const [clickCircle, moveToCircle] = scene.makeMouseHelpers(582, 217) const [clickCircle, moveToCircle] = scene.makeMouseHelpers(582, 217)
@ -74,6 +72,7 @@ test.describe('Point-and-click tests', () => {
await test.step('do extrude flow and check extrude code is added to editor', async () => { await test.step('do extrude flow and check extrude code is added to editor', async () => {
await toolbar.extrudeButton.click() await toolbar.extrudeButton.click()
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'distance', currentArgKey: 'distance',
@ -187,7 +186,6 @@ test.describe('Point-and-click tests', () => {
editor, editor,
toolbar, toolbar,
scene, scene,
cmdBar,
}) => { }) => {
const file = await fs.readFile( const file = await fs.readFile(
path.resolve( path.resolve(
@ -202,7 +200,9 @@ test.describe('Point-and-click tests', () => {
}, file) }, file)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await expect(
page.getByTestId('model-state-indicator-receive-reliable')
).toBeVisible()
const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene) const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene)
@ -210,7 +210,7 @@ test.describe('Point-and-click tests', () => {
clickCoords: { x: 570, y: 220 }, clickCoords: { x: 570, y: 220 },
cameraPos: { x: 16020, y: -2000, z: 10500 }, cameraPos: { x: 16020, y: -2000, z: 10500 },
cameraTarget: { x: -150, y: -4500, z: -80 }, cameraTarget: { x: -150, y: -4500, z: -80 },
beforeChamferSnippet: `angledLine(angle=segAng(rectangleSegmentA001)-90,length=217.26,tag=$seg01) beforeChamferSnippet: `angledLine([segAng(rectangleSegmentA001)-90,217.26],%,$seg01)
chamfer(length = 30,tags = [ chamfer(length = 30,tags = [
seg01, seg01,
getNextAdjacentEdge(yo), getNextAdjacentEdge(yo),
@ -223,9 +223,9 @@ test.describe('Point-and-click tests', () => {
'sketch002 = startSketchOn(extrude001, seg03)', 'sketch002 = startSketchOn(extrude001, seg03)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([205.96, 254.59], sketch002)', 'startProfileAt([205.96, 254.59], sketch002)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.39,tag=$rectangleSegmentA002) afterRectangle2ndClickSnippet: `angledLine([0,11.39],%,$rectangleSegmentA002)
|>angledLine(angle=segAng(rectangleSegmentA002)-90,length=105.26) |>angledLine([segAng(rectangleSegmentA002)-90,105.26],%)
|>angledLine(angle=segAng(rectangleSegmentA002),length=-segLen(rectangleSegmentA002)) |>angledLine([segAng(rectangleSegmentA002),-segLen(rectangleSegmentA002)],%)
|>line(endAbsolute=[profileStartX(%),profileStartY(%)]) |>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|>close()`, |>close()`,
}) })
@ -234,7 +234,10 @@ test.describe('Point-and-click tests', () => {
clickCoords: { x: 690, y: 250 }, clickCoords: { x: 690, y: 250 },
cameraPos: { x: 16020, y: -2000, z: 10500 }, cameraPos: { x: 16020, y: -2000, z: 10500 },
cameraTarget: { x: -150, y: -4500, z: -80 }, cameraTarget: { x: -150, y: -4500, z: -80 },
beforeChamferSnippet: `angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 217.26, tag = $seg01)chamfer( beforeChamferSnippet: `angledLine([
segAng(rectangleSegmentA001) - 90,
217.26
], %, $seg01)chamfer(
length = 30, length = 30,
tags = [ tags = [
seg01, seg01,
@ -247,9 +250,9 @@ test.describe('Point-and-click tests', () => {
'sketch003 = startSketchOn(extrude001, seg04)', 'sketch003 = startSketchOn(extrude001, seg04)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([-209.64, 255.28], sketch003)', 'startProfileAt([-209.64, 255.28], sketch003)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.56,tag=$rectangleSegmentA003) afterRectangle2ndClickSnippet: `angledLine([0,11.56],%,$rectangleSegmentA003)
|>angledLine(angle=segAng(rectangleSegmentA003)-90,length=106.84) |>angledLine([segAng(rectangleSegmentA003)-90,106.84],%)
|>angledLine(angle=segAng(rectangleSegmentA003),length=-segLen(rectangleSegmentA003)) |>angledLine([segAng(rectangleSegmentA003),-segLen(rectangleSegmentA003)],%)
|>line(endAbsolute=[profileStartX(%),profileStartY(%)]) |>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|>close()`, |>close()`,
}) })
@ -258,7 +261,7 @@ test.describe('Point-and-click tests', () => {
clickCoords: { x: 677, y: 87 }, clickCoords: { x: 677, y: 87 },
cameraPos: { x: -6200, y: 1500, z: 6200 }, cameraPos: { x: -6200, y: 1500, z: 6200 },
cameraTarget: { x: 8300, y: 1100, z: 4800 }, cameraTarget: { x: 8300, y: 1100, z: 4800 },
beforeChamferSnippet: `angledLine(angle = 0, length = 268.43, tag = $rectangleSegmentA001)chamfer( beforeChamferSnippet: `angledLine([0, 268.43], %, $rectangleSegmentA001)chamfer(
length = 30, length = 30,
tags = [ tags = [
getNextAdjacentEdge(yo), getNextAdjacentEdge(yo),
@ -269,9 +272,9 @@ test.describe('Point-and-click tests', () => {
'sketch004 = startSketchOn(extrude001, seg05)', 'sketch004 = startSketchOn(extrude001, seg05)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([82.57, 322.96], sketch004)', 'startProfileAt([82.57, 322.96], sketch004)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.16,tag=$rectangleSegmentA004) afterRectangle2ndClickSnippet: `angledLine([0,11.16],%,$rectangleSegmentA004)
|>angledLine(angle=segAng(rectangleSegmentA004)-90,length=103.07) |>angledLine([segAng(rectangleSegmentA004)-90,103.07],%)
|>angledLine(angle=segAng(rectangleSegmentA004),length=-segLen(rectangleSegmentA004)) |>angledLine([segAng(rectangleSegmentA004),-segLen(rectangleSegmentA004)],%)
|>line(endAbsolute=[profileStartX(%),profileStartY(%)]) |>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|>close()`, |>close()`,
}) })
@ -287,9 +290,9 @@ test.describe('Point-and-click tests', () => {
'sketch005 = startSketchOn(extrude001, seg06)', 'sketch005 = startSketchOn(extrude001, seg06)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([-23.43, 19.69], sketch005)', 'startProfileAt([-23.43, 19.69], sketch005)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=9.1,tag=$rectangleSegmentA005) afterRectangle2ndClickSnippet: `angledLine([0,9.1],%,$rectangleSegmentA005)
|>angledLine(angle=segAng(rectangleSegmentA005)-90,length=84.07) |>angledLine([segAng(rectangleSegmentA005)-90,84.07],%)
|>angledLine(angle=segAng(rectangleSegmentA005),length=-segLen(rectangleSegmentA005)) |>angledLine([segAng(rectangleSegmentA005),-segLen(rectangleSegmentA005)],%)
|>line(endAbsolute=[profileStartX(%),profileStartY(%)]) |>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|>close()`, |>close()`,
}) })
@ -299,9 +302,15 @@ test.describe('Point-and-click tests', () => {
`@settings(defaultLengthUnit = in) `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag] |> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]
|> angledLine(angle = 0, length = 268.43, tag = $rectangleSegmentA001) |> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 217.26, tag = $seg01) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $yo) segAng(rectangleSegmentA001) - 90,
217.26
], %, $seg01)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $yo)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02) |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close() |> close()
extrude001 = extrude(sketch001, length = 100) extrude001 = extrude(sketch001, length = 100)
@ -311,30 +320,48 @@ extrude001 = extrude(sketch001, length = 100)
|> chamfer(length = 30, tags = [getNextAdjacentEdge(yo)], tag = $seg06) |> chamfer(length = 30, tags = [getNextAdjacentEdge(yo)], tag = $seg06)
sketch005 = startSketchOn(extrude001, seg06) sketch005 = startSketchOn(extrude001, seg06)
profile004=startProfileAt([-23.43,19.69], sketch005) profile004=startProfileAt([-23.43,19.69], sketch005)
|> angledLine(angle = 0, length = 9.1, tag = $rectangleSegmentA005) |> angledLine([0, 9.1], %, $rectangleSegmentA005)
|> angledLine(angle = segAng(rectangleSegmentA005) - 90, length = 84.07) |> angledLine([segAng(rectangleSegmentA005) - 90, 84.07], %)
|> angledLine(angle = segAng(rectangleSegmentA005), length = -segLen(rectangleSegmentA005)) |> angledLine([segAng(rectangleSegmentA005), -segLen(rectangleSegmentA005)], %)
|> line(endAbsolute=[profileStartX(%), profileStartY(%)]) |> line(endAbsolute=[profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch004 = startSketchOn(extrude001, seg05) sketch004 = startSketchOn(extrude001, seg05)
profile003 = startProfileAt([82.57, 322.96], sketch004) profile003 = startProfileAt([82.57, 322.96], sketch004)
|> angledLine(angle = 0, length = 11.16, tag = $rectangleSegmentA004) |> angledLine([0, 11.16], %, $rectangleSegmentA004)
|> angledLine(angle = segAng(rectangleSegmentA004) - 90, length = 103.07) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA004), length = -segLen(rectangleSegmentA004)) segAng(rectangleSegmentA004) - 90,
103.07
], %)
|> angledLine([
segAng(rectangleSegmentA004),
-segLen(rectangleSegmentA004)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch003 = startSketchOn(extrude001, seg04) sketch003 = startSketchOn(extrude001, seg04)
profile002 = startProfileAt([-209.64, 255.28], sketch003) profile002 = startProfileAt([-209.64, 255.28], sketch003)
|> angledLine(angle = 0, length = 11.56, tag = $rectangleSegmentA003) |> angledLine([0, 11.56], %, $rectangleSegmentA003)
|> angledLine(angle = segAng(rectangleSegmentA003) - 90, length = 106.84) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA003), length = -segLen(rectangleSegmentA003)) segAng(rectangleSegmentA003) - 90,
106.84
], %)
|> angledLine([
segAng(rectangleSegmentA003),
-segLen(rectangleSegmentA003)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch002 = startSketchOn(extrude001, seg03) sketch002 = startSketchOn(extrude001, seg03)
profile001 = startProfileAt([205.96, 254.59], sketch002) profile001 = startProfileAt([205.96, 254.59], sketch002)
|> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002) |> angledLine([0, 11.39], %, $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002)) segAng(rectangleSegmentA002) - 90,
105.26
], %)
|> angledLine([
segAng(rectangleSegmentA002),
-segLen(rectangleSegmentA002)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
`, `,
@ -350,7 +377,6 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
editor, editor,
toolbar, toolbar,
scene, scene,
cmdBar,
}) => { }) => {
const file = await fs.readFile( const file = await fs.readFile(
path.resolve( path.resolve(
@ -366,7 +392,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene) const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene)
@ -374,7 +400,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
clickCoords: { x: 570, y: 220 }, clickCoords: { x: 570, y: 220 },
cameraPos: { x: 16020, y: -2000, z: 10500 }, cameraPos: { x: 16020, y: -2000, z: 10500 },
cameraTarget: { x: -150, y: -4500, z: -80 }, cameraTarget: { x: -150, y: -4500, z: -80 },
beforeChamferSnippet: `angledLine(angle=segAng(rectangleSegmentA001)-90,length=217.26,tag=$seg01) beforeChamferSnippet: `angledLine([segAng(rectangleSegmentA001)-90,217.26],%,$seg01)
chamfer(extrude001,length=30,tags=[ chamfer(extrude001,length=30,tags=[
seg01, seg01,
getNextAdjacentEdge(yo), getNextAdjacentEdge(yo),
@ -386,9 +412,9 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
'sketch002 = startSketchOn(extrude001, seg03)', 'sketch002 = startSketchOn(extrude001, seg03)',
afterRectangle1stClickSnippet: afterRectangle1stClickSnippet:
'startProfileAt([205.96, 254.59], sketch002)', 'startProfileAt([205.96, 254.59], sketch002)',
afterRectangle2ndClickSnippet: `angledLine(angle=0,length=11.39,tag=$rectangleSegmentA002) afterRectangle2ndClickSnippet: `angledLine([0,11.39],%,$rectangleSegmentA002)
|>angledLine(angle=segAng(rectangleSegmentA002)-90,length=105.26) |>angledLine([segAng(rectangleSegmentA002)-90,105.26],%)
|>angledLine(angle=segAng(rectangleSegmentA002),length=-segLen(rectangleSegmentA002)) |>angledLine([segAng(rectangleSegmentA002),-segLen(rectangleSegmentA002)],%)
|>line(endAbsolute=[profileStartX(%),profileStartY(%)]) |>line(endAbsolute=[profileStartX(%),profileStartY(%)])
|>close()`, |>close()`,
}) })
@ -396,9 +422,15 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
`@settings(defaultLengthUnit = in) `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %) |> startProfileAt([75.8, 317.2], %)
|> angledLine(angle = 0, length = 268.43, tag = $rectangleSegmentA001) |> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 217.26, tag = $seg01) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $yo) segAng(rectangleSegmentA001) - 90,
217.26
], %, $seg01)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $yo)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02) |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg02)
|> close() |> close()
extrude001 = extrude(sketch001, length = 100) extrude001 = extrude(sketch001, length = 100)
@ -418,9 +450,15 @@ chamf = chamfer(
) )
sketch002 = startSketchOn(extrude001, seg03) sketch002 = startSketchOn(extrude001, seg03)
profile001 = startProfileAt([205.96, 254.59], sketch002) profile001 = startProfileAt([205.96, 254.59], sketch002)
|> angledLine(angle = 0, length = 11.39, tag = $rectangleSegmentA002) |> angledLine([0, 11.39], %, $rectangleSegmentA002)
|> angledLine(angle = segAng(rectangleSegmentA002) - 90, length = 105.26) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA002), length = -segLen(rectangleSegmentA002)) segAng(rectangleSegmentA002) - 90,
105.26
], %)
|> angledLine([
segAng(rectangleSegmentA002),
-segLen(rectangleSegmentA002)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
`, `,
@ -441,7 +479,6 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
await page.setBodyDimensions(viewPortSize) await page.setBodyDimensions(viewPortSize)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished()
// Constants and locators // Constants and locators
// These are mappings from screenspace to KCL coordinates, // These are mappings from screenspace to KCL coordinates,
@ -500,7 +537,8 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
await toolbar.startSketchPlaneSelection() await toolbar.startSketchPlaneSelection()
await moveToXzPlane() await moveToXzPlane()
await clickOnXzPlane() await clickOnXzPlane()
await toolbar.waitUntilSketchingReady() // timeout wait for engine animation is unavoidable
await page.waitForTimeout(600)
await editor.expectEditor.toContain(expectedCodeSnippets.sketchOnXzPlane) await editor.expectEditor.toContain(expectedCodeSnippets.sketchOnXzPlane)
}) })
await test.step(`Place a point a few pixels off the middle, verify it still snaps to 0,0`, async () => { await test.step(`Place a point a few pixels off the middle, verify it still snaps to 0,0`, async () => {
@ -542,8 +580,9 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
editor, editor,
toolbar, toolbar,
scene, scene,
cmdBar,
}) => { }) => {
const u = await getUtils(page)
const initialCode = `closedSketch = startSketchOn(XZ) const initialCode = `closedSketch = startSketchOn(XZ)
|> circle(center = [8, 5], radius = 2) |> circle(center = [8, 5], radius = 2)
openSketch = startSketchOn(XY) openSketch = startSketchOn(XY)
@ -560,6 +599,8 @@ openSketch = startSketchOn(XY)
}, initialCode) }, initialCode)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await u.waitForPageLoad()
await page.waitForTimeout(1000)
const pointInsideCircle = { const pointInsideCircle = {
x: viewPortSize.width * 0.63, x: viewPortSize.width * 0.63,
@ -584,16 +625,15 @@ openSketch = startSketchOn(XY)
const exitSketch = async () => { const exitSketch = async () => {
await test.step(`Exit sketch mode`, async () => { await test.step(`Exit sketch mode`, async () => {
await toolbar.exitSketchBtn.click() await toolbar.exitSketchBtn.click()
await expect(toolbar.exitSketchBtn).not.toBeVisible()
await expect(toolbar.startSketchBtn).toBeEnabled() await expect(toolbar.startSketchBtn).toBeEnabled()
}) })
} }
await test.step(`Double-click on the closed sketch`, async () => { await test.step(`Double-click on the closed sketch`, async () => {
await scene.settled(cmdBar)
await moveToCircle() await moveToCircle()
await page.waitForTimeout(1000)
await dblClickCircle() await dblClickCircle()
await page.waitForTimeout(1000) await expect(toolbar.startSketchBtn).not.toBeVisible()
await expect(toolbar.exitSketchBtn).toBeVisible() await expect(toolbar.exitSketchBtn).toBeVisible()
await editor.expectState({ await editor.expectState({
activeLines: [`|>circle(center=[8,5],radius=2)`], activeLines: [`|>circle(center=[8,5],radius=2)`],
@ -630,6 +670,7 @@ openSketch = startSketchOn(XY)
// There is a full execution after exiting sketch that clears the scene. // There is a full execution after exiting sketch that clears the scene.
await page.waitForTimeout(500) await page.waitForTimeout(500)
await dblClickOpenPath() await dblClickOpenPath()
await expect(toolbar.startSketchBtn).not.toBeVisible()
await expect(toolbar.exitSketchBtn).toBeVisible() await expect(toolbar.exitSketchBtn).toBeVisible()
// Wait for enter sketch mode to complete // Wait for enter sketch mode to complete
await page.waitForTimeout(500) await page.waitForTimeout(500)
@ -990,9 +1031,6 @@ openSketch = startSketchOn(XY)
}) })
await test.step(`Go through the command bar flow`, async () => { await test.step(`Go through the command bar flow`, async () => {
await toolbar.offsetPlaneButton.click() await toolbar.offsetPlaneButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'plane', currentArgKey: 'plane',
@ -1050,7 +1088,6 @@ openSketch = startSketchOn(XY)
const expectedLine = `axis=X,` const expectedLine = `axis=X,`
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished()
await test.step(`Go through the command bar flow`, async () => { await test.step(`Go through the command bar flow`, async () => {
await toolbar.helixButton.click() await toolbar.helixButton.click()
@ -1069,7 +1106,6 @@ openSketch = startSketchOn(XY)
commandName: 'Helix', commandName: 'Helix',
}) })
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await expect.poll(() => page.getByText('Axis').count()).toBe(6)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
@ -1197,7 +1233,6 @@ openSketch = startSketchOn(XY)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar)
await test.step(`Go through the command bar flow`, async () => { await test.step(`Go through the command bar flow`, async () => {
await toolbar.closePane('code') await toolbar.closePane('code')
@ -1217,22 +1252,15 @@ openSketch = startSketchOn(XY)
commandName: 'Helix', commandName: 'Helix',
}) })
await cmdBar.selectOption({ name: 'Edge' }).click() await cmdBar.selectOption({ name: 'Edge' }).click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await clickOnEdge() await clickOnEdge()
await page.waitForTimeout(1000)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(1000)
await cmdBar.argumentInput.focus() await cmdBar.argumentInput.focus()
await page.waitForTimeout(1000)
await page.keyboard.insertText('20') await page.keyboard.insertText('20')
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.keyboard.insertText('0') await page.keyboard.insertText('0')
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.keyboard.insertText('1') await page.keyboard.insertText('1')
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.keyboard.insertText('100')
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'review', stage: 'review',
headerArguments: { headerArguments: {
@ -1246,7 +1274,6 @@ openSketch = startSketchOn(XY)
commandName: 'Helix', commandName: 'Helix',
}) })
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(1000)
}) })
await test.step(`Confirm code is added to the editor, scene has changed`, async () => { await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
@ -1342,7 +1369,7 @@ extrude001 = extrude(profile001, length = 100)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 620, y: 257 } const testPoint = { x: 620, y: 257 }
@ -1503,9 +1530,6 @@ extrude001 = extrude(profile001, length = 100)
if (!shouldPreselect) { if (!shouldPreselect) {
await test.step(`Go through the command bar flow without preselected sketches`, async () => { await test.step(`Go through the command bar flow without preselected sketches`, async () => {
await toolbar.loftButton.click() await toolbar.loftButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'selection', currentArgKey: 'selection',
@ -1555,7 +1579,6 @@ extrude001 = extrude(profile001, length = 100)
page, page,
homePage, homePage,
scene, scene,
cmdBar,
}) => { }) => {
const initialCode = `sketch001 = startSketchOn(XZ) const initialCode = `sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 30) |> circle(center = [0, 0], radius = 30)
@ -1569,7 +1592,7 @@ loft001 = loft([sketch001, sketch002])
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 575, y: 200 } const testPoint = { x: 575, y: 200 }
@ -1632,9 +1655,15 @@ sketch002 = startSketchOn(XZ)
initialCode: `@settings(defaultLengthUnit = in) initialCode: `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ) sketch001 = startSketchOn(YZ)
profile001 = startProfileAt([-400, -400], sketch001) profile001 = startProfileAt([-400, -400], sketch001)
|> angledLine(angle = 0, length = 800, tag = $rectangleSegmentA001) |> angledLine([0, 800], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) + 90, length = 800) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001)) segAng(rectangleSegmentA001) + 90,
800
], %)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
sketch002 = startSketchOn(XZ) sketch002 = startSketchOn(XZ)
@ -1658,7 +1687,7 @@ sketch002 = startSketchOn(XZ)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y) const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
@ -1678,9 +1707,6 @@ sketch002 = startSketchOn(XZ)
await test.step(`Go through the command bar flow`, async () => { await test.step(`Go through the command bar flow`, async () => {
await toolbar.sweepButton.click() await toolbar.sweepButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
commandName: 'Sweep', commandName: 'Sweep',
currentArgKey: 'target', currentArgKey: 'target',
@ -1800,7 +1826,7 @@ sketch002 = startSketchOn(XZ)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 700, y: 250 } const testPoint = { x: 700, y: 250 }
@ -1817,9 +1843,6 @@ sketch002 = startSketchOn(XZ)
await test.step(`Go through the command bar flow and fail validation with a toast`, async () => { await test.step(`Go through the command bar flow and fail validation with a toast`, async () => {
await toolbar.sweepButton.click() await toolbar.sweepButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
commandName: 'Sweep', commandName: 'Sweep',
currentArgKey: 'target', currentArgKey: 'target',
@ -2036,9 +2059,6 @@ extrude001 = extrude(sketch001, length = -12)
await test.step(`Open fillet UI without selecting edges`, async () => { await test.step(`Open fillet UI without selecting edges`, async () => {
await page.waitForTimeout(100) await page.waitForTimeout(100)
await toolbar.filletButton.click() await toolbar.filletButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'selection', currentArgKey: 'selection',
@ -2164,7 +2184,6 @@ extrude001 = extrude(sketch001, length = -12)
homePage, homePage,
scene, scene,
toolbar, toolbar,
cmdBar,
}) => { }) => {
const initialCode = `sketch001 = startSketchOn(XY) const initialCode = `sketch001 = startSketchOn(XY)
profile001 = circle( profile001 = circle(
@ -2181,7 +2200,7 @@ fillet001 = fillet(extrude001, radius = 5, tags = [getOppositeEdge(seg01)])
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await test.step('Double-click in feature tree and expect error toast', async () => { await test.step('Double-click in feature tree and expect error toast', async () => {
await toolbar.openPane('feature-tree') await toolbar.openPane('feature-tree')
@ -2502,7 +2521,7 @@ extrude001 = extrude(sketch001, length = -12)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
}) })
// Test 1: Command bar flow with preselected edges // Test 1: Command bar flow with preselected edges
@ -2535,7 +2554,6 @@ extrude001 = extrude(sketch001, length = -12)
stage: 'arguments', stage: 'arguments',
}) })
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(1000)
await cmdBar.expectState({ await cmdBar.expectState({
commandName: 'Chamfer', commandName: 'Chamfer',
highlightedHeaderArg: 'length', highlightedHeaderArg: 'length',
@ -2547,10 +2565,7 @@ extrude001 = extrude(sketch001, length = -12)
}, },
stage: 'arguments', stage: 'arguments',
}) })
await cmdBar.argumentInput.focus()
await page.waitForTimeout(1000)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(1000)
await cmdBar.expectState({ await cmdBar.expectState({
commandName: 'Chamfer', commandName: 'Chamfer',
headerArguments: { headerArguments: {
@ -2634,9 +2649,6 @@ extrude001 = extrude(sketch001, length = -12)
await test.step(`Open chamfer UI without selecting edges`, async () => { await test.step(`Open chamfer UI without selecting edges`, async () => {
await page.waitForTimeout(100) await page.waitForTimeout(100)
await toolbar.chamferButton.click() await toolbar.chamferButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'selection', currentArgKey: 'selection',
@ -2759,7 +2771,6 @@ extrude001 = extrude(sketch001, length = -12)
scene, scene,
editor, editor,
toolbar, toolbar,
cmdBar,
}) => { }) => {
// Code samples // Code samples
const initialCode = `@settings(defaultLengthUnit = in) const initialCode = `@settings(defaultLengthUnit = in)
@ -2803,7 +2814,7 @@ chamfer04 = chamfer(extrude001, length = 5, tags = [getOppositeEdge(seg02)])
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// verify modeling scene is loaded // verify modeling scene is loaded
await scene.expectPixelColor( await scene.expectPixelColor(
@ -2925,11 +2936,9 @@ extrude001 = extrude(sketch001, length = 30)
await context.addInitScript((initialCode) => { await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode) localStorage.setItem('persistCode', initialCode)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 575, y: 200 } const testPoint = { x: 575, y: 200 }
@ -2946,9 +2955,6 @@ extrude001 = extrude(sketch001, length = 30)
if (!shouldPreselect) { if (!shouldPreselect) {
await test.step(`Go through the command bar flow without preselected faces`, async () => { await test.step(`Go through the command bar flow without preselected faces`, async () => {
await toolbar.shellButton.click() await toolbar.shellButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'selection', currentArgKey: 'selection',
@ -3009,6 +3015,7 @@ extrude001 = extrude(sketch001, length = 30)
}) })
await test.step('Edit shell via feature tree selection works', async () => { await test.step('Edit shell via feature tree selection works', async () => {
await toolbar.closePane('code')
await toolbar.openPane('feature-tree') await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation( const operationButton = await toolbar.getFeatureTreeOperation(
'Shell', 'Shell',
@ -3037,6 +3044,7 @@ extrude001 = extrude(sketch001, length = 30)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree') await toolbar.closePane('feature-tree')
await scene.expectPixelColor([150, 150, 150], testPoint, 15) await scene.expectPixelColor([150, 150, 150], testPoint, 15)
await toolbar.openPane('code')
await editor.expectEditor.toContain(editedShellDeclaration) await editor.expectEditor.toContain(editedShellDeclaration)
await editor.expectState({ await editor.expectState({
diagnostics: [], diagnostics: [],
@ -3071,7 +3079,7 @@ extrude001 = extrude(sketch001, length = 40)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 580, y: 180 } const testPoint = { x: 580, y: 180 }
@ -3089,9 +3097,6 @@ extrude001 = extrude(sketch001, length = 40)
await test.step(`Go through the command bar flow, selecting a wall and keeping default thickness`, async () => { await test.step(`Go through the command bar flow, selecting a wall and keeping default thickness`, async () => {
await toolbar.shellButton.click() await toolbar.shellButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'selection', currentArgKey: 'selection',
@ -3103,9 +3108,6 @@ extrude001 = extrude(sketch001, length = 40)
highlightedHeaderArg: 'selection', highlightedHeaderArg: 'selection',
commandName: 'Shell', commandName: 'Shell',
}) })
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await clickOnCap() await clickOnCap()
await page.keyboard.down('Shift') await page.keyboard.down('Shift')
await clickOnWall() await clickOnWall()
@ -3114,7 +3116,6 @@ extrude001 = extrude(sketch001, length = 40)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(500) await page.waitForTimeout(500)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(500)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'review', stage: 'review',
headerArguments: { headerArguments: {
@ -3123,9 +3124,7 @@ extrude001 = extrude(sketch001, length = 40)
}, },
commandName: 'Shell', commandName: 'Shell',
}) })
await page.waitForTimeout(500)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(500)
}) })
await test.step(`Confirm code is added to the editor, scene has changed`, async () => { await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
@ -3140,6 +3139,7 @@ extrude001 = extrude(sketch001, length = 40)
}) })
await test.step('Edit shell via feature tree selection works', async () => { await test.step('Edit shell via feature tree selection works', async () => {
await editor.closePane()
const operationButton = await toolbar.getFeatureTreeOperation('Shell', 0) const operationButton = await toolbar.getFeatureTreeOperation('Shell', 0)
await operationButton.dblclick({ button: 'left' }) await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({ await cmdBar.expectState({
@ -3154,7 +3154,6 @@ extrude001 = extrude(sketch001, length = 40)
}) })
await page.keyboard.insertText('1') await page.keyboard.insertText('1')
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(500)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'review', stage: 'review',
headerArguments: { headerArguments: {
@ -3165,6 +3164,7 @@ extrude001 = extrude(sketch001, length = 40)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree') await toolbar.closePane('feature-tree')
await scene.expectPixelColor([150, 150, 150], testPoint, 15) await scene.expectPixelColor([150, 150, 150], testPoint, 15)
await toolbar.openPane('code')
await editor.expectEditor.toContain(editedShellDeclaration) await editor.expectEditor.toContain(editedShellDeclaration)
await editor.expectState({ await editor.expectState({
diagnostics: [], diagnostics: [],
@ -3218,7 +3218,7 @@ extrude002 = extrude(sketch002, length = 50)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 580, y: 320 } const testPoint = { x: 580, y: 320 }
@ -3243,13 +3243,12 @@ extrude002 = extrude(sketch002, length = 50)
highlightedHeaderArg: 'selection', highlightedHeaderArg: 'selection',
commandName: 'Shell', commandName: 'Shell',
}) })
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await clickOnCap() await clickOnCap()
await page.waitForTimeout(1000) await page.waitForTimeout(500)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(500)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await page.waitForTimeout(500)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'review', stage: 'review',
headerArguments: { headerArguments: {
@ -3307,7 +3306,7 @@ profile001 = startProfileAt([-20, 20], sketch001)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
await toolbar.openPane('feature-tree') await toolbar.openPane('feature-tree')
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
@ -3387,7 +3386,7 @@ sweep001 = sweep(sketch001, path = sketch002)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 500, y: 250 } const testPoint = { x: 500, y: 250 }
@ -3400,9 +3399,6 @@ sweep001 = sweep(sketch001, path = sketch002)
await test.step(`Go through the Shell flow and fail validation with a toast`, async () => { await test.step(`Go through the Shell flow and fail validation with a toast`, async () => {
await toolbar.shellButton.click() await toolbar.shellButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({ await cmdBar.expectState({
stage: 'arguments', stage: 'arguments',
currentArgKey: 'selection', currentArgKey: 'selection',
@ -3437,29 +3433,26 @@ sweep001 = sweep(sketch001, path = sketch002)
const initialCode = ` const initialCode = `
sketch001 = startSketchOn(XZ) sketch001 = startSketchOn(XZ)
|> startProfileAt([-100.0, 100.0], %) |> startProfileAt([-100.0, 100.0], %)
|> angledLine(angle = 0, length = 200.0, tag = $rectangleSegmentA001) |> angledLine([0, 200.0], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 200, tag = $rectangleSegmentB001) |> angledLine([segAng(rectangleSegmentA001) - 90, 200], %, $rectangleSegmentB001)
|> angledLine( |> angledLine([
angle=segAng(rectangleSegmentA001), segAng(rectangleSegmentA001),
length=-segLen(rectangleSegmentA001), -segLen(rectangleSegmentA001)
tag=$rectangleSegmentC001, ], %, $rectangleSegmentC001)
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude001 = extrude(sketch001, length = 200) extrude001 = extrude(sketch001, length = 200)
sketch002 = startSketchOn(extrude001, rectangleSegmentA001) sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|> startProfileAt([-66.77, 84.81], %) |> startProfileAt([-66.77, 84.81], %)
|> angledLine(angle = 180, length = 27.08, tag = $rectangleSegmentA002) |> angledLine([180, 27.08], %, $rectangleSegmentA002)
|> angledLine( |> angledLine([
angle=segAng(rectangleSegmentA002) - 90, segAng(rectangleSegmentA002) - 90,
length=27.8, 27.8
tag=$rectangleSegmentB002, ], %, $rectangleSegmentB002)
) |> angledLine([
|> angledLine( segAng(rectangleSegmentA002),
angle=segAng(rectangleSegmentA002), -segLen(rectangleSegmentA002)
length=-segLen(rectangleSegmentA002), ], %, $rectangleSegmentC002)
tag=$rectangleSegmentC002,
)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
` `
@ -3469,13 +3462,12 @@ tag=$rectangleSegmentC002,
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// select line of code // select line of code
const codeToSelection = `segAng(rectangleSegmentA002) - 90,` const codeToSelecton = `segAng(rectangleSegmentA002) - 90,`
// revolve // revolve
await editor.scrollToText(codeToSelection) await page.getByText(codeToSelecton).click()
await page.getByText(codeToSelection).click()
await toolbar.revolveButton.click() await toolbar.revolveButton.click()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
@ -3529,32 +3521,35 @@ tag=$rectangleSegmentC002,
}) => { }) => {
const initialCode = `sketch001 = startSketchOn(XZ) const initialCode = `sketch001 = startSketchOn(XZ)
|> startProfileAt([-102.57, 101.72], %) |> startProfileAt([-102.57, 101.72], %)
|> angledLine(angle = 0, length = 202.6, tag = $rectangleSegmentA001) |> angledLine([0, 202.6], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 202.6, tag = $rectangleSegmentB001) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) segAng(rectangleSegmentA001) - 90,
202.6
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude001 = extrude(sketch001, length = 50) extrude001 = extrude(sketch001, length = 50)
sketch002 = startSketchOn(extrude001, rectangleSegmentA001) sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|> circle(center = [-11.34, 10.0], radius = 8.69) |> circle(center = [-11.34, 10.0], radius = 8.69)
` `
await context.addInitScript((initialCode) => { await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode) localStorage.setItem('persistCode', initialCode)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
await scene.settled(cmdBar)
// select line of code // select line of code
const codeToSelection = `center = [-11.34, 10.0]` const codeToSelecton = `center = [-11.34, 10.0]`
// revolve // revolve
await editor.scrollToText(codeToSelection) await page.getByText(codeToSelecton).click()
await page.getByText(codeToSelection).click()
await toolbar.revolveButton.click() await toolbar.revolveButton.click()
await page.getByText('Edge', { exact: true }).click() await page.getByText('Edge', { exact: true }).click()
const lineCodeToSelection = `angledLine(angle = 0, length = 202.6, tag = $rectangleSegmentA001)` const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)`
await page.getByText(lineCodeToSelection).click() await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
@ -3600,7 +3595,6 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
await editor.expectEditor.toContain( await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = angle001') newCodeToFind.replace('angle = 360', 'angle = angle001')
) )
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
}) })
test('revolve sketch circle around line segment from startProfileAt sketch', async ({ test('revolve sketch circle around line segment from startProfileAt sketch', async ({
context, context,
@ -3611,23 +3605,22 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
toolbar, toolbar,
cmdBar, cmdBar,
}) => { }) => {
const initialCode = ` const initialCode = `sketch002 = startSketchOn(XY)
sketch002 = startSketchOn(XY)
|> startProfileAt([-2.02, 1.79], %) |> startProfileAt([-2.02, 1.79], %)
|> xLine(length = 2.6) |> xLine(length = 2.6)
sketch001 = startSketchOn('-XY') sketch001 = startSketchOn(-XY)
|> startProfileAt([-0.48, 1.25], %) |> startProfileAt([-0.48, 1.25], %)
|> angledLine(angle = 0, length = 2.38, tag = $rectangleSegmentA001) |> angledLine([0, 2.38], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 2.4, tag = $rectangleSegmentB001) |> angledLine([segAng(rectangleSegmentA001) - 90, 2.4], %, $rectangleSegmentB001)
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) |> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude001 = extrude(sketch001, length = 5) extrude001 = extrude(sketch001, length = 5)
sketch003 = startSketchOn(extrude001, 'START') sketch003 = startSketchOn(extrude001, 'START')
|> circle( |> circle(center = [-0.69, 0.56], radius = 0.28)
center = [-0.69, 0.56],
radius = 0.28
)
` `
await context.addInitScript((initialCode) => { await context.addInitScript((initialCode) => {
@ -3635,20 +3628,15 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.connectionEstablished() await scene.waitForExecutionDone()
await scene.settled(cmdBar)
// select line of code // select line of code
const codeToSelection = `center = [-0.69, 0.56]` const codeToSelecton = `center = [-0.69, 0.56]`
// revolve // revolve
await page.getByText(codeToSelecton).click()
await toolbar.revolveButton.click() await toolbar.revolveButton.click()
await page.waitForTimeout(1000)
await editor.scrollToText(codeToSelection)
await page.getByText(codeToSelection).click()
await expect.poll(() => page.getByText('AxisOrEdge').count()).toBe(2)
await page.getByText('Edge', { exact: true }).click() await page.getByText('Edge', { exact: true }).click()
const lineCodeToSelection = `length = 2.6` const lineCodeToSelection = `|> xLine(length = 2.6)`
await editor.scrollToText(lineCodeToSelection)
await page.getByText(lineCodeToSelection).click() await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
@ -3715,22 +3703,21 @@ extrude001 = extrude(profile001, length = 100)
}, initialCode) }, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 }) await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
// One dumb hardcoded screen pixel value // One dumb hardcoded screen pixel value
const testPoint = { x: 500, y: 250 } const testPoint = { x: 500, y: 250 }
const initialColor: [number, number, number] = [123, 123, 123] const initialColor: [number, number, number] = [123, 123, 123]
const tolerance = 50
await test.step(`Confirm extrude exists with default appearance`, async () => { await test.step(`Confirm extrude exists with default appearance`, async () => {
await toolbar.closePane('code') await toolbar.closePane('code')
await scene.expectPixelColor(initialColor, testPoint, tolerance) await scene.expectPixelColor(initialColor, testPoint, 15)
}) })
async function setApperanceAndCheck( async function setApperanceAndCheck(
option: string, option: string,
hex: string, hex: string,
shapeColor?: [number, number, number] shapeColor: [number, number, number]
) { ) {
await toolbar.openPane('feature-tree') await toolbar.openPane('feature-tree')
const enterAppearanceFlow = async (stepName: string) => const enterAppearanceFlow = async (stepName: string) =>
@ -3779,9 +3766,7 @@ extrude001 = extrude(profile001, length = 100)
}) })
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree') await toolbar.closePane('feature-tree')
if (shapeColor) { await scene.expectPixelColor(shapeColor, testPoint, 10)
await scene.expectPixelColor(shapeColor, testPoint, tolerance)
}
await toolbar.openPane('code') await toolbar.openPane('code')
if (hex === 'default') { if (hex === 'default') {
const anyAppearanceDeclaration = `|> appearance(` const anyAppearanceDeclaration = `|> appearance(`
@ -3800,17 +3785,16 @@ extrude001 = extrude(profile001, length = 100)
} }
await test.step(`Go through the Set Appearance flow for all options`, async () => { await test.step(`Go through the Set Appearance flow for all options`, async () => {
await setApperanceAndCheck('Red', '#FF0000', [180, 30, 30]) await setApperanceAndCheck('Red', '#FF0000', [180, 0, 0])
// Not checking the scene color every time cause that's not really deterministic. Red seems reliable though await setApperanceAndCheck('Green', '#00FF00', [0, 180, 0])
await setApperanceAndCheck('Green', '#00FF00') await setApperanceAndCheck('Blue', '#0000FF', [0, 0, 180])
await setApperanceAndCheck('Blue', '#0000FF') await setApperanceAndCheck('Turquoise', '#00FFFF', [0, 180, 180])
await setApperanceAndCheck('Turquoise', '#00FFFF') await setApperanceAndCheck('Purple', '#FF00FF', [180, 0, 180])
await setApperanceAndCheck('Purple', '#FF00FF') await setApperanceAndCheck('Yellow', '#FFFF00', [180, 180, 0])
await setApperanceAndCheck('Yellow', '#FFFF00') await setApperanceAndCheck('Black', '#000000', [0, 0, 0])
await setApperanceAndCheck('Black', '#000000') await setApperanceAndCheck('Dark Grey', '#080808', [0x33, 0x33, 0x33])
await setApperanceAndCheck('Dark Grey', '#080808') await setApperanceAndCheck('Light Grey', '#D3D3D3', [176, 176, 176])
await setApperanceAndCheck('Light Grey', '#D3D3D3') await setApperanceAndCheck('White', '#FFFFFF', [184, 184, 184])
await setApperanceAndCheck('White', '#FFFFFF')
await setApperanceAndCheck( await setApperanceAndCheck(
'Default (clear appearance)', 'Default (clear appearance)',
'default', 'default',

View File

@ -83,7 +83,7 @@ test(
test( test(
'click help/keybindings from project page', 'click help/keybindings from project page',
{ tag: '@electron' }, { tag: '@electron' },
async ({ scene, cmdBar, context, page }, testInfo) => { async ({ context, page }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'bracket') const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })
@ -95,11 +95,17 @@ test(
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
page.on('console', console.log)
// expect to see the text bracket // expect to see the text bracket
await expect(page.getByText('bracket')).toBeVisible() await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click() await page.getByText('bracket').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
// click ? button // click ? button
await page.getByTestId('help-button').click() await page.getByTestId('help-button').click()
@ -114,7 +120,7 @@ test(
test( test(
'open a file in a project works and renders, open another file in different project with errors, it should clear the scene', 'open a file in a project works and renders, open another file in different project with errors, it should clear the scene',
{ tag: '@electron' }, { tag: '@electron' },
async ({ scene, cmdBar, context, page, editor }, testInfo) => { async ({ context, page, editor }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'bracket') const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })
@ -143,7 +149,24 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [110, 110, 110]), {
timeout: 10_000,
})
.toBeLessThan(20)
}) })
await test.step('Clicking the logo takes us back to the projects page / home', async () => { await test.step('Clicking the logo takes us back to the projects page / home', async () => {
@ -186,7 +209,7 @@ test(
test( test(
'open a file in a project works and renders, open another file in different project that is empty, it should clear the scene', 'open a file in a project works and renders, open another file in different project that is empty, it should clear the scene',
{ tag: '@electron' }, { tag: '@electron' },
async ({ scene, cmdBar, context, page }, testInfo) => { async ({ context, page }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'bracket') const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true }) await fsp.mkdir(bracketDir, { recursive: true })
@ -212,7 +235,24 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
timeout: 10_000,
})
.toBeLessThan(15)
}) })
await test.step('Clicking the logo takes us back to the projects page / home', async () => { await test.step('Clicking the logo takes us back to the projects page / home', async () => {
@ -312,7 +352,7 @@ test(
test( test(
'open a file in a project works and renders, open another file in the same project with errors, it should clear the scene', 'open a file in a project works and renders, open another file in the same project with errors, it should clear the scene',
{ tag: '@electron' }, { tag: '@electron' },
async ({ scene, cmdBar, context, page }, testInfo) => { async ({ context, page }, testInfo) => {
if (runningOnWindows()) { if (runningOnWindows()) {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
} }
@ -340,7 +380,10 @@ test(
await page.getByText('bracket').click() await page.getByText('bracket').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
@ -400,10 +443,10 @@ test(
await expect(page.getByText('broken-code')).toBeVisible() await expect(page.getByText('broken-code')).toBeVisible()
await page.getByText('broken-code').click() await page.getByText('broken-code').click()
// Gotcha: You can not use scene.settled() since the KCL code is going to fail // Gotcha: You can not use scene.waitForExecutionDone() since the KCL code is going to fail
await expect( await expect(page.getByTestId('loading')).not.toBeAttached({
page.getByTestId('model-state-indicator-playing') timeout: 20_000,
).toBeAttached() })
// Gotcha: Scroll to the text content in code mirror because CodeMirror lazy loads DOM content // Gotcha: Scroll to the text content in code mirror because CodeMirror lazy loads DOM content
await editor.scrollToText( await editor.scrollToText(
@ -426,7 +469,7 @@ test.describe('Can export from electron app', () => {
test( test(
`Can export using ${method}`, `Can export using ${method}`,
{ tag: ['@electron', '@skipLocalEngine'] }, { tag: ['@electron', '@skipLocalEngine'] },
async ({ scene, cmdBar, context, page, tronApp }, testInfo) => { async ({ context, page, tronApp }, testInfo) => {
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
@ -456,7 +499,10 @@ test.describe('Can export from electron app', () => {
await page.getByText('bracket').click() await page.getByText('bracket').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect( await expect(
page.getByRole('button', { name: 'Start Sketch' }) page.getByRole('button', { name: 'Start Sketch' })
@ -766,7 +812,7 @@ test.describe(`Project management commands`, () => {
test( test(
`Rename from project page`, `Rename from project page`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page, scene, cmdBar }, testInfo) => { async ({ context, page }, testInfo) => {
const projectName = `my_project_to_rename` const projectName = `my_project_to_rename`
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true }) await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
@ -775,6 +821,7 @@ test.describe(`Project management commands`, () => {
`${dir}/${projectName}/main.kcl` `${dir}/${projectName}/main.kcl`
) )
}) })
const u = await getUtils(page)
// Constants and locators // Constants and locators
const projectHomeLink = page.getByTestId('project-link') const projectHomeLink = page.getByTestId('project-link')
@ -796,7 +843,7 @@ test.describe(`Project management commands`, () => {
page.on('console', console.log) page.on('console', console.log)
await projectHomeLink.click() await projectHomeLink.click()
await scene.settled(cmdBar) await u.waitForPageLoad()
}) })
await test.step(`Run rename command via command palette`, async () => { await test.step(`Run rename command via command palette`, async () => {
@ -835,6 +882,7 @@ test.describe(`Project management commands`, () => {
`${dir}/${projectName}/main.kcl` `${dir}/${projectName}/main.kcl`
) )
}) })
const u = await getUtils(page)
// Constants and locators // Constants and locators
const projectHomeLink = page.getByTestId('project-link') const projectHomeLink = page.getByTestId('project-link')
@ -852,9 +900,9 @@ test.describe(`Project management commands`, () => {
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
page.on('console', console.log) page.on('console', console.log)
await page.waitForTimeout(3000)
await projectHomeLink.click() await projectHomeLink.click()
await u.waitForPageLoad()
await scene.connectionEstablished()
await scene.settled(cmdBar) await scene.settled(cmdBar)
}) })
@ -878,7 +926,7 @@ test.describe(`Project management commands`, () => {
test( test(
`Rename from home page`, `Rename from home page`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page, homePage, scene, cmdBar }, testInfo) => { async ({ context, page, homePage }, testInfo) => {
const projectName = `my_project_to_rename` const projectName = `my_project_to_rename`
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true }) await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
@ -934,7 +982,7 @@ test.describe(`Project management commands`, () => {
test( test(
`Delete from home page`, `Delete from home page`,
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page, scene, cmdBar }, testInfo) => { async ({ context, page }, testInfo) => {
const projectName = `my_project_to_delete` const projectName = `my_project_to_delete`
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true }) await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
@ -985,7 +1033,6 @@ test.describe(`Project management commands`, () => {
homePage, homePage,
toolbar, toolbar,
cmdBar, cmdBar,
scene,
}) => { }) => {
const projectName = 'test-project' const projectName = 'test-project'
await test.step(`Setup`, async () => { await test.step(`Setup`, async () => {
@ -1025,11 +1072,10 @@ test.describe(`Project management commands`, () => {
}) })
await cmdBar.argumentInput.fill(projectName) await cmdBar.argumentInput.fill(projectName)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await scene.settled(cmdBar)
await toolbar.logoLink.click()
}) })
await test.step(`Check the project was created with a non-colliding name`, async () => { await test.step(`Check the project was created with a non-colliding name`, async () => {
await toolbar.logoLink.click()
await homePage.expectState({ await homePage.expectState({
projectCards: [ projectCards: [
{ {
@ -1060,11 +1106,10 @@ test.describe(`Project management commands`, () => {
}) })
await cmdBar.argumentInput.fill(projectName) await cmdBar.argumentInput.fill(projectName)
await cmdBar.progressCmdBar() await cmdBar.progressCmdBar()
await scene.settled(cmdBar)
await toolbar.logoLink.click()
}) })
await test.step(`Check the second project was created with a non-colliding name`, async () => { await test.step(`Check the second project was created with a non-colliding name`, async () => {
await toolbar.logoLink.click()
await homePage.expectState({ await homePage.expectState({
projectCards: [ projectCards: [
{ {
@ -1150,7 +1195,7 @@ test(
test( test(
'Nested directories in project without main.kcl do not create main.kcl', 'Nested directories in project without main.kcl do not create main.kcl',
{ tag: '@electron' }, { tag: '@electron' },
async ({ scene, cmdBar, context, page }, testInfo) => { async ({ context, page }, testInfo) => {
let testDir: string | undefined let testDir: string | undefined
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
await fsp.mkdir(path.join(dir, 'router-template-slate', 'nested'), { await fsp.mkdir(path.join(dir, 'router-template-slate', 'nested'), {
@ -1173,7 +1218,10 @@ test(
await test.step('Open the project', async () => { await test.step('Open the project', async () => {
await page.getByText('router-template-slate').click() await page.getByText('router-template-slate').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
// It actually loads. // It actually loads.
await expect(u.codeLocator).toContainText('mounting bracket') await expect(u.codeLocator).toContainText('mounting bracket')
@ -1286,7 +1334,7 @@ test(
test( test(
'Can load a file with CRLF line endings', 'Can load a file with CRLF line endings',
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page, scene, cmdBar }, testInfo) => { async ({ context, page }, testInfo) => {
if (runningOnWindows()) { if (runningOnWindows()) {
test.fixme(orRunWhenFullSuiteEnabled()) test.fixme(orRunWhenFullSuiteEnabled())
} }
@ -1309,8 +1357,13 @@ test(
const u = await getUtils(page) const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
page.on('console', console.log)
await page.getByText('router-template-slate').click() await page.getByText('router-template-slate').click()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(u.codeLocator).toContainText('routerDiameter') await expect(u.codeLocator).toContainText('routerDiameter')
await expect(u.codeLocator).toContainText('templateGap') await expect(u.codeLocator).toContainText('templateGap')
@ -1525,7 +1578,7 @@ extrude001 = extrude(sketch001, length = 200)`)
test( test(
'Opening a project should successfully load the stream, (regression test that this also works when switching between projects)', 'Opening a project should successfully load the stream, (regression test that this also works when switching between projects)',
{ tag: '@electron' }, { tag: '@electron' },
async ({ context, page, cmdBar, homePage, scene }, testInfo) => { async ({ context, page, cmdBar, homePage }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
await fsp.mkdir(path.join(dir, 'router-template-slate'), { await fsp.mkdir(path.join(dir, 'router-template-slate'), {
recursive: true, recursive: true,
@ -1554,10 +1607,13 @@ test(
path.join(dir, 'bracket', 'main.kcl') path.join(dir, 'bracket', 'main.kcl')
) )
}) })
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
page.on('console', console.log) page.on('console', console.log)
const pointOnModel = { x: 630, y: 280 }
await test.step('Opening the bracket project via command palette should load the stream', async () => { await test.step('Opening the bracket project via command palette should load the stream', async () => {
await homePage.expectState({ await homePage.expectState({
projectCards: [ projectCards: [
@ -1591,7 +1647,15 @@ test(
stage: 'commandBarClosed', stage: 'commandBarClosed',
}) })
await scene.settled(cmdBar) await u.waitForPageLoad()
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
timeout: 10_000,
})
.toBeLessThan(15)
}) })
await test.step('Clicking the logo takes us back to the projects page / home', async () => { await test.step('Clicking the logo takes us back to the projects page / home', async () => {
@ -1608,7 +1672,15 @@ test(
await page.getByText('router-template-slate').click() await page.getByText('router-template-slate').click()
await scene.settled(cmdBar) await u.waitForPageLoad()
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), {
timeout: 10_000,
})
.toBeLessThan(15)
}) })
await test.step('The projects on the home page should still be normal', async () => { await test.step('The projects on the home page should still be normal', async () => {
@ -1661,6 +1733,8 @@ test(
}) })
await page.setBodyDimensions({ width: 1200, height: 500 }) await page.setBodyDimensions({ width: 1200, height: 500 })
page.on('console', console.log)
// we'll grab this from the settings on screen before we switch // we'll grab this from the settings on screen before we switch
let originalProjectDirName: string let originalProjectDirName: string
const newProjectDirName = testInfo.outputPath( const newProjectDirName = testInfo.outputPath(
@ -1801,7 +1875,7 @@ test(
test( test(
'file pane is scrollable when there are many files', 'file pane is scrollable when there are many files',
{ tag: '@electron' }, { tag: '@electron' },
async ({ scene, cmdBar, context, page }, testInfo) => { async ({ context, page }, testInfo) => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
const testDir = path.join(dir, 'testProject') const testDir = path.join(dir, 'testProject')
await fsp.mkdir(testDir, { recursive: true }) await fsp.mkdir(testDir, { recursive: true })
@ -1880,8 +1954,10 @@ test(
await test.step('setup, open file pane', async () => { await test.step('setup, open file pane', async () => {
await page.getByText('testProject').click() await page.getByText('testProject').click()
await expect(page.getByTestId('loading')).toBeAttached()
await scene.settled(cmdBar) await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await page.getByTestId('files-pane-button').click() await page.getByTestId('files-pane-button').click()
}) })

View File

@ -41,13 +41,15 @@ sketch002 = startSketchOn(XZ)
extrude002 = extrude(sketch002, length = 50) extrude002 = extrude(sketch002, length = 50)
sketch003 = startSketchOn(XY) sketch003 = startSketchOn(XY)
|> startProfileAt([52.92, 157.81], %) |> startProfileAt([52.92, 157.81], %)
|> angledLine(angle = 0, length = 176.4, tag = $rectangleSegmentA001) |> angledLine([0, 176.4], %, $rectangleSegmentA001)
|> angledLine( |> angledLine([
angle = segAng(rectangleSegmentA001) - 90, segAng(rectangleSegmentA001) - 90,
length = 53.4, 53.4
tag = $rectangleSegmentB001, ], %, $rectangleSegmentB001)
) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude003 = extrude(sketch003, length = 20) extrude003 = extrude(sketch003, length = 20)
@ -61,7 +63,7 @@ test.describe('edit with AI example snapshots', () => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
const body1CapCoords = { x: 571, y: 351 } const body1CapCoords = { x: 571, y: 351 }
const [clickBody1Cap] = scene.makeMouseHelpers( const [clickBody1Cap] = scene.makeMouseHelpers(
@ -72,6 +74,7 @@ test.describe('edit with AI example snapshots', () => {
const submittingToast = page.getByText('Submitting to Text-to-CAD API...') const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
await test.step('wait for scene to load select body and check selection came through', async () => { 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 clickBody1Cap()
await scene.expectPixelColor(yellow, body1CapCoords, 20) await scene.expectPixelColor(yellow, body1CapCoords, 20)
await editor.expectState({ await editor.expectState({

View File

@ -22,9 +22,15 @@ sketch002 = startSketchOn(XZ)
extrude002 = extrude(sketch002, length = 50) extrude002 = extrude(sketch002, length = 50)
sketch003 = startSketchOn(XY) sketch003 = startSketchOn(XY)
|> startProfileAt([52.92, 157.81], %) |> startProfileAt([52.92, 157.81], %)
|> angledLine(angle = 0, length = 176.4, tag = $rectangleSegmentA001) |> angledLine([0, 176.4], %, $rectangleSegmentA001)
|> angledLine(angle = segAng(rectangleSegmentA001) - 90, length = 53.4, tag = $rectangleSegmentB001) |> angledLine([
|> angledLine(angle = segAng(rectangleSegmentA001), length = -segLen(rectangleSegmentA001), tag = $rectangleSegmentC001) segAng(rectangleSegmentA001) - 90,
53.4
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)]) |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close() |> close()
extrude003 = extrude(sketch003, length = 20) extrude003 = extrude(sketch003, length = 20)
@ -51,12 +57,11 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
page, page,
scene, scene,
}) => { }) => {
test.fixme(orRunWhenFullSuiteEnabled())
await context.addInitScript((file) => { await context.addInitScript((file) => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
const body1CapCoords = { x: 571, y: 311 } const body1CapCoords = { x: 571, y: 311 }
const greenCheckCoords = { x: 565, y: 305 } const greenCheckCoords = { x: 565, y: 305 }
@ -151,7 +156,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
const body1CapCoords = { x: 571, y: 311 } const body1CapCoords = { x: 571, y: 311 }
const [clickBody1Cap] = scene.makeMouseHelpers( const [clickBody1Cap] = scene.makeMouseHelpers(
@ -207,7 +212,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
const submittingToast = page.getByText('Submitting to Text-to-CAD API...') const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
const successToast = page.getByText('Prompt to edit successful') const successToast = page.getByText('Prompt to edit successful')
@ -260,7 +265,6 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
page, page,
scene, scene,
}) => { }) => {
test.fixme(orRunWhenFullSuiteEnabled())
const body1CapCoords = { x: 571, y: 311 } const body1CapCoords = { x: 571, y: 311 }
const body2WallCoords = { x: 620, y: 152 } const body2WallCoords = { x: 620, y: 152 }
const [clickBody1Cap] = scene.makeMouseHelpers( const [clickBody1Cap] = scene.makeMouseHelpers(
@ -277,7 +281,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)
await homePage.goToModelingScene() await homePage.goToModelingScene()
await scene.settled(cmdBar) await scene.waitForExecutionDone()
const submittingToast = page.getByText('Submitting to Text-to-CAD API...') const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
const successToast = page.getByText('Prompt to edit successful') const successToast = page.getByText('Prompt to edit successful')

Some files were not shown because too many files have changed in this diff Show More