Compare commits
3 Commits
v0.24.11
...
jtran/requ
Author | SHA1 | Date | |
---|---|---|---|
7b46656c0f | |||
6c79b15adf | |||
b45aa89d16 |
@ -1,3 +1,3 @@
|
|||||||
[codespell]
|
[codespell]
|
||||||
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue,afterall
|
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue
|
||||||
skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,./src-tauri/gen/schemas
|
skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,./src-tauri/gen/schemas
|
||||||
|
48
.github/workflows/ci.yml
vendored
@ -20,11 +20,6 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
actions: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-format:
|
check-format:
|
||||||
runs-on: 'ubuntu-latest'
|
runs-on: 'ubuntu-latest'
|
||||||
@ -89,43 +84,8 @@ jobs:
|
|||||||
- run: yarn build:wasm
|
- run: yarn build:wasm
|
||||||
|
|
||||||
- run: yarn simpleserver:ci
|
- run: yarn simpleserver:ci
|
||||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
|
||||||
|
|
||||||
- name: Install Chromium Browser
|
|
||||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
|
||||||
run: yarn playwright install chromium --with-deps
|
|
||||||
|
|
||||||
- name: run unit tests
|
|
||||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
|
||||||
run: yarn test:nowatch
|
|
||||||
env:
|
|
||||||
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
|
||||||
|
|
||||||
- name: check for changes
|
|
||||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
|
||||||
id: git-check
|
|
||||||
run: |
|
|
||||||
git add src/lang/std/artifactMapGraphs
|
|
||||||
if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed"
|
|
||||||
then echo "modified=true" >> $GITHUB_OUTPUT
|
|
||||||
else echo "modified=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
- name: Commit changes, if any
|
|
||||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }}
|
|
||||||
run: |
|
|
||||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --local user.name "github-actions[bot]"
|
|
||||||
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
|
||||||
git fetch origin
|
|
||||||
echo ${{ github.head_ref }}
|
|
||||||
git checkout ${{ github.head_ref }}
|
|
||||||
# TODO when webkit works on ubuntu remove the os part of the commit message
|
|
||||||
git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true
|
|
||||||
git push
|
|
||||||
git push origin ${{ github.head_ref }}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- run: yarn test:nowatch
|
||||||
|
|
||||||
|
|
||||||
prepare-json-files:
|
prepare-json-files:
|
||||||
@ -535,7 +495,7 @@ jobs:
|
|||||||
project_id: kittycadapi
|
project_id: kittycadapi
|
||||||
|
|
||||||
- name: Upload release files to public bucket
|
- name: Upload release files to public bucket
|
||||||
uses: google-github-actions/upload-cloud-storage@v2.1.1
|
uses: google-github-actions/upload-cloud-storage@v2.1.0
|
||||||
with:
|
with:
|
||||||
path: artifact
|
path: artifact
|
||||||
glob: '*/Zoo*'
|
glob: '*/Zoo*'
|
||||||
@ -543,13 +503,13 @@ jobs:
|
|||||||
destination: ${{ env.BUCKET_DIR }}/${{ env.VERSION }}
|
destination: ${{ env.BUCKET_DIR }}/${{ env.VERSION }}
|
||||||
|
|
||||||
- name: Upload update endpoint to public bucket
|
- name: Upload update endpoint to public bucket
|
||||||
uses: google-github-actions/upload-cloud-storage@v2.1.1
|
uses: google-github-actions/upload-cloud-storage@v2.1.0
|
||||||
with:
|
with:
|
||||||
path: last_update.json
|
path: last_update.json
|
||||||
destination: ${{ env.BUCKET_DIR }}
|
destination: ${{ env.BUCKET_DIR }}
|
||||||
|
|
||||||
- name: Upload download endpoint to public bucket
|
- name: Upload download endpoint to public bucket
|
||||||
uses: google-github-actions/upload-cloud-storage@v2.1.1
|
uses: google-github-actions/upload-cloud-storage@v2.1.0
|
||||||
with:
|
with:
|
||||||
path: last_download.json
|
path: last_download.json
|
||||||
destination: ${{ env.BUCKET_DIR }}
|
destination: ${{ env.BUCKET_DIR }}
|
||||||
|
49
.github/workflows/generate-machine-api-types.yml
vendored
@ -1,49 +0,0 @@
|
|||||||
name: generate machine-api types
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'openapi/machine-api.json'
|
|
||||||
- '.github/workflows/generate-machine-api-types.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
jobs:
|
|
||||||
generate:
|
|
||||||
runs-on: 'ubuntu-latest'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version-file: '.nvmrc'
|
|
||||||
cache: 'yarn'
|
|
||||||
- run: yarn install
|
|
||||||
- run: yarn generate:machine-api
|
|
||||||
- run: yarn fmt
|
|
||||||
- name: check for changes
|
|
||||||
id: git-check
|
|
||||||
run: |
|
|
||||||
git add .
|
|
||||||
if git status | grep -q "Changes to be committed"
|
|
||||||
then echo "modified=true" >> $GITHUB_OUTPUT
|
|
||||||
else echo "modified=false" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
- name: Commit changes, if any
|
|
||||||
if: steps.git-check.outputs.modified == 'true'
|
|
||||||
run: |
|
|
||||||
git add .
|
|
||||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --local user.name "github-actions[bot]"
|
|
||||||
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
|
||||||
git fetch origin
|
|
||||||
echo ${{ github.head_ref }}
|
|
||||||
git checkout ${{ github.head_ref }}
|
|
||||||
git commit -am "New machine-api types" || true
|
|
||||||
git push
|
|
||||||
git push origin ${{ github.head_ref }}
|
|
||||||
|
|
51
.github/workflows/playwright.yml
vendored
@ -34,13 +34,8 @@ jobs:
|
|||||||
- 'src/wasm-lib/**'
|
- 'src/wasm-lib/**'
|
||||||
|
|
||||||
playwright-ubuntu:
|
playwright-ubuntu:
|
||||||
timeout-minutes: 30
|
timeout-minutes: 60
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest-8-cores
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
shardIndex: [1, 2, 3, 4]
|
|
||||||
shardTotal: [4]
|
|
||||||
needs: check-rust-changes
|
needs: check-rust-changes
|
||||||
steps:
|
steps:
|
||||||
- name: Tune GitHub-hosted runner network
|
- name: Tune GitHub-hosted runner network
|
||||||
@ -111,19 +106,13 @@ jobs:
|
|||||||
- name: build web
|
- name: build web
|
||||||
run: yarn build:local
|
run: yarn build:local
|
||||||
- name: Run ubuntu/chrome snapshots
|
- name: Run ubuntu/chrome snapshots
|
||||||
|
continue-on-error: true
|
||||||
run: |
|
run: |
|
||||||
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --retries="3" --update-snapshots --grep=@snapshot --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
yarn playwright test --project="Google Chrome" --update-snapshots e2e/playwright/snapshot-tests.spec.ts
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
|
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: playwright-report-ubuntu-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
|
|
||||||
path: playwright-report/
|
|
||||||
retention-days: 30
|
|
||||||
overwrite: true
|
|
||||||
- name: Clean up test-results
|
- name: Clean up test-results
|
||||||
if: always()
|
if: always()
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@ -154,7 +143,7 @@ jobs:
|
|||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: steps.git-check.outputs.modified == 'true'
|
if: steps.git-check.outputs.modified == 'true'
|
||||||
with:
|
with:
|
||||||
name: playwright-report-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
|
name: playwright-report-ubuntu-${{ github.sha }}
|
||||||
path: playwright-report/
|
path: playwright-report/
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
# if have previous run results, use them
|
# if have previous run results, use them
|
||||||
@ -162,7 +151,7 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
name: test-results-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
|
name: test-results-ubuntu-${{ github.sha }}
|
||||||
path: test-results/
|
path: test-results/
|
||||||
- name: Run ubuntu/chrome flow (with retries)
|
- name: Run ubuntu/chrome flow (with retries)
|
||||||
id: retry
|
id: retry
|
||||||
@ -171,7 +160,7 @@ jobs:
|
|||||||
if [[ ! -f "test-results/.last-run.json" ]]; then
|
if [[ ! -f "test-results/.last-run.json" ]]; then
|
||||||
# if no last run artifact, than run plawright normally
|
# if no last run artifact, than run plawright normally
|
||||||
echo "run playwright normally"
|
echo "run playwright normally"
|
||||||
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --grep-invert=@snapshot || true
|
yarn playwright test --project="Google Chrome" e2e/playwright/flow-tests.spec.ts || true
|
||||||
# # send to axiom
|
# # send to axiom
|
||||||
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
@ -186,7 +175,7 @@ jobs:
|
|||||||
if [[ $failed_tests -gt 0 ]]; then
|
if [[ $failed_tests -gt 0 ]]; then
|
||||||
echo "retried=true" >>$GITHUB_OUTPUT
|
echo "retried=true" >>$GITHUB_OUTPUT
|
||||||
echo "run playwright with last failed tests and retry $retry"
|
echo "run playwright with last failed tests and retry $retry"
|
||||||
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --last-failed --grep-invert=@snapshot || true
|
yarn playwright test --project="Google Chrome" --last-failed e2e/playwright/flow-tests.spec.ts || true
|
||||||
# send to axiom
|
# send to axiom
|
||||||
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
retry=$((retry + 1))
|
retry=$((retry + 1))
|
||||||
@ -221,26 +210,21 @@ jobs:
|
|||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: test-results-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
|
name: test-results-ubuntu-${{ github.sha }}
|
||||||
path: test-results/
|
path: test-results/
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: playwright-report-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
|
name: playwright-report-ubuntu-${{ github.sha }}
|
||||||
path: playwright-report/
|
path: playwright-report/
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
playwright-macos:
|
playwright-macos:
|
||||||
timeout-minutes: 30
|
timeout-minutes: 60
|
||||||
runs-on: macos-14
|
runs-on: macos-14-large
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
shardIndex: [1, 2, 3, 4]
|
|
||||||
shardTotal: [4]
|
|
||||||
needs: check-rust-changes
|
needs: check-rust-changes
|
||||||
steps:
|
steps:
|
||||||
- name: Tune GitHub-hosted runner network
|
- name: Tune GitHub-hosted runner network
|
||||||
@ -316,7 +300,7 @@ jobs:
|
|||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
name: test-results-macos-${{ matrix.shardIndex }}-${{ github.sha }}
|
name: test-results-macos-${{ github.sha }}
|
||||||
path: test-results/
|
path: test-results/
|
||||||
- name: Run macos/safari flow (with retries)
|
- name: Run macos/safari flow (with retries)
|
||||||
id: retry
|
id: retry
|
||||||
@ -325,7 +309,7 @@ jobs:
|
|||||||
if [[ ! -f "test-results/.last-run.json" ]]; then
|
if [[ ! -f "test-results/.last-run.json" ]]; then
|
||||||
# if no last run artifact, than run plawright normally
|
# if no last run artifact, than run plawright normally
|
||||||
echo "run playwright normally"
|
echo "run playwright normally"
|
||||||
yarn playwright test --project="webkit" --config=playwright.ci.config.ts --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --grep-invert=@snapshot || true
|
yarn playwright test --project="webkit" e2e/playwright/flow-tests.spec.ts || true
|
||||||
# # send to axiom
|
# # send to axiom
|
||||||
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
@ -340,7 +324,7 @@ jobs:
|
|||||||
if [[ $failed_tests -gt 0 ]]; then
|
if [[ $failed_tests -gt 0 ]]; then
|
||||||
echo "retried=true" >>$GITHUB_OUTPUT
|
echo "retried=true" >>$GITHUB_OUTPUT
|
||||||
echo "run playwright with last failed tests and retry $retry"
|
echo "run playwright with last failed tests and retry $retry"
|
||||||
yarn playwright test --project="webkit" --config=playwright.ci.config.ts --last-failed --grep-invert=@snapshot || true
|
yarn playwright test --project="webkit" --last-failed e2e/playwright/flow-tests.spec.ts || true
|
||||||
# send to axiom
|
# send to axiom
|
||||||
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
|
||||||
retry=$((retry + 1))
|
retry=$((retry + 1))
|
||||||
@ -370,14 +354,15 @@ jobs:
|
|||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: test-results-macos-${{ matrix.shardIndex }}-${{ github.sha }}
|
name: test-results-macos-${{ github.sha }}
|
||||||
path: test-results/
|
path: test-results/
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
overwrite: true
|
overwrite: true
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: playwright-report-macos-${{ matrix.shardIndex }}-${{ github.sha }}
|
name: playwright-report-macos-${{ github.sha }}
|
||||||
path: playwright-report/
|
path: playwright-report/
|
||||||
retention-days: 30
|
retention-days: 30
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
|
2
.gitignore
vendored
@ -39,7 +39,6 @@ src/wasm-lib/grackle/test_json_output
|
|||||||
e2e/playwright/playwright-secrets.env
|
e2e/playwright/playwright-secrets.env
|
||||||
e2e/playwright/temp1.png
|
e2e/playwright/temp1.png
|
||||||
e2e/playwright/temp2.png
|
e2e/playwright/temp2.png
|
||||||
e2e/playwright/temp3.png
|
|
||||||
# exports from snapshot-tests.spec.ts "exports of each format should work"
|
# exports from snapshot-tests.spec.ts "exports of each format should work"
|
||||||
e2e/playwright/export-snapshots/*
|
e2e/playwright/export-snapshots/*
|
||||||
!e2e/playwright/export-snapshots/*.png
|
!e2e/playwright/export-snapshots/*.png
|
||||||
@ -49,7 +48,6 @@ e2e/playwright/export-snapshots/*
|
|||||||
/playwright-report/
|
/playwright-report/
|
||||||
/blob-report/
|
/blob-report/
|
||||||
/playwright/.cache/
|
/playwright/.cache/
|
||||||
/src/lang/std/artifactMapCache
|
|
||||||
|
|
||||||
|
|
||||||
## generated files
|
## generated files
|
||||||
|
11
README.md
@ -110,17 +110,6 @@ Note that these became separate apps on Macos, so make sure you open the right o
|
|||||||
|
|
||||||
<img width="1232" alt="image (1)" src="https://user-images.githubusercontent.com/29681384/211947073-e76b4933-bef5-4636-bc4d-e930ac8e290f.png">
|
<img width="1232" alt="image (1)" src="https://user-images.githubusercontent.com/29681384/211947073-e76b4933-bef5-4636-bc4d-e930ac8e290f.png">
|
||||||
|
|
||||||
## Checking out commits / Bisecting
|
|
||||||
|
|
||||||
Which commands from setup are one off vs need to be run every time?
|
|
||||||
|
|
||||||
The following will need to be run when checking out a new commit and guarantees the build is not stale:
|
|
||||||
```bash
|
|
||||||
yarn install
|
|
||||||
yarn build:wasm-dev # or yarn build:wasm for slower but more production-like build
|
|
||||||
yarn start # or yarn build:local && yarn serve for slower but more production-like build
|
|
||||||
```
|
|
||||||
|
|
||||||
## Before submitting a PR
|
## Before submitting a PR
|
||||||
|
|
||||||
Before you submit a contribution PR to this repo, please ensure that:
|
Before you submit a contribution PR to this repo, please ensure that:
|
||||||
|
@ -25,5 +25,5 @@ once fixed in engine will just start working here with no language changes.
|
|||||||
|
|
||||||
Sketching on the chamfered face does not currently work.
|
Sketching on the chamfered face does not currently work.
|
||||||
|
|
||||||
- **Shell**: Shell sometimes does not work when arcs or fillets are involved.
|
- **Shell**: Shell is only working for `end` faces, not for `side` or `start`
|
||||||
We are tracking the engine side bug on this.
|
faces. We are tracking the engine side bug on this.
|
||||||
|
@ -21,7 +21,6 @@ layout: manual
|
|||||||
* [`arc`](kcl/arc)
|
* [`arc`](kcl/arc)
|
||||||
* [`asin`](kcl/asin)
|
* [`asin`](kcl/asin)
|
||||||
* [`assert`](kcl/assert)
|
* [`assert`](kcl/assert)
|
||||||
* [`assertEqual`](kcl/assertEqual)
|
|
||||||
* [`assertGreaterThan`](kcl/assertGreaterThan)
|
* [`assertGreaterThan`](kcl/assertGreaterThan)
|
||||||
* [`assertGreaterThanOrEq`](kcl/assertGreaterThanOrEq)
|
* [`assertGreaterThanOrEq`](kcl/assertGreaterThanOrEq)
|
||||||
* [`assertLessThan`](kcl/assertLessThan)
|
* [`assertLessThan`](kcl/assertLessThan)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
title: "legAngX"
|
title: "legAngX"
|
||||||
excerpt: "Compute the angle of the given leg for x."
|
excerpt: "Returns the angle of the given leg for x."
|
||||||
layout: manual
|
layout: manual
|
||||||
---
|
---
|
||||||
|
|
||||||
Compute the angle of the given leg for x.
|
Returns the angle of the given leg for x.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
title: "legAngY"
|
title: "legAngY"
|
||||||
excerpt: "Compute the angle of the given leg for y."
|
excerpt: "Returns the angle of the given leg for y."
|
||||||
layout: manual
|
layout: manual
|
||||||
---
|
---
|
||||||
|
|
||||||
Compute the angle of the given leg for y.
|
Returns the angle of the given leg for y.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
title: "legLen"
|
title: "legLen"
|
||||||
excerpt: "Compute the length of the given leg."
|
excerpt: "Returns the length of the given leg."
|
||||||
layout: manual
|
layout: manual
|
||||||
---
|
---
|
||||||
|
|
||||||
Compute the length of the given leg.
|
Returns the length of the given leg.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3736
docs/kcl/std.json
@ -1,153 +0,0 @@
|
|||||||
import { test, expect, Page } from '@playwright/test'
|
|
||||||
import {
|
|
||||||
getUtils,
|
|
||||||
TEST_COLORS,
|
|
||||||
setup,
|
|
||||||
tearDown,
|
|
||||||
commonPoints,
|
|
||||||
PERSIST_MODELING_CONTEXT,
|
|
||||||
} from './test-utils'
|
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }) => {
|
|
||||||
await setup(context, page)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
|
||||||
await tearDown(page, testInfo)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.setTimeout(120000)
|
|
||||||
|
|
||||||
async function doBasicSketch(page: Page, openPanes: string[]) {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
await u.openDebugPanel()
|
|
||||||
|
|
||||||
// If we have the code pane open, we should see the code.
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
await expect(u.codeLocator).toHaveText(``)
|
|
||||||
} else {
|
|
||||||
// Ensure we don't see the code.
|
|
||||||
await expect(u.codeLocator).not.toBeVisible()
|
|
||||||
}
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
).not.toBeDisabled()
|
|
||||||
await expect(page.getByRole('button', { name: 'Start Sketch' })).toBeVisible()
|
|
||||||
|
|
||||||
// click on "Start Sketch" button
|
|
||||||
await u.clearCommandLogs()
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
|
|
||||||
// select a plane
|
|
||||||
await page.mouse.click(700, 200)
|
|
||||||
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
await expect(u.codeLocator).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XZ')`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
await page.waitForTimeout(1000) // TODO detect animation ending, or disable animation
|
|
||||||
|
|
||||||
const startXPx = 600
|
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
await expect(u.codeLocator)
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)`)
|
|
||||||
}
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
await expect(u.codeLocator)
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|
||||||
|> line([${commonPoints.num1}, 0], %)`)
|
|
||||||
}
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
await expect(u.codeLocator)
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|
||||||
|> line([0, ${commonPoints.num1 + 0.01}], %)`)
|
|
||||||
} else {
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
}
|
|
||||||
await page.mouse.click(startXPx, 500 - PUR * 20)
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
await expect(u.codeLocator)
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|
||||||
|> line([${commonPoints.num1}, 0], %)
|
|
||||||
|> line([0, ${commonPoints.num1 + 0.01}], %)
|
|
||||||
|> line([-${commonPoints.num2}, 0], %)`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// deselect line tool
|
|
||||||
await page.getByRole('button', { name: 'Line', exact: true }).click()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
|
|
||||||
const line1 = await u.getSegmentBodyCoords(`[data-overlay-index="${0}"]`, 0)
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
expect(await u.getGreatestPixDiff(line1, TEST_COLORS.WHITE)).toBeLessThan(3)
|
|
||||||
await expect(
|
|
||||||
await u.getGreatestPixDiff(line1, [249, 249, 249])
|
|
||||||
).toBeLessThan(3)
|
|
||||||
}
|
|
||||||
// click between first two clicks to get center of the line
|
|
||||||
await page.mouse.click(startXPx + PUR * 15, 500 - PUR * 10)
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
expect(await u.getGreatestPixDiff(line1, TEST_COLORS.BLUE)).toBeLessThan(3)
|
|
||||||
await expect(await u.getGreatestPixDiff(line1, [0, 0, 255])).toBeLessThan(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
// hold down shift
|
|
||||||
await page.keyboard.down('Shift')
|
|
||||||
// click between the latest two clicks to get center of the line
|
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 20)
|
|
||||||
|
|
||||||
// selected two lines therefore there should be two cursors
|
|
||||||
if (openPanes.includes('code')) {
|
|
||||||
await expect(page.locator('.cm-cursor')).toHaveCount(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Length: open menu' }).click()
|
|
||||||
await page.getByRole('button', { name: 'Equal Length' }).click()
|
|
||||||
|
|
||||||
// Open the code pane.
|
|
||||||
await u.openKclCodePanel()
|
|
||||||
await expect(u.codeLocator).toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt(${commonPoints.startAt}, %)
|
|
||||||
|> line([${commonPoints.num1}, 0], %, $seg01)
|
|
||||||
|> line([0, ${commonPoints.num1 + 0.01}], %)
|
|
||||||
|> angledLine([180, segLen(seg01)], %)`)
|
|
||||||
}
|
|
||||||
|
|
||||||
test.describe('Basic sketch', () => {
|
|
||||||
test('code pane open at start', async ({ page }) => {
|
|
||||||
await doBasicSketch(page, ['code'])
|
|
||||||
})
|
|
||||||
|
|
||||||
test('code pane closed at start', async ({ page }) => {
|
|
||||||
// Load the app with the code panes
|
|
||||||
await page.addInitScript(async (persistModelingContext) => {
|
|
||||||
localStorage.setItem(
|
|
||||||
persistModelingContext,
|
|
||||||
JSON.stringify({ openPanes: [] })
|
|
||||||
)
|
|
||||||
}, PERSIST_MODELING_CONTEXT)
|
|
||||||
await doBasicSketch(page, [])
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,111 +0,0 @@
|
|||||||
import { test, expect } from '@playwright/test'
|
|
||||||
import { getUtils, setup, tearDown } from './test-utils'
|
|
||||||
import { EngineCommand } from 'lang/std/artifactGraph'
|
|
||||||
import { uuidv4 } from 'lib/utils'
|
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }) => {
|
|
||||||
await setup(context, page)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
|
||||||
await tearDown(page, testInfo)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.describe('Can create sketches on all planes and their back sides', () => {
|
|
||||||
const sketchOnPlaneAndBackSideTest = async (
|
|
||||||
page: any,
|
|
||||||
plane: string,
|
|
||||||
clickCoords: { x: number; y: number }
|
|
||||||
) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
await u.openDebugPanel()
|
|
||||||
|
|
||||||
const coord =
|
|
||||||
plane === '-XY' || plane === '-YZ' || plane === 'XZ' ? -100 : 100
|
|
||||||
const camCommand: EngineCommand = {
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd_id: uuidv4(),
|
|
||||||
cmd: {
|
|
||||||
type: 'default_camera_look_at',
|
|
||||||
center: { x: 0, y: 0, z: 0 },
|
|
||||||
vantage: { x: coord, y: coord, z: coord },
|
|
||||||
up: { x: 0, y: 0, z: 1 },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const updateCamCommand: EngineCommand = {
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd_id: uuidv4(),
|
|
||||||
cmd: {
|
|
||||||
type: 'default_camera_get_settings',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const code = `const sketch001 = startSketchOn('${plane}')
|
|
||||||
|> startProfileAt([0.9, -1.22], %)`
|
|
||||||
|
|
||||||
await u.openDebugPanel()
|
|
||||||
|
|
||||||
await u.clearCommandLogs()
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
|
||||||
|
|
||||||
await u.sendCustomCmd(camCommand)
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await u.sendCustomCmd(updateCamCommand)
|
|
||||||
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
await page.mouse.click(clickCoords.x, clickCoords.y)
|
|
||||||
await page.waitForTimeout(300) // wait for animation
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Line', exact: true })
|
|
||||||
).toBeVisible()
|
|
||||||
|
|
||||||
// draw a line
|
|
||||||
const startXPx = 600
|
|
||||||
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(code)
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Line', exact: true }).click()
|
|
||||||
await u.openAndClearDebugPanel()
|
|
||||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
|
|
||||||
await u.clearCommandLogs()
|
|
||||||
await u.removeCurrentCode()
|
|
||||||
}
|
|
||||||
test('XY', async ({ page }) => {
|
|
||||||
await sketchOnPlaneAndBackSideTest(
|
|
||||||
page,
|
|
||||||
'XY',
|
|
||||||
{ x: 600, y: 388 } // red plane
|
|
||||||
// { x: 600, y: 400 }, // red plane // clicks grid helper and that causes problems, should fix so that these coords work too.
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('YZ', async ({ page }) => {
|
|
||||||
await sketchOnPlaneAndBackSideTest(page, 'YZ', { x: 700, y: 250 }) // green plane
|
|
||||||
})
|
|
||||||
|
|
||||||
test('XZ', async ({ page }) => {
|
|
||||||
await sketchOnPlaneAndBackSideTest(page, '-XZ', { x: 700, y: 80 }) // blue plane
|
|
||||||
})
|
|
||||||
|
|
||||||
test('-XY', async ({ page }) => {
|
|
||||||
await sketchOnPlaneAndBackSideTest(page, '-XY', { x: 600, y: 118 }) // back of red plane
|
|
||||||
})
|
|
||||||
|
|
||||||
test('-YZ', async ({ page }) => {
|
|
||||||
await sketchOnPlaneAndBackSideTest(page, '-YZ', { x: 700, y: 219 }) // back of green plane
|
|
||||||
})
|
|
||||||
|
|
||||||
test('-XZ', async ({ page }) => {
|
|
||||||
await sketchOnPlaneAndBackSideTest(page, 'XZ', { x: 700, y: 427 }) // back of blue plane
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,219 +0,0 @@
|
|||||||
import { test, expect } from '@playwright/test'
|
|
||||||
|
|
||||||
import { getUtils, setup, tearDown } from './test-utils'
|
|
||||||
import { bracket } from 'lib/exampleKcl'
|
|
||||||
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from './storageStates'
|
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }) => {
|
|
||||||
await setup(context, page)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
|
||||||
await tearDown(page, testInfo)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.describe('Code pane and errors', () => {
|
|
||||||
test('Typing KCL errors induces a badge on the code pane button', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
|
|
||||||
// Load the app with the working starter code
|
|
||||||
await page.addInitScript((code) => {
|
|
||||||
localStorage.setItem('persistCode', code)
|
|
||||||
}, bracket)
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// wait for execution done
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// Ensure no badge is present
|
|
||||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
|
||||||
await expect(codePaneButtonHolder).not.toContainText('notification')
|
|
||||||
|
|
||||||
// Delete a character to break the KCL
|
|
||||||
await u.openKclCodePanel()
|
|
||||||
await page.getByText('extrude(').click()
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
|
|
||||||
// Ensure that a badge appears on the button
|
|
||||||
await expect(codePaneButtonHolder).toContainText('notification')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Opening and closing the code pane will consistently show error diagnostics', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
|
|
||||||
// Load the app with the working starter code
|
|
||||||
await page.addInitScript((code) => {
|
|
||||||
localStorage.setItem('persistCode', code)
|
|
||||||
}, bracket)
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1200, height: 900 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// wait for execution done
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// Ensure we have no errors in the gutter.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
// Ensure no badge is present
|
|
||||||
const codePaneButton = page.getByRole('button', { name: 'KCL Code pane' })
|
|
||||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
|
||||||
await expect(codePaneButtonHolder).not.toContainText('notification')
|
|
||||||
|
|
||||||
// Delete a character to break the KCL
|
|
||||||
await u.openKclCodePanel()
|
|
||||||
await page.getByText('extrude(').click()
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
|
|
||||||
// Ensure that a badge appears on the button
|
|
||||||
await expect(codePaneButtonHolder).toContainText('notification')
|
|
||||||
|
|
||||||
// Ensure we have an error diagnostic.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
||||||
|
|
||||||
// error text on hover
|
|
||||||
await page.hover('.cm-lint-marker-error')
|
|
||||||
await expect(page.getByText('Unexpected token').first()).toBeVisible()
|
|
||||||
|
|
||||||
// Close the code pane
|
|
||||||
await codePaneButton.click()
|
|
||||||
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
|
|
||||||
// Ensure that a badge appears on the button
|
|
||||||
await expect(codePaneButtonHolder).toContainText('notification')
|
|
||||||
// Ensure we have no errors in the gutter.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
// Open the code pane
|
|
||||||
await u.openKclCodePanel()
|
|
||||||
|
|
||||||
// Ensure that a badge appears on the button
|
|
||||||
await expect(codePaneButtonHolder).toContainText('notification')
|
|
||||||
|
|
||||||
// Ensure we have an error diagnostic.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
||||||
|
|
||||||
// error text on hover
|
|
||||||
await page.hover('.cm-lint-marker-error')
|
|
||||||
await expect(page.getByText('Unexpected token').first()).toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('When error is not in view you can click the badge to scroll to it', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
|
|
||||||
// Load the app with the working starter code
|
|
||||||
await page.addInitScript((code) => {
|
|
||||||
localStorage.setItem('persistCode', code)
|
|
||||||
}, TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW)
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await page.waitForTimeout(1000)
|
|
||||||
|
|
||||||
// Ensure badge is present
|
|
||||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
|
||||||
await expect(codePaneButtonHolder).toContainText('notification')
|
|
||||||
|
|
||||||
// Ensure we have no errors in the gutter, since error out of view.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
// Click the badge.
|
|
||||||
const badge = page.locator('#code-badge')
|
|
||||||
await expect(badge).toBeVisible()
|
|
||||||
await badge.click()
|
|
||||||
|
|
||||||
// Ensure we have an error diagnostic.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
|
|
||||||
|
|
||||||
// Hover over the error to see the error message
|
|
||||||
await page.hover('.cm-lint-marker-error')
|
|
||||||
await expect(
|
|
||||||
page
|
|
||||||
.getByText(
|
|
||||||
'sketch profile must lie entirely on one side of the revolution axis'
|
|
||||||
)
|
|
||||||
.first()
|
|
||||||
).toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
|
|
||||||
// Load the app with the working starter code
|
|
||||||
await page.addInitScript((code) => {
|
|
||||||
localStorage.setItem('persistCode', code)
|
|
||||||
}, TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW)
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await page.waitForTimeout(1000)
|
|
||||||
|
|
||||||
// Ensure badge is present
|
|
||||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
|
||||||
await expect(codePaneButtonHolder).toContainText('notification')
|
|
||||||
|
|
||||||
// Ensure we have no errors in the gutter, since error out of view.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
// click in the editor to focus it
|
|
||||||
await page.locator('.cm-content').click()
|
|
||||||
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
|
|
||||||
// go to the start of the editor and enter more text which will trigger
|
|
||||||
// a lint error.
|
|
||||||
// GO to the start of the editor.
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await page.keyboard.press('Home')
|
|
||||||
await page.keyboard.type('const foo_bar = 1')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
// ensure we have a lint error
|
|
||||||
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
|
||||||
|
|
||||||
// Click the badge.
|
|
||||||
const badge = page.locator('#code-badge')
|
|
||||||
await expect(badge).toBeVisible()
|
|
||||||
await badge.click()
|
|
||||||
|
|
||||||
// Ensure we have an error diagnostic.
|
|
||||||
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
|
|
||||||
|
|
||||||
// Hover over the error to see the error message
|
|
||||||
await page.hover('.cm-lint-marker-error')
|
|
||||||
await expect(
|
|
||||||
page
|
|
||||||
.getByText(
|
|
||||||
'sketch profile must lie entirely on one side of the revolution axis'
|
|
||||||
)
|
|
||||||
.first()
|
|
||||||
).toBeVisible()
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,364 +0,0 @@
|
|||||||
import { test, expect } from '@playwright/test'
|
|
||||||
|
|
||||||
import { getUtils, setup, tearDown } from './test-utils'
|
|
||||||
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
|
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }) => {
|
|
||||||
await setup(context, page)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
|
||||||
await tearDown(page, testInfo)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.describe('Command bar tests', () => {
|
|
||||||
test('Extrude from command bar selects extrude line after', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> xLine(-20, %)
|
|
||||||
|> close(%)
|
|
||||||
`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// Click the line of code for xLine.
|
|
||||||
await page.getByText(`close(%)`).click() // TODO remove this and reinstate // await topHorzSegmentClick()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Extrude' }).click()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await expect(page.locator('.cm-activeLine')).toHaveText(
|
|
||||||
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Fillet from command bar', async ({ page }) => {
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-5, -5], %)
|
|
||||||
|> line([0, 10], %)
|
|
||||||
|> line([10, 0], %)
|
|
||||||
|> line([0, -10], %)
|
|
||||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
|
||||||
|> close(%)
|
|
||||||
const extrude001 = extrude(-10, sketch001)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
const selectSegment = () => page.getByText(`line([0, -10], %)`).click()
|
|
||||||
|
|
||||||
await selectSegment()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.getByRole('button', { name: 'Fillet' }).click()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await expect(page.locator('.cm-activeLine')).toContainText(
|
|
||||||
`fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Command bar can change a setting, and switch back and forth between arguments', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
const commandBarButton = page.getByRole('button', { name: 'Commands' })
|
|
||||||
const cmdSearchBar = page.getByPlaceholder('Search commands')
|
|
||||||
const commandName = 'debug panel'
|
|
||||||
const commandOption = page.getByRole('option', {
|
|
||||||
name: commandName,
|
|
||||||
exact: false,
|
|
||||||
})
|
|
||||||
const commandLevelArgButton = page.getByRole('button', { name: 'level' })
|
|
||||||
const commandThemeArgButton = page.getByRole('button', { name: 'value' })
|
|
||||||
const paneSelector = page.getByRole('button', { name: 'debug panel' })
|
|
||||||
// This selector changes after we set the setting
|
|
||||||
let commandOptionInput = page.getByPlaceholder('On')
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
).not.toBeDisabled()
|
|
||||||
|
|
||||||
// First try opening the command bar and closing it
|
|
||||||
await page
|
|
||||||
.getByRole('button', { name: 'Commands', exact: false })
|
|
||||||
.or(page.getByRole('button', { name: '⌘K' }))
|
|
||||||
.click()
|
|
||||||
|
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
|
||||||
await page.keyboard.press('Escape')
|
|
||||||
await expect(cmdSearchBar).not.toBeVisible()
|
|
||||||
|
|
||||||
// Now try the same, but with the keyboard shortcut, check focus
|
|
||||||
await page.keyboard.press('Meta+K')
|
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
|
||||||
await expect(cmdSearchBar).toBeFocused()
|
|
||||||
|
|
||||||
// Try typing in the command bar
|
|
||||||
await cmdSearchBar.fill(commandName)
|
|
||||||
await expect(commandOption).toBeVisible()
|
|
||||||
await commandOption.click()
|
|
||||||
const toggleInput = page.getByPlaceholder('On')
|
|
||||||
await expect(toggleInput).toBeVisible()
|
|
||||||
await expect(toggleInput).toBeFocused()
|
|
||||||
// Select On
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await expect(page.getByRole('option', { name: 'Off' })).toHaveAttribute(
|
|
||||||
'data-headlessui-state',
|
|
||||||
'active'
|
|
||||||
)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
// Check the toast appeared
|
|
||||||
await expect(
|
|
||||||
page.getByText(`Set show debug panel to "false" for this project`)
|
|
||||||
).toBeVisible()
|
|
||||||
// Check that the visibility changed
|
|
||||||
await expect(paneSelector).not.toBeVisible()
|
|
||||||
|
|
||||||
commandOptionInput = page.getByPlaceholder('off')
|
|
||||||
|
|
||||||
// Test case for https://github.com/KittyCAD/modeling-app/issues/2882
|
|
||||||
await commandBarButton.click()
|
|
||||||
await cmdSearchBar.focus()
|
|
||||||
await cmdSearchBar.fill(commandName)
|
|
||||||
await commandOption.click()
|
|
||||||
await expect(commandThemeArgButton).toBeDisabled()
|
|
||||||
await commandOptionInput.focus()
|
|
||||||
await commandOptionInput.fill('on')
|
|
||||||
await commandLevelArgButton.click()
|
|
||||||
await expect(commandLevelArgButton).toBeDisabled()
|
|
||||||
|
|
||||||
// Test case for https://github.com/KittyCAD/modeling-app/issues/2881
|
|
||||||
await commandThemeArgButton.click()
|
|
||||||
await expect(commandThemeArgButton).toBeDisabled()
|
|
||||||
await expect(commandLevelArgButton).toHaveText('level: project')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Command bar keybinding works from code editor and can change a setting', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
).not.toBeDisabled()
|
|
||||||
|
|
||||||
// Put the cursor in the code editor
|
|
||||||
await page.locator('.cm-content').click()
|
|
||||||
|
|
||||||
// Now try the same, but with the keyboard shortcut, check focus
|
|
||||||
await page.keyboard.press('Meta+K')
|
|
||||||
|
|
||||||
let cmdSearchBar = page.getByPlaceholder('Search commands')
|
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
|
||||||
await expect(cmdSearchBar).toBeFocused()
|
|
||||||
|
|
||||||
// Try typing in the command bar
|
|
||||||
await cmdSearchBar.fill('theme')
|
|
||||||
const themeOption = page.getByRole('option', {
|
|
||||||
name: 'Settings · app · theme',
|
|
||||||
})
|
|
||||||
await expect(themeOption).toBeVisible()
|
|
||||||
await themeOption.click()
|
|
||||||
const themeInput = page.getByPlaceholder('dark')
|
|
||||||
await expect(themeInput).toBeVisible()
|
|
||||||
await expect(themeInput).toBeFocused()
|
|
||||||
// Select dark theme
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await expect(page.getByRole('option', { name: 'system' })).toHaveAttribute(
|
|
||||||
'data-headlessui-state',
|
|
||||||
'active'
|
|
||||||
)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
// Check the toast appeared
|
|
||||||
await expect(
|
|
||||||
page.getByText(`Set theme to "system" as a user default`)
|
|
||||||
).toBeVisible()
|
|
||||||
// Check that the theme changed
|
|
||||||
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Can extrude from the command bar', async ({ page }) => {
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const distance = sqrt(20)
|
|
||||||
const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([-6.95, 10.98], %)
|
|
||||||
|> line([25.1, 0.41], %)
|
|
||||||
|> line([0.73, -20.93], %)
|
|
||||||
|> line([-23.44, 0.52], %)
|
|
||||||
|> close(%)
|
|
||||||
`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// Make sure the stream is up
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
).not.toBeDisabled()
|
|
||||||
await u.clearCommandLogs()
|
|
||||||
await page.getByRole('button', { name: 'Extrude' }).isEnabled()
|
|
||||||
|
|
||||||
let cmdSearchBar = page.getByPlaceholder('Search commands')
|
|
||||||
await page.keyboard.press('Meta+K')
|
|
||||||
await expect(cmdSearchBar).toBeVisible()
|
|
||||||
|
|
||||||
// Search for extrude command and choose it
|
|
||||||
await page.getByRole('option', { name: 'Extrude' }).click()
|
|
||||||
|
|
||||||
// Assert that we're on the selection step
|
|
||||||
await expect(page.getByRole('button', { name: 'selection' })).toBeDisabled()
|
|
||||||
// Select a face
|
|
||||||
await page.mouse.move(700, 200)
|
|
||||||
await page.mouse.click(700, 200)
|
|
||||||
|
|
||||||
// Assert that we're on the distance step
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'distance', exact: false })
|
|
||||||
).toBeDisabled()
|
|
||||||
|
|
||||||
// Assert that the an alternative variable name is chosen,
|
|
||||||
// since the default variable name is already in use (distance)
|
|
||||||
await page.getByRole('button', { name: 'Create new variable' }).click()
|
|
||||||
await expect(page.getByPlaceholder('Variable name')).toHaveValue(
|
|
||||||
'distance001'
|
|
||||||
)
|
|
||||||
|
|
||||||
const continueButton = page.getByRole('button', { name: 'Continue' })
|
|
||||||
const submitButton = page.getByRole('button', { name: 'Submit command' })
|
|
||||||
await continueButton.click()
|
|
||||||
|
|
||||||
// Review step and argument hotkeys
|
|
||||||
await expect(submitButton).toBeEnabled()
|
|
||||||
await expect(submitButton).toBeFocused()
|
|
||||||
await submitButton.press('Backspace')
|
|
||||||
|
|
||||||
// Assert we're back on the distance step
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'distance', exact: false })
|
|
||||||
).toBeDisabled()
|
|
||||||
|
|
||||||
await continueButton.click()
|
|
||||||
await submitButton.click()
|
|
||||||
|
|
||||||
// Check that the code was updated
|
|
||||||
await u.waitForCmdReceive('extrude')
|
|
||||||
// Unfortunately this indentation seems to matter for the test
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const distance = sqrt(20)
|
|
||||||
const distance001 = ${KCL_DEFAULT_LENGTH}
|
|
||||||
const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([-6.95, 10.98], %)
|
|
||||||
|> line([25.1, 0.41], %)
|
|
||||||
|> line([0.73, -20.93], %)
|
|
||||||
|> line([-23.44, 0.52], %)
|
|
||||||
|> close(%)
|
|
||||||
const extrude001 = extrude(distance001, sketch001)`.replace(
|
|
||||||
/(\r\n|\n|\r)/gm,
|
|
||||||
''
|
|
||||||
) // remove newlines
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Can switch between sketch tools via command bar', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
const cmdBarButton = page.getByRole('button', { name: 'Commands' })
|
|
||||||
const rectangleToolCommand = page.getByRole('option', {
|
|
||||||
name: 'rectangle',
|
|
||||||
})
|
|
||||||
const rectangleToolButton = page.getByRole('button', {
|
|
||||||
name: 'Corner rectangle',
|
|
||||||
exact: true,
|
|
||||||
})
|
|
||||||
const lineToolCommand = page.getByRole('option', {
|
|
||||||
name: 'Line',
|
|
||||||
})
|
|
||||||
const lineToolButton = page.getByRole('button', {
|
|
||||||
name: 'Line',
|
|
||||||
exact: true,
|
|
||||||
})
|
|
||||||
const arcToolCommand = page.getByRole('option', { name: 'Tangential Arc' })
|
|
||||||
const arcToolButton = page.getByRole('button', {
|
|
||||||
name: 'Tangential Arc',
|
|
||||||
exact: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Start a sketch
|
|
||||||
await sketchButton.click()
|
|
||||||
await page.mouse.click(700, 200)
|
|
||||||
|
|
||||||
// Switch between sketch tools via the command bar
|
|
||||||
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
|
|
||||||
await cmdBarButton.click()
|
|
||||||
await rectangleToolCommand.click()
|
|
||||||
await expect(rectangleToolButton).toHaveAttribute('aria-pressed', 'true')
|
|
||||||
await cmdBarButton.click()
|
|
||||||
await lineToolCommand.click()
|
|
||||||
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
|
|
||||||
|
|
||||||
// Click in the scene a couple times to draw a line
|
|
||||||
// so tangential arc is valid
|
|
||||||
await page.mouse.click(700, 200)
|
|
||||||
await page.mouse.move(700, 300, { steps: 5 })
|
|
||||||
await page.mouse.click(700, 300)
|
|
||||||
|
|
||||||
// switch to tangential arc via command bar
|
|
||||||
await cmdBarButton.click()
|
|
||||||
await arcToolCommand.click()
|
|
||||||
await expect(arcToolButton).toHaveAttribute('aria-pressed', 'true')
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,519 +0,0 @@
|
|||||||
import { test, expect } from '@playwright/test'
|
|
||||||
import { getUtils, setup, tearDown } from './test-utils'
|
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }) => {
|
|
||||||
await setup(context, page)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
|
||||||
await tearDown(page, testInfo)
|
|
||||||
})
|
|
||||||
test.describe('Copilot ghost text', () => {
|
|
||||||
test.skip(true, 'Needs to get covered again')
|
|
||||||
|
|
||||||
test('completes code in empty file', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// We should be able to hit Tab to accept the completion.
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hit enter a few times.
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %) `
|
|
||||||
)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test.skip('copilot disabled in sketch mode no select plane', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
// Click sketch mode.
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
// Exit sketch mode.
|
|
||||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
|
||||||
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// We should be able to hit Tab to accept the completion.
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await expect(page.locator('.cm-content')).toContainText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('copilot disabled in sketch mode after selecting plane', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
// Click sketch mode.
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
).not.toBeDisabled()
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
|
||||||
|
|
||||||
// select a plane
|
|
||||||
await page.mouse.click(700, 200)
|
|
||||||
await page.waitForTimeout(700) // wait for animation
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XZ')`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Escape to exit the tool.
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
await page.keyboard.press('Escape')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XZ')`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Escape again to exit sketch mode.
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
await page.keyboard.press('Escape')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XZ')fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// We should be able to hit Tab to accept the completion.
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XZ')fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Hit enter a few times.
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XZ')fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %) `
|
|
||||||
)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('ArrowUp in code rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.press('ArrowUp')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('ArrowDown in code rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('ArrowLeft in code rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.press('ArrowLeft')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('ArrowRight in code rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.press('ArrowRight')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Enter in code scoots it down', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Ctrl+shift+z in code rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
const CtrlKey = process.platform === 'darwin' ? 'Meta' : 'Control'
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.down(CtrlKey)
|
|
||||||
await page.keyboard.down('Shift')
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up(CtrlKey)
|
|
||||||
await page.keyboard.up('Shift')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('Ctrl+z in code rejects the suggestion and undos the last code', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
const CtrlKey = process.platform === 'darwin' ? 'Meta' : 'Control'
|
|
||||||
|
|
||||||
await page.waitForTimeout(800)
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await page.keyboard.type('{thing: "blah"}', { delay: 0 })
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(`{thing: "blah"}`)
|
|
||||||
|
|
||||||
// We wanna make sure the code saves.
|
|
||||||
await page.waitForTimeout(800)
|
|
||||||
|
|
||||||
// Ctrl+z
|
|
||||||
await page.keyboard.down(CtrlKey)
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up(CtrlKey)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
// Ctrl+shift+z
|
|
||||||
await page.keyboard.down(CtrlKey)
|
|
||||||
await page.keyboard.down('Shift')
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up(CtrlKey)
|
|
||||||
await page.keyboard.up('Shift')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(`{thing: "blah"}`)
|
|
||||||
|
|
||||||
// We wanna make sure the code saves.
|
|
||||||
await page.waitForTimeout(800)
|
|
||||||
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`{thing: "blah"}fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Once for the enter.
|
|
||||||
await page.keyboard.down(CtrlKey)
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up(CtrlKey)
|
|
||||||
|
|
||||||
// Once for the text.
|
|
||||||
await page.keyboard.down(CtrlKey)
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up(CtrlKey)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
// TODO when we make codemirror a widget, we can test this.
|
|
||||||
//await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('delete in code rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.press('Delete')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('backspace in code rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going elsewhere in the code should hide the ghost text.
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('focus outside code pane rejects the suggestion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).toHaveText(
|
|
||||||
`fn cube = (pos, scale) => {`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Going outside the editor should hide the ghost text.
|
|
||||||
await page.mouse.move(0, 0)
|
|
||||||
await page
|
|
||||||
.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
.waitFor({ state: 'visible' })
|
|
||||||
await page.getByRole('button', { name: 'Start Sketch' }).click()
|
|
||||||
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,867 +0,0 @@
|
|||||||
import { test, expect } from '@playwright/test'
|
|
||||||
import { uuidv4 } from 'lib/utils'
|
|
||||||
import { getUtils, setup, tearDown } from './test-utils'
|
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }) => {
|
|
||||||
await setup(context, page)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
|
||||||
await tearDown(page, testInfo)
|
|
||||||
})
|
|
||||||
|
|
||||||
test.describe('Editor tests', () => {
|
|
||||||
test('can comment out code with ctrl+/', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
const CtrlKey = process.platform === 'darwin' ? 'Meta' : 'Control'
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await page.keyboard.type(`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`)
|
|
||||||
|
|
||||||
await page.keyboard.down(CtrlKey)
|
|
||||||
await page.keyboard.press('/')
|
|
||||||
await page.keyboard.up(CtrlKey)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
// |> close(%)`)
|
|
||||||
|
|
||||||
// uncomment the code
|
|
||||||
await page.keyboard.down(CtrlKey)
|
|
||||||
await page.keyboard.press('/')
|
|
||||||
await page.keyboard.up(CtrlKey)
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('if you click the format button it formats your code', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await page.keyboard.type(`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`)
|
|
||||||
await page.locator('#code-pane button:first-child').click()
|
|
||||||
await page.locator('button:has-text("Format code")').click()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('fold gutters work', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
|
|
||||||
const fullCode = `const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// TODO: Jess needs to fix this but you have to mod the code to get them to show
|
|
||||||
// up, its an annoying codemirror thing.
|
|
||||||
await page.locator('.cm-content').click()
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
const foldGutterFoldLine = page.locator('[title="Fold line"]')
|
|
||||||
const foldGutterUnfoldLine = page.locator('[title="Unfold line"]')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(fullCode)
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
// Make sure we have a fold gutter
|
|
||||||
await expect(foldGutterFoldLine).toBeVisible()
|
|
||||||
await expect(foldGutterUnfoldLine).not.toBeVisible()
|
|
||||||
|
|
||||||
// Collapse the code
|
|
||||||
await foldGutterFoldLine.click()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XY')… `
|
|
||||||
)
|
|
||||||
await expect(page.locator('.cm-content')).not.toHaveText(fullCode)
|
|
||||||
await expect(foldGutterFoldLine).not.toBeVisible()
|
|
||||||
await expect(foldGutterUnfoldLine.nth(1)).toBeVisible()
|
|
||||||
|
|
||||||
// Expand the code
|
|
||||||
await foldGutterUnfoldLine.nth(1).click()
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(fullCode)
|
|
||||||
|
|
||||||
// Delete all the code.
|
|
||||||
await page.locator('.cm-content').click()
|
|
||||||
// Select all
|
|
||||||
await page.keyboard.press('Control+A')
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
await page.keyboard.press('Meta+A')
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(``)
|
|
||||||
await expect(page.locator('.cm-content')).not.toHaveText(fullCode)
|
|
||||||
|
|
||||||
await expect(foldGutterUnfoldLine).not.toBeVisible()
|
|
||||||
await expect(foldGutterFoldLine).not.toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('hover over functions shows function description', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// focus the editor
|
|
||||||
await u.codeLocator.click()
|
|
||||||
|
|
||||||
// Hover over the startSketchOn function
|
|
||||||
await page.getByText('startSketchOn').hover()
|
|
||||||
await expect(page.locator('.hover-tooltip')).toBeVisible()
|
|
||||||
await expect(
|
|
||||||
page.getByText(
|
|
||||||
'Start a new 2-dimensional sketch on a specific plane or face'
|
|
||||||
)
|
|
||||||
).toBeVisible()
|
|
||||||
|
|
||||||
// Hover over the line function
|
|
||||||
await page.getByText('line').first().hover()
|
|
||||||
await expect(page.locator('.hover-tooltip')).toBeVisible()
|
|
||||||
await expect(page.getByText('Draw a line')).toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('if you use the format keyboard binding it formats your code', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`
|
|
||||||
)
|
|
||||||
localStorage.setItem('disableAxis', 'true')
|
|
||||||
})
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// focus the editor
|
|
||||||
await u.codeLocator.click()
|
|
||||||
|
|
||||||
// Hit alt+shift+f to format the code
|
|
||||||
await page.keyboard.press('Alt+Shift+KeyF')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-10, -10], %)
|
|
||||||
|> line([20, 0], %)
|
|
||||||
|> line([0, 20], %)
|
|
||||||
|> line([-20, 0], %)
|
|
||||||
|> close(%)`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('if you write kcl with lint errors you get lints', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await page.keyboard.type('const my_snake_case_var = 5')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type('const myCamelCaseVar = 5')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
// press arrows to clear autocomplete
|
|
||||||
await page.keyboard.press('ArrowLeft')
|
|
||||||
await page.keyboard.press('ArrowRight')
|
|
||||||
|
|
||||||
// error in guter
|
|
||||||
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
|
||||||
|
|
||||||
// error text on hover
|
|
||||||
await page.hover('.cm-lint-marker-info')
|
|
||||||
await expect(
|
|
||||||
page.getByText('Identifiers must be lowerCamelCase').first()
|
|
||||||
).toBeVisible()
|
|
||||||
|
|
||||||
// select the line that's causing the error and delete it
|
|
||||||
await page.getByText('const my_snake_case_var = 5').click()
|
|
||||||
await page.keyboard.press('End')
|
|
||||||
await page.keyboard.down('Shift')
|
|
||||||
await page.keyboard.press('Home')
|
|
||||||
await page.keyboard.up('Shift')
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
|
|
||||||
// wait for .cm-lint-marker-info not to be visible
|
|
||||||
await expect(page.locator('.cm-lint-marker-info')).not.toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('if you fixup kcl errors you clear lints', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([3.29, 7.86], %)
|
|
||||||
|> line([2.48, 2.44], %)
|
|
||||||
|> line([2.66, 1.17], %)
|
|
||||||
|> close(%)
|
|
||||||
`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
|
|
||||||
await page.getByText(' |> line([2.48, 2.44], %)').click()
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
page.locator('.cm-lint-marker-error').first()
|
|
||||||
).not.toBeVisible()
|
|
||||||
await page.keyboard.press('End')
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
|
|
||||||
await page.keyboard.type(')')
|
|
||||||
await expect(
|
|
||||||
page.locator('.cm-lint-marker-error').first()
|
|
||||||
).not.toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('if you write invalid kcl you get inlined errors', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
/* add the following code to the editor ($ error is not a valid line)
|
|
||||||
$ error
|
|
||||||
const topAng = 30
|
|
||||||
const bottomAng = 25
|
|
||||||
*/
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await page.keyboard.type('$ error')
|
|
||||||
|
|
||||||
// press arrows to clear autocomplete
|
|
||||||
await page.keyboard.press('ArrowLeft')
|
|
||||||
await page.keyboard.press('ArrowRight')
|
|
||||||
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type('const topAng = 30')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type('const bottomAng = 25')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
|
|
||||||
// error in guter
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
||||||
|
|
||||||
// error text on hover
|
|
||||||
await page.hover('.cm-lint-marker-error')
|
|
||||||
await expect(page.getByText('Unexpected token').first()).toBeVisible()
|
|
||||||
|
|
||||||
// select the line that's causing the error and delete it
|
|
||||||
await page.getByText('$ error').click()
|
|
||||||
await page.keyboard.press('End')
|
|
||||||
await page.keyboard.down('Shift')
|
|
||||||
await page.keyboard.press('Home')
|
|
||||||
await page.keyboard.up('Shift')
|
|
||||||
await page.keyboard.press('Backspace')
|
|
||||||
|
|
||||||
// wait for .cm-lint-marker-error not to be visible
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
// let's check we get an error when defining the same variable twice
|
|
||||||
await page.getByText('const bottomAng = 25').click()
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type("// Let's define the same thing twice")
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type('const topAng = 42')
|
|
||||||
await page.keyboard.press('ArrowLeft')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
||||||
await expect(
|
|
||||||
page.locator('.cm-lint-marker.cm-lint-marker-error')
|
|
||||||
).toBeVisible()
|
|
||||||
|
|
||||||
await page.locator('.cm-lint-marker.cm-lint-marker-error').hover()
|
|
||||||
await expect(page.locator('.cm-diagnosticText').first()).toBeVisible()
|
|
||||||
await expect(
|
|
||||||
page.getByText('Cannot redefine `topAng`').first()
|
|
||||||
).toBeVisible()
|
|
||||||
|
|
||||||
const secondTopAng = page.getByText('topAng').first()
|
|
||||||
await secondTopAng?.dblclick()
|
|
||||||
await page.keyboard.type('otherAng')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('error with 2 source ranges gets 2 diagnostics', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const length = .750
|
|
||||||
const width = 0.500
|
|
||||||
const height = 0.500
|
|
||||||
const dia = 4
|
|
||||||
|
|
||||||
fn squareHole = (l, w) => {
|
|
||||||
const squareHoleSketch = startSketchOn('XY')
|
|
||||||
|> startProfileAt([-width / 2, -length / 2], %)
|
|
||||||
|> lineTo([width / 2, -length / 2], %)
|
|
||||||
|> lineTo([width / 2, length / 2], %)
|
|
||||||
|> lineTo([-width / 2, length / 2], %)
|
|
||||||
|> close(%)
|
|
||||||
return squareHoleSketch
|
|
||||||
}
|
|
||||||
`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// check no error to begin with
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
|
||||||
|
|
||||||
// Click on the bottom of the code editor to add a new line
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type(`const extrusion = startSketchOn('XY')
|
|
||||||
|> circle([0, 0], dia/2, %)
|
|
||||||
|> hole(squareHole(length, width, height), %)
|
|
||||||
|> extrude(height, %)`)
|
|
||||||
|
|
||||||
// error in gutter
|
|
||||||
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
|
|
||||||
await page.hover('.cm-lint-marker-error:first-child')
|
|
||||||
await expect(
|
|
||||||
page.getByText('Expected 2 arguments, got 3').first()
|
|
||||||
).toBeVisible()
|
|
||||||
|
|
||||||
// Make sure there are two diagnostics
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2)
|
|
||||||
})
|
|
||||||
test('if your kcl gets an error from the engine it is inlined', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const box = startSketchOn('XY')
|
|
||||||
|> startProfileAt([0, 0], %)
|
|
||||||
|> line([0, 10], %)
|
|
||||||
|> line([10, 0], %)
|
|
||||||
|> line([0, -10], %, $revolveAxis)
|
|
||||||
|> close(%)
|
|
||||||
|> extrude(10, %)
|
|
||||||
|
|
||||||
const sketch001 = startSketchOn(box, revolveAxis)
|
|
||||||
|> startProfileAt([5, 10], %)
|
|
||||||
|> line([0, -10], %)
|
|
||||||
|> line([2, 0], %)
|
|
||||||
|> line([0, -10], %)
|
|
||||||
|> close(%)
|
|
||||||
|> revolve({
|
|
||||||
axis: revolveAxis,
|
|
||||||
angle: 90
|
|
||||||
}, %)
|
|
||||||
`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1000, height: 500 })
|
|
||||||
|
|
||||||
await page.goto('/')
|
|
||||||
await u.waitForPageLoad()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
|
|
||||||
|
|
||||||
// error text on hover
|
|
||||||
await page.hover('.cm-lint-marker-error')
|
|
||||||
const searchText =
|
|
||||||
'sketch profile must lie entirely on one side of the revolution axis'
|
|
||||||
await expect(page.getByText(searchText)).toBeVisible()
|
|
||||||
})
|
|
||||||
test.describe('Autocomplete works', () => {
|
|
||||||
test('with enter/click to accept the completion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// this test might be brittle as we add and remove functions
|
|
||||||
// but should also be easy to update.
|
|
||||||
// tests clicking on an option, selection the first option
|
|
||||||
// and arrowing down to an option
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await page.keyboard.type('const sketch001 = start')
|
|
||||||
|
|
||||||
// expect there to be six auto complete options
|
|
||||||
await expect(page.locator('.cm-completionLabel')).toHaveCount(8)
|
|
||||||
// this makes sure we can accept a completion with click
|
|
||||||
await page.getByText('startSketchOn').click()
|
|
||||||
await page.keyboard.type("'XZ'")
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type(' |> startProfi')
|
|
||||||
// expect there be a single auto complete option that we can just hit enter on
|
|
||||||
await expect(page.locator('.cm-completionLabel')).toBeVisible()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Enter') // accepting the auto complete, not a new line
|
|
||||||
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.type('12')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.type(' |> lin')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-tooltip-autocomplete')).toBeVisible()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
// press arrow down twice then enter to accept xLine
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
// finish line with comment
|
|
||||||
await page.keyboard.type('5')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
|
|
||||||
await page.keyboard.type(' // ')
|
|
||||||
// Since we need to parse the ast to know we are in a comment we gotta hang tight.
|
|
||||||
await page.waitForTimeout(700)
|
|
||||||
await page.keyboard.type('lin ')
|
|
||||||
await page.waitForTimeout(200)
|
|
||||||
// there shouldn't be any auto complete options for 'lin' in the comment
|
|
||||||
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([3.14, 12], %)
|
|
||||||
|> xLine(5, %) // lin`)
|
|
||||||
})
|
|
||||||
|
|
||||||
test('with tab to accept the completion', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
// const PUR = 400 / 37.5 //pixeltoUnitRatio
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
|
|
||||||
// this test might be brittle as we add and remove functions
|
|
||||||
// but should also be easy to update.
|
|
||||||
// tests clicking on an option, selection the first option
|
|
||||||
// and arrowing down to an option
|
|
||||||
|
|
||||||
await u.codeLocator.click()
|
|
||||||
await page.keyboard.type('const sketch001 = startSketchO')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
|
|
||||||
// Make sure just hitting tab will take the only one left
|
|
||||||
await expect(page.locator('.cm-completionLabel')).toHaveCount(1)
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(500)
|
|
||||||
await page.keyboard.type("'XZ'")
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.keyboard.type(' |> startProfi')
|
|
||||||
// expect there be a single auto complete option that we can just hit enter on
|
|
||||||
await expect(page.locator('.cm-completionLabel')).toBeVisible()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab') // accepting the auto complete, not a new line
|
|
||||||
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.keyboard.type('12')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.type(' |> lin')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-tooltip-autocomplete')).toBeVisible()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
// press arrow down twice then tab to accept xLine
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('ArrowDown')
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
// finish line with comment
|
|
||||||
await page.keyboard.type('5')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.keyboard.press('Tab')
|
|
||||||
|
|
||||||
await page.keyboard.type(' // ')
|
|
||||||
// Since we need to parse the ast to know we are in a comment we gotta hang tight.
|
|
||||||
await page.waitForTimeout(700)
|
|
||||||
await page.keyboard.type('lin ')
|
|
||||||
await page.waitForTimeout(200)
|
|
||||||
// there shouldn't be any auto complete options for 'lin' in the comment
|
|
||||||
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([3.14, 12], %)
|
|
||||||
|> xLine(5, %) // lin`)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
test('Can undo a click and point extrude with ctrl+z', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([4.61, -14.01], %)
|
|
||||||
|> line([12.73, -0.09], %)
|
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|
||||||
|> close(%)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
).not.toBeDisabled()
|
|
||||||
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await u.openAndClearDebugPanel()
|
|
||||||
await u.sendCustomCmd({
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd_id: uuidv4(),
|
|
||||||
cmd: {
|
|
||||||
type: 'default_camera_look_at',
|
|
||||||
vantage: { x: 0, y: -1250, z: 580 },
|
|
||||||
center: { x: 0, y: 0, z: 0 },
|
|
||||||
up: { x: 0, y: 0, z: 1 },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await u.sendCustomCmd({
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd_id: uuidv4(),
|
|
||||||
cmd: {
|
|
||||||
type: 'default_camera_get_settings',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
|
|
||||||
const startPX = [665, 458]
|
|
||||||
|
|
||||||
const dragPX = 40
|
|
||||||
|
|
||||||
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
|
|
||||||
await expect(page.getByRole('button', { name: 'Extrude' })).toBeVisible()
|
|
||||||
await page.getByRole('button', { name: 'Extrude' }).click()
|
|
||||||
|
|
||||||
await expect(page.getByTestId('command-bar')).toBeVisible()
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await expect(page.getByText('Confirm Extrude')).toBeVisible()
|
|
||||||
await page.keyboard.press('Enter')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
|
|
||||||
// expect the code to have changed
|
|
||||||
await expect(page.locator('.cm-content')).toHaveText(
|
|
||||||
`const sketch001 = startSketchOn('XZ') |> startProfileAt([4.61, -14.01], %) |> line([12.73, -0.09], %) |> tangentialArcTo([24.95, -5.38], %) |> close(%)const extrude001 = extrude(5, sketch001)`
|
|
||||||
)
|
|
||||||
|
|
||||||
// Now hit undo
|
|
||||||
await page.keyboard.down('Control')
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up('Control')
|
|
||||||
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([4.61, -14.01], %)
|
|
||||||
|> line([12.73, -0.09], %)
|
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|
||||||
|> close(%)`)
|
|
||||||
})
|
|
||||||
|
|
||||||
// failing for the same reason as "Can edit a sketch that has been extruded in the same pipe"
|
|
||||||
// please fix together
|
|
||||||
test.fixme('Can undo a sketch modification with ctrl+z', async ({ page }) => {
|
|
||||||
const u = await getUtils(page)
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'persistCode',
|
|
||||||
`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([4.61, -14.01], %)
|
|
||||||
|> line([12.73, -0.09], %)
|
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|
||||||
|> close(%)
|
|
||||||
|> extrude(5, %)`
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.setViewportSize({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
await u.waitForAuthSkipAppStart()
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Start Sketch' })
|
|
||||||
).not.toBeDisabled()
|
|
||||||
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await u.openAndClearDebugPanel()
|
|
||||||
await u.sendCustomCmd({
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd_id: uuidv4(),
|
|
||||||
cmd: {
|
|
||||||
type: 'default_camera_look_at',
|
|
||||||
vantage: { x: 0, y: -1250, z: 580 },
|
|
||||||
center: { x: 0, y: 0, z: 0 },
|
|
||||||
up: { x: 0, y: 0, z: 1 },
|
|
||||||
},
|
|
||||||
})
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await u.sendCustomCmd({
|
|
||||||
type: 'modeling_cmd_req',
|
|
||||||
cmd_id: uuidv4(),
|
|
||||||
cmd: {
|
|
||||||
type: 'default_camera_get_settings',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
|
|
||||||
const startPX = [665, 458]
|
|
||||||
|
|
||||||
const dragPX = 40
|
|
||||||
|
|
||||||
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
|
|
||||||
await expect(
|
|
||||||
page.getByRole('button', { name: 'Edit Sketch' })
|
|
||||||
).toBeVisible()
|
|
||||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
|
||||||
await page.waitForTimeout(400)
|
|
||||||
let prevContent = await page.locator('.cm-content').innerText()
|
|
||||||
|
|
||||||
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
|
|
||||||
|
|
||||||
// drag startProfieAt handle
|
|
||||||
await page.dragAndDrop('#stream', '#stream', {
|
|
||||||
sourcePosition: { x: startPX[0], y: startPX[1] },
|
|
||||||
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
|
|
||||||
})
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
|
||||||
prevContent = await page.locator('.cm-content').innerText()
|
|
||||||
|
|
||||||
// drag line handle
|
|
||||||
// we wait so it saves the code
|
|
||||||
await page.waitForTimeout(800)
|
|
||||||
|
|
||||||
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await page.dragAndDrop('#stream', '#stream', {
|
|
||||||
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
|
|
||||||
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
|
|
||||||
})
|
|
||||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
|
||||||
prevContent = await page.locator('.cm-content').innerText()
|
|
||||||
|
|
||||||
// we wait so it saves the code
|
|
||||||
await page.waitForTimeout(800)
|
|
||||||
|
|
||||||
// drag tangentialArcTo handle
|
|
||||||
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
|
|
||||||
await page.dragAndDrop('#stream', '#stream', {
|
|
||||||
sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 },
|
|
||||||
targetPosition: {
|
|
||||||
x: tangentEnd.x + dragPX,
|
|
||||||
y: tangentEnd.y + dragPX,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
|
|
||||||
|
|
||||||
// expect the code to have changed
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([7.12, -16.82], %)
|
|
||||||
|> line([15.4, -2.74], %)
|
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|
||||||
|> line([2.65, -2.69], %)
|
|
||||||
|> close(%)
|
|
||||||
|> extrude(5, %)`)
|
|
||||||
|
|
||||||
// Hit undo
|
|
||||||
await page.keyboard.down('Control')
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up('Control')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([7.12, -16.82], %)
|
|
||||||
|> line([15.4, -2.74], %)
|
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|
||||||
|> close(%)
|
|
||||||
|> extrude(5, %)`)
|
|
||||||
|
|
||||||
// Hit undo again.
|
|
||||||
await page.keyboard.down('Control')
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up('Control')
|
|
||||||
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([7.12, -16.82], %)
|
|
||||||
|> line([12.73, -0.09], %)
|
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|
||||||
|> close(%)
|
|
||||||
|> extrude(5, %)`)
|
|
||||||
|
|
||||||
// Hit undo again.
|
|
||||||
await page.keyboard.down('Control')
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up('Control')
|
|
||||||
|
|
||||||
await page.waitForTimeout(100)
|
|
||||||
await expect(page.locator('.cm-content'))
|
|
||||||
.toHaveText(`const sketch001 = startSketchOn('XZ')
|
|
||||||
|> startProfileAt([4.61, -14.01], %)
|
|
||||||
|> line([12.73, -0.09], %)
|
|
||||||
|> tangentialArcTo([24.95, -5.38], %)
|
|
||||||
|> close(%)
|
|
||||||
|> extrude(5, %)`)
|
|
||||||
})
|
|
||||||
})
|
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 249 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 249 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 249 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 171 KiB |