Compare commits

..

5 Commits

Author SHA1 Message Date
f441998f1a updates
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-08-20 11:59:01 -07:00
531496420e Cut release v0.24.13 (#3571)
* bump version;

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

* actual veriosn

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-08-20 11:57:18 -07:00
13bb482904 updates
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-08-20 11:25:00 -07:00
562959ee22 skip windows shit
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-08-20 11:19:56 -07:00
b044f6faef Fix CPU-driven churn once Text-to-CAD toast appears in the app (#3523)
* Dispose of requestAnimationFrame loop when component unmounts

* Only run requestAnimationFrame loop when mouse is on canvas

* Better animation loop disposal on canvas mouseout

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

* Text-to-cad test flakiness

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

* Re-run CI

* Remove arbitrary timeout which may cause us to miss the toast on a fast-running test

* Remove a couple more arbitrary timeouts in text-to-cad tests

* Remove all the arbitrary 5s awaits from these tests

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-20 11:03:42 -07:00
502 changed files with 19062 additions and 30431 deletions

View File

@ -1,3 +1,3 @@
[codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast,ue,afterall
skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,.yarn.lock,**/yarn.lock
skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,./src-tauri/gen/schemas

View File

@ -1,5 +1,3 @@
NODE_ENV=development
DEV=true
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev

View File

@ -25,9 +25,7 @@
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"rules": {
"@typescript-eslint/no-floating-promises": "warn",
"suggest-no-throw/suggest-no-throw": "off",
"testing-library/prefer-screen-queries": "off",
"jest/valid-expect": "off"
"testing-library/prefer-screen-queries": "off"
}
},
{

View File

@ -10,7 +10,7 @@ updates:
schedule:
interval: 'daily'
reviewers:
- franknoirot
- franknoirot
- irev-dev
- package-ecosystem: 'github-actions' # See documentation for possible values
directory: '/' # Location of package manifests
@ -26,3 +26,10 @@ updates:
reviewers:
- adamchalmers
- jessfraz
- package-ecosystem: 'cargo' # See documentation for possible values
directory: '/src-tauri/' # Location of package manifests
schedule:
interval: 'daily'
reviewers:
- adamchalmers
- jessfraz

View File

@ -1,366 +0,0 @@
name: build-publish-apps
on:
pull_request:
push:
branches:
- main
release:
types: [published]
schedule:
- cron: '0 4 * * *'
# Daily at 04:00 AM UTC
# Will checkout the last commit from the default branch (main as of 2023-10-04)
env:
CUT_RELEASE_PR: ${{ github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
prepare-files:
runs-on: ubuntu-22.04 # seperate job on Ubuntu for easy string manipulations (compared to Windows)
outputs:
version: ${{ steps.export_version.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
# TODO: see if we can fetch from main instead if no diff at src/wasm-lib
- name: Run build:wasm
run: "yarn build:wasm${{ env.BUILD_RELEASE == 'true' && '-dev' || ''}}"
- name: Set nightly version
if: github.event_name == 'schedule'
run: |
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
# TODO: see if we need to inject updater nightly URL here https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json
# TODO: see if we ned to add updater test URL here https://dl.zoo.dev/releases/modeling-app/updater-test/last_update.json
- uses: actions/upload-artifact@v3
with:
name: prepared-files
path: |
package.json
src/wasm-lib/pkg/wasm_lib*
- id: export_version
run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT"
build-apps:
needs: [prepare-files]
strategy:
fail-fast: false
matrix:
os: [macos-14, windows-2022, ubuntu-22.04]
runs-on: ${{ matrix.os }}
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
CSC_FOR_PULL_REQUEST: true
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
VERSION: ${{ github.event_name == 'schedule' && needs.prepare-files.outputs.version || format('v{0}', needs.prepare-files.outputs.version) }}
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
WINDOWS_CERTIFICATE_THUMBPRINT: F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
name: prepared-files
- name: Copy prepared files
run: |
ls -R prepared-files
cp prepared-files/package.json package.json
cp prepared-files/src/wasm-lib/pkg/wasm_lib_bg.wasm public
mkdir src/wasm-lib/pkg
cp prepared-files/src/wasm-lib/pkg/wasm_lib* src/wasm-lib/pkg
- name: Sync node version and setup cache
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn' # Set this to npm, yarn or pnpm.
- run: yarn install
- run: yarn tronb:vite
- name: Prepare certificate and variables (Windows only)
if: ${{ env.BUILD_RELEASE == 'true' && matrix.os == 'windows-2022' }}
run: |
echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
cat /d/Certificate_pkcs12.p12
echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH
shell: bash
- name: Setup certicate with SSM KSP (Windows only)
if: ${{ env.BUILD_RELEASE == 'true' && matrix.os == 'windows-2022' }}
run: |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi
msiexec /i smtools-windows-x64.msi /quiet /qn
smksp_registrar.exe list
smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe
shell: cmd
- name: Build the app
run: yarn electron-builder --config ${{ env.BUILD_RELEASE && '--publish always' || '' }}
- name: List artifacts in out/
run: ls -R out
- name: Prepare the tauri update bundles (macOS)
if: ${{ env.BUILD_RELEASE && matrix.os == 'macos-14' }}
run: |
for ARCH in arm64 x64; do
TAURI_DIR=out/tauri/$VERSION/macos
TEMP_DIR=temp/$ARCH
mkdir -p $TAURI_DIR
mkdir -p $TEMP_DIR
unzip out/*-$ARCH-mac.zip -d $TEMP_DIR
tar -czvf "$TAURI_DIR/Zoo Modeling App-$ARCH.app.tar.gz" -C $TEMP_DIR "Zoo Modeling App.app"
yarn tauri signer sign "$TAURI_DIR/Zoo Modeling App-$ARCH.app.tar.gz"
done
ls -R out
- name: Prepare the tauri update bundles (Windows)
if: ${{ env.BUILD_RELEASE && matrix.os == 'windows-2022' }}
run: |
$env:TAURI_DIR="out/tauri/${env:VERSION}/nsis"
mkdir -p ${env:TAURI_DIR}
$env:OUT_FILE="${env:TAURI_DIR}/Zoo Modeling App_${env:VERSION_NO_V}_x64-setup.nsis.zip"
7z a -mm=Copy "${env:OUT_FILE}" ./out/*-x64-win.exe
yarn tauri signer sign "${env:OUT_FILE}"
ls -R out
- uses: actions/upload-artifact@v3
with:
name: out-${{ matrix.os }}
path: |
out/Zoo*.*
out/latest*.yml
out/tauri
# TODO: add the 'Build for Mac TestFlight (nightly)' stage back
# TODO: add the updater tests back
publish-apps-release:
runs-on: ubuntu-22.04
permissions:
contents: write
if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }}
needs: [prepare-files, build-apps]
env:
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
VERSION: ${{ github.event_name == 'schedule' && needs.prepare-files.outputs.version || format('v{0}', needs.prepare-files.outputs.version) }}
PUB_DATE: ${{ github.event_name == 'release' && github.event.release.created_at || github.event.repository.updated_at }}
NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Non-release build, commit {0}', github.sha) }}
BUCKET_DIR: ${{ github.event_name == 'schedule' && 'dl.kittycad.io/releases/modeling-app/nightly' || 'dl.kittycad.io/releases/modeling-app' }}
WEBSITE_DIR: ${{ github.event_name == 'schedule' && 'dl.zoo.dev/releases/modeling-app/nightly' || 'dl.zoo.dev/releases/modeling-app' }}
BUCKET_DIR_TAURI: 'dl.kittycad.io/releases/modeling-app/tauri-compat'
WEBSITE_DIR_TAURI: 'dl.zoo.dev/releases/modeling-app/tauri-compat'
URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
with:
name: out-windows-2022
path: out
- uses: actions/download-artifact@v3
with:
name: out-macos-14
path: out
- uses: actions/download-artifact@v3
with:
name: out-ubuntu-22.04
path: out
- name: Generate the download static endpoint
run: |
RELEASE_DIR=https://${WEBSITE_DIR}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg mac_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-mac.dmg" \
--arg mac_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-mac.dmg" \
--arg windows_arm64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-arm64-win.msi" \
--arg windows_x64_url "$RELEASE_DIR/${{ env.URL_CODED_NAME }}-${VERSION_NO_V}-x64-win.msi" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"dmg-arm64": {
"url": $mac_arm64_url
},
"dmg-x64": {
"url": $mac_x64_url
},
"msi-arm64": {
"url": $windows_arm64_url
},
"msi-x64": {
"url": $windows_x64_url
}
}
}' > last_download.json
cat last_download.json
- name: Generate the update static endpoint for tauri
run: |
TAURI_DIR=out/tauri/$VERSION
MAC_ARM64_SIG=`cat $TAURI_DIR/macos/*-arm64.app.tar.gz.sig`
MAC_X64_SIG=`cat $TAURI_DIR/macos/*-x64.app.tar.gz.sig`
WINDOWS_SIG=`cat $TAURI_DIR/nsis/*.nsis.zip.sig`
RELEASE_DIR=https://${WEBSITE_DIR_TAURI}/${VERSION}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg mac_arm64_sig "$MAC_ARM64_SIG" \
--arg mac_arm64_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}-arm64.app.tar.gz" \
--arg mac_x64_sig "$MAC_X64_SIG" \
--arg mac_x64_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}-x64.app.tar.gz" \
--arg windows_sig "$WINDOWS_SIG" \
--arg windows_url "$RELEASE_DIR/nsis/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64-setup.nsis.zip" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"darwin-x86_64": {
"signature": $mac_x64_sig,
"url": $mac_x64_url
},
"darwin-aarch64": {
"signature": $mac_arm64_sig,
"url": $mac_arm64_url
},
"windows-x86_64": {
"signature": $windows_sig,
"url": $windows_url
}
}
}' > last_update.json
cat last_update.json
- name: List artifacts
run: "ls -R out"
- name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v2.1.5'
with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2.1.0
with:
project_id: ${{ env.GOOGLE_CLOUD_PROJECT_ID }}
- name: Upload release files to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.3
with:
path: out
glob: 'Zoo*'
parent: false
destination: ${{ env.BUCKET_DIR }}
- name: Upload update endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.3
with:
path: out
glob: 'latest*'
parent: false
destination: ${{ env.BUCKET_DIR }}
- name: Upload download endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.3
with:
path: last_download.json
destination: ${{ env.BUCKET_DIR }}
- name: Upload release files to public bucket for tauri
uses: google-github-actions/upload-cloud-storage@v2.1.1
with:
path: "out/tauri/${{ env.VERSION }}"
glob: '*/Zoo*'
parent: false
destination: ${{ env.BUCKET_DIR_TAURI }}/${{ env.VERSION }}
- name: Upload update endpoint to public bucket for tauri
uses: google-github-actions/upload-cloud-storage@v2.1.1
with:
path: last_update.json
destination: ${{ env.BUCKET_DIR }}
- name: Upload release files to Github
if: ${{ github.event_name == 'release' }}
uses: softprops/action-gh-release@v2
with:
files: 'out/Zoo*'
# TODO: Add GitHub publisher
announce_release:
needs: [publish-apps-release]
runs-on: ubuntu-22.04
if: github.event_name == 'release'
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Announce Release
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
RELEASE_VERSION: ${{ github.event.release.tag_name }}
RELEASE_BODY: ${{ github.event.release.body}}
run: python public/announce_release.py

View File

@ -1,117 +0,0 @@
name: build-test-web
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
actions: read
jobs:
check-format:
runs-on: 'ubuntu-22.04'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- run: yarn fmt-check
check-types:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- run: yarn build:wasm
- run: yarn xstate:typegen
- run: yarn tsc
- name: Lint
run: yarn eslint --max-warnings 0 src e2e
check-typos:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
- name: Install codespell
run: |
python -m pip install codespell
- name: Run codespell
run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration.
build-test-web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- run: yarn build:wasm
- 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 }}

View File

@ -37,4 +37,4 @@ jobs:
# We specifically want to test the disable-println feature
# Since it is not enabled by default, we need to specify it
# This is used in kcl-lsp
cargo check --all --features disable-println --features pyo3 --features cli
cargo check --all --features disable-println --features pyo3

View File

@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
dir: ['src/wasm-lib']
dir: ['src/wasm-lib', 'src-tauri']
steps:
- uses: actions/checkout@v4
- name: Install latest rust
@ -35,6 +35,24 @@ jobs:
override: true
components: clippy
- name: install dependencies
if: matrix.dir == 'src-tauri'
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libayatana-appindicator3-dev \
webkit2gtk-driver \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
at-spi2-core \
xvfb
yarn install
yarn build:wasm
yarn build:local
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1

View File

@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
dir: ['src/wasm-lib']
dir: ['src/wasm-lib', 'src-tauri']
steps:
- uses: actions/checkout@v4
- name: Install latest rust

57
.github/workflows/cargo-test-tauri.yml vendored Normal file
View File

@ -0,0 +1,57 @@
on:
push:
branches:
- main
paths:
- 'src-tauri/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-test-tauri.yml
pull_request:
paths:
- 'src-tauri/**.rs'
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- .github/workflows/cargo-test-tauri.yml
workflow_dispatch:
permissions: read-all
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
name: cargo test of tauri
jobs:
cargotest:
name: cargo test
runs-on: ubuntu-latest-8-cores
strategy:
matrix:
dir: ['src-tauri']
steps:
- uses: actions/checkout@v4
- name: Install latest rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: install dependencies
if: matrix.dir == 'src-tauri'
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libayatana-appindicator3-dev \
webkit2gtk-driver \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
at-spi2-core \
xvfb
- name: Rust Cache
uses: Swatinem/rust-cache@v2.6.1
- name: cargo test
shell: bash
run: |-
cd "${{ matrix.dir }}"
cargo test --all

View File

@ -7,7 +7,6 @@ on:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'src/wasm-lib/**.kcl'
- .github/workflows/cargo-test.yml
pull_request:
@ -16,7 +15,6 @@ on:
- '**/Cargo.toml'
- '**/Cargo.lock'
- '**/rust-toolchain.toml'
- 'src/wasm-lib/**.kcl'
- .github/workflows/cargo-test.yml
workflow_dispatch:
permissions: read-all
@ -38,6 +36,11 @@ jobs:
with:
toolchain: stable
override: true
- name: install dependencies
if: matrix.dir == 'src-tauri'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- name: Install vector
run: |
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh

575
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,575 @@
name: CI
on:
pull_request:
push:
branches:
- tauri
release:
types: [published]
schedule:
- cron: '0 4 * * *'
# Daily at 04:00 AM UTC
# Will checkout the last commit from the default branch (main as of 2023-10-04)
env:
CUT_RELEASE_PR: ${{ github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
BUILD_RELEASE: ${{ github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'pull_request' && (contains(github.event.pull_request.title, 'Cut release v')) }}
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
actions: read
jobs:
check-format:
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 fmt-check
check-types:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- run: yarn build:wasm
- run: yarn xstate:typegen
- run: yarn tsc
check-typos:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
- name: Install codespell
run: |
python -m pip install codespell
- name: Run codespell
run: codespell --config .codespellrc # Edit this file to tweak the typo list and other configuration.
build-test-web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- run: yarn build:wasm
- 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 }}
prepare-json-files:
runs-on: ubuntu-latest # seperate job on Ubuntu for easy string manipulations (compared to Windows)
outputs:
version: ${{ steps.export_version.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Set nightly version
if: github.event_name == 'schedule'
run: |
VERSION=$(date +'%-y.%-m.%-d') yarn bump-jsons
echo "$(jq --arg url 'https://dl.zoo.dev/releases/modeling-app/nightly/last_update.json' \
'.plugins.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
echo "$(jq --arg id 'dev.zoo.modeling-app-nightly' \
'.identifier=$id' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
echo "$(jq --arg name 'Zoo Modeling App (Nightly)' \
'.productName=$name' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
- name: Set updater test version
if: ${{ env.CUT_RELEASE_PR == 'true' }}
run: |
echo "$(jq --arg url 'https://dl.zoo.dev/releases/modeling-app/test/last_update.json' \
'.plugins.updater.endpoints[]=$url' src-tauri/tauri.release.conf.json --indent 2)" > src-tauri/tauri.release.conf.json
- uses: actions/upload-artifact@v3
if: ${{ github.event_name == 'schedule' || env.CUT_RELEASE_PR == 'true' }}
with:
path: |
package.json
src-tauri/tauri.conf.json
src-tauri/tauri.release.conf.json
- id: export_version
run: echo "version=`cat package.json | jq -r '.version'`" >> "$GITHUB_OUTPUT"
build-test-apps:
needs: [prepare-json-files]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-14, ubuntu-latest, windows-latest]
env:
# Specific Apple Universal target for macos
TAURI_ARGS_MACOS: ${{ matrix.os == 'macos-14' && '--target universal-apple-darwin' || '' }}
# Only build executable on linux (no appimage or deb)
TAURI_ARGS_UBUNTU: ${{ matrix.os == 'ubuntu-latest' && '--bundles' || '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v3
if: github.event_name == 'schedule'
- name: Copy updated .json files
if: github.event_name == 'schedule'
run: |
ls -l artifact
cp artifact/package.json package.json
cp artifact/src-tauri/tauri.conf.json src-tauri/tauri.conf.json
cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json
- name: Update WebView2 on Windows
if: matrix.os == 'windows-latest'
# Workaround needed to build the tauri windows app with matching edge version.
# From https://github.com/actions/runner-images/issues/9538
run: |
Invoke-WebRequest -Uri 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' -OutFile 'setup.exe'
Start-Process -FilePath setup.exe -Verb RunAs -Wait
- name: Install ubuntu system dependencies
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libayatana-appindicator3-dev \
webkit2gtk-driver \
libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev \
libwebkit2gtk-4.1-dev \
at-spi2-core \
xvfb
- name: Sync node version and setup cache
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn' # Set this to npm, yarn or pnpm.
- run: yarn install
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Setup Rust cache
uses: swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
- uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: Run build:wasm manually
shell: bash
env:
MODE: ${{ env.BUILD_RELEASE == 'true' && '--release' || '--debug' }}
run: |
mkdir src/wasm-lib/pkg; cd src/wasm-lib
echo "building with ${{ env.MODE }}"
npx wasm-pack build --target web --out-dir pkg ${{ env.MODE }}
cd ../../
cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
- name: Run vite build (build:both)
run: yarn vite build --mode ${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }}
- name: Fix format
run: yarn fmt
- name: Install x86 target for Universal builds (MacOS only)
if: matrix.os == 'macos-14'
run: |
rustup target add x86_64-apple-darwin
- name: Prepare certificate and variables (Windows only)
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }}
run: |
echo "${{secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > /d/Certificate_pkcs12.p12
cat /d/Certificate_pkcs12.p12
echo "::set-output name=version::${GITHUB_REF#refs/tags/v}"
echo "SM_HOST=${{ secrets.SM_HOST }}" >> "$GITHUB_ENV"
echo "SM_API_KEY=${{ secrets.SM_API_KEY }}" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_FILE=D:\\Certificate_pkcs12.p12" >> "$GITHUB_ENV"
echo "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" >> "$GITHUB_ENV"
echo "C:\Program Files (x86)\Windows Kits\10\App Certification Kit" >> $GITHUB_PATH
echo "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools" >> $GITHUB_PATH
echo "C:\Program Files\DigiCert\DigiCert One Signing Manager Tools" >> $GITHUB_PATH
shell: bash
- name: Setup certicate with SSM KSP (Windows only)
if: ${{ matrix.os == 'windows-latest' && env.BUILD_RELEASE == 'true' }}
run: |
curl -X GET https://one.digicert.com/signingmanager/api-ui/v1/releases/smtools-windows-x64.msi/download -H "x-api-key:%SM_API_KEY%" -o smtools-windows-x64.msi
msiexec /i smtools-windows-x64.msi /quiet /qn
smksp_registrar.exe list
smctl.exe keypair ls
C:\Windows\System32\certutil.exe -csp "DigiCert Signing Manager KSP" -key -user
smksp_cert_sync.exe
shell: cmd
- name: Build the app (debug)
if: ${{ env.BUILD_RELEASE == 'false' }}
run: "yarn tauri build --debug ${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}"
- name: Build for Mac TestFlight (nightly)
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
shell: bash
run: |
unset APPLE_SIGNING_IDENTITY
unset APPLE_CERTIFICATE
sign_app="3rd Party Mac Developer Application: KittyCAD Inc (${APPLE_TEAM_ID})"
sign_install="3rd Party Mac Developer Installer: KittyCAD Inc (${APPLE_TEAM_ID})"
profile="src-tauri/entitlements/Mac_App_Distribution.provisionprofile"
mkdir -p src-tauri/entitlements
echo -n "${APPLE_STORE_PROVISIONING_PROFILE}" | base64 --decode -o "${profile}"
echo -n "${APPLE_STORE_DISTRIBUTION_CERT}" | base64 --decode -o "dist.cer"
echo -n "${APPLE_STORE_INSTALLER_CERT}" | base64 --decode -o "installer.cer"
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD="password"
# create temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# import certificate to keychain
security import "dist.cer" -P "$APPLE_STORE_P12_PASSWORD" -k $KEYCHAIN_PATH -f pkcs12 -t cert -A
security import "installer.cer" -P "$APPLE_STORE_P12_PASSWORD" -k $KEYCHAIN_PATH -f pkcs12 -t cert -A
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
target="universal-apple-darwin"
# Turn off the default target
# We don't want to install the updater for the apple store build
sed -i.bu "s/default =/# default =/" src-tauri/Cargo.toml
rm src-tauri/Cargo.toml.bu
git diff src-tauri/Cargo.toml
yarn tauri build --target "${target}" --verbose --config src-tauri/tauri.app-store.conf.json
app_path="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.app"
build_name="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.pkg"
cp_dir="src-tauri/target/${target}/release/bundle/macos/Zoo Modeling App.app/Contents/embedded.provisionprofile"
entitlements="src-tauri/entitlements/app-store.entitlements"
cp "${profile}" "${cp_dir}"
codesign --deep --force -s "${sign_app}" --entitlements "${entitlements}" "${app_path}"
productbuild --component "${app_path}" /Applications/ --sign "${sign_install}" "${build_name}"
# Undo the changes to the Cargo.toml
git checkout src-tauri/Cargo.toml
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_STORE_PROVISIONING_PROFILE: ${{ secrets.APPLE_STORE_PROVISIONING_PROFILE }}
APPLE_STORE_DISTRIBUTION_CERT: ${{ secrets.APPLE_STORE_DISTRIBUTION_CERT }}
APPLE_STORE_INSTALLER_CERT: ${{ secrets.APPLE_STORE_INSTALLER_CERT }}
APPLE_STORE_P12_PASSWORD: ${{ secrets.APPLE_STORE_P12_PASSWORD }}
- name: 'Upload to Mac TestFlight (nightly)'
uses: apple-actions/upload-testflight-build@v1
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
with:
app-path: 'src-tauri/target/universal-apple-darwin/release/bundle/macos/Zoo Modeling App.pkg'
issuer-id: ${{ secrets.APPLE_STORE_ISSUER_ID }}
api-key-id: ${{ secrets.APPLE_STORE_API_KEY_ID }}
api-private-key: ${{ secrets.APPLE_STORE_API_PRIVATE_KEY }}
app-type: osx
- name: Clean up after Mac TestFlight (nightly)
if: ${{ github.event_name == 'schedule' && matrix.os == 'macos-14' }}
shell: bash
run: |
git status
# remove our target builds because we want to make sure the later build
# includes the updater, and that anything we changed with the target
# does not persist
rm -rf src-tauri/target
# Lets get rid of the info.plist for the normal mac builds since its
# being sketchy.
rm src-tauri/Info.plist
# We do this after the apple store because the apple store build is
# specific and we want to overwrite it with the this new build after and
# not upload the apple store build to the public bucket
- name: Build the app (release) and sign
if: ${{ env.BUILD_RELEASE == 'true' }}
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
TAURI_CONF_ARGS: "--config ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}"
run: "yarn tauri build ${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}"
- uses: actions/upload-artifact@v3
if: matrix.os != 'ubuntu-latest'
env:
PREFIX: ${{ matrix.os == 'macos-14' && 'src-tauri/target/universal-apple-darwin' || 'src-tauri/target' }}
MODE: ${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}
with:
path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*"
- name: Run e2e tests (linux only)
if: ${{ matrix.os == 'ubuntu-latest' && github.event_name != 'release' && github.event_name != 'schedule' }}
run: |
cargo install tauri-driver --force
source .env.${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }}
export VITE_KC_API_BASE_URL
xvfb-run yarn test:e2e:tauri
env:
E2E_APPLICATION: "./src-tauri/target/${{ env.BUILD_RELEASE == 'true' && 'release' || 'debug' }}/zoo-modeling-app"
KITTYCAD_API_TOKEN: ${{ env.BUILD_RELEASE == 'true' && secrets.KITTYCAD_API_TOKEN || secrets.KITTYCAD_API_TOKEN_DEV }}
- uses: actions/download-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' }}
- name: Copy updated .json file for updater test
if: ${{ env.CUT_RELEASE_PR == 'true' }}
run: |
ls -l artifact
cp artifact/src-tauri/tauri.release.conf.json src-tauri/tauri.release.conf.json
cat src-tauri/tauri.release.conf.json
- name: Build the app (release, updater test)
if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }}
env:
TAURI_CONF_ARGS: "-c ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}"
TAURI_BUNDLE_ARGS: "-b ${{ matrix.os == 'windows-latest' && 'msi' || 'dmg' }}"
run: "yarn tauri build ${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_BUNDLE_ARGS }} ${{ env.TAURI_ARGS_MACOS }}"
- uses: actions/upload-artifact@v3
if: ${{ env.CUT_RELEASE_PR == 'true' && matrix.os != 'ubuntu-latest' }}
with:
path: "${{ matrix.os == 'macos-14' && 'src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg' || 'src-tauri/target/release/bundle/msi/*.msi' }}"
name: updater-test
publish-apps-release:
permissions:
contents: write
runs-on: ubuntu-latest
if: ${{ github.event_name == 'release' || github.event_name == 'schedule' }}
needs: [check-format, check-types, check-typos, build-test-web, prepare-json-files, build-test-apps]
env:
VERSION_NO_V: ${{ needs.prepare-json-files.outputs.version }}
VERSION: ${{ github.event_name == 'release' && format('v{0}', needs.prepare-json-files.outputs.version) || needs.prepare-json-files.outputs.version }}
PUB_DATE: ${{ github.event_name == 'release' && github.event.release.created_at || github.event.repository.updated_at }}
NOTES: ${{ github.event_name == 'release' && github.event.release.body || format('Nightly build, commit {0}', github.sha) }}
BUCKET_DIR: ${{ github.event_name == 'release' && 'dl.kittycad.io/releases/modeling-app' || 'dl.kittycad.io/releases/modeling-app/nightly' }}
WEBSITE_DIR: ${{ github.event_name == 'release' && 'dl.zoo.dev/releases/modeling-app' || 'dl.zoo.dev/releases/modeling-app/nightly' }}
URL_CODED_NAME: ${{ github.event_name == 'schedule' && 'Zoo%20Modeling%20App%20%28Nightly%29' || 'Zoo%20Modeling%20App' }}
steps:
- uses: actions/download-artifact@v3
- name: Generate the update static endpoint
run: |
ls -l artifact/*/*oo*
DARWIN_SIG=`cat artifact/macos/*.app.tar.gz.sig`
WINDOWS_SIG=`cat artifact/msi/*.msi.zip.sig`
RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg darwin_sig "$DARWIN_SIG" \
--arg darwin_url "$RELEASE_DIR/macos/${{ env.URL_CODED_NAME }}.app.tar.gz" \
--arg windows_sig "$WINDOWS_SIG" \
--arg windows_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi.zip" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"darwin-x86_64": {
"signature": $darwin_sig,
"url": $darwin_url
},
"darwin-aarch64": {
"signature": $darwin_sig,
"url": $darwin_url
},
"windows-x86_64": {
"signature": $windows_sig,
"url": $windows_url
}
}
}' > last_update.json
cat last_update.json
- name: Generate the download static endpoint
run: |
RELEASE_DIR=https://${WEBSITE_DIR}/${VERSION}
jq --null-input \
--arg version "${VERSION}" \
--arg pub_date "${PUB_DATE}" \
--arg notes "${NOTES}" \
--arg darwin_url "$RELEASE_DIR/dmg/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_universal.dmg" \
--arg windows_url "$RELEASE_DIR/msi/${{ env.URL_CODED_NAME }}_${VERSION_NO_V}_x64_en-US.msi" \
'{
"version": $version,
"pub_date": $pub_date,
"notes": $notes,
"platforms": {
"dmg-universal": {
"url": $darwin_url
},
"msi-x86_64": {
"url": $windows_url
}
}
}' > last_download.json
cat last_download.json
- name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@v2.1.3'
with:
credentials_json: '${{ secrets.GOOGLE_CLOUD_DL_SA }}'
- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2.1.0
with:
project_id: kittycadapi
- name: Upload release files to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.1
with:
path: artifact
glob: '*/Zoo*'
parent: false
destination: ${{ env.BUCKET_DIR }}/${{ env.VERSION }}
- name: Upload update endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.1
with:
path: last_update.json
destination: ${{ env.BUCKET_DIR }}
- name: Upload download endpoint to public bucket
uses: google-github-actions/upload-cloud-storage@v2.1.1
with:
path: last_download.json
destination: ${{ env.BUCKET_DIR }}
- name: Upload release files to Github
if: ${{ github.event_name == 'release' }}
uses: softprops/action-gh-release@v2
with:
files: 'artifact/*/Zoo*'
announce_release:
needs: [publish-apps-release]
runs-on: ubuntu-latest
if: github.event_name == 'release'
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Announce Release
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
RELEASE_VERSION: ${{ github.event.release.tag_name }}
RELEASE_BODY: ${{ github.event.release.body}}
run: python public/announce_release.py

View File

@ -3,7 +3,7 @@ name: Create Release
on:
push:
branches:
- main
- tauri
jobs:
create-release:

View File

@ -1,31 +0,0 @@
name: Label Issues
on:
issues:
types: [opened]
permissions:
issues: write
jobs:
label:
runs-on: ubuntu-latest
steps:
- name: Check if issue opener is ZooSpiritWolf
id: check_opener
uses: actions/github-script@v7
with:
script: |
const issueOpener = context.payload.issue.user.login;
return issueOpener === 'ZooSpiritWolf';
- name: Add labels
if: steps.check_opener.outputs.result == 'true'
uses: actions/github-script@v7
with:
script: |
github.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
labels: ['bug', 'regression', 'high-priority']
});

View File

@ -6,7 +6,7 @@ on:
branches: [ main ]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
@ -33,15 +33,14 @@ jobs:
rust:
- 'src/wasm-lib/**'
playwright-chrome:
timeout-minutes: ${{ matrix.os == 'macos-14' && 60 || 40 }}
playwright-ubuntu:
timeout-minutes: 30
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
runs-on: ${{ matrix.os }}
needs: check-rust-changes
steps:
- name: Tune GitHub-hosted runner network
@ -53,7 +52,6 @@ jobs:
cache: 'yarn'
- uses: KittyCAD/action-install-cli@main
- name: Install dependencies
shell: bash
run: yarn
- name: Cache Playwright Browsers
uses: actions/cache@v4
@ -62,7 +60,6 @@ jobs:
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Browsers
shell: bash
run: yarn playwright install --with-deps
- name: Download Wasm Cache
id: download-wasm
@ -77,7 +74,6 @@ jobs:
path: src/wasm-lib/pkg
- name: copy wasm blob
if: needs.check-rust-changes.outputs.rust-changed == 'false'
shell: bash
run: cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
continue-on-error: true
- name: Setup Rust
@ -92,15 +88,7 @@ jobs:
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: install good sed
if: ${{ startsWith(matrix.os, 'macos') }}
shell: bash
run: |
brew install gnu-sed
echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
- name: Install vector
shell: bash
if: ${{ !startsWith(matrix.os, 'windows') }}
run: |
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
chmod +x /tmp/vector.sh
@ -116,39 +104,31 @@ jobs:
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- name: Build Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
shell: bash
run: yarn build:wasm
- name: OR Build Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
shell: bash
run: yarn build:wasm
- name: build web
run: yarn build:local
shell: bash
- name: Run ubuntu/chrome snapshots
shell: bash
run: |
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --retries="3" --update-snapshots --grep=@snapshot --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
env:
CI: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
if: always()
with:
name: playwright-report-${{ matrix.os }}-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
name: playwright-report-ubuntu-snapshot-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
retention-days: 30
overwrite: true
- name: Clean up test-results
if: ${{ !cancelled() && (success() || failure()) }}
if: always()
continue-on-error: true
run: rm -r test-results
- name: check for changes
shell: bash
id: git-check
run: |
git add .
@ -158,7 +138,6 @@ jobs:
fi
- name: Commit changes, if any
if: steps.git-check.outputs.modified == 'true'
shell: bash
run: |
git add .
git config --local user.email "github-actions[bot]@users.noreply.github.com"
@ -167,31 +146,32 @@ jobs:
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
git commit -am "A snapshot a day keeps the bugs away! 📷🐛 (OS: ${{matrix.os}})" || true
# TODO when webkit works on ubuntu remove the os part of the commit message
git commit -am "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" || true
git push
git push origin ${{ github.head_ref }}
# only upload artifacts if there's actually changes
- uses: actions/upload-artifact@v4
if: steps.git-check.outputs.modified == 'true'
with:
name: playwright-report-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
name: playwright-report-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
retention-days: 30
# if have previous run results, use them
- uses: actions/download-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
if: always()
continue-on-error: true
with:
name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
name: test-results-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
- name: Run playwright/chrome flow (with retries)
- name: Run ubuntu/chrome flow (with retries)
id: retry
if: ${{ !cancelled() && (success() || failure()) }}
shell: bash
if: always()
run: |
if [[ ! -f "test-results/.last-run.json" ]]; then
# if no last run artifact, than run plawright normally
echo "run playwright normally"
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --grep-invert="@snapshot|@electron" || true
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --grep-invert=@snapshot || true
# # send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
fi
@ -206,7 +186,7 @@ jobs:
if [[ $failed_tests -gt 0 ]]; then
echo "retried=true" >>$GITHUB_OUTPUT
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|@electron" || true
yarn playwright test --project="Google Chrome" --config=playwright.ci.config.ts --last-failed --grep-invert=@snapshot || true
# send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
retry=$((retry + 1))
@ -232,9 +212,6 @@ jobs:
exit 0
env:
CI: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: send to axiom
if: always()
@ -244,26 +221,26 @@ jobs:
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
name: test-results-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
retention-days: 30
overwrite: true
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.os }}-${{ matrix.shardIndex }}-${{ github.sha }}
name: playwright-report-ubuntu-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
retention-days: 30
overwrite: true
playwright-electron:
playwright-macos:
timeout-minutes: 30
runs-on: macos-14
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-14]
timeout-minutes: 30
runs-on: ${{ matrix.os }}
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
needs: check-rust-changes
steps:
- name: Tune GitHub-hosted runner network
@ -273,19 +250,18 @@ jobs:
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- uses: KittyCAD/action-install-cli@main
- name: Install dependencies
shell: bash
run: yarn
- name: Cache Playwright Browsers
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright Browsers
shell: bash
run: yarn playwright install chromium --with-deps
run: yarn playwright install --with-deps
- name: Download Wasm Cache
id: download-wasm
if: needs.check-rust-changes.outputs.rust-changed == 'false'
@ -299,7 +275,6 @@ jobs:
path: src/wasm-lib/pkg
- name: copy wasm blob
if: needs.check-rust-changes.outputs.rust-changed == 'false'
shell: bash
run: cp src/wasm-lib/pkg/wasm_lib_bg.wasm public
continue-on-error: true
- name: Setup Rust
@ -314,64 +289,49 @@ jobs:
uses: Swatinem/rust-cache@v2
with:
workspaces: './src/wasm-lib'
- name: install good sed
if: ${{ startsWith(matrix.os, 'macos') }}
shell: bash
run: |
brew install gnu-sed
echo "/opt/homebrew/opt/gnu-sed/libexec/gnubin" >> $GITHUB_PATH
- name: Install vector
if: ${{ !startsWith(matrix.os, 'windows') }}
shell: bash
run: |
curl --proto '=https' --tlsv1.2 -sSfL https://sh.vector.dev > /tmp/vector.sh
chmod +x /tmp/vector.sh
/tmp/vector.sh -y -no-modify-path
mkdir -p /tmp/vector
cp .github/workflows/vector.toml /tmp/vector.toml
sed -i "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
sed -i "" "s#GITHUB_WORKFLOW#${GITHUB_WORKFLOW}#g" /tmp/vector.toml
sed -i "" "s#GITHUB_REPOSITORY#${GITHUB_REPOSITORY}#g" /tmp/vector.toml
sed -i "" "s#GITHUB_SHA#${GITHUB_SHA}#g" /tmp/vector.toml
sed -i "" "s#GITHUB_REF_NAME#${GITHUB_REF_NAME}#g" /tmp/vector.toml
sed -i "" "s#GH_ACTIONS_AXIOM_TOKEN#${{secrets.GH_ACTIONS_AXIOM_TOKEN}}#g" /tmp/vector.toml
cat /tmp/vector.toml
${HOME}/.vector/bin/vector --config /tmp/vector.toml &
- name: Build Wasm (because rust diff)
if: needs.check-rust-changes.outputs.rust-changed == 'true'
shell: bash
run: yarn build:wasm
- name: OR Build Wasm (because wasm cache failed)
if: steps.download-wasm.outcome == 'failure'
shell: bash
run: yarn build:wasm
- name: build electron
shell: bash
run: yarn tron:package
- name: build web
run: yarn build:local
# if have previous run results, use them
- uses: actions/download-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
if: ${{ always() }}
continue-on-error: true
with:
name: test-results-${{ matrix.os }}-${{ github.sha }}
name: test-results-macos-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
- name: Run electron tests (with retries)
- name: Run macos/safari flow (with retries)
id: retry
if: ${{ !cancelled() && (success() || failure()) }}
shell: bash
if: always()
run: |
if [[ ! -f "test-results/.last-run.json" ]]; then
# if no last run artifact, than run plawright normally
echo "run playwright normally"
if [[ "$IS_UBUNTU" == "true" ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn playwright test --config=playwright.electron.config.ts --grep=@electron || true
else
yarn playwright test --config=playwright.electron.config.ts --grep=@electron || true
fi
yarn playwright test --project="webkit" --config=playwright.ci.config.ts --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --grep-invert=@snapshot || true
# # send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
fi
retry=1
max_retrys=2
max_retrys=4
# retry failed tests, doing our own retries because using inbuilt playwright retries causes connection issues
while [[ $retry -le $max_retrys ]]; do
@ -380,11 +340,7 @@ jobs:
if [[ $failed_tests -gt 0 ]]; then
echo "retried=true" >>$GITHUB_OUTPUT
echo "run playwright with last failed tests and retry $retry"
if [[ "$IS_UBUNTU" == "true" ]]; then
xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn playwright test --config=playwright.electron.config.ts --grep=@electron || true
else
yarn playwright test --config=playwright.electron.config.ts --grep=@electron || true
fi
yarn playwright test --project="webkit" --config=playwright.ci.config.ts --last-failed --grep-invert=@snapshot || true
# send to axiom
node playwrightProcess.mjs | tee /tmp/github-actions.log > /dev/null 2>&1
retry=$((retry + 1))
@ -410,27 +366,18 @@ jobs:
exit 0
env:
CI: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
IS_UBUNTU: ${{ startsWith(matrix.os, 'ubuntu') && 'true' || 'false' }}
#DEBUG: 'pw:browser*'
- name: send to axiom
if: ${{ !cancelled() && (success() || failure()) && !startsWith(matrix.os, 'windows') }}
shell: bash
run: |
node playwrightProcess.mjs | tee /tmp/github-actions.log
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
if: ${{ always() }}
with:
name: test-results-electron-${{ matrix.os }}-${{ github.sha }}
name: test-results-macos-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
retention-days: 30
overwrite: true
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
if: ${{ always() }}
with:
name: playwright-report-electron-${{ matrix.os }}-${{ github.sha }}
name: playwright-report-macos-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/
retention-days: 30
overwrite: true

6
.gitignore vendored
View File

@ -54,15 +54,11 @@ e2e/playwright/export-snapshots/*
## generated files
src/**/*.typegen.ts
src-tauri/gen
src/wasm-lib/grackle/stdlib_cube_partial.json
Mac_App_Distribution.provisionprofile
*.tsbuildinfo
src/wasm-lib/pkg
venv
.vite/
# electron
out/

View File

@ -89,19 +89,26 @@ enable third-party cookies. You can enable third-party cookies by clicking on
the eye with a slash through it in the URL bar, and clicking on "Enable
Third-Party Cookies".
## Desktop
## Tauri
To spin up the desktop app, `yarn install` and `yarn build:wasm-dev` need to have been done before hand then
To spin up up tauri dev, `yarn install` and `yarn build:wasm-dev` need to have been done before hand then
```
yarn electron:start
yarn tauri dev
```
This will start the application and hot-reload on changed.
Will spin up the web app before opening up the tauri dev desktop app. Note that it's probably a good idea to close the browser tab that gets opened since at the time of writing they can conflict.
Devtools can be opened with the usual Cmd/Ctrl-Shift-I.
The dev instance automatically opens up the browser devtools which can be disabled by [commenting it out](https://github.com/KittyCAD/modeling-app/blob/main/src-tauri/src/main.rs#L92.)
To build, run `yarn tron:package`.
To build, run `yarn tauri build`, or `yarn tauri build --debug` to keep access to the devtools.
Note that these became separate apps on Macos, so make sure you open the right one after a build 😉
![image](https://github.com/KittyCAD/modeling-app/assets/29681384/a08762c5-8d16-42d8-a02f-a5efc9ae5551)
<img width="1232" alt="image" src="https://user-images.githubusercontent.com/29681384/211947063-46164bb4-7bdd-45cb-9a76-2f40c71a24aa.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
@ -110,6 +117,7 @@ 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 wasm-prep
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
```
@ -188,22 +196,12 @@ For more information on fuzzing you can check out
### Playwright tests
You will need a `./e2e/playwright/playwright-secrets.env` file:
```bash
$ touch ./e2e/playwright/playwright-secrets.env
$ cat ./e2e/playwright/playwright-secrets.env
token=<dev.zoo.dev/account/api-tokens>
snapshottoken=<your-snapshot-token>
```
For a portable way to run Playwright you'll need Docker.
#### Generic example
After that, open a terminal and run:
```bash
docker run --network host --rm --init -it playwright/chrome:playwright-x.xx.x
docker run --network host --rm --init -it playwright/chrome:playwright-1.43.1
```
and in another terminal, run:
@ -212,27 +210,21 @@ and in another terminal, run:
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn playwright test --project="Google Chrome" <test suite>
```
An example of a `<test suite>` is: `e2e/playwright/flow-tests.spec.ts`
#### Specific example
YOU WILL NEED A PLAYWRIGHT-SECRETS.ENV FILE:
open a terminal and run:
```bash
docker run --network host --rm --init -it playwright/chrome:playwright-1.46.0
```
and in another terminal, run:
```bash
PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:4444/ yarn playwright test --project="Google Chrome" e2e/playwright/command-bar-tests.spec.ts
# ./e2e/playwright/playwright-secrets.env
token=<your-token>
snapshottoken=<your-snapshot-token>
```
then replace "your-token" with a dev token from dev.zoo.dev/account/api-tokens
run a specific test change the test from `test('...` to `test.only('...`
(note if you commit this, the tests will instantly fail without running any of the tests)
**Gotcha**: running the docker container with a mismatched image against your `./node_modules/playwright` will cause a failure. Make sure the versions are matched and up to date.
run headed
```

View File

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

View File

@ -236,7 +236,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -254,7 +254,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -445,7 +445,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -463,7 +463,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -240,7 +240,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -258,7 +258,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -449,7 +449,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -467,7 +467,7 @@ const extrusion = extrude(5, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -155,7 +155,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -173,7 +173,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -364,7 +364,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -382,7 +382,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -575,7 +575,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -593,7 +593,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -784,7 +784,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -802,7 +802,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -154,7 +154,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -172,7 +172,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -363,7 +363,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -381,7 +381,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -574,7 +574,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -592,7 +592,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -783,7 +783,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -801,7 +801,7 @@ const extrusion = extrude(10, sketch001)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -156,7 +156,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -174,7 +174,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -365,7 +365,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -383,7 +383,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -576,7 +576,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -594,7 +594,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -785,7 +785,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -803,7 +803,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -248,7 +248,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -266,7 +266,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -457,7 +457,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -475,7 +475,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -668,7 +668,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -686,7 +686,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -877,7 +877,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -895,7 +895,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -153,7 +153,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -171,7 +171,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -362,7 +362,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -380,7 +380,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -573,7 +573,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -591,7 +591,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -782,7 +782,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -800,7 +800,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -153,7 +153,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -171,7 +171,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -362,7 +362,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -380,7 +380,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -573,7 +573,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -591,7 +591,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -782,7 +782,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -800,7 +800,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -166,7 +166,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -184,7 +184,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -375,7 +375,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -393,7 +393,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -586,7 +586,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -604,7 +604,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -795,7 +795,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -813,7 +813,7 @@ const exampleSketch = startSketchOn('XZ')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

View File

@ -159,7 +159,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -177,7 +177,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -368,7 +368,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -386,7 +386,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -579,7 +579,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -597,7 +597,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -788,7 +788,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -806,7 +806,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -381,7 +381,7 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -399,7 +399,7 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -785,7 +785,7 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -803,7 +803,7 @@ const mountingPlate = extrude(thickness, mountingPlateSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

View File

@ -154,7 +154,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -172,7 +172,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -363,7 +363,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -381,7 +381,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -574,7 +574,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -592,7 +592,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -783,7 +783,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -801,7 +801,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -32,21 +32,17 @@ layout: manual
* [`chamfer`](kcl/chamfer)
* [`circle`](kcl/circle)
* [`close`](kcl/close)
* [`cm`](kcl/cm)
* [`cos`](kcl/cos)
* [`e`](kcl/e)
* [`extrude`](kcl/extrude)
* [`fillet`](kcl/fillet)
* [`floor`](kcl/floor)
* [`ft`](kcl/ft)
* [`getNextAdjacentEdge`](kcl/getNextAdjacentEdge)
* [`getOppositeEdge`](kcl/getOppositeEdge)
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
* [`helix`](kcl/helix)
* [`hole`](kcl/hole)
* [`hollow`](kcl/hollow)
* [`import`](kcl/import)
* [`inch`](kcl/inch)
* [`int`](kcl/int)
* [`lastSegX`](kcl/lastSegX)
* [`lastSegY`](kcl/lastSegY)
@ -59,10 +55,8 @@ layout: manual
* [`log`](kcl/log)
* [`log10`](kcl/log10)
* [`log2`](kcl/log2)
* [`m`](kcl/m)
* [`max`](kcl/max)
* [`min`](kcl/min)
* [`mm`](kcl/mm)
* [`patternCircular2d`](kcl/patternCircular2d)
* [`patternCircular3d`](kcl/patternCircular3d)
* [`patternLinear2d`](kcl/patternLinear2d)
@ -88,7 +82,6 @@ layout: manual
* [`tan`](kcl/tan)
* [`tangentialArc`](kcl/tangentialArc)
* [`tangentialArcTo`](kcl/tangentialArcTo)
* [`tangentialArcToRelative`](kcl/tangentialArcToRelative)
* [`tau`](kcl/tau)
* [`toDegrees`](kcl/toDegrees)
* [`toRadians`](kcl/toRadians)
@ -96,4 +89,3 @@ layout: manual
* [`xLineTo`](kcl/xLineTo)
* [`yLine`](kcl/yLine)
* [`yLineTo`](kcl/yLineTo)
* [`yd`](kcl/yd)

File diff suppressed because one or more lines are too long

View File

@ -145,7 +145,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -163,7 +163,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -354,7 +354,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -372,7 +372,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -145,7 +145,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -163,7 +163,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -354,7 +354,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -372,7 +372,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -158,7 +158,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -176,7 +176,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -367,7 +367,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -385,7 +385,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -578,7 +578,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -596,7 +596,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -787,7 +787,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -805,7 +805,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -145,7 +145,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -163,7 +163,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -354,7 +354,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -372,7 +372,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -565,7 +565,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -583,7 +583,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -774,7 +774,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -792,7 +792,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -45,7 +45,7 @@ const example = extrude(1, exampleSketch)
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
repetitions: number,
// Whether or not to rotate the duplicates as they are copied.
rotateDuplicates: bool,
rotateDuplicates: string,
}
```
* `sketch_group_set`: `SketchGroupSet` - A sketch group or a group of sketch groups. (REQUIRED)
@ -163,7 +163,7 @@ const example = extrude(1, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -181,7 +181,7 @@ const example = extrude(1, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -373,7 +373,7 @@ const example = extrude(1, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -391,7 +391,7 @@ const example = extrude(1, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -285,7 +285,7 @@ const example = extrude(1, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -303,7 +303,7 @@ const example = extrude(1, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -287,7 +287,7 @@ let vase = layer()
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -305,7 +305,7 @@ let vase = layer()
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

View File

@ -146,7 +146,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -164,7 +164,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -355,7 +355,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -373,7 +373,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -141,7 +141,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -159,7 +159,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -350,7 +350,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -368,7 +368,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -140,7 +140,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -158,7 +158,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -349,7 +349,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -367,7 +367,7 @@ const sketch001 = startSketchOn('XY')
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -399,7 +399,7 @@ shell({ faces: [myTag], thickness: 0.25 }, firstSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -417,7 +417,7 @@ shell({ faces: [myTag], thickness: 0.25 }, firstSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -794,7 +794,7 @@ shell({ faces: [myTag], thickness: 0.25 }, firstSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -812,7 +812,7 @@ shell({ faces: [myTag], thickness: 0.25 }, firstSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -224,7 +224,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -242,7 +242,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -527,7 +527,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -545,7 +545,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -736,7 +736,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -754,7 +754,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -171,7 +171,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -189,7 +189,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -380,7 +380,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -398,7 +398,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -148,7 +148,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -166,7 +166,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -357,7 +357,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -375,7 +375,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -568,7 +568,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -586,7 +586,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -777,7 +777,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -795,7 +795,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -148,7 +148,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -166,7 +166,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -357,7 +357,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -375,7 +375,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -568,7 +568,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -586,7 +586,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -777,7 +777,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -795,7 +795,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -146,7 +146,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -164,7 +164,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -355,7 +355,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -373,7 +373,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -566,7 +566,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -584,7 +584,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -775,7 +775,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -793,7 +793,7 @@ const example = extrude(10, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

View File

@ -144,7 +144,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -162,7 +162,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -353,7 +353,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -371,7 +371,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -564,7 +564,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -582,7 +582,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -773,7 +773,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.
@ -791,7 +791,7 @@ const example = extrude(5, exampleSketch)
} |
{
// arc's direction
ccw: bool,
ccw: string,
// the arc's center
center: [number, number],
// The from point.

File diff suppressed because one or more lines are too long

View File

@ -1,66 +0,0 @@
import { test, expect } from '@playwright/test'
import { setupElectron, tearDown } from './test-utils'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Electron app header tests', () => {
test(
'Open Command Palette button has correct shortcut',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async () => {},
})
await page.setViewportSize({ width: 1200, height: 500 })
// No space before the shortcut since it checks textContent.
let text
switch (process.platform) {
case 'darwin':
text = 'Commands⌘K'
break
case 'win32':
text = 'CommandsCtrl+K'
break
default: // 'linux' etc.
text = 'CommandsCtrl+K'
break
}
const commandsButton = page.getByRole('button', { name: 'Commands' })
await expect(commandsButton).toBeVisible()
await expect(commandsButton).toHaveText(text)
await electronApp.close()
}
)
test(
'User settings has correct shortcut',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async () => {},
})
await page.setViewportSize({ width: 1200, height: 500 })
// Open the user sidebar menu.
await page.getByTestId('user-sidebar-toggle').click()
// No space after "User settings" since it's textContent.
const text =
process.platform === 'darwin' ? 'User settings⌘,' : 'User settingsCtrl,'
const userSettingsButton = page.getByTestId('user-settings')
await expect(userSettingsButton).toBeVisible()
await expect(userSettingsButton).toHaveText(text)
await electronApp.close()
}
)
})

View File

@ -84,7 +84,6 @@ async function doBasicSketch(page: Page, openPanes: string[]) {
} else {
await page.waitForTimeout(500)
}
await page.waitForTimeout(200)
await page.mouse.click(startXPx, 500 - PUR * 20)
if (openPanes.includes('code')) {
await expect(u.codeLocator)
@ -96,49 +95,32 @@ async function doBasicSketch(page: Page, openPanes: string[]) {
}
// deselect line tool
const btnLine = page.getByTestId('line')
const btnLineAriaPressed = await btnLine.getAttribute('aria-pressed')
if (btnLineAriaPressed === 'true') {
await btnLine.click()
}
await page.waitForTimeout(100)
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')) {
await expect
.poll(async () => u.getGreatestPixDiff(line1, TEST_COLORS.WHITE))
.toBeLessThan(3)
await page.waitForTimeout(100)
await expect
.poll(async () => u.getGreatestPixDiff(line1, [249, 249, 249]))
.toBeLessThan(3)
await page.waitForTimeout(100)
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')) {
await expect(
await u.getGreatestPixDiff(line1, TEST_COLORS.BLUE)
).toBeLessThan(3)
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')
await page.waitForTimeout(100)
// click between the latest two clicks to get center of the line
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 20)
await page.waitForTimeout(100)
// selected two lines therefore there should be two cursors
if (openPanes.includes('code')) {
await expect(page.locator('.cm-cursor')).toHaveCount(2)
await page.waitForTimeout(100)
}
await page.getByRole('button', { name: 'Length: open menu' }).click()
@ -155,8 +137,6 @@ async function doBasicSketch(page: Page, openPanes: string[]) {
test.describe('Basic sketch', () => {
test('code pane open at start', async ({ page }) => {
// Skip on windows it is being weird.
test.skip(process.platform === 'win32', 'Skip on windows')
await doBasicSketch(page, ['code'])
})

View File

@ -61,7 +61,7 @@ test.describe('Can create sketches on all planes and their back sides', () => {
await page.waitForTimeout(300) // wait for animation
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
page.getByRole('button', { name: 'Line', exact: true })
).toBeVisible()
// draw a line
@ -72,10 +72,7 @@ test.describe('Can create sketches on all planes and their back sides', () => {
await expect(page.locator('.cm-content')).toHaveText(code)
await page
.getByRole('button', { name: 'line Line', exact: true })
.first()
.click()
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"]')

View File

@ -1,16 +1,8 @@
import { test, expect } from '@playwright/test'
import {
getUtils,
setup,
setupElectron,
tearDown,
executorInputPath,
} from './test-utils'
import { join } from 'path'
import { getUtils, setup, tearDown } from './test-utils'
import { bracket } from 'lib/exampleKcl'
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from './storageStates'
import fsp from 'fs/promises'
test.beforeEach(async ({ context, page }) => {
await setup(context, page)
@ -91,7 +83,7 @@ test.describe('Code pane and errors', () => {
// error text on hover
await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: |').first()).toBeVisible()
await expect(page.getByText('Unexpected token').first()).toBeVisible()
// Close the code pane
await codePaneButton.click()
@ -114,7 +106,7 @@ test.describe('Code pane and errors', () => {
// error text on hover
await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: |').first()).toBeVisible()
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 ({
@ -225,91 +217,3 @@ test.describe('Code pane and errors', () => {
).toBeVisible()
})
})
test(
'Opening multiple panes persists when switching projects',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
// Setup multiple projects.
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const routerTemplateDir = join(dir, 'router-template-slate')
const bracketDir = join(dir, 'bracket')
await Promise.all([
fsp.mkdir(routerTemplateDir, { recursive: true }),
fsp.mkdir(bracketDir, { recursive: true }),
])
await Promise.all([
fsp.copyFile(
executorInputPath('router-template-slate.kcl'),
join(routerTemplateDir, 'main.kcl')
),
fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
),
])
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await test.step('Opening the bracket project should load', async () => {
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
})
// If they're open by default, we're not actually testing anything.
await test.step('Pre-condition: panes are not already visible', async () => {
await expect(page.locator('#variables-pane')).not.toBeVisible()
await expect(page.locator('#logs-pane')).not.toBeVisible()
})
await test.step('Open multiple panes', async () => {
await u.openKclCodePanel()
await u.openVariablesPane()
await u.openLogsPane()
})
await test.step('Clicking the logo takes us back to the projects page / home', async () => {
await page.getByTestId('app-logo').click()
await expect(page.getByRole('link', { name: 'bracket' })).toBeVisible()
await expect(page.getByText('router-template-slate')).toBeVisible()
await expect(page.getByText('New Project')).toBeVisible()
})
await test.step('Opening the router-template project should load', async () => {
await expect(page.getByText('router-template-slate')).toBeVisible()
await page.getByText('router-template-slate').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
})
await test.step('All panes opened before should be visible', async () => {
await expect(page.locator('#code-pane')).toBeVisible()
await expect(page.locator('#variables-pane')).toBeVisible()
await expect(page.locator('#logs-pane')).toBeVisible()
})
await electronApp.close()
}
)

View File

@ -42,11 +42,11 @@ test.describe('Command bar tests', () => {
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Extrude' }).click()
await page.waitForTimeout(200)
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(200)
await page.waitForTimeout(100)
await page.keyboard.press('Enter')
await page.waitForTimeout(200)
await page.waitForTimeout(100)
await expect(page.locator('.cm-activeLine')).toHaveText(
`const extrude001 = extrude(${KCL_DEFAULT_LENGTH}, sketch001)`
)
@ -124,7 +124,7 @@ const extrude001 = extrude(-10, sketch001)`
await expect(cmdSearchBar).not.toBeVisible()
// Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('ControlOrMeta+K')
await page.keyboard.press('Meta+K')
await expect(cmdSearchBar).toBeVisible()
await expect(cmdSearchBar).toBeFocused()
@ -185,7 +185,7 @@ const extrude001 = extrude(-10, sketch001)`
await page.locator('.cm-content').click()
// Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('ControlOrMeta+K')
await page.keyboard.press('Meta+K')
let cmdSearchBar = page.getByPlaceholder('Search commands')
await expect(cmdSearchBar).toBeVisible()
@ -250,7 +250,7 @@ const extrude001 = extrude(-10, sketch001)`
await page.getByRole('button', { name: 'Extrude' }).isEnabled()
let cmdSearchBar = page.getByPlaceholder('Search commands')
await page.keyboard.press('ControlOrMeta+K')
await page.keyboard.press('Meta+K')
await expect(cmdSearchBar).toBeVisible()
// Search for extrude command and choose it
@ -321,18 +321,20 @@ const extrude001 = extrude(distance001, sketch001)`.replace(
name: 'rectangle',
})
const rectangleToolButton = page.getByRole('button', {
name: 'rectangle Corner rectangle',
name: 'Corner rectangle',
exact: true,
})
const lineToolCommand = page.getByRole('option', {
name: 'Line',
})
const lineToolButton = page.getByRole('button', {
name: 'line Line',
name: 'Line',
exact: true,
})
const arcToolCommand = page.getByRole('option', { name: 'Tangential Arc' })
const arcToolButton = page.getByRole('button', {
name: 'arc Tangential Arc',
name: 'Tangential Arc',
exact: true,
})
// Start a sketch

View File

@ -9,7 +9,6 @@ test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Copilot ghost text', () => {
// eslint-disable-next-line jest/valid-title
test.skip(true, 'Needs to get covered again')
test('completes code in empty file', async ({ page }) => {
@ -332,6 +331,7 @@ test.describe('Copilot ghost text', () => {
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(``)
@ -348,10 +348,10 @@ test.describe('Copilot ghost text', () => {
)
// Going elsewhere in the code should hide the ghost text.
await page.keyboard.down('ControlOrMeta')
await page.keyboard.down(CtrlKey)
await page.keyboard.down('Shift')
await page.keyboard.press('KeyZ')
await page.keyboard.up('ControlOrMeta')
await page.keyboard.up(CtrlKey)
await page.keyboard.up('Shift')
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
@ -367,6 +367,8 @@ test.describe('Copilot ghost text', () => {
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(``)
@ -379,17 +381,17 @@ test.describe('Copilot ghost text', () => {
await page.waitForTimeout(800)
// Ctrl+z
await page.keyboard.down('ControlOrMeta')
await page.keyboard.down(CtrlKey)
await page.keyboard.press('KeyZ')
await page.keyboard.up('ControlOrMeta')
await page.keyboard.up(CtrlKey)
await expect(page.locator('.cm-content')).toHaveText(``)
// Ctrl+shift+z
await page.keyboard.down('ControlOrMeta')
await page.keyboard.down(CtrlKey)
await page.keyboard.down('Shift')
await page.keyboard.press('KeyZ')
await page.keyboard.up('ControlOrMeta')
await page.keyboard.up(CtrlKey)
await page.keyboard.up('Shift')
await expect(page.locator('.cm-content')).toHaveText(`{thing: "blah"}`)
@ -408,14 +410,14 @@ test.describe('Copilot ghost text', () => {
)
// Once for the enter.
await page.keyboard.down('ControlOrMeta')
await page.keyboard.down(CtrlKey)
await page.keyboard.press('KeyZ')
await page.keyboard.up('ControlOrMeta')
await page.keyboard.up(CtrlKey)
// Once for the text.
await page.keyboard.down('ControlOrMeta')
await page.keyboard.down(CtrlKey)
await page.keyboard.press('KeyZ')
await page.keyboard.up('ControlOrMeta')
await page.keyboard.up(CtrlKey)
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()

View File

@ -1,191 +0,0 @@
import { test, expect } from '@playwright/test'
import { join } from 'path'
import {
getUtils,
setupElectron,
tearDown,
executorInputPath,
} from './test-utils'
import fsp from 'fs/promises'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test(
'export works on the first try',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const bracketDir = join(dir, 'bracket')
await Promise.all([fsp.mkdir(bracketDir, { recursive: true })])
await Promise.all([
fsp.copyFile(
executorInputPath('router-template-slate.kcl'),
join(bracketDir, 'other.kcl')
),
fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
),
])
},
})
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await test.step('on open of project', async () => {
await expect(page.getByText(`bracket`)).toBeVisible()
// open the project
await page.getByText(`bracket`).click()
// wait for the project to load
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
// expect zero errors in guter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// export the model
const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible()
const gltfOption = page.getByText('glTF')
const submitButton = page.getByText('Confirm Export')
const exportingToastMessage = page.getByText(`Exporting...`)
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
// Click the export button
await exportButton.click()
await expect(gltfOption).toBeVisible()
await expect(page.getByText('STL')).toBeVisible()
await page.keyboard.press('Enter')
// Click the checkbox
await expect(submitButton).toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter')
// Find the toast.
// Look out for the toast message
await expect(exportingToastMessage).toBeVisible()
await expect(alreadyExportingToastMessage).not.toBeVisible()
// Expect it to succeed.
await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible()
await test.step('Check the export size', async () => {
await expect
.poll(
async () => {
try {
const outputGltf = await fsp.readFile('output.gltf')
return outputGltf.byteLength
} catch (e) {
return 0
}
},
{ timeout: 15_000 }
)
.toBe(477327)
// clean up output.gltf
await fsp.rm('output.gltf')
})
})
await test.step('on open of file in file pane', async () => {
const u = await getUtils(page)
await u.openFilePanel()
const otherKclButton = page.getByRole('button', { name: 'other.kcl' })
// Click the file
await otherKclButton.click()
// Close the file pane
await u.closeFilePanel()
// wait for it to finish executing (todo: make this more robust)
await page.waitForTimeout(1000)
// expect zero errors in guter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// export the model
const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible()
const gltfOption = page.getByText('glTF')
const submitButton = page.getByText('Confirm Export')
const exportingToastMessage = page.getByText(`Exporting...`)
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
// Click the export button
await exportButton.click()
await expect(gltfOption).toBeVisible()
await expect(page.getByText('STL')).toBeVisible()
await page.keyboard.press('Enter')
// Click the checkbox
await expect(submitButton).toBeVisible()
await page.keyboard.press('Enter')
// Find the toast.
// Look out for the toast message
await expect(exportingToastMessage).toBeVisible()
await expect(alreadyExportingToastMessage).not.toBeVisible()
// Expect it to succeed.
await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible()
await test.step('Check the export size', async () => {
await expect
.poll(
async () => {
try {
const outputGltf = await fsp.readFile('output.gltf')
return outputGltf.byteLength
} catch (e) {
return 0
}
},
{ timeout: 15_000 }
)
.toBe(105022)
// clean up output.gltf
await fsp.rm('output.gltf')
})
await electronApp.close()
})
await electronApp.close()
}
)

View File

@ -16,6 +16,7 @@ test.describe('Editor tests', () => {
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()
@ -28,9 +29,9 @@ test.describe('Editor tests', () => {
|> line([-20, 0], %)
|> close(%)`)
await page.keyboard.down('ControlOrMeta')
await page.keyboard.down(CtrlKey)
await page.keyboard.press('/')
await page.keyboard.up('ControlOrMeta')
await page.keyboard.up(CtrlKey)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XY')
@ -41,9 +42,9 @@ test.describe('Editor tests', () => {
// |> close(%)`)
// uncomment the code
await page.keyboard.down('ControlOrMeta')
await page.keyboard.down(CtrlKey)
await page.keyboard.press('/')
await page.keyboard.up('ControlOrMeta')
await page.keyboard.up(CtrlKey)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XY')
@ -84,63 +85,6 @@ test.describe('Editor tests', () => {
|> close(%)`)
})
test('if you click the format button it formats your code and executes so lints are still there', 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 sketch_001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)`)
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
// error text on hover
await page.hover('.cm-lint-marker-info')
await expect(
page.getByText('Identifiers must be lowerCamelCase').first()
).toBeVisible()
await page.locator('#code-pane button:first-child').click()
await page.locator('button:has-text("Format code")').click()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch_001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)`)
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
// error text on hover
await page.hover('.cm-lint-marker-info')
await expect(
page.getByText('Identifiers must be lowerCamelCase').first()
).toBeVisible()
})
test('fold gutters work', async ({ page }) => {
const u = await getUtils(page)
@ -204,7 +148,9 @@ test.describe('Editor tests', () => {
// Delete all the code.
await page.locator('.cm-content').click()
// Select all
await page.keyboard.press('ControlOrMeta+A')
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(``)
@ -298,67 +244,6 @@ test.describe('Editor tests', () => {
|> close(%)`)
})
test('if you use the format keyboard binding it formats your code and executes so lints are shown', async ({
page,
}) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch_001 = 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()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
// error text on hover
await page.hover('.cm-lint-marker-info')
await expect(
page.getByText('Identifiers must be lowerCamelCase').first()
).toBeVisible()
// focus the editor
await u.codeLocator.click()
// Hit alt+shift+f to format the code
await page.keyboard.press('Alt+Shift+KeyF')
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch_001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)`)
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
// error text on hover
await page.hover('.cm-lint-marker-info')
await expect(
page.getByText('Identifiers must be lowerCamelCase').first()
).toBeVisible()
})
test('if you write kcl with lint errors you get lints', async ({ page }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 })
@ -469,7 +354,7 @@ test.describe('Editor tests', () => {
// error text on hover
await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: $').first()).toBeVisible()
await expect(page.getByText('Unexpected token').first()).toBeVisible()
// select the line that's causing the error and delete it
await page.getByText('$ error').click()
@ -517,7 +402,7 @@ test.describe('Editor tests', () => {
const width = 0.500
const height = 0.500
const dia = 4
fn squareHole = (l, w) => {
const squareHoleSketch = startSketchOn('XY')
|> startProfileAt([-width / 2, -length / 2], %)
@ -797,6 +682,10 @@ test.describe('Editor tests', () => {
})
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()
@ -804,10 +693,10 @@ test.describe('Editor tests', () => {
await expect(page.getByTestId('command-bar')).toBeVisible()
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'arrow right Continue' }).click()
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
await expect(page.getByText('Confirm Extrude')).toBeVisible()
await page.getByRole('button', { name: 'checkmark Submit command' }).click()
await page.keyboard.press('Enter')
await page.waitForTimeout(100)
// expect the code to have changed
@ -829,15 +718,17 @@ test.describe('Editor tests', () => {
|> close(%)`)
})
test('Can undo a sketch modification with ctrl+z', async ({ page }) => {
// 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, -10.01], %)
|> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %)
|> tangentialArcTo([24.95, -5.38], %)
|> close(%)
|> extrude(5, %)`
)
@ -872,11 +763,11 @@ test.describe('Editor tests', () => {
})
await page.waitForTimeout(100)
const startPX = [665, 397]
const startPX = [665, 458]
const dragPX = 40
await page.getByText('startProfileAt([4.61, -10.01], %)').click()
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
@ -914,7 +805,7 @@ test.describe('Editor tests', () => {
// drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 },
targetPosition: {
x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX,
@ -926,12 +817,12 @@ test.describe('Editor tests', () => {
// expect the code to have changed
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %)
|> close(%)
|> extrude(5, %)
`)
|> 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')
@ -940,11 +831,11 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %)
|> tangentialArcTo([24.95, -0.38], %)
|> close(%)
|> extrude(5, %)`)
|> 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')
@ -953,12 +844,11 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %)
|> close(%)
|> extrude(5, %)
`)
|> 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')
@ -968,9 +858,9 @@ test.describe('Editor tests', () => {
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %)
|> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %)
|> tangentialArcTo([24.95, -5.38], %)
|> close(%)
|> extrude(5, %)`)
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -1,204 +0,0 @@
import { test, expect } from '@playwright/test'
import * as fsp from 'fs/promises'
import { getUtils, setup, setupElectron, tearDown } from './test-utils'
test.beforeEach(async ({ context, page }) => {
await setup(context, page)
})
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('when using the file tree to', () => {
const fromFile = 'main.kcl'
const toFile = 'hello.kcl'
test(
`rename ${fromFile} to ${toFile}, and doesn't crash on reload and settings load`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async () => {},
})
const {
panesOpen,
createAndSelectProject,
pasteCodeInEditor,
renameFile,
editorTextMatches,
} = await getUtils(page, test)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await panesOpen(['files', 'code'])
await createAndSelectProject('project-000')
// File the main.kcl with contents
const kclCube = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/cube.kcl',
'utf-8'
)
await pasteCodeInEditor(kclCube)
await renameFile(fromFile, toFile)
await page.reload()
await test.step('Postcondition: editor has same content as before the rename', async () => {
await editorTextMatches(kclCube)
})
await test.step('Postcondition: opening and closing settings works', async () => {
const settingsOpenButton = page.getByRole('link', {
name: 'settings Settings',
})
const settingsCloseButton = page.getByTestId('settings-close-button')
await settingsOpenButton.click()
await settingsCloseButton.click()
})
await electronApp.close()
}
)
test(
`create many new untitled files they increment their names`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async () => {},
})
const { panesOpen, createAndSelectProject, createNewFile } =
await getUtils(page, test)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await panesOpen(['files'])
await createAndSelectProject('project-000')
await createNewFile('')
await createNewFile('')
await createNewFile('')
await createNewFile('')
await createNewFile('')
await test.step('Postcondition: there are 5 new Untitled-*.kcl files', async () => {
await expect(
page
.locator('[data-testid="file-pane-scroll-container"] button')
.filter({ hasText: /Untitled[-]?[0-5]?/ })
).toHaveCount(5)
})
await electronApp.close()
}
)
test(
'create a new file with the same name as an existing file cancels the operation',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async () => {},
})
const {
panesOpen,
createAndSelectProject,
pasteCodeInEditor,
createNewFileAndSelect,
renameFile,
selectFile,
editorTextMatches,
} = await getUtils(page, test)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await panesOpen(['files', 'code'])
await createAndSelectProject('project-000')
// File the main.kcl with contents
const kclCube = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/cube.kcl',
'utf-8'
)
await pasteCodeInEditor(kclCube)
const kcl1 = 'main.kcl'
const kcl2 = '2.kcl'
await createNewFileAndSelect(kcl2)
const kclCylinder = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/cylinder.kcl',
'utf-8'
)
await pasteCodeInEditor(kclCylinder)
await renameFile(kcl2, kcl1)
await test.step(`Postcondition: ${kcl1} still has the original content`, async () => {
await selectFile(kcl1)
await editorTextMatches(kclCube)
})
await test.step(`Postcondition: ${kcl2} still exists with the original content`, async () => {
await selectFile(kcl2)
await editorTextMatches(kclCylinder)
})
await electronApp.close()
}
)
test(
'deleting all files recreates a default main.kcl with no code',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async () => {},
})
const {
panesOpen,
createAndSelectProject,
pasteCodeInEditor,
deleteFile,
editorTextMatches,
} = await getUtils(page, test)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await panesOpen(['files', 'code'])
await createAndSelectProject('project-000')
// File the main.kcl with contents
const kclCube = await fsp.readFile(
'src/wasm-lib/tests/executor/inputs/cube.kcl',
'utf-8'
)
await pasteCodeInEditor(kclCube)
const kcl1 = 'main.kcl'
await deleteFile(kcl1)
await test.step(`Postcondition: ${kcl1} is recreated but has no content`, async () => {
await editorTextMatches('')
})
await electronApp.close()
}
)
})

View File

@ -1,97 +0,0 @@
import { test, expect } from '@playwright/test'
import { setupElectron, tearDown, executorInputPath } from './test-utils'
import { join } from 'path'
import fsp from 'fs/promises'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test(
'When machine-api server not found butt is disabled and shows the reason',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
)
},
})
await page.setViewportSize({ width: 1200, height: 500 })
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
const notFoundText = 'Machine API server was not discovered'
await expect(page.getByText(notFoundText).first()).not.toBeVisible()
// Find the make button
const makeButton = page.getByRole('button', { name: 'Make' })
// Make sure the button is visible but disabled
await expect(makeButton).toBeVisible()
await expect(makeButton).toBeDisabled()
// When you hover over the button, the tooltip should show
// that the machine-api server is not found
await makeButton.hover()
await expect(page.getByText(notFoundText).first()).toBeVisible()
await electronApp.close()
}
)
test(
'When machine-api server not found home screen & project status shows the reason',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
)
},
})
await page.setViewportSize({ width: 1200, height: 500 })
const notFoundText = 'Machine API server was not discovered'
await expect(page.getByText(notFoundText)).not.toBeVisible()
const networkMachineToggle = page.getByTestId('network-machine-toggle')
await networkMachineToggle.hover()
await expect(page.getByText(notFoundText)).toBeVisible()
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(page.getByText(notFoundText).nth(1)).not.toBeVisible()
await networkMachineToggle.hover()
await expect(page.getByText(notFoundText).nth(1)).toBeVisible()
await electronApp.close()
}
)

View File

@ -1,13 +1,6 @@
import { test, expect } from '@playwright/test'
import { join } from 'path'
import fsp from 'fs/promises'
import {
getUtils,
setup,
setupElectron,
tearDown,
executorInputPath,
} from './test-utils'
import { getUtils, setup, tearDown } from './test-utils'
import { bracket } from 'lib/exampleKcl'
import { onboardingPaths } from 'routes/Onboarding/paths'
import {
@ -19,10 +12,7 @@ import {
} from './storageStates'
import * as TOML from '@iarna/toml'
test.beforeEach(async ({ context, page }, testInfo) => {
if (testInfo.tags.includes('@electron')) {
return
}
test.beforeEach(async ({ context, page }) => {
await setup(context, page)
})
@ -349,97 +339,3 @@ test.describe('Onboarding tests', () => {
}
})
})
test(
'Restarting onboarding on desktop takes one attempt',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const routerTemplateDir = join(dir, 'router-template-slate')
await fsp.mkdir(routerTemplateDir, { recursive: true })
await fsp.copyFile(
executorInputPath('router-template-slate.kcl'),
join(routerTemplateDir, 'main.kcl')
)
},
})
// Our constants
const u = await getUtils(page)
const projectCard = page.getByText('router-template-slate')
const helpMenuButton = page.getByRole('button', {
name: 'Help and resources',
})
const restartOnboardingButton = page.getByRole('button', {
name: 'Reset onboarding',
})
const restartConfirmationButton = page.getByRole('button', {
name: 'Make a new project',
})
const tutorialProjectIndicator = page.getByText('Tutorial Project 00')
const tutorialModalText = page.getByText('Welcome to Modeling App!')
const tutorialDismissButton = page.getByRole('button', { name: 'Dismiss' })
const userMenuButton = page.getByTestId('user-sidebar-toggle')
const userMenuSettingsButton = page.getByRole('button', {
name: 'User settings',
})
const settingsHeading = page.getByRole('heading', {
name: 'Settings',
exact: true,
})
const restartOnboardingSettingsButton = page.getByRole('button', {
name: 'Replay onboarding',
})
await test.step('Navigate into project', async () => {
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await expect(
page.getByRole('heading', { name: 'Your Projects' })
).toBeVisible()
await expect(projectCard).toBeVisible()
await projectCard.click()
await u.waitForPageLoad()
})
await test.step('Restart the onboarding from help menu', async () => {
await helpMenuButton.click()
await restartOnboardingButton.click()
await expect(restartConfirmationButton).toBeVisible()
await restartConfirmationButton.click()
})
await test.step('Confirm that the onboarding has restarted', async () => {
await expect(tutorialProjectIndicator).toBeVisible()
await expect(tutorialModalText).toBeVisible()
await tutorialDismissButton.click()
})
await test.step('Clear code and restart onboarding from settings', async () => {
await u.openKclCodePanel()
await expect(u.codeLocator).toContainText('// Shelf Bracket')
await u.codeLocator.selectText()
await u.codeLocator.fill('')
await test.step('Navigate to settings', async () => {
await userMenuButton.click()
await userMenuSettingsButton.click()
await expect(settingsHeading).toBeVisible()
await expect(restartOnboardingSettingsButton).toBeVisible()
})
await restartOnboardingSettingsButton.click()
// Since the code is empty, we should not see the confirmation dialog
await expect(restartConfirmationButton).not.toBeVisible()
await expect(tutorialProjectIndicator).toBeVisible()
await expect(tutorialModalText).toBeVisible()
})
await electronApp.close()
}
)

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,12 @@
import { test, expect, Page } from '@playwright/test'
import { join } from 'path'
import * as fsp from 'fs/promises'
import {
getUtils,
setup,
setupElectron,
tearDown,
executorInputPath,
} from './test-utils'
import { getUtils, setup, tearDown } from './test-utils'
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates'
import { bracket } from 'lib/exampleKcl'
import {
PLAYWRIGHT_MOCK_EXPORT_DURATION,
PLAYWRIGHT_TOAST_DURATION,
} from 'lib/constants'
test.beforeEach(async ({ context, page }) => {
await setup(context, page)
@ -161,12 +158,6 @@ const sketch001 = startSketchAt([-0, -0])
await expect(zooLogo).not.toHaveAttribute('href')
})
test('Position _ Is Out Of Range... regression test', async ({ page }) => {
// SKip on windows, its being weird.
test.skip(
process.platform === 'win32',
'This test is being weird on windows'
)
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 })
@ -201,7 +192,7 @@ const sketch001 = startSketchAt([-0, -0])
// error text on hover
await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: |').first()).toBeVisible()
await expect(page.getByText('Unexpected token').first()).toBeVisible()
// Okay execution finished, let's start editing text below the error.
await u.codeLocator.click()
@ -238,18 +229,13 @@ const sketch001 = startSketchAt([-0, -0])
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
})
test('when engine fails export we handle the failure and alert the user', async ({
page,
}) => {
const u = await getUtils(page)
await page.addInitScript(
async ({ code }) => {
localStorage.setItem('persistCode', code)
;(window as any).playwrightSkipFilePicker = true
},
{ code: TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR }
)
await page.addInitScript(async (code) => {
localStorage.setItem('persistCode', code)
}, TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR)
await page.setViewportSize({ width: 1000, height: 500 })
@ -336,7 +322,7 @@ const sketch001 = startSketchAt([-0, -0])
await expect(exportingToastMessage).toBeVisible()
// Expect it to succeed.
await expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 })
await expect(exportingToastMessage).not.toBeVisible()
await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
@ -346,21 +332,22 @@ const sketch001 = startSketchAt([-0, -0])
test('ensure you can not export while an export is already going', async ({
page,
}) => {
// This is being weird on ubuntu and windows.
test.skip(
// eslint-disable-next-line jest/valid-title
process.platform === 'linux' || process.platform === 'win32',
'This test is being weird on ubuntu'
)
const u = await getUtils(page)
await test.step('Set up the code and durations', async () => {
await page.addInitScript(
async ({ code }) => {
async ({ code, toastDurationKey, exportDurationKey }) => {
localStorage.setItem('persistCode', code)
// Normally we make these durations short to speed up PW tests
// to superhuman speeds. But in this case we want to make sure
// the export toast is visible for a while, and the export
// duration is long enough to make sure the export toast is visible
localStorage.setItem(toastDurationKey, '1500')
localStorage.setItem(exportDurationKey, '750')
},
{
code: bracket,
toastDurationKey: PLAYWRIGHT_TOAST_DURATION,
exportDurationKey: PLAYWRIGHT_MOCK_EXPORT_DURATION,
}
)
@ -427,53 +414,6 @@ const sketch001 = startSketchAt([-0, -0])
await expect(successToastMessage).toBeVisible()
})
})
test(
`Network health indicator only appears in modeling view`,
{ tag: '@electron' },
async ({ browserName: _ }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
)
},
})
await page.setViewportSize({ width: 1200, height: 500 })
const u = await getUtils(page)
// Locators
const projectsHeading = page.getByRole('heading', {
name: 'Your projects',
})
const projectLink = page.getByRole('link', { name: 'bracket' })
const networkHealthIndicator = page.getByTestId('network-toggle')
await test.step('Check the home page', async () => {
await expect(projectsHeading).toBeVisible()
await expect(projectLink).toBeVisible()
await expect(networkHealthIndicator).not.toBeVisible()
})
await test.step('Open the project', async () => {
await projectLink.click()
})
await test.step('Check the modeling view', async () => {
await expect(networkHealthIndicator).toBeVisible()
await expect(networkHealthIndicator).toContainText('Problem')
await u.waitForPageLoad()
await expect(networkHealthIndicator).toContainText('Connected')
})
await electronApp.close()
}
)
})
async function clickExportButton(page: Page) {
@ -485,7 +425,7 @@ async function clickExportButton(page: Page) {
// Click the export button
await exportButton.click()
// Click the gltf.
// Click the stl.
const gltfOption = page.getByRole('option', { name: 'glTF' })
await expect(gltfOption).toBeVisible()

View File

@ -146,7 +146,7 @@ test.describe('Sketch tests', () => {
await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'line Line', exact: true }).click()
await page.getByRole('button', { name: 'Line', exact: true }).click()
await page.waitForTimeout(100)
await page.mouse.click(700, 200)
@ -344,108 +344,111 @@ test.describe('Sketch tests', () => {
})
})
test('Can edit a sketch that has been extruded in the same pipe', async ({
page,
}) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %)
// failing for the same reason as "Can undo a sketch modification with ctrl+z"
// please fix together
test.fixme(
'Can edit a sketch that has been extruded in the same pipe',
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, -0.38], %)
|> tangentialArcTo([24.95, -5.38], %)
|> close(%)
|> extrude(5, %)`
)
})
)
})
await page.setViewportSize({ width: 1200, height: 500 })
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
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)
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, 397]
const startPX = [665, 458]
const dragPX = 40
const dragPX = 40
await page.getByText('startProfileAt([4.61, -10.01], %)').click()
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(400)
let prevContent = await page.locator('.cm-content').innerText()
await 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)
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 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
await page.waitForTimeout(100)
// drag line handle
await page.waitForTimeout(100)
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()
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()
// drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
targetPosition: {
x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX,
},
})
await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// 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, -12.68], %)
|> line([15.39, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %)
|> close(%)
|> extrude(5, %)
`)
})
// 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, %)`)
}
)
test('Can edit a sketch that has been revolved in the same pipe', async ({
page,
@ -599,7 +602,7 @@ test.describe('Sketch tests', () => {
await expect(u.codeLocator).toHaveText(codeStr)
// exit the sketch, reset relative clicker
await click00r(undefined, undefined)
click00r(undefined, undefined)
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
await u.expectCmdLog('[data-message-type="execution-done"]')
@ -722,7 +725,7 @@ test.describe('Sketch tests', () => {
await expect(page.locator('.cm-content')).toHaveText(code)
// Assert the tool was unequipped
await expect(
page.getByRole('button', { name: 'line Line', exact: true })
page.getByRole('button', { name: 'Line', exact: true })
).not.toHaveAttribute('aria-pressed', 'true')
// exit sketch

View File

@ -7,11 +7,7 @@ import { spawn } from 'child_process'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import JSZip from 'jszip'
import path from 'path'
import {
IS_PLAYWRIGHT_KEY,
TEST_SETTINGS,
TEST_SETTINGS_KEY,
} from './storageStates'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates'
import * as TOML from '@iarna/toml'
test.beforeEach(async ({ page }) => {
@ -20,17 +16,16 @@ test.beforeEach(async ({ page }) => {
// set the default settings
await page.addInitScript(
async ({ token, settingsKey, settings, IS_PLAYWRIGHT_KEY }) => {
async ({ token, settingsKey, settings }) => {
localStorage.setItem('TOKEN_PERSIST_KEY', token)
localStorage.setItem('persistCode', ``)
localStorage.setItem(settingsKey, settings)
localStorage.setItem(IS_PLAYWRIGHT_KEY, 'true')
localStorage.setItem('playwright', 'true')
},
{
token: secrets.token,
settingsKey: TEST_SETTINGS_KEY,
settings: TOML.stringify({ settings: TEST_SETTINGS }),
IS_PLAYWRIGHT_KEY: IS_PLAYWRIGHT_KEY,
}
)
@ -51,13 +46,6 @@ test(
'exports of each format should work',
{ tag: '@snapshot' },
async ({ page, context }) => {
// skip on macos and windows.
test.skip(
// eslint-disable-next-line jest/valid-title
process.platform === 'darwin' || process.platform === 'win32',
'Skip on macos and windows'
)
// FYI this test doesn't work with only engine running locally
// And you will need to have the KittyCAD CLI installed
const u = await getUtils(page)
@ -377,9 +365,6 @@ test.describe(
'extrude on default planes should be stable',
{ tag: '@snapshot' },
() => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
test('XY', async ({ page, context }) => {
await extrudeDefaultPlane(context, page, 'XY')
})
@ -410,9 +395,6 @@ test(
'Draft segments should look right',
{ tag: '@snapshot' },
async ({ page, context }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -463,7 +445,7 @@ test(
await expect(page.locator('.cm-content')).toHaveText(code)
await page
.getByRole('button', { name: 'arc Tangential Arc', exact: true })
.getByRole('button', { name: 'Tangential Arc', exact: true })
.click()
await page.mouse.move(startXPx + PUR * 30, 500 - PUR * 20, { steps: 10 })
@ -480,9 +462,6 @@ test(
'Draft rectangles should look right',
{ tag: '@snapshot' },
async ({ page, context }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -517,9 +496,9 @@ test(
const startXPx = 600
// Equip the rectangle tool
await page.getByRole('button', { name: 'line Line', exact: true }).click()
await page.getByRole('button', { name: 'Line', exact: true }).click()
await page
.getByRole('button', { name: 'rectangle Corner rectangle', exact: true })
.getByRole('button', { name: 'Corner rectangle', exact: true })
.click()
// Draw the rectangle
@ -537,9 +516,6 @@ test.describe(
'Client side scene scale should match engine scale',
{ tag: '@snapshot' },
() => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
test('Inch scale', async ({ page }) => {
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
@ -587,7 +563,7 @@ test.describe(
await expect(u.codeLocator).toHaveText(code)
await page
.getByRole('button', { name: 'arc Tangential Arc', exact: true })
.getByRole('button', { name: 'Tangential Arc', exact: true })
.click()
await page.waitForTimeout(100)
@ -599,7 +575,7 @@ test.describe(
// click tangential arc tool again to unequip it
await page
.getByRole('button', { name: 'arc Tangential Arc', exact: true })
.getByRole('button', { name: 'Tangential Arc', exact: true })
.click()
await page.waitForTimeout(100)
@ -690,7 +666,7 @@ test.describe(
await expect(u.codeLocator).toHaveText(code)
await page
.getByRole('button', { name: 'arc Tangential Arc', exact: true })
.getByRole('button', { name: 'Tangential Arc', exact: true })
.click()
await page.waitForTimeout(100)
@ -701,7 +677,7 @@ test.describe(
await expect(u.codeLocator).toHaveText(code)
await page
.getByRole('button', { name: 'arc Tangential Arc', exact: true })
.getByRole('button', { name: 'Tangential Arc', exact: true })
.click()
await page.waitForTimeout(100)
@ -734,9 +710,6 @@ test(
'Sketch on face with none z-up',
{ tag: '@snapshot' },
async ({ page, context }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page)
await context.addInitScript(async (KCL_DEFAULT_LENGTH) => {
localStorage.setItem(
@ -799,9 +772,6 @@ test(
'Zoom to fit on load - solid 2d',
{ tag: '@snapshot' },
async ({ page, context }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
@ -842,9 +812,6 @@ test(
'Zoom to fit on load - solid 3d',
{ tag: '@snapshot' },
async ({ page, context }) => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
@ -883,9 +850,6 @@ test(
)
test.describe('Grid visibility', { tag: '@snapshot' }, () => {
// FIXME: Skip on macos its being weird.
test.skip(process.platform === 'darwin', 'Skip on macos')
test('Grid turned off', async ({ page }) => {
const u = await getUtils(page)
const stream = page.getByTestId('stream')
@ -964,69 +928,3 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
})
})
})
test('theme persists', async ({ page, context }) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('XY')
|> startProfileAt([-10, -10], %)
|> line([20, 0], %)
|> line([0, 20], %)
|> line([-20, 0], %)
|> close(%)
|> extrude(10, %)
`
)
}, KCL_DEFAULT_LENGTH)
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await page.waitForTimeout(500)
// await page.getByRole('link', { name: 'Settings Settings (tooltip)' }).click()
await expect(page.getByTestId('settings-link')).toBeVisible()
await page.getByTestId('settings-link').click()
// open user settingns
await page.getByRole('radio', { name: 'person User' }).click()
await page.getByTestId('app-theme').selectOption('light')
await page.getByTestId('settings-close-button').click()
const networkToggle = page.getByTestId('network-toggle')
// simulate network down
await u.emulateNetworkConditions({
offline: true,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
// Disconnect and reconnect to check the theme persists through a reload
// Expect the network to be down
await expect(networkToggle).toContainText('Offline')
// simulate network up
await u.emulateNetworkConditions({
offline: false,
// values of 0 remove any active throttling. crbug.com/456324#c9
latency: 0,
downloadThroughput: -1,
uploadThroughput: -1,
})
await expect(networkToggle).toContainText('Connected')
await expect(page.getByText('building scene')).not.toBeVisible()
await expect(page, 'expect screenshot to have light theme').toHaveScreenshot({
maxDiffPixels: 100,
})
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 45 KiB

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