Compare commits

..

2 Commits

Author SHA1 Message Date
ccb3edb0ec Update rust/kcl-lib/src/execution/memory.rs
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-03-28 21:01:24 -07:00
252050468d ascii art diagram
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-03-28 14:30:45 -07:00
765 changed files with 21148 additions and 31001 deletions

91
.eslintrc Normal file
View File

@ -0,0 +1,91 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": [
"react-perf",
"css-modules",
"jest",
"jsx-a11y",
"react",
"react-hooks",
"suggest-no-throw",
"testing-library",
"@typescript-eslint"
],
"extends": [
"plugin:css-modules/recommended",
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended"
],
"rules": {
"no-array-constructor": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-array-delete": "error",
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-duplicate-type-constituents": "error",
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-floating-promises": "error",
"no-implied-eval": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-implied-eval": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"no-unused-vars": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-unused-vars": ["error", {
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_",
"ignoreRestSiblings": true,
"vars": "all",
"args": "none"
}],
"@typescript-eslint/prefer-as-const": "warn",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",
"no-restricted-globals": [
"error",
{
"name": "isNaN",
"message": "Use Number.isNaN() instead."
},
],
"no-restricted-syntax": [
"error",
{
"selector": "CallExpression[callee.object.name='Array'][callee.property.name='isArray']",
"message": "Use isArray() in lib/utils.ts instead of Array.isArray()."
}
],
"semi": [
"error",
"never"
],
"react-hooks/exhaustive-deps": "off",
"suggest-no-throw/suggest-no-throw": "warn",
},
"overrides": [
{
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"extends": [
"plugin:testing-library/react"
],
"rules": {
"suggest-no-throw/suggest-no-throw": "off",
"testing-library/prefer-screen-queries": "off",
"jest/valid-expect": "off"
}
},
{
"files": ["src/**/*.test.ts"],
"extends": [
"plugin:testing-library/react"
],
"rules": {
"suggest-no-throw/suggest-no-throw": "off",
}
}
]
}

View File

@ -1,127 +0,0 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": [
"react-perf",
"css-modules",
"jest",
"jsx-a11y",
"react",
"react-hooks",
"suggest-no-throw",
"testing-library",
"@typescript-eslint"
],
"extends": [
"plugin:css-modules/recommended",
"plugin:jsx-a11y/recommended",
"plugin:react-hooks/recommended"
],
"rules": {
"no-array-constructor": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-array-delete": "error",
"@typescript-eslint/no-duplicate-enum-values": "error",
"@typescript-eslint/no-duplicate-type-constituents": "error",
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-extra-non-null-assertion": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-for-in-array": "error",
"no-implied-eval": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-implied-eval": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-namespace": "error",
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
"@typescript-eslint/no-redundant-type-constituents": "error",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unnecessary-type-constraint": "error",
"no-unused-vars": "off", // This is wrong; use the @typescript-eslint one instead.
"@typescript-eslint/no-unused-vars": [
"error",
{
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_",
"ignoreRestSiblings": true,
"vars": "all",
"args": "none"
}
],
"@typescript-eslint/no-unsafe-unary-minus": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"no-throw-literal": "off", // Use @typescript-eslint/only-throw-error instead.
"@typescript-eslint/only-throw-error": "error",
"@typescript-eslint/prefer-as-const": "warn",
"@typescript-eslint/prefer-namespace-keyword": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",
"no-restricted-globals": [
"error",
{
"name": "isNaN",
"message": "Use Number.isNaN() instead."
}
],
"no-restricted-syntax": [
"error",
{
"selector": "CallExpression[callee.object.name='Array'][callee.property.name='isArray']",
"message": "Use isArray() in lib/utils.ts instead of Array.isArray()."
},
{
"selector": "CallExpression[callee.object.name='TOML'][callee.property.name='stringify']",
"message": "Do not use TOML.stringify directly. Use the wrappers in test-utils instead like settingsToToml."
},
{
"selector": "CallExpression[callee.object.name='TOML'][callee.property.name='parse']",
"message": "Do not use TOML.parse directly. Use the wrappers in test-utils instead like tomlToSettings."
}
],
"no-restricted-imports": [
"error",
{
"patterns": [
// Restrict all relative imports except for .css files.
{
"group": ["./*", "../*", "!./*.css", "!../*.css"],
"message": "Use absolute imports instead."
}
]
}
],
"semi": ["error", "never"],
"react-hooks/exhaustive-deps": "off",
"suggest-no-throw/suggest-no-throw": "error"
},
"overrides": [
{
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"extends": ["plugin:testing-library/react"],
"rules": {
"suggest-no-throw/suggest-no-throw": "off",
"testing-library/prefer-screen-queries": "off",
"jest/valid-expect": "off"
}
},
{
"files": ["src/**/*.test.ts"],
"extends": ["plugin:testing-library/react"],
"rules": {
"suggest-no-throw/suggest-no-throw": "off"
}
},
{
"files": ["packages/**/*.ts", "rust/**/*.ts"],
"extends": [],
"rules": {
"no-restricted-imports": "off"
}
}
]
}

View File

@ -229,6 +229,10 @@ jobs:
timeout_minutes: 30
max_attempts: 3
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 }}
@ -373,7 +377,11 @@ jobs:
timeout_minutes: 45
max_attempts: 15
env:
CI: true
FAIL_ON_CONSOLE_ERRORS: true
NODE_ENV: development
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_SKIP_AUTH: true
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- uses: actions/upload-artifact@v4

View File

@ -136,36 +136,6 @@ jobs:
- run: yarn lint
yarn-circular-dependencies:
runs-on: ubuntu-latest
needs: yarn-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- run: yarn install
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: yarn circular-deps:diff
python-codespell:
runs-on: ubuntu-22.04
steps:

View File

@ -4,38 +4,18 @@ all: install build check
###############################################################################
# INSTALL
ifeq ($(OS),Windows_NT)
CARGO ?= ~/.cargo/bin/cargo.exe
WASM_PACK ?= ~/.cargo/bin/wasm-pack.exe
else
CARGO ?= ~/.cargo/bin/cargo
WASM_PACK ?= ~/.cargo/bin/wasm-pack
endif
WASM_PACK ?= ~/.cargo/bin/wasm-pack
.PHONY: install
install: node_modules/.yarn-integrity $(CARGO) $(WASM_PACK) ## Install dependencies
install: node_modules/.yarn-integrity $(WASM_PACK) ## Install dependencies
node_modules/.yarn-integrity: package.json yarn.lock
yarn install
ifeq ($(OS),Windows_NT)
@ type nul > $@
else
@ touch $@
endif
$(CARGO):
ifeq ($(OS),Windows_NT)
yarn install:rust:windows
else
yarn install:rust
endif
$(WASM_PACK):
ifeq ($(OS),Windows_NT)
yarn install:wasm-pack:cargo
else
yarn install:rust
yarn install:wasm-pack:sh
endif
###############################################################################
# BUILD
@ -51,17 +31,13 @@ VITE_SOURCES := $(wildcard vite.*) $(wildcard vite/**/*.tsx)
build: build-web build-desktop
.PHONY: build-web
build-web: install public/kcl_wasm_lib_bg.wasm build/index.html
build-web: public/kcl_wasm_lib_bg.wasm build/index.html
.PHONY: build-desktop
build-desktop: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js
build-desktop: public/kcl_wasm_lib_bg.wasm .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES)
ifeq ($(OS),Windows_NT)
yarn build:wasm:dev:windows
else
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES)$(RUST_SOURCES)
yarn build:wasm:dev
endif
build/index.html: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
yarn build:local
@ -87,10 +63,8 @@ lint: install ## Lint the code
###############################################################################
# RUN
TARGET ?= web
.PHONY: run
run: run-$(TARGET)
run: run-web
.PHONY: run-web
run-web: install build-web ## Start the web app
@ -116,7 +90,7 @@ test-unit: install ## Run the unit tests
yarn test:unit
.PHONY: test-e2e
test-e2e: test-e2e-$(TARGET)
test-e2e: test-e2e-desktop
.PHONY: test-e2e-web
test-e2e-web: install build-web ## Run the web e2e tests
@ -132,23 +106,15 @@ test-e2e-desktop: install build-desktop ## Run the desktop e2e tests
.PHONY: clean
clean: ## Delete all artifacts
ifeq ($(OS),Windows_NT)
git clean --force -d -X
else
rm -rf .vite/ build/
rm -rf trace.zip playwright-report/ test-results/
rm -rf public/kcl_wasm_lib_bg.wasm
rm -rf rust/*/bindings/ rust/*/pkg/ rust/target/
rm -rf node_modules/ rust/*/node_modules/
endif
.PHONY: help
help: install
ifeq ($(OS),Windows_NT)
@ powershell -Command "Get-Content $(MAKEFILE_LIST) | Select-String -Pattern '^[^\s]+:.*##\s.*$$' | ForEach-Object { $$line = $$_.Line -split ':.*?##\s+'; Write-Host -NoNewline $$line[0].PadRight(30) -ForegroundColor Cyan; Write-Host $$line[1] }"
else
@ grep -E '^[^[:space:]]+:.*## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
endif
.DEFAULT_GOAL := help

View File

@ -9,9 +9,13 @@ layout: manual
### `std`
- [`HALF_TURN`](/docs/kcl/consts/std-HALF_TURN)
- [`QUARTER_TURN`](/docs/kcl/consts/std-QUARTER_TURN)
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-THREE_QUARTER_TURN)
- [`XY`](/docs/kcl/consts/std-XY)
- [`XZ`](/docs/kcl/consts/std-XZ)
- [`YZ`](/docs/kcl/consts/std-YZ)
- [`ZERO`](/docs/kcl/consts/std-ZERO)
### `std::math`
@ -19,10 +23,3 @@ layout: manual
- [`PI`](/docs/kcl/consts/std-math-PI)
- [`TAU`](/docs/kcl/consts/std-math-TAU)
### `std::turns`
- [`HALF_TURN`](/docs/kcl/consts/std-turns-HALF_TURN)
- [`QUARTER_TURN`](/docs/kcl/consts/std-turns-QUARTER_TURN)
- [`THREE_QUARTER_TURN`](/docs/kcl/consts/std-turns-THREE_QUARTER_TURN)
- [`ZERO`](/docs/kcl/consts/std-turns-ZERO)

View File

@ -0,0 +1,15 @@
---
title: "std::HALF_TURN"
excerpt: ""
layout: manual
---
```js
std::HALF_TURN: number(deg) = 180deg
```

View File

@ -0,0 +1,15 @@
---
title: "std::QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::QUARTER_TURN: number(deg) = 90deg
```

View File

@ -0,0 +1,15 @@
---
title: "std::THREE_QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::THREE_QUARTER_TURN: number(deg) = 270deg
```

View File

@ -0,0 +1,15 @@
---
title: "std::ZERO"
excerpt: ""
layout: manual
---
```js
std::ZERO: number = 0
```

View File

@ -1,15 +0,0 @@
---
title: "std::turns::HALF_TURN"
excerpt: ""
layout: manual
---
```js
std::turns::HALF_TURN: number(deg) = 180deg
```

View File

@ -1,15 +0,0 @@
---
title: "std::turns::QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::turns::QUARTER_TURN: number(deg) = 90deg
```

View File

@ -1,15 +0,0 @@
---
title: "std::turns::THREE_QUARTER_TURN"
excerpt: ""
layout: manual
---
```js
std::turns::THREE_QUARTER_TURN: number(deg) = 270deg
```

View File

@ -1,15 +0,0 @@
---
title: "std::turns::ZERO"
excerpt: ""
layout: manual
---
```js
std::turns::ZERO: number = 0
```

View File

@ -23,15 +23,19 @@ layout: manual
* [`tag`](kcl/types/tag)
* **std**
* [`Face`](kcl/types/Face)
* [`HALF_TURN`](kcl/consts/std-HALF_TURN)
* [`Helix`](kcl/types/Helix)
* [`Plane`](kcl/types/Plane)
* [`Point2d`](kcl/types/Point2d)
* [`Point3d`](kcl/types/Point3d)
* [`QUARTER_TURN`](kcl/consts/std-QUARTER_TURN)
* [`Sketch`](kcl/types/Sketch)
* [`Solid`](kcl/types/Solid)
* [`THREE_QUARTER_TURN`](kcl/consts/std-THREE_QUARTER_TURN)
* [`XY`](kcl/consts/std-XY)
* [`XZ`](kcl/consts/std-XZ)
* [`YZ`](kcl/consts/std-YZ)
* [`ZERO`](kcl/consts/std-ZERO)
* [`abs`](kcl/abs)
* [`acos`](kcl/acos)
* [`angleToMatchLengthX`](kcl/angleToMatchLengthX)
@ -142,8 +146,3 @@ layout: manual
* [`tan`](kcl/std-math-tan)
* **std::sketch**
* [`circle`](kcl/std-sketch-circle)
* **std::turns**
* [`turns::HALF_TURN`](kcl/consts/std-turns-HALF_TURN)
* [`turns::QUARTER_TURN`](kcl/consts/std-turns-QUARTER_TURN)
* [`turns::THREE_QUARTER_TURN`](kcl/consts/std-turns-THREE_QUARTER_TURN)
* [`turns::ZERO`](kcl/consts/std-turns-ZERO)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,7 @@ circle(@sketch_or_surface: Sketch | Plane | Face, center: Point2d, radius: numbe
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketch_or_surface` | [`Sketch`](/docs/kcl/types/Sketch) OR [`Plane`](/docs/kcl/types/Plane) OR [`Face`](/docs/kcl/types/Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
| `sketch_or_surface` | [`Sketch`](/docs/kcl/types/Sketch) `|` [`Plane`](/docs/kcl/types/Face) `|` [`Plane`](/docs/kcl/types/Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
| `center` | [`Point2d`](/docs/kcl/types/Point2d) | The center of the circle. | Yes |
| `radius` | [`number`](/docs/kcl/types/number) | The radius of the circle. | Yes |
| [`tag`](/docs/kcl/types/tag) | [`tag`](/docs/kcl/types/tag) | Create a new tag which refers to this circle. | No |

View File

@ -207302,8 +207302,372 @@
},
"definitions": {
"TyF64": {
"type": "number",
"format": "double"
"type": "object",
"required": [
"n",
"ty"
],
"properties": {
"n": {
"type": "number",
"format": "double"
},
"ty": {
"$ref": "#/components/schemas/NumericType"
}
}
},
"NumericType": {
"oneOf": [
{
"type": "object",
"oneOf": [
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Count"
]
}
}
},
{
"description": "A unit of length.",
"type": "object",
"oneOf": [
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Mm"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Cm"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"M"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Inches"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Feet"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Yards"
]
}
}
}
],
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Length"
]
}
}
},
{
"description": "A unit of angle.",
"type": "object",
"oneOf": [
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Degrees"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Radians"
]
}
}
}
],
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Angle"
]
}
}
}
],
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Known"
]
}
}
},
{
"type": "object",
"required": [
"angle",
"len",
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Default"
]
},
"len": {
"$ref": "#/components/schemas/UnitLen"
},
"angle": {
"$ref": "#/components/schemas/UnitAngle"
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Unknown"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Any"
]
}
}
}
]
},
"UnitLen": {
"description": "A unit of length.",
"oneOf": [
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Mm"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Cm"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"M"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Inches"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Feet"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Yards"
]
}
}
}
]
},
"UnitAngle": {
"description": "A unit of angle.",
"oneOf": [
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Degrees"
]
}
}
},
{
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"type": "string",
"enum": [
"Radians"
]
}
}
}
]
}
}
},
@ -256392,7 +256756,7 @@
},
"required": false,
"includeInSnippet": true,
"description": "The roll angle in degrees. Must be between -360 and 360. Default is 0 if not given.",
"description": "The roll angle in degrees. Must be used with `pitch` and `yaw`. Must be between -360 and 360.",
"labelRequired": true
},
{
@ -257990,7 +258354,7 @@
},
"required": false,
"includeInSnippet": true,
"description": "The pitch angle in degrees. Must be between -360 and 360. Default is 0 if not given.",
"description": "The pitch angle in degrees. Must be used with `roll` and `yaw`. Must be between -360 and 360.",
"labelRequired": true
},
{
@ -259588,7 +259952,7 @@
},
"required": false,
"includeInSnippet": true,
"description": "The yaw angle in degrees. Must be between -360 and 360. Default is 0 if not given.",
"description": "The yaw angle in degrees. Must be used with `roll` and `pitch`. Must be between -360 and 360.",
"labelRequired": true
},
{
@ -266057,7 +266421,6 @@
"deprecated": false,
"examples": [
"// Rotate a pipe with roll, pitch, and yaw.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(roll = 10, pitch = 10, yaw = 90)",
"// Rotate a pipe with just roll.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(roll = 10)",
"// Rotate a pipe about an axis with an angle.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> rotate(axis = [0, 0, 1.0], angle = 90)",
"// Rotate an imported model.\n\n\nimport \"tests/inputs/cube.sldprt\" as cube\n\ncube\n |> rotate(axis = [0, 0, 1.0], angle = 90)",
"// Sweep two sketches along the same path.\n\n\nsketch001 = startSketchOn(XY)\nrectangleSketch = startProfileAt([-200, 23.86], sketch001)\n |> angledLine([0, 73.47], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 50.61\n ], %)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n\ncircleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)\n\nsketch002 = startSketchOn(YZ)\nsweepPath = startProfileAt([0, 0], sketch002)\n |> yLine(length = 231.81)\n |> tangentialArc({ radius = 80, offset = -90 }, %)\n |> xLine(length = 384.93)\n\nparts = sweep([rectangleSketch, circleSketch], path = sweepPath)\n\n// Rotate the sweeps.\nrotate(parts, axis = [0, 0, 1.0], angle = 90)",
@ -267785,10 +268148,9 @@
"type": "number",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "Nullable_double",
"title": "double",
"type": "number",
"format": "double",
"nullable": true,
"definitions": {
"Solid": {
"type": "object",
@ -269373,9 +269735,9 @@
}
}
},
"required": false,
"required": true,
"includeInSnippet": true,
"description": "The scale factor for the x axis. Default is 1 if not provided.",
"description": "The scale factor for the x axis.",
"labelRequired": true
},
{
@ -269383,10 +269745,9 @@
"type": "number",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "Nullable_double",
"title": "double",
"type": "number",
"format": "double",
"nullable": true,
"definitions": {
"Solid": {
"type": "object",
@ -270971,9 +271332,9 @@
}
}
},
"required": false,
"required": true,
"includeInSnippet": true,
"description": "The scale factor for the y axis. Default is 1 if not provided.",
"description": "The scale factor for the y axis.",
"labelRequired": true
},
{
@ -270981,10 +271342,9 @@
"type": "number",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "Nullable_double",
"title": "double",
"type": "number",
"format": "double",
"nullable": true,
"definitions": {
"Solid": {
"type": "object",
@ -272569,9 +272929,9 @@
}
}
},
"required": false,
"required": true,
"includeInSnippet": true,
"description": "The scale factor for the z axis. Default is 1 if not provided.",
"description": "The scale factor for the z axis.",
"labelRequired": true
},
{
@ -275840,9 +276200,9 @@
"unpublished": false,
"deprecated": false,
"examples": [
"// Scale a pipe.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> scale(z = 2.5)",
"// Scale an imported model.\n\n\nimport \"tests/inputs/cube.sldprt\" as cube\n\ncube\n |> scale(z = 2.5)",
"// Sweep two sketches along the same path.\n\n\nsketch001 = startSketchOn(XY)\nrectangleSketch = startProfileAt([-200, 23.86], sketch001)\n |> angledLine([0, 73.47], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 50.61\n ], %)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n\ncircleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)\n\nsketch002 = startSketchOn(YZ)\nsweepPath = startProfileAt([0, 0], sketch002)\n |> yLine(length = 231.81)\n |> tangentialArc({ radius = 80, offset = -90 }, %)\n |> xLine(length = 384.93)\n\nparts = sweep([rectangleSketch, circleSketch], path = sweepPath)\n\n// Scale the sweep.\nscale(parts, z = 0.5)"
"// Scale a pipe.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> scale(x = 1.0, y = 1.0, z = 2.5)",
"// Scale an imported model.\n\n\nimport \"tests/inputs/cube.sldprt\" as cube\n\ncube\n |> scale(x = 1.0, y = 1.0, z = 2.5)",
"// Sweep two sketches along the same path.\n\n\nsketch001 = startSketchOn(XY)\nrectangleSketch = startProfileAt([-200, 23.86], sketch001)\n |> angledLine([0, 73.47], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 50.61\n ], %)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n\ncircleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)\n\nsketch002 = startSketchOn(YZ)\nsweepPath = startProfileAt([0, 0], sketch002)\n |> yLine(length = 231.81)\n |> tangentialArc({ radius = 80, offset = -90 }, %)\n |> xLine(length = 384.93)\n\nparts = sweep([rectangleSketch, circleSketch], path = sweepPath)\n\n// Scale the sweep.\nscale(\n parts,\n x = 1.0,\n y = 1.0,\n z = 0.5,\n)"
]
},
{
@ -326055,10 +326415,9 @@
"type": "number",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "Nullable_double",
"title": "double",
"type": "number",
"format": "double",
"nullable": true,
"definitions": {
"Solid": {
"type": "object",
@ -327643,9 +328002,9 @@
}
}
},
"required": false,
"required": true,
"includeInSnippet": true,
"description": "The amount to move the solid or sketch along the x axis. Defaults to 0 if not provided.",
"description": "The amount to move the solid or sketch along the x axis.",
"labelRequired": true
},
{
@ -327653,10 +328012,9 @@
"type": "number",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "Nullable_double",
"title": "double",
"type": "number",
"format": "double",
"nullable": true,
"definitions": {
"Solid": {
"type": "object",
@ -329241,9 +329599,9 @@
}
}
},
"required": false,
"required": true,
"includeInSnippet": true,
"description": "The amount to move the solid or sketch along the y axis. Defaults to 0 if not provided.",
"description": "The amount to move the solid or sketch along the y axis.",
"labelRequired": true
},
{
@ -329251,10 +329609,9 @@
"type": "number",
"schema": {
"$schema": "https://spec.openapis.org/oas/3.0/schema/2019-04-02#/definitions/Schema",
"title": "Nullable_double",
"title": "double",
"type": "number",
"format": "double",
"nullable": true,
"definitions": {
"Solid": {
"type": "object",
@ -330839,9 +331196,9 @@
}
}
},
"required": false,
"required": true,
"includeInSnippet": true,
"description": "The amount to move the solid or sketch along the z axis. Defaults to 0 if not provided.",
"description": "The amount to move the solid or sketch along the z axis.",
"labelRequired": true
},
{
@ -334113,8 +334470,8 @@
"// Move a pipe.\n\n// Create a path for the sweep.\nsweepPath = startSketchOn(XZ)\n |> startProfileAt([0.05, 0.05], %)\n |> line(end = [0, 7])\n |> tangentialArc({ offset = 90, radius = 5 }, %)\n |> line(end = [-3, 0])\n |> tangentialArc({ offset = -90, radius = 5 }, %)\n |> line(end = [0, 7])\n\n// Create a hole for the pipe.\npipeHole = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 1.5)\n\nsweepSketch = startSketchOn(XY)\n |> circle(center = [0, 0], radius = 2)\n |> hole(pipeHole, %)\n |> sweep(path = sweepPath)\n |> translate(x = 1.0, y = 1.0, z = 2.5)",
"// Move an imported model.\n\n\nimport \"tests/inputs/cube.sldprt\" as cube\n\ncube\n |> translate(x = 1.0, y = 1.0, z = 2.5)",
"// Sweep two sketches along the same path.\n\n\nsketch001 = startSketchOn(XY)\nrectangleSketch = startProfileAt([-200, 23.86], sketch001)\n |> angledLine([0, 73.47], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 50.61\n ], %)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n\ncircleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)\n\nsketch002 = startSketchOn(YZ)\nsweepPath = startProfileAt([0, 0], sketch002)\n |> yLine(length = 231.81)\n |> tangentialArc({ radius = 80, offset = -90 }, %)\n |> xLine(length = 384.93)\n\nparts = sweep([rectangleSketch, circleSketch], path = sweepPath)\n\n// Move the sweeps.\ntranslate(\n parts,\n x = 1.0,\n y = 1.0,\n z = 2.5,\n)",
"// Move a sketch.\n\n\nfn square(length) {\n l = length / 2\n p0 = [-l, -l]\n p1 = [-l, l]\n p2 = [l, l]\n p3 = [l, -l]\n\n return startSketchOn(XY)\n |> startProfileAt(p0, %)\n |> line(endAbsolute = p1)\n |> line(endAbsolute = p2)\n |> line(endAbsolute = p3)\n |> close()\n}\n\nsquare(10)\n |> translate(x = 5, y = 5)\n |> extrude(length = 10)",
"// Translate and rotate a sketch to create a loft.\nsketch001 = startSketchOn(XY)\n\nfn square() {\n return startProfileAt([-10, 10], sketch001)\n |> xLine(length = 20)\n |> yLine(length = -20)\n |> xLine(length = -20)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n}\n\nprofile001 = square()\n\nprofile002 = square()\n |> translate(z = 20)\n |> rotate(axis = [0, 0, 1.0], angle = 45)\n\nloft([profile001, profile002])"
"// Move a sketch.\n\n\nfn square(length) {\n l = length / 2\n p0 = [-l, -l]\n p1 = [-l, l]\n p2 = [l, l]\n p3 = [l, -l]\n\n return startSketchOn(XY)\n |> startProfileAt(p0, %)\n |> line(endAbsolute = p1)\n |> line(endAbsolute = p2)\n |> line(endAbsolute = p3)\n |> close()\n}\n\nsquare(10)\n |> translate(x = 5, y = 5, z = 0)\n |> extrude(length = 10)",
"// Translate and rotate a sketch to create a loft.\nsketch001 = startSketchOn(XY)\n\nfn square() {\n return startProfileAt([-10, 10], sketch001)\n |> xLine(length = 20)\n |> yLine(length = -20)\n |> xLine(length = -20)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\n}\n\nprofile001 = square()\n\nprofile002 = square()\n |> translate(x = 0, y = 0, z = 20)\n |> rotate(axis = [0, 0, 1.0], angle = 45)\n\nloft([profile001, profile002])"
]
},
{

View File

@ -13,9 +13,9 @@ Translate is really useful for sketches if you want to move a sketch and then ro
```js
translate(
objects: SolidOrSketchOrImportedGeometry,
x?: number,
y?: number,
z?: number,
x: number,
y: number,
z: number,
global?: bool,
): SolidOrSketchOrImportedGeometry
```
@ -26,9 +26,9 @@ translate(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `objects` | [`SolidOrSketchOrImportedGeometry`](/docs/kcl/types/SolidOrSketchOrImportedGeometry) | The solid, sketch, or set of solids or sketches to move. | Yes |
| `x` | [`number`](/docs/kcl/types/number) | The amount to move the solid or sketch along the x axis. Defaults to 0 if not provided. | No |
| `y` | [`number`](/docs/kcl/types/number) | The amount to move the solid or sketch along the y axis. Defaults to 0 if not provided. | No |
| `z` | [`number`](/docs/kcl/types/number) | The amount to move the solid or sketch along the z axis. Defaults to 0 if not provided. | No |
| `x` | [`number`](/docs/kcl/types/number) | The amount to move the solid or sketch along the x axis. | Yes |
| `y` | [`number`](/docs/kcl/types/number) | The amount to move the solid or sketch along the y axis. | Yes |
| `z` | [`number`](/docs/kcl/types/number) | The amount to move the solid or sketch along the z axis. | Yes |
| `global` | [`bool`](/docs/kcl/types/bool) | If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move. | No |
### Returns
@ -134,7 +134,7 @@ fn square(length) {
}
square(10)
|> translate(x = 5, y = 5)
|> translate(x = 5, y = 5, z = 0)
|> extrude(length = 10)
```
@ -156,7 +156,7 @@ fn square() {
profile001 = square()
profile002 = square()
|> translate(z = 20)
|> translate(x = 0, y = 0, z = 20)
|> rotate(axis = [0, 0, 1.0], angle = 45)
loft([profile001, profile002])

View File

@ -28,7 +28,7 @@ An extrude plane.
| `faceId` |[`string`](/docs/kcl/types/string)| The face id for the extrude plane. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
----
@ -48,7 +48,7 @@ An extruded arc.
| `faceId` |[`string`](/docs/kcl/types/string)| The face id for the extrude plane. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
----
@ -68,7 +68,7 @@ Geometry metadata.
| `faceId` |[`string`](/docs/kcl/types/string)| The id for the chamfer surface. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
----
@ -88,7 +88,7 @@ Geometry metadata.
| `faceId` |[`string`](/docs/kcl/types/string)| The id for the fillet surface. | No |
| [`tag`](/docs/kcl/types/tag) |[`TagDeclarator`](/docs/kcl/types#tag-declaration)| The tag. | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |
----

View File

@ -17,6 +17,6 @@ Geometry metadata.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `id` |[`string`](/docs/kcl/types/string)| The id of the geometry. | No |
| `sourceRange` |`[integer, integer, integer]`| The source range. | No |
| `sourceRange` |[`SourceRange`](/docs/kcl/types/SourceRange)| The source range. | No |

View File

@ -17,7 +17,7 @@ A helix.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `value` |[`string`](/docs/kcl/types/string)| The id of the helix. | No |
| `artifactId` |[`string`](/docs/kcl/types/string)| The artifact ID. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
| `revolutions` |[`number`](/docs/kcl/types/number)| Number of revolutions. | No |
| `angleStart` |[`number`](/docs/kcl/types/number)| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |

View File

@ -285,7 +285,7 @@ Data for an imported geometry.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: `Module`| | No |
| `value` |`integer`| Identifier of a source file. Uses a u32 to keep the size small. | No |
| `value` |[`ModuleId`](/docs/kcl/types/ModuleId)| Identifier of a source file. Uses a u32 to keep the size small. | No |
----

View File

@ -17,6 +17,6 @@ Data for polar coordinates.
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `angle` |[`number`](/docs/kcl/types/number)| The angle of the line (in degrees). | No |
| `length` |[`number`](/docs/kcl/types/number)| The length of the line. | No |
| `length` |[`TyF64`](/docs/kcl/types/TyF64)| The length of the line. | No |

View File

@ -25,7 +25,7 @@ A sketch type.
|----------|------|-------------|----------|
| `type` |enum: `plane`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the plane. | No |
| `artifactId` |[`string`](/docs/kcl/types/string)| The artifact ID. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| Type for a plane. | No |
| `origin` |[`Point3d`](/docs/kcl/types/Point3d)| Origin of the plane. | No |
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane's X axis be? | No |
@ -49,7 +49,7 @@ A face.
|----------|------|-------------|----------|
| `type` |enum: `face`| | No |
| `id` |[`string`](/docs/kcl/types/string)| The id of the face. | No |
| `artifactId` |[`string`](/docs/kcl/types/string)| The artifact ID. | No |
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
| `value` |[`string`](/docs/kcl/types/string)| The tag of the face. | No |
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's X axis be? | No |
| `yAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face's Y axis be? | No |

View File

@ -0,0 +1,15 @@
---
title: "SourceRange"
excerpt: ""
layout: manual
---
**Type:** `integer` (`uint`)

View File

@ -5,11 +5,17 @@ layout: manual
---
**Type:** [`number`](/docs/kcl/types/number) (`double`)
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `n` |[`number`](/docs/kcl/types/number)| | No |
| `ty` |[`NumericType`](/docs/kcl/types/NumericType)| | No |

View File

@ -1,4 +1,4 @@
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
test.describe('Electron app header tests', () => {
test(

View File

@ -1,14 +1,13 @@
import type { Page } from '@playwright/test'
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
import { Page } from '@playwright/test'
import { test, expect } from './zoo-test'
import {
PERSIST_MODELING_CONTEXT,
getUtils,
TEST_COLORS,
commonPoints,
getUtils,
PERSIST_MODELING_CONTEXT,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import { HomePageFixture } from './fixtures/homePageFixture'
test.setTimeout(120000)
@ -86,7 +85,7 @@ async function doBasicSketch(
await page.mouse.click(startXPx, 500 - PUR * 20)
if (openPanes.includes('code')) {
await expect(u.codeLocator)
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1})
@ -120,7 +119,10 @@ async function doBasicSketch(
await page.waitForTimeout(100)
if (openPanes.includes('code')) {
expect(await u.getGreatestPixDiff(line1, TEST_COLORS.BLUE)).toBeLessThan(3)
await expect(
await u.getGreatestPixDiff(line1, TEST_COLORS.BLUE)
).toBeLessThan(3)
await expect(await u.getGreatestPixDiff(line1, [0, 0, 255])).toBeLessThan(3)
}
// hold down shift
@ -143,7 +145,7 @@ async function doBasicSketch(
// Open the code pane.
await u.openKclCodePanel()
await expect(u.codeLocator)
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1}, tag = $seg01)

View File

@ -1,8 +1,7 @@
import { test, expect } from './zoo-test'
import fs from 'node:fs/promises'
import path from 'node:path'
import { expect, test } from '@e2e/playwright/zoo-test'
test.describe('Point and click for boolean workflows', () => {
// Boolean operations to test
const booleanOperations = [

View File

@ -1,11 +1,10 @@
import type { Page } from '@playwright/test'
import type { EngineCommand } from '@src/lang/std/artifactGraph'
import { uuidv4 } from '@src/lib/utils'
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { Page } from '@playwright/test'
import { test, expect } from './zoo-test'
import { HomePageFixture } from './fixtures/homePageFixture'
import { getUtils } from './test-utils'
import { EngineCommand } from 'lang/std/artifactGraph'
import { uuidv4 } from 'lib/utils'
import { SceneFixture } from './fixtures/sceneFixture'
test.describe(
'Can create sketches on all planes and their back sides',
@ -47,7 +46,7 @@ test.describe(
},
}
const code = `@settings(defaultLengthUnit = in)sketch001 = startSketchOn(${plane})profile001 = startProfileAt([0.91, -1.22], sketch001)`
const code = `sketch001 = startSketchOn(${plane})profile001 = startProfileAt([0.91, -1.22], sketch001)`
await u.openDebugPanel()

View File

@ -1,14 +1,13 @@
import { bracket } from '@src/lib/exampleKcl'
import fsp from 'fs/promises'
import { join } from 'path'
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from '@e2e/playwright/storageStates'
import { test, expect } from './zoo-test'
import {
executorInputPath,
getUtils,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
getUtils,
executorInputPath,
} from './test-utils'
import { join } from 'path'
import { bracket } from 'lib/exampleKcl'
import { TEST_CODE_LONG_WITH_ERROR_OUT_OF_VIEW } from './storageStates'
import fsp from 'fs/promises'
test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
test('Typing KCL errors induces a badge on the code pane button', async ({
@ -252,11 +251,11 @@ test(
])
await Promise.all([
fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('router-template-slate.kcl'),
join(routerTemplateDir, 'main.kcl')
),
fsp.copyFile(
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
),
])

View File

@ -1,13 +1,12 @@
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
import { test, expect } from './zoo-test'
import * as fsp from 'fs/promises'
import path, { join } from 'path'
import {
executorInputPath,
getUtils,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import path, { join } from 'path'
test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
test('Extrude from command bar selects extrude line after', async ({

View File

@ -1,5 +1,5 @@
import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
import { getUtils } from './test-utils'
test.describe('Copilot ghost text', () => {
// eslint-disable-next-line jest/valid-title

View File

@ -1,5 +1,6 @@
import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
import { getUtils } from './test-utils'
function countNewlines(input: string): number {
let count = 0

View File

@ -1,12 +1,11 @@
import fsp from 'fs/promises'
import { test, expect } from './zoo-test'
import path from 'path'
import {
getUtils,
executorInputPath,
getPlaywrightDownloadDir,
getUtils,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import fsp from 'fs/promises'
test(
'export works on the first try',
@ -21,11 +20,11 @@ test(
await Promise.all([fsp.mkdir(bracketDir, { recursive: true })])
await Promise.all([
fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('router-template-slate.kcl'),
path.join(bracketDir, 'other.kcl')
),
fsp.copyFile(
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
),
])
@ -108,7 +107,7 @@ test(
},
{ timeout: 15_000 }
)
.toBeGreaterThan(30_000)
.toBeGreaterThan(300_000)
})
})
@ -188,7 +187,7 @@ test(
},
{ timeout: 15_000 }
)
.toBeGreaterThan(50_000)
.toBeGreaterThan(70_000)
})
})
}

View File

@ -1,14 +1,14 @@
import { uuidv4 } from '@src/lib/utils'
import { test, expect } from './zoo-test'
import fsp from 'fs/promises'
import { join } from 'path'
import { uuidv4 } from 'lib/utils'
import {
TEST_COLORS,
executorInputPath,
getUtils,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
TEST_COLORS,
} from './test-utils'
import { join } from 'path'
test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
test('can comment out code with ctrl+/', async ({ page, homePage }) => {
@ -32,30 +32,26 @@ test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
await page.keyboard.press('/')
await page.keyboard.up('ControlOrMeta')
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
// |> close()`.replaceAll('\n', '')
)
// |> close()`)
// uncomment the code
await page.keyboard.down('ControlOrMeta')
await page.keyboard.press('/')
await page.keyboard.up('ControlOrMeta')
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
|> close()`.replaceAll('\n', '')
)
|> close()`)
})
test('ensure we use the cache, and do not re-execute', async ({
@ -182,15 +178,13 @@ sketch001 = startSketchOn(XY)
await page.locator('#code-pane button:first-child').click()
await page.locator('button:has-text("Format code")').click()
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
|> close()`.replaceAll('\n', '')
)
|> close()`)
})
test('if you click the format button it formats your code and executes so lints are still there', async ({
@ -233,15 +227,13 @@ sketch001 = startSketchOn(XY)
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch_001 = startSketchOn(XY)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch_001 = startSketchOn(XY)
|> startProfileAt([-10, -10], %)
|> line(end = [20, 0])
|> line(end = [0, 20])
|> line(end = [-20, 0])
|> close()`.replaceAll('\n', '')
)
|> close()`)
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
@ -479,7 +471,6 @@ sketch_001 = startSketchOn(XY)
test('if you write kcl with lint errors you get lints', async ({
page,
homePage,
scene,
}) => {
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1000, height: 500 })
@ -499,7 +490,10 @@ sketch_001 = startSketchOn(XY)
await page.keyboard.press('ArrowLeft')
await page.keyboard.press('ArrowRight')
await scene.waitForExecutionDone()
// FIXME: lsp errors do not propagate to the frontend until engine is connected and code is executed
// This timeout is to wait for engine connection. LSP and code execution errors should be handled differently
// LSP can emit errors as fast as it waits and show them in the editor
await page.waitForTimeout(10000)
// error in guter
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
@ -821,12 +815,10 @@ sketch_001 = startSketchOn(XY)
// there shouldn't be any auto complete options for 'lin' in the comment
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([3.14, 12], %)
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
)
|> xLine(%, length = 5) // lin`)
// expect there to be no KCL errors
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0)
@ -896,12 +888,10 @@ sketch001 = startSketchOn(XZ)
// there shouldn't be any auto complete options for 'lin' in the comment
await expect(page.locator('.cm-completionLabel')).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([3.14, 12], %)
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
)
|> xLine(%, length = 5) // lin`)
})
})
test('Can undo a click and point extrude with ctrl+z', async ({
@ -985,13 +975,12 @@ sketch001 = startSketchOn(XZ)
test(
'Can undo a sketch modification with ctrl+z',
{ tag: ['@skipWin'] },
async ({ page, homePage, editor }) => {
async ({ page, homePage }) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit=in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -0.38], %)
@ -1081,45 +1070,41 @@ sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// expect the code to have changed
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78])
|> tangentialArcTo([27.6, -3.05], %)
|> close()
|> extrude(length = 5)`,
{ shouldNormalise: true }
)
|> extrude(length = 5)
`)
// Hit undo
await page.keyboard.down('Control')
await page.keyboard.press('KeyZ')
await page.keyboard.up('Control')
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %)
|> line(end = [15.4, -2.78])
|> tangentialArcTo([24.95, -0.38], %)
|> close()
|> extrude(length = 5)`,
{ shouldNormalise: true }
)
|> extrude(length = 5)`)
// Hit undo again.
await page.keyboard.down('Control')
await page.keyboard.press('KeyZ')
await page.keyboard.up('Control')
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([2.71, -2.71], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -0.38], %)
|> close()
|> extrude(length = 5)`,
{ shouldNormalise: true }
)
|> extrude(length = 5)
`)
// Hit undo again.
await page.keyboard.down('Control')
@ -1127,15 +1112,13 @@ sketch001 = startSketchOn(XZ)
await page.keyboard.up('Control')
await page.waitForTimeout(100)
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -0.38], %)
|> close()
|> extrude(length = 5)`,
{ shouldNormalise: true }
)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -0.38], %)
|> close()
|> extrude(length = 5)`)
}
)
@ -1223,55 +1206,4 @@ sketch001 = startSketchOn(XZ)
})
}
)
test('Rectangle tool panning with middle click', async ({
page,
homePage,
toolbar,
scene,
cmdBar,
editor,
}) => {
await page.setBodyDimensions({ width: 1200, height: 900 })
await homePage.goToModelingScene()
// wait until scene is ready to be interacted with
await scene.connectionEstablished()
await scene.settled(cmdBar)
await page.getByRole('button', { name: 'Start Sketch' }).click()
// select an axis plane
await page.mouse.click(700, 200)
// Needed as we don't yet have a way to get a signal from the engine that the camera has animated to the sketch plane
await page.waitForTimeout(1000)
const middleMousePan = async (
startX: number,
startY: number,
endX: number,
endY: number
) => {
const initialCode = await editor.getCurrentCode()
await page.mouse.click(startX, startY, { button: 'middle' })
await page.mouse.move(endX, endY, {
steps: 10,
})
// We expect the code to be the same, middle mouse click should not modify the code, only do panning
await editor.expectEditor.toBe(initialCode)
}
await test.step(`Verify corner rectangle panning`, async () => {
await page.getByTestId('corner-rectangle').click()
await middleMousePan(800, 500, 900, 600)
})
await test.step(`Verify center rectangle panning`, async () => {
await toolbar.selectCenterRectangle()
await middleMousePan(800, 200, 900, 300)
})
})
})

View File

@ -1,8 +1,7 @@
import { test, expect } from './zoo-test'
import * as fsp from 'fs/promises'
import { join } from 'path'
import { expect, test } from '@e2e/playwright/zoo-test'
const FEATURE_TREE_EXAMPLE_CODE = `export fn timesFive(x) {
return 5 * x
}

View File

@ -1,16 +1,15 @@
import { FILE_EXT } from '@src/lib/constants'
import * as fs from 'fs'
import { test, expect } from './zoo-test'
import * as fsp from 'fs/promises'
import { join } from 'path'
import * as fs from 'fs'
import {
createProject,
executorInputPath,
getUtils,
orRunWhenFullSuiteEnabled,
runningOnWindows,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import { join } from 'path'
import { FILE_EXT } from 'lib/constants'
test.describe('integrations tests', () => {
test(

View File

@ -1,5 +1,5 @@
import type { Locator, Page, Request, Route, TestInfo } from '@playwright/test'
import { expect } from '@playwright/test'
import type { Page, Locator, Route, Request } from '@playwright/test'
import { expect, TestInfo } from '@playwright/test'
import * as fs from 'fs'
import * as path from 'path'

View File

@ -1,12 +1,11 @@
import type { Locator, Page } from '@playwright/test'
import type { Page, Locator } from '@playwright/test'
import { expect } from '@playwright/test'
import {
checkIfPaneIsOpen,
closePane,
checkIfPaneIsOpen,
openPane,
sansWhitespace,
} from '@e2e/playwright/test-utils'
} from '../test-utils'
interface EditorState {
activeLines: Array<string>
@ -82,13 +81,6 @@ export class EditorFixture {
expectEditor = {
toContain: this._expectEditorToContain(),
not: { toContain: this._expectEditorToContain(true) },
toBe: async (code: string) => {
const currentCode = await this.getCurrentCode()
return expect(currentCode).toBe(code)
},
}
getCurrentCode = async () => {
return await this.codeContent.innerText()
}
snapshot = async (options?: { timeout?: number; name?: string }) => {
const wasPaneOpen = await this.checkIfPaneIsOpen()

View File

@ -1,28 +1,28 @@
/* eslint-disable react-hooks/rules-of-hooks */
import type {
BrowserContext,
ElectronApplication,
Page,
TestInfo,
Page,
} from '@playwright/test'
import { _electron as electron } from '@playwright/test'
import { SETTINGS_FILE_NAME } from '@src/lib/constants'
import type { DeepPartial } from '@src/lib/types'
import * as TOML from '@iarna/toml'
import { TEST_SETTINGS } from '../storageStates'
import { SETTINGS_FILE_NAME } from 'lib/constants'
import { getUtils, setup } from '../test-utils'
import fsp from 'fs/promises'
import fs from 'node:fs'
import path from 'path'
import type { Settings } from '@rust/kcl-lib/bindings/Settings'
import { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
import { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
import { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import { TEST_SETTINGS } from '@e2e/playwright/storageStates'
import { getUtils, settingsToToml, setup } from '@e2e/playwright/test-utils'
import { CmdBarFixture } from './cmdBarFixture'
import { EditorFixture } from './editorFixture'
import { ToolbarFixture } from './toolbarFixture'
import { SceneFixture } from './sceneFixture'
import { HomePageFixture } from './homePageFixture'
import { DeepPartial } from 'lib/types'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
export class AuthenticatedApp {
public readonly page: Page
@ -124,7 +124,6 @@ export class ElectronZoo {
// We need to expose this in order for some tests that require folder
// creation and some code below.
// eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this
const options = {
@ -287,30 +286,26 @@ export class ElectronZoo {
let settingsOverridesToml = ''
if (appSettings) {
settingsOverridesToml = settingsToToml({
settingsOverridesToml = TOML.stringify({
// @ts-expect-error
settings: {
...TEST_SETTINGS,
...appSettings,
app: {
...TEST_SETTINGS.app,
project_directory: this.projectDirName,
...appSettings.app,
},
project: {
...TEST_SETTINGS.project,
directory: this.projectDirName,
},
},
})
} else {
settingsOverridesToml = settingsToToml({
settingsOverridesToml = TOML.stringify({
// @ts-expect-error
settings: {
...TEST_SETTINGS,
app: {
...TEST_SETTINGS.app,
},
project: {
...TEST_SETTINGS.project,
directory: this.projectDirName,
project_directory: this.projectDirName,
},
},
})

View File

@ -1,4 +1,4 @@
import type { Locator, Page } from '@playwright/test'
import type { Page, Locator } from '@playwright/test'
import { expect } from '@playwright/test'
interface ProjectCardState {

View File

@ -1,17 +1,15 @@
import type { Locator, Page } from '@playwright/test'
import { isArray, uuidv4 } from '@src/lib/utils'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import type { Page, Locator } from '@playwright/test'
import { expect } from '../zoo-test'
import { isArray, uuidv4 } from 'lib/utils'
import { CmdBarFixture } from './cmdBarFixture'
import {
closeDebugPanel,
doAndWaitForImageDiff,
getPixelRGBs,
getUtils,
openAndClearDebugPanel,
sendCustomCmd,
} from '@e2e/playwright/test-utils'
import { expect } from '@e2e/playwright/zoo-test'
getUtils,
} from '../test-utils'
type MouseParams = {
pixelDiff?: number
@ -312,9 +310,7 @@ export async function expectPixelColor(
.toBeTruthy()
.catch((cause) => {
throw new Error(
`ExpectPixelColor: point ${JSON.stringify(
coords
)} was expecting ${colour} but got ${finalValue}`,
`ExpectPixelColor: expecting ${colour} got ${finalValue}`,
{ cause }
)
})

View File

@ -1,18 +1,14 @@
import { type Locator, type Page, test } from '@playwright/test'
import type { SidebarType } from '@src/components/ModelingSidebar/ModelingPanes'
import { SIDEBAR_BUTTON_SUFFIX } from '@src/lib/constants'
import type { ToolbarModeName } from '@src/lib/toolbar'
import { type Page, type Locator, test } from '@playwright/test'
import { expect } from '../zoo-test'
import {
checkIfPaneIsOpen,
closePane,
doAndWaitForImageDiff,
openPane,
} from '@e2e/playwright/test-utils'
import { expect } from '@e2e/playwright/zoo-test'
import { type baseUnitLabels } from '@src/lib/settings/settingsTypes'
type LengthUnitLabel = (typeof baseUnitLabels)[keyof typeof baseUnitLabels]
} from '../test-utils'
import { SidebarType } from 'components/ModelingSidebar/ModelingPanes'
import { SIDEBAR_BUTTON_SUFFIX } from 'lib/constants'
import { ToolbarModeName } from 'lib/toolbar'
export class ToolbarFixture {
public page: Page
@ -239,12 +235,6 @@ export class ToolbarFixture {
async checkIfFeatureTreePaneIsOpen() {
return this.checkIfPaneIsOpen(this.featureTreeId)
}
async selectUnit(unit: LengthUnitLabel) {
await this.page.getByTestId('units-menu').click()
const optionLocator = this.page.getByRole('button', { name: unit })
await expect(optionLocator).toBeVisible()
await optionLocator.click()
}
/**
* Get a specific operation button from the Feature Tree pane.

View File

@ -272,6 +272,14 @@ export const isErrorWhitelisted = (exception: Error) => {
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/snapshot-tests.spec.ts',
},
// TODO: fix this error in the code
{
name: 'ReferenceError',
message: 'createNewVariableCheckbox is not defined',
stack: '',
project: 'Google Chrome',
foundInSpec: 'e2e/playwright/testing-constraints.spec.ts',
},
{
name: 'Error',
message: 'The "path" argument must be of type string. Received undefined',

View File

@ -1,8 +1,7 @@
import fsp from 'fs/promises'
import { test, expect } from './zoo-test'
import { executorInputPath } from './test-utils'
import { join } from 'path'
import { executorInputPath } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import fsp from 'fs/promises'
test(
'When machine-api server not found butt is disabled and shows the reason',
@ -12,7 +11,7 @@ test(
const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
)
})
@ -52,7 +51,7 @@ test(
const bracketDir = join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
)
})

View File

@ -1,15 +1,13 @@
import { PROJECT_SETTINGS_FILE_NAME } from '@src/lib/constants'
import { test, expect } from './zoo-test'
import { PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
import * as fsp from 'fs/promises'
import { join } from 'path'
import type { NamedView } from '@rust/kcl-lib/bindings/NamedView'
import {
createProject,
perProjectsettingsToToml,
tomlToPerProjectSettings,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
perProjectsettingsToToml,
} from './test-utils'
import { NamedView } from '@rust/kcl-lib/bindings/NamedView'
// Helper function to determine if the file path on disk exists
// Specifically this is used to check if project.toml exists on disk

View File

@ -1,4 +1,4 @@
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
/**
* Not all menu actions are tested. Some are default electron menu actions.
@ -10,7 +10,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('File.Create project', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const newProject =
@ -30,7 +29,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('File.Open project', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const openProject =
@ -54,7 +52,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
}) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const userSettings = app.applicationMenu.getMenuItemById(
@ -78,7 +75,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
}) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const keybindings = app.applicationMenu.getMenuItemById(
@ -100,7 +96,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
}) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -117,7 +112,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('File.Preferences.Theme', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -142,7 +136,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
}) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -159,7 +152,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('File.Preferences.Sign out', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById('File.Sign out')
@ -178,7 +170,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('Edit.Rename project', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -197,7 +188,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('Edit.Delete project', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -220,7 +210,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
}) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -239,7 +228,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('View.Command Palette...', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -257,7 +245,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('Help.Show all commands', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -273,7 +260,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('Help.KCL code samples', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -289,7 +275,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
}) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(
@ -308,7 +293,6 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
test('Help.Reset onboarding', async ({ tronApp, cmdBar, page }) => {
if (!tronApp) fail()
// Run electron snippet to find the Menu!
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
await tronApp.electron.evaluate(async ({ app }) => {
if (!app || !app.applicationMenu) fail()
const menu = app.applicationMenu.getMenuItemById(

View File

@ -2,7 +2,8 @@
// application, check it can make it to the project pane, and nothing more.
// It also tests our test wrappers are working.
// Additionally this serves as a nice minimal example.
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
test.describe('Open the application', () => {
test('see the project view', async ({ page, context }) => {

View File

@ -1,23 +1,22 @@
import { bracket } from '@src/lib/exampleKcl'
import { onboardingPaths } from '@src/routes/Onboarding/paths'
import fsp from 'fs/promises'
import { test, expect } from './zoo-test'
import { join } from 'path'
import { expectPixelColor } from '@e2e/playwright/fixtures/sceneFixture'
import fsp from 'fs/promises'
import {
getUtils,
executorInputPath,
createProject,
settingsToToml,
orRunWhenFullSuiteEnabled,
} from './test-utils'
import { bracket } from 'lib/exampleKcl'
import { onboardingPaths } from 'routes/Onboarding/paths'
import {
TEST_SETTINGS_KEY,
TEST_SETTINGS_ONBOARDING_EXPORT,
TEST_SETTINGS_ONBOARDING_START,
TEST_SETTINGS_ONBOARDING_EXPORT,
TEST_SETTINGS_ONBOARDING_USER_MENU,
} from '@e2e/playwright/storageStates'
import {
createProject,
executorInputPath,
getUtils,
orRunWhenFullSuiteEnabled,
settingsToToml,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './storageStates'
import { expectPixelColor } from './fixtures/sceneFixture'
// Because our default test settings have the onboardingStatus set to 'dismissed',
// we must set it to empty for the tests where we want to see the onboarding immediately.

View File

@ -1,4 +1,4 @@
import { expect, test } from '@playwright/test'
import { test, expect } from '@playwright/test'
/** @deprecated, import from ./fixtureSetup.ts instead */
export const _test = test

View File

@ -1,12 +1,12 @@
import type { Locator, Page } from '@playwright/test'
import { Page } from '@playwright/test'
import { test, expect } from './zoo-test'
import { EditorFixture } from './fixtures/editorFixture'
import { SceneFixture } from './fixtures/sceneFixture'
import { ToolbarFixture } from './fixtures/toolbarFixture'
import fs from 'node:fs/promises'
import path from 'node:path'
import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { getUtils, orRunWhenFullSuiteEnabled } from './test-utils'
import { Locator } from '@playwright/test'
// test file is for testing point an click code gen functionality that's not sketch mode related
@ -137,7 +137,7 @@ test.describe('Point-and-click tests', () => {
await scene.moveCameraTo(cameraPos, cameraTarget)
await test.step('check chamfer selection changes cursor position', async () => {
await test.step('check chamfer selection changes cursor positon', async () => {
await expect(async () => {
// sometimes initial click doesn't register
await clickChamfer()
@ -173,7 +173,7 @@ test.describe('Point-and-click tests', () => {
})
await test.step('Check there is no errors after code created in previous steps executes', async () => {
await editor.expectState({
activeLines: ['@settings(defaultLengthUnit = in)'],
activeLines: ['sketch001 = startSketchOn(XZ)'],
highlightedCode: '',
diagnostics: [],
})
@ -299,8 +299,7 @@ test.describe('Point-and-click tests', () => {
await test.step('verify at the end of the test that final code is what is expected', async () => {
await editor.expectEditor.toContain(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine([
@ -370,7 +369,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
})
})
test('Works on chamfers that are not in a pipeExpression can break up multi edges in a chamfer array', async ({
test('Works on chamfers that are non in a pipeExpression can break up multi edges in a chamfer array', async ({
context,
page,
homePage,
@ -419,8 +418,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|>close()`,
})
await editor.expectEditor.toContain(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %)
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine([
@ -1641,10 +1639,9 @@ loft001 = loft([sketch001, sketch002])
{
targetType: 'circle',
testPoint: { x: 700, y: 250 },
initialCode: `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
initialCode: `sketch001 = startSketchOn('YZ')
profile001 = circle(sketch001, center = [0, 0], radius = 500)
sketch002 = startSketchOn(XZ)
sketch002 = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> xLine(length = -500)
|> tangentialArcTo([-2000, 500], %)`,
@ -1652,8 +1649,7 @@ sketch002 = startSketchOn(XZ)
{
targetType: 'rectangle',
testPoint: { x: 710, y: 255 },
initialCode: `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
initialCode: `sketch001 = startSketchOn('YZ')
profile001 = startProfileAt([-400, -400], sketch001)
|> angledLine([0, 800], %, $rectangleSegmentA001)
|> angledLine([
@ -1666,7 +1662,7 @@ profile001 = startProfileAt([-400, -400], sketch001)
], %)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
sketch002 = startSketchOn(XZ)
sketch002 = startSketchOn('XZ')
|> startProfileAt([0, 0], %)
|> xLine(length = -500)
|> tangentialArcTo([-2000, 500], %)`,
@ -1810,8 +1806,7 @@ sketch002 = startSketchOn(XZ)
toolbar,
cmdBar,
}) => {
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
const initialCode = `sketch001 = startSketchOn(YZ)
|> circle(
center = [0, 0],
radius = 500
@ -2480,8 +2475,7 @@ extrude001 = extrude(profile001, length = 5)
cmdBar,
}) => {
// Code samples
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
const initialCode = `sketch001 = startSketchOn(XY)
|> startProfileAt([-12, -6], %)
|> line(end = [0, 12])
|> line(end = [24, 0])
@ -2773,8 +2767,7 @@ extrude001 = extrude(sketch001, length = -12)
toolbar,
}) => {
// Code samples
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
const initialCode = `sketch001 = startSketchOn(XY)
|> startProfileAt([-12, -6], %)
|> line(end = [0, 12])
|> line(end = [24, 0], tag = $seg02)
@ -2928,8 +2921,7 @@ chamfer04 = chamfer(extrude001, length = 5, tags = [getOppositeEdge(seg02)])
toolbar,
cmdBar,
}) => {
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
const initialCode = `sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 30)
extrude001 = extrude(sketch001, length = 30)
`
@ -3064,8 +3056,7 @@ extrude001 = extrude(sketch001, length = 30)
toolbar,
cmdBar,
}) => {
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XY)
const initialCode = `sketch001 = startSketchOn(XY)
|> startProfileAt([-20, 20], %)
|> xLine(length = 40)
|> yLine(length = -60)
@ -3183,8 +3174,7 @@ extrude001 = extrude(sketch001, length = 40)
})
const shellSketchOnFacesCases = [
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 100)
|> extrude(length = 100)
@ -3192,8 +3182,7 @@ sketch002 = startSketchOn(sketch001, 'END')
|> circle(center = [0, 0], radius = 50)
|> extrude(length = 50)
`,
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> circle(center = [0, 0], radius = 100)
extrude001 = extrude(sketch001, length = 100)
@ -3476,39 +3465,6 @@ segAng(rectangleSegmentA002),
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = 'X')`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
// Edit flow
const newAngle = '90'
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation(
'Revolve',
0
)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
commandName: 'Revolve',
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Angle: '360',
},
highlightedHeaderArg: 'angle',
stage: 'arguments',
})
await page.keyboard.insertText(newAngle)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = ' + newAngle)
)
})
test('revolve surface around edge from an extruded solid2d', async ({
context,
@ -3519,22 +3475,26 @@ segAng(rectangleSegmentA002),
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(XZ)
|> startProfileAt([-102.57, 101.72], %)
|> angledLine([0, 202.6], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001) - 90,
202.6
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
const initialCode = `
sketch001 = startSketchOn(XZ)
|> startProfileAt([-102.57, 101.72], %)
|> angledLine([0, 202.6], %, $rectangleSegmentA001)
|> angledLine([
segAng(rectangleSegmentA001) - 90,
202.6
], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 50)
sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|> circle(center = [-11.34, 10.0], radius = 8.69)
|> circle(
center = [-11.34, 10.0],
radius = 8.69
)
`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
@ -3552,49 +3512,9 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)`
await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = rectangleSegmentA001)`
await editor.expectEditor.toContain(newCodeToFind)
// Edit flow
const newAngle = '180'
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation(
'Revolve',
0
)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
commandName: 'Revolve',
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Angle: '360',
},
highlightedHeaderArg: 'angle',
stage: 'arguments',
})
await page.keyboard.insertText(newAngle)
await page.getByRole('button', { name: 'Create new variable' }).click()
await expect(page.getByPlaceholder('Variable name')).toHaveValue(
'angle001'
)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain('angle001 = ' + newAngle)
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = angle001')
)
const newCodeToFind = `revolve001 = revolve(sketch002, angle = 360, axis = getOppositeEdge(rectangleSegmentA001)) `
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
})
test('revolve sketch circle around line segment from startProfileAt sketch', async ({
context,
@ -3605,22 +3525,26 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
toolbar,
cmdBar,
}) => {
const initialCode = `sketch002 = startSketchOn(XY)
|> startProfileAt([-2.02, 1.79], %)
|> xLine(length = 2.6)
sketch001 = startSketchOn(-XY)
|> startProfileAt([-0.48, 1.25], %)
|> angledLine([0, 2.38], %, $rectangleSegmentA001)
|> angledLine([segAng(rectangleSegmentA001) - 90, 2.4], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 5)
sketch003 = startSketchOn(extrude001, 'START')
|> circle(center = [-0.69, 0.56], radius = 0.28)
const initialCode = `
sketch002 = startSketchOn(XY)
|> startProfileAt([-2.02, 1.79], %)
|> xLine(length = 2.6)
sketch001 = startSketchOn('-XY')
|> startProfileAt([-0.48, 1.25], %)
|> angledLine([0, 2.38], %, $rectangleSegmentA001)
|> angledLine([segAng(rectangleSegmentA001) - 90, 2.4], %, $rectangleSegmentB001)
|> angledLine([
segAng(rectangleSegmentA001),
-segLen(rectangleSegmentA001)
], %, $rectangleSegmentC001)
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
extrude001 = extrude(sketch001, length = 5)
sketch003 = startSketchOn(extrude001, 'START')
|> circle(
center = [-0.69, 0.56],
radius = 0.28
)
`
await context.addInitScript((initialCode) => {
@ -3639,44 +3563,9 @@ sketch003 = startSketchOn(extrude001, 'START')
const lineCodeToSelection = `|> xLine(length = 2.6)`
await page.getByText(lineCodeToSelection).click()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
const newCodeToFind = `revolve001 = revolve(sketch003, angle = 360, axis = seg01)`
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
// Edit flow
const newAngle = '270'
await toolbar.openPane('feature-tree')
const operationButton = await toolbar.getFeatureTreeOperation(
'Revolve',
0
)
await operationButton.dblclick({ button: 'left' })
await cmdBar.expectState({
commandName: 'Revolve',
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Angle: '360',
},
highlightedHeaderArg: 'angle',
stage: 'arguments',
})
await page.keyboard.insertText(newAngle)
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Angle: newAngle,
},
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
await toolbar.closePane('feature-tree')
await editor.expectEditor.toContain(
newCodeToFind.replace('angle = 360', 'angle = ' + newAngle)
)
})
})
@ -3689,8 +3578,7 @@ sketch003 = startSketchOn(extrude001, 'START')
toolbar,
cmdBar,
}) => {
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
const initialCode = `sketch001 = startSketchOn(XZ)
profile001 = circle(
sketch001,
center = [0, 0],

View File

@ -1,20 +1,19 @@
import { DEFAULT_PROJECT_KCL_FILE } from '@src/lib/constants'
import fs from 'fs'
import fsp from 'fs/promises'
import path from 'path'
import type { Paths } from '@e2e/playwright/test-utils'
import { test, expect } from './zoo-test'
import {
createProject,
doExport,
executorInputPath,
getPlaywrightDownloadDir,
getUtils,
isOutOfViewInScrollContainer,
Paths,
createProject,
getPlaywrightDownloadDir,
orRunWhenFullSuiteEnabled,
runningOnWindows,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import fsp from 'fs/promises'
import fs from 'fs'
import path from 'path'
import { DEFAULT_PROJECT_KCL_FILE } from 'lib/constants'
test(
'projects reload if a new one is created, deleted, or renamed externally',
@ -88,7 +87,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
@ -125,7 +124,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
)
const errorDir = path.join(dir, 'broken-code')
@ -163,7 +162,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [110, 110, 110]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
timeout: 10_000,
})
.toBeLessThan(20)
@ -214,7 +213,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
)
const emptyDir = path.join(dir, 'empty')
@ -249,7 +248,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -291,7 +290,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
)
@ -320,7 +319,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -360,7 +359,7 @@ test(
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
)
await fsp.copyFile(
@ -394,7 +393,7 @@ test(
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -444,6 +443,7 @@ test(
await page.getByText('broken-code').click()
// Gotcha: You can not use scene.waitForExecutionDone() since the KCL code is going to fail
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
@ -481,7 +481,7 @@ test.describe('Can export from electron app', () => {
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
@ -513,7 +513,7 @@ test.describe('Can export from electron app', () => {
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
timeout: 10_000,
})
.toBeLessThan(15)
@ -554,7 +554,7 @@ test.describe('Can export from electron app', () => {
},
{ timeout: 15_000 }
)
.toBeGreaterThan(50_000)
.toBeGreaterThan(300_000)
// clean up exported file
await fsp.rm(filepath)
@ -1507,12 +1507,7 @@ test(
await u.waitForPageLoad()
// The file should be prepopulated with the user's unit settings.
await expect(page.locator('.cm-content')).toHaveText(
'@settings(defaultLengthUnit = in)'
)
await page.locator('.cm-content').fill(`sketch001 = startSketchOn('XZ')
await page.locator('.cm-content').fill(`sketch001 = startSketchOn(XZ)
|> startProfileAt([-87.4, 282.92], %)
|> line(end = [324.07, 27.199], tag = $seg01)
|> line(end = [118.328, -291.754])

View File

@ -1,5 +1,4 @@
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
/* eslint-disable jest/no-conditional-expect */
/**

View File

@ -1,5 +1,5 @@
import { orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
import { orRunWhenFullSuiteEnabled } from './test-utils'
/* eslint-disable jest/no-conditional-expect */

View File

@ -1,18 +1,17 @@
import type { Page } from '@playwright/test'
import { bracket } from '@src/lib/exampleKcl'
import { reportRejection } from '@src/lib/trap'
import * as fsp from 'fs/promises'
import { Page } from '@playwright/test'
import { test, expect } from './zoo-test'
import path from 'path'
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from '@e2e/playwright/storageStates'
import type { TestColor } from '@e2e/playwright/test-utils'
import * as fsp from 'fs/promises'
import {
TEST_COLORS,
executorInputPath,
getUtils,
executorInputPath,
TEST_COLORS,
TestColor,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import { TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR } from './storageStates'
import { bracket } from 'lib/exampleKcl'
import { reportRejection } from 'lib/trap'
test.describe('Regression tests', { tag: ['@skipWin'] }, () => {
// bugs we found that don't fit neatly into other categories
@ -332,7 +331,7 @@ extrude001 = extrude(sketch001, length = 50)
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = mm)
sketch002 = startSketchOn(XY)
sketch002 = startSketchOn('XY')
profile002 = startProfileAt([72.24, -52.05], sketch002)
|> angledLine([0, 181.26], %, $rectangleSegmentA001)
|> angledLine([
@ -583,7 +582,7 @@ extrude002 = extrude(profile002, length = 150)
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
@ -620,7 +619,6 @@ extrude002 = extrude(profile002, length = 150)
test(`View gizmo stays visible even when zoomed out all the way`, async ({
page,
homePage,
scene,
}) => {
const u = await getUtils(page)
@ -634,7 +632,7 @@ extrude002 = extrude(profile002, length = 150)
await test.step(`Load an empty file`, async () => {
await page.addInitScript(async () => {
localStorage.setItem('persistCode', '@settings(defaultLengthUnit = in)')
localStorage.setItem('persistCode', '')
})
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
@ -648,31 +646,22 @@ extrude002 = extrude(profile002, length = 150)
timeout: 5000,
message: 'Plane color is visible',
})
.toBeLessThanOrEqual(20)
await expect(scene.startEditSketchBtn).toBeEnabled()
.toBeLessThanOrEqual(15)
let maxZoomOuts = 10
let middlePixelIsBackgroundColor =
(await middlePixelIsColor(bgColor)) < 10
console.time('pressing control')
await page.keyboard.down('Control')
while (!middlePixelIsBackgroundColor && maxZoomOuts > 0) {
await page.waitForTimeout(100)
await page.mouse.move(650, 460)
console.time('moved to start point')
await page.keyboard.down('Control')
await page.mouse.move(600, 460)
await page.mouse.down({ button: 'right' })
console.time('moused down')
await page.mouse.move(650, 50, { steps: 20 })
console.time('moved to end point')
await page.waitForTimeout(100)
await page.mouse.move(600, 50, { steps: 20 })
await page.mouse.up({ button: 'right' })
console.time('moused up')
await page.keyboard.up('Control')
await page.waitForTimeout(100)
maxZoomOuts--
middlePixelIsBackgroundColor = (await middlePixelIsColor(bgColor)) < 15
middlePixelIsBackgroundColor = (await middlePixelIsColor(bgColor)) < 10
}
await page.keyboard.up('Control')
expect(middlePixelIsBackgroundColor, {
message: 'We should not see the default planes',
@ -689,12 +678,13 @@ extrude002 = extrude(profile002, length = 150)
homePage,
scene,
toolbar,
viewport,
}) => {
await context.folderSetupFn(async (dir) => {
const legoDir = path.join(dir, 'lego')
await fsp.mkdir(legoDir, { recursive: true })
await fsp.copyFile(
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
executorInputPath('lego.kcl'),
path.join(legoDir, 'main.kcl')
)
})
@ -707,8 +697,11 @@ extrude002 = extrude(profile002, length = 150)
await scene.loadingIndicator.waitFor({ state: 'detached' })
})
await test.step(`The part should start loading quickly, not waiting until execution is complete`, async () => {
// TODO: use the viewport size to pick the center point, but the `viewport` fixture's values were wrong.
await scene.expectPixelColor([116, 116, 116], { x: 500, y: 250 }, 15)
await scene.expectPixelColor(
[143, 143, 143],
{ x: (viewport?.width ?? 1200) / 2, y: (viewport?.height ?? 500) / 2 },
15
)
})
})
@ -798,74 +791,6 @@ plane002 = offsetPlane(XZ, offset = -2 * x)`
await page.getByTestId('custom-cmd-send-button').click()
}
)
test('scale other than default works with sketch mode', async ({
page,
homePage,
toolbar,
editor,
scene,
}) => {
await test.step('Load the washer code', async () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
innerDiameter = 0.203
outerDiameter = 0.438
thicknessMax = 0.038
thicknessMin = 0.024
washerSketch = startSketchOn(XY)
|> circle(center = [0, 0], radius = outerDiameter / 2)
washer = extrude(washerSketch, length = thicknessMax)`
)
})
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
})
const [circleCenterClick] = scene.makeMouseHelpers(650, 300)
const [circleRadiusClick] = scene.makeMouseHelpers(800, 320)
const [washerFaceClick] = scene.makeMouseHelpers(657, 286)
await page.waitForTimeout(100)
await test.step('Start sketching on the washer face', async () => {
await toolbar.startSketchPlaneSelection()
await washerFaceClick()
await page.waitForTimeout(600) // engine animation
await toolbar.expectToolbarMode.toBe('sketching')
})
await test.step('Draw a circle and verify code', async () => {
// select circle tool
await expect
.poll(async () => {
await toolbar.circleBtn.click()
return toolbar.circleBtn.getAttribute('aria-pressed')
})
.toBe('true')
await page.waitForTimeout(100)
await circleCenterClick()
// this number will be different if the scale is not set correctly for inches
await editor.expectEditor.toContain(
'circle(sketch001, center = [0.06, -0.06]'
)
await circleRadiusClick()
await editor.expectEditor.toContain(
'circle(sketch001, center = [0.06, -0.06], radius = 0.18'
)
})
await test.step('Exit sketch mode', async () => {
await toolbar.exitSketch()
await toolbar.expectToolbarMode.toBe('modeling')
await toolbar.selectUnit('Yards')
await editor.expectEditor.toContain('@settings(defaultLengthUnit = yd)')
})
})
})
async function clickExportButton(page: Page) {

View File

@ -1,20 +1,20 @@
import type { Page } from '@playwright/test'
import { roundOff, uuidv4 } from '@src/lib/utils'
import { Page } from '@playwright/test'
import { test, expect } from './zoo-test'
import fs from 'node:fs/promises'
import path from 'node:path'
import { HomePageFixture } from './fixtures/homePageFixture'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import {
PERSIST_MODELING_CONTEXT,
TEST_COLORS,
getMovementUtils,
getUtils,
PERSIST_MODELING_CONTEXT,
TEST_COLORS,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import { uuidv4, roundOff } from 'lib/utils'
import { SceneFixture } from './fixtures/sceneFixture'
import { ToolbarFixture } from './fixtures/toolbarFixture'
import { CmdBarFixture } from './fixtures/cmdBarFixture'
test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
test('multi-sketch file shows multiple Edit Sketch buttons', async ({
@ -113,8 +113,7 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([2.61, -4.01], %)
|> xLine(length = 8.73)
|> tangentialArcTo([8.33, -1.31], %)`
@ -160,10 +159,7 @@ sketch001 = startSketchOn(XZ)
await page.mouse.click(700, 200)
await expect.poll(u.normalisedEditorCode, { timeout: 1000 })
.toBe(`@settings(defaultLengthUnit = in)
sketch002 = startSketchOn(XZ)
.toBe(`sketch002 = startSketchOn(XZ)
sketch001 = startProfileAt([12.34, -12.34], sketch002)
|> yLine(length = 12.34)
@ -479,8 +475,7 @@ sketch001 = startProfileAt([12.34, -12.34], sketch002)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit=in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> circle(center = [4.61, -5.01], radius = 8)`
)
})
@ -565,14 +560,12 @@ sketch001 = startSketchOn(XZ)
test('Can edit a sketch that has been extruded in the same pipe', async ({
page,
homePage,
editor,
}) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit=in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -10.01], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -0.38], %)
@ -657,29 +650,26 @@ sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// expect the code to have changed
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([7.12, -12.68], %)
|> line(end = [12.68, -1.09])
|> tangentialArcTo([24.89, 0.68], %)
|> close()
|> extrude(length = 5)`,
{ shouldNormalise: true }
)
|> extrude(length = 5)
`)
})
test('Can edit a sketch that has been revolved in the same pipe', async ({
page,
homePage,
scene,
editor,
}) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit=in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([4.61, -14.01], %)
|> line(end = [12.73, -0.09])
|> tangentialArcTo([24.95, -5.38], %)
@ -764,16 +754,14 @@ sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// expect the code to have changed
await editor.expectEditor.toContain(
`sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content'))
.toHaveText(`sketch001 = startSketchOn(XZ)
|> startProfileAt([6.44, -12.07], %)
|> line(end = [14.72, 1.97])
|> tangentialArcTo([24.95, -5.38], %)
|> line(end = [1.97, 2.06])
|> close()
|> revolve(axis = "X")`,
{ shouldNormalise: true }
)
|> revolve(axis = "X")`)
})
test('Can add multiple sketches', async ({ page, homePage }) => {
const u = await getUtils(page)
@ -801,8 +789,7 @@ sketch001 = startSketchOn(XZ)
200
)
let codeStr =
'@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XY)'
let codeStr = 'sketch001 = startSketchOn(XY)'
await page.mouse.click(center.x, viewportSize.height * 0.55)
await expect(u.codeLocator).toHaveText(codeStr)
@ -881,8 +868,7 @@ sketch001 = startSketchOn(XZ)
await u.openDebugPanel()
const code = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(-XZ)
const code = `sketch001 = startSketchOn(-XZ)
profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
scale * 34.8
)}], sketch001)
@ -912,7 +898,7 @@ profile001 = startProfileAt([${roundOff(scale * 69.6)}, ${roundOff(
await page.mouse.move(700, 200, { steps: 10 })
await page.mouse.click(700, 200, { delay: 200 })
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(-XZ)`
`sketch001 = startSketchOn(-XZ)`
)
let prevContent = await page.locator('.cm-content').innerText()
@ -1440,8 +1426,7 @@ test.describe(`Sketching with offset planes`, () => {
await context.addInitScript(() => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
offsetPlane001 = offsetPlane(XY, offset = 10)`
`offsetPlane001 = offsetPlane(XY, offset = 10)`
)
})
@ -1455,7 +1440,7 @@ offsetPlane001 = offsetPlane(XY, offset = 10)`
await test.step(`Hovering should highlight code`, async () => {
await planeHover()
await editor.expectState({
activeLines: [`@settings(defaultLengthUnit = in)`],
activeLines: [`offsetPlane001=offsetPlane(XY,offset=10)`],
diagnostics: [],
highlightedCode: 'offsetPlane(XY, offset = 10)',
})
@ -1468,7 +1453,7 @@ offsetPlane001 = offsetPlane(XY, offset = 10)`
await expect(toolbar.lineBtn).toBeEnabled()
await editor.expectEditor.toContain('startSketchOn(offsetPlane001)')
await editor.expectState({
activeLines: [`@settings(defaultLengthUnit = in)`],
activeLines: [`offsetPlane001=offsetPlane(XY,offset=10)`],
diagnostics: [],
highlightedCode: '',
})
@ -1619,8 +1604,7 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
await context.addInitScript(() => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile002 = startProfileAt([40.68, 87.67], sketch001)
|> xLine(length = 239.17)
profile003 = startProfileAt([206.63, -56.73], sketch001)
@ -2188,8 +2172,7 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([6.24, 4.54], sketch001)
|> line(end = [-0.41, 6.99])
|> line(end = [8.61, 0.74])
@ -2334,8 +2317,7 @@ profile004 = circleThreePoint(sketch001, p1 = [13.44, -6.8], p2 = [13.39, -2.07]
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([6.24, 4.54], sketch001)
|> line(end = [-0.41, 6.99])
|> line(end = [8.61, 0.74])
@ -2440,8 +2422,7 @@ profile003 = circle(sketch001, center = [6.92, -4.2], radius = 3.16)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([-63.43, 193.08], sketch001)
|> line(end = [168.52, 149.87])
|> line(end = [190.29, -39.18])
@ -2505,11 +2486,7 @@ extrude001 = extrude(profile003, length = 5)
page,
}) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
myVar = 5`
)
localStorage.setItem('persistCode', `myVar = 5`)
})
await page.setBodyDimensions({ width: 1000, height: 500 })
@ -2556,8 +2533,7 @@ extrude001 = extrude(profile003, length = 5)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([85.19, 338.59], sketch001)
|> line(end = [213.3, -94.52])
|> line(end = [-230.09, -55.34])
@ -2599,8 +2575,7 @@ profile002 = startProfileAt([85.81, 52.55], sketch002)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
thePart = startSketchOn(XZ)
`thePart = startSketchOn(XZ)
|> startProfileAt([7.53, 10.51], %)
|> line(end = [12.54, 1.83])
|> line(end = [6.65, -6.91])
@ -2661,8 +2636,7 @@ extrude001 = extrude(thePart, length = 75)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([6.71, -3.66], sketch001)
|> line(end = [2.65, 9.02], tag = $seg02)
|> line(end = [3.73, -9.36], tag = $seg01)
@ -2835,8 +2809,7 @@ extrude003 = extrude(profile011, length = 2.5)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([34, 42.66], sketch001)
|> line(end = [102.65, 151.99])
|> line(end = [76, -138.66])

View File

@ -1,22 +1,21 @@
import type { Models } from '@kittycad/lib'
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
import { spawn } from 'child_process'
import fsp from 'fs/promises'
import JSZip from 'jszip'
import path from 'path'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import { secrets } from '@e2e/playwright/secrets'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from '@e2e/playwright/storageStates'
import type { Paths } from '@e2e/playwright/test-utils'
import { test, expect } from './zoo-test'
import { secrets } from './secrets'
import {
Paths,
doExport,
getUtils,
orRunWhenFullSuiteEnabled,
settingsToToml,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
orRunWhenFullSuiteEnabled,
} from './test-utils'
import { Models } from '@kittycad/lib'
import fsp from 'fs/promises'
import { spawn } from 'child_process'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import JSZip from 'jszip'
import path from 'path'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates'
import { SceneFixture } from './fixtures/sceneFixture'
import { CmdBarFixture } from './fixtures/cmdBarFixture'
test.beforeEach(async ({ page, context }) => {
// Make the user avatar image always 404
@ -77,11 +76,11 @@ part001 = startSketchOn(-XZ)
|> xLine(endAbsolute = totalLen, tag = $seg03)
|> yLine(length = -armThick, tag = $seg01)
|> angledLineThatIntersects({
angle = turns::HALF_TURN,
angle = HALF_TURN,
offset = -armThick,
intersectTag = seg04
}, %)
|> angledLineToY([segAng(seg04, %) + 180, turns::ZERO], %)
|> angledLineToY([segAng(seg04, %) + 180, ZERO], %)
|> angledLineToY({
angle = -bottomAng,
to = -totalHeightHalf - armThick,
@ -89,12 +88,12 @@ part001 = startSketchOn(-XZ)
|> xLine(length = endAbsolute = segEndX(seg03) + 0)
|> yLine(length = -segLen(seg01, %))
|> angledLineThatIntersects({
angle = turns::HALF_TURN,
angle = HALF_TURN,
offset = -armThick,
intersectTag = seg02
}, %)
|> angledLineToY([segAng(seg02, %) + 180, -baseHeight], %)
|> xLine(endAbsolute = turns::ZERO)
|> xLine(endAbsolute = ZERO)
|> close()
|> extrude(length = 4)`
)
@ -346,9 +345,7 @@ const extrudeDefaultPlane = async (
app: {
onboarding_status: 'dismissed',
show_debug_panel: true,
appearance: {
theme: 'dark',
},
theme: 'dark',
},
project: {
default_project_name: 'project-$nnn',
@ -455,7 +452,7 @@ test(
await page.waitForTimeout(700) // TODO detect animation ending, or disable animation
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
code += `profile001 = startProfileAt([182.59, -246.32], sketch001)`
code += `profile001 = startProfileAt([7.19, -9.7], sketch001)`
await expect(page.locator('.cm-content')).toHaveText(code)
await page.waitForTimeout(100)
@ -473,7 +470,7 @@ test(
await page.waitForTimeout(500)
code += `
|> xLine(length = 184.3)`
|> xLine(length = 7.25)`
await expect(page.locator('.cm-content')).toHaveText(code)
await page
@ -631,7 +628,7 @@ test(
mask: [page.getByTestId('model-state-indicator')],
})
await expect(page.locator('.cm-content')).toHaveText(
`sketch001 = startSketchOn(XZ)profile001 = circle(sketch001, center = [366.89, -62.01], radius = 1)`
`sketch001 = startSketchOn(XZ)profile001 = circle(sketch001, center = [14.44, -2.44], radius = 1)`
)
}
)
@ -668,7 +665,7 @@ test.describe(
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
code += `profile001 = startProfileAt([182.59, -246.32], sketch001)`
code += `profile001 = startProfileAt([7.19, -9.7], sketch001)`
await expect(u.codeLocator).toHaveText(code)
await page.waitForTimeout(100)
@ -676,7 +673,7 @@ test.describe(
await page.waitForTimeout(100)
code += `
|> xLine(length = 184.3)`
|> xLine(length = 7.25)`
await expect(u.codeLocator).toHaveText(code)
await page
@ -691,7 +688,7 @@ test.describe(
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
code += `
|> tangentialArcTo([551.2, -62.01], %)`
|> tangentialArcTo([21.7, -2.44], %)`
await expect(u.codeLocator).toHaveText(code)
// click tangential arc tool again to unequip it

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -1,5 +1,5 @@
{
"original_source_code": "sketch001 = startSketchOn('XZ')\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn('XZ')\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn(XY)\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine([0, 176.4], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 53.4\n ], %, $rectangleSegmentB001)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %, $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
"original_source_code": "sketch001 = startSketchOn('XZ')\nprofile001 = startProfileAt([57.81, 250.51], sketch001)\n |> line(end = [121.13, 56.63], tag = $seg02)\n |> line(end = [83.37, -34.61], tag = $seg01)\n |> line(end = [19.66, -116.4])\n |> line(end = [-221.8, -41.69])\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude001 = extrude(profile001, length = 200)\nsketch002 = startSketchOn('XZ')\n |> startProfileAt([-73.64, -42.89], %)\n |> xLine(length = 173.71)\n |> line(end = [-22.12, -94.4])\n |> xLine(length = -156.98)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude002 = extrude(sketch002, length = 50)\nsketch003 = startSketchOn('XY')\n |> startProfileAt([52.92, 157.81], %)\n |> angledLine([0, 176.4], %, $rectangleSegmentA001)\n |> angledLine([\n segAng(rectangleSegmentA001) - 90,\n 53.4\n ], %, $rectangleSegmentB001)\n |> angledLine([\n segAng(rectangleSegmentA001),\n -segLen(rectangleSegmentA001)\n ], %, $rectangleSegmentC001)\n |> line(endAbsolute = [profileStartX(%), profileStartY(%)])\n |> close()\nextrude003 = extrude(sketch003, length = 20)\n",
"prompt": "make this neon green please, use #39FF14",
"source_ranges": [
{
@ -30,4 +30,4 @@
}
],
"kcl_version": "0.2.48"
}
}

View File

@ -1,19 +1,17 @@
import type { SaveSettingsPayload } from '@src/lib/settings/settingsTypes'
import { Themes } from '@src/lib/theme'
import type { DeepPartial } from '@src/lib/types'
import { onboardingPaths } from '@src/routes/Onboarding/paths'
import type { Settings } from '@rust/kcl-lib/bindings/Settings'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { Themes } from 'lib/theme'
import { DeepPartial } from 'lib/types'
import { onboardingPaths } from 'routes/Onboarding/paths'
export const IS_PLAYWRIGHT_KEY = 'playwright'
export const TEST_SETTINGS_KEY = '/settings.toml'
export const TEST_SETTINGS: DeepPartial<Settings> = {
app: {
appearance: {
theme: Themes.Dark,
},
theme: Themes.Dark,
onboarding_status: 'dismissed',
project_directory: '',
show_debug_panel: true,
},
modeling: {
@ -24,7 +22,6 @@ export const TEST_SETTINGS: DeepPartial<Settings> = {
},
project: {
default_project_name: 'project-$nnn',
directory: '',
},
text_editor: {
text_wrapping: true,
@ -57,7 +54,7 @@ export const TEST_SETTINGS_ONBOARDING_START: DeepPartial<Settings> = {
export const TEST_SETTINGS_DEFAULT_THEME: DeepPartial<Settings> = {
...TEST_SETTINGS,
app: { ...TEST_SETTINGS.app, appearance: { theme: Themes.System } },
app: { ...TEST_SETTINGS.app, theme: Themes.System },
}
export const TEST_SETTINGS_CORRUPTED = {

View File

@ -1,12 +1,7 @@
import type { EngineCommand } from '@src/lang/std/artifactGraph'
import { uuidv4 } from '@src/lib/utils'
import {
commonPoints,
getUtils,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
import { commonPoints, getUtils, orRunWhenFullSuiteEnabled } from './test-utils'
import { EngineCommand } from 'lang/std/artifactGraph'
import { uuidv4 } from 'lib/utils'
test.describe('Test network and connection issues', () => {
test(

View File

@ -1,9 +1,9 @@
import {
orRunWhenFullSuiteEnabled,
runningOnLinux,
runningOnMac,
runningOnWindows,
} from '@e2e/playwright/test-utils'
orRunWhenFullSuiteEnabled,
} from './test-utils'
describe('platform detection utilities', () => {
const originalPlatform = process.platform

View File

@ -1,29 +1,32 @@
import * as TOML from '@iarna/toml'
import type { Models } from '@kittycad/lib'
import type { BrowserContext, Locator, Page, TestInfo } from '@playwright/test'
import { expect } from '@playwright/test'
import type { EngineCommand } from '@src/lang/std/artifactGraph'
import type { Configuration } from '@src/lang/wasm'
import { COOKIE_NAME } from '@src/lib/constants'
import { reportRejection } from '@src/lib/trap'
import type { DeepPartial } from '@src/lib/types'
import { isArray } from '@src/lib/utils'
import {
expect,
BrowserContext,
TestInfo,
Locator,
Page,
} from '@playwright/test'
import { test } from './zoo-test'
import { EngineCommand } from 'lang/std/artifactGraph'
import fsp from 'fs/promises'
import path from 'path'
import pixelMatch from 'pixelmatch'
import type { Protocol } from 'playwright-core/types/protocol'
import { PNG } from 'pngjs'
import type { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
import { isErrorWhitelisted } from '@e2e/playwright/lib/console-error-whitelist'
import { secrets } from '@e2e/playwright/secrets'
import { Protocol } from 'playwright-core/types/protocol'
import type { Models } from '@kittycad/lib'
import { COOKIE_NAME } from 'lib/constants'
import { secrets } from './secrets'
import {
IS_PLAYWRIGHT_KEY,
TEST_SETTINGS,
TEST_SETTINGS_KEY,
} from '@e2e/playwright/storageStates'
import { test } from '@e2e/playwright/zoo-test'
TEST_SETTINGS,
IS_PLAYWRIGHT_KEY,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { isErrorWhitelisted } from './lib/console-error-whitelist'
import { isArray } from 'lib/utils'
import { reportRejection } from 'lib/trap'
import { DeepPartial } from 'lib/types'
import { Configuration } from 'lang/wasm'
import { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
const toNormalizedCode = (text: string) => {
return text.replace(/\s+/g, '')
@ -680,8 +683,8 @@ const _makeTemplate = (
isArray(currentOptions)
? currentOptions[i]
: typeof currentOptions === 'number'
? currentOptions
: ''
? currentOptions
: ''
)
)
})
@ -900,21 +903,15 @@ export async function setup(
settings: {
...TEST_SETTINGS,
app: {
appearance: {
...TEST_SETTINGS.app?.appearance,
theme: 'dark',
},
...TEST_SETTINGS.project,
project_directory: TEST_SETTINGS.app?.project_directory,
onboarding_status: 'dismissed',
},
project: {
...TEST_SETTINGS.project,
directory: TEST_SETTINGS.project?.directory,
theme: 'dark',
},
},
}),
IS_PLAYWRIGHT_KEY,
PLAYWRIGHT_TEST_DIR: TEST_SETTINGS.project?.directory || '',
PLAYWRIGHT_TEST_DIR: TEST_SETTINGS.app?.project_directory || '',
PERSIST_MODELING_CONTEXT,
}
)
@ -1115,25 +1112,21 @@ export async function pollEditorLinesSelectedLength(page: Page, lines: number) {
}
export function settingsToToml(settings: DeepPartial<Configuration>) {
// eslint-disable-next-line no-restricted-syntax
return TOML.stringify(settings as any)
}
export function tomlToSettings(toml: string): DeepPartial<Configuration> {
// eslint-disable-next-line no-restricted-syntax
return TOML.parse(toml)
}
export function tomlToPerProjectSettings(
toml: string
): DeepPartial<ProjectConfiguration> {
// eslint-disable-next-line no-restricted-syntax
return TOML.parse(toml)
}
export function perProjectsettingsToToml(
settings: DeepPartial<ProjectConfiguration>
) {
// eslint-disable-next-line no-restricted-syntax
return TOML.stringify(settings as any)
}

View File

@ -1,8 +1,7 @@
import type { EngineCommand } from '@src/lang/std/artifactGraph'
import { uuidv4 } from '@src/lib/utils'
import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
import { EngineCommand } from 'lang/std/artifactGraph'
import { uuidv4 } from 'lib/utils'
import { getUtils, orRunWhenFullSuiteEnabled } from './test-utils'
test.describe('Testing Camera Movement', { tag: ['@skipWin'] }, () => {
test('Can move camera reliably', async ({ page, context, homePage }) => {

View File

@ -1,14 +1,14 @@
import { XOR } from '@src/lib/utils'
import { test, expect } from './zoo-test'
import * as fsp from 'fs/promises'
import path from 'node:path'
import {
TEST_COLORS,
getUtils,
orRunWhenFullSuiteEnabled,
TEST_COLORS,
pollEditorLinesSelectedLength,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
executorInputPath,
orRunWhenFullSuiteEnabled,
} from './test-utils'
import { XOR } from 'lib/utils'
import path from 'node:path'
test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
test('Can constrain line length', async ({ page, homePage }) => {
@ -81,8 +81,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 79
`yo = 79
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4], tag = $seg01)
@ -146,8 +145,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4], tag = $seg01)
@ -161,6 +159,31 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|> xLine(length = segLen(seg_what))
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])`
)
const isChecked = await createNewVariableCheckbox.isChecked()
const addVariable = testName === 'Add variable'
XOR(isChecked, addVariable) && // XOR because no need to click the checkbox if the state is already correct
(await createNewVariableCheckbox.click())
await page
.getByRole('button', { name: 'Add constraining value' })
.click()
// Wait for the codemod to take effect
await expect(page.locator('.cm-content')).toContainText(`angle: -57,`)
await expect(page.locator('.cm-content')).toContainText(
`offset: ${offset},`
)
await pollEditorLinesSelectedLength(page, 2)
const activeLinesContent = await page.locator('.cm-activeLine').all()
await expect(activeLinesContent[0]).toHaveText(
`|> line(end = [74.36, 130.4], tag = $seg01)`
)
await expect(activeLinesContent[1]).toHaveText(`}, %)`)
// checking the count of the overlays is a good proxy check that the client sketch scene is in a good state
await expect(page.getByTestId('segment-overlay')).toHaveCount(4)
})
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
@ -254,8 +277,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -365,8 +387,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -465,13 +486,13 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
testName: 'Add variable, selecting axis',
addVariable: true,
axisSelect: true,
value: 'turns::QUARTER_TURN - angle001',
value: 'QUARTER_TURN - angle001',
},
{
testName: 'No variable, selecting axis',
addVariable: false,
axisSelect: true,
value: 'turns::QUARTER_TURN - 7',
value: 'QUARTER_TURN - 7',
},
] as const
for (const { testName, addVariable, value, axisSelect } of cases) {
@ -479,8 +500,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -582,8 +602,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -669,8 +688,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -750,8 +768,7 @@ part002 = startSketchOn(XZ)
await page.addInitScript(async (customCode) => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -852,8 +869,7 @@ part002 = startSketchOn(XZ)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -919,12 +935,12 @@ part002 = startSketchOn(XZ)
test.describe('Axis & segment - no modal constraints', () => {
const cases = [
{
codeAfter: `|> line(endAbsolute = [154.9, turns::ZERO])`,
codeAfter: `|> line(endAbsolute = [154.9, ZERO])`,
axisClick: { x: 950, y: 250 },
constraintName: 'Snap To X',
},
{
codeAfter: `|> line(endAbsolute = [turns::ZERO, 61.34])`,
codeAfter: `|> line(endAbsolute = [ZERO, 61.34])`,
axisClick: { x: 600, y: 150 },
constraintName: 'Snap To Y',
},
@ -934,8 +950,7 @@ part002 = startSketchOn(XZ)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 5
`yo = 5
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> line(end = [74.36, 130.4])
@ -1098,23 +1113,13 @@ test.describe('Electron constraint tests', () => {
test(
'Able to double click label to set constraint',
{ tag: '@electron' },
async ({ page, context, homePage, scene, editor, toolbar, cmdBar }) => {
async ({ page, context, homePage, scene, editor, toolbar }) => {
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'test-sample')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.writeFile(
path.join(bracketDir, 'main.kcl'),
`@settings(defaultLengthUnit = in)
const part001 = startSketchOn(XY)
|> startProfileAt([4.83, 12.56], %)
|> line(end = [15.1, 2.48])
|> line(end = [3.15, -9.85], tag = $seg01)
|> line(end = [-15.17, -4.1])
|> angledLine([segAng(seg01), 12.35], %)
|> line(end = [-13.02, 10.03])
|> close()
|> extrude(length = 4)`,
'utf-8'
await fsp.copyFile(
executorInputPath('angled_line.kcl'),
path.join(bracketDir, 'main.kcl')
)
})
@ -1132,14 +1137,6 @@ test.describe('Electron constraint tests', () => {
await scene.waitForExecutionDone()
})
async function clickOnFirstSegmentLabel() {
const child = page
.locator('.segment-length-label-text')
.first()
.locator('xpath=..')
await child.dblclick()
}
await test.step('Double click to constrain', async () => {
// Enter sketch edit mode via feature tree
await toolbar.openPane('feature-tree')
@ -1147,19 +1144,21 @@ test.describe('Electron constraint tests', () => {
await op.dblclick()
await toolbar.closePane('feature-tree')
await clickOnFirstSegmentLabel()
await cmdBar.progressCmdBar()
await editor.expectEditor.toContain('length001 = 15.3')
await editor.expectEditor.toContain('|> angledLine([9, length001], %)')
})
await test.step('Double click again and expect failure', async () => {
await clickOnFirstSegmentLabel()
await expect(
page.getByText('Unable to constrain the length of this segment')
).toBeVisible()
const child = page
.locator('.segment-length-label-text')
.first()
.locator('xpath=..')
await child.dblclick()
const cmdBarSubmitButton = page.getByRole('button', {
name: 'arrow right Continue',
})
await cmdBarSubmitButton.click()
await expect(page.locator('.cm-content')).toContainText(
'length001 = 15.3'
)
await expect(page.locator('.cm-content')).toContainText(
'|> angledLine([9, length001], %)'
)
await page.getByRole('button', { name: 'Exit Sketch' }).click()
})
}

View File

@ -1,8 +1,7 @@
import { uuidv4 } from '@src/lib/utils'
import { TEST_CODE_GIZMO } from '@e2e/playwright/storageStates'
import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
import { getUtils } from './test-utils'
import { uuidv4 } from 'lib/utils'
import { TEST_CODE_GIZMO } from './storageStates'
test.describe('Testing Gizmo', { tag: ['@skipWin'] }, () => {
const cases = [
@ -256,7 +255,7 @@ test.describe(`Testing gizmo, fixture-based`, () => {
await context.addInitScript(() => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
`
const sketch002 = startSketchOn(XZ)
|> startProfileAt([-108.83, -57.48], %)
|> angledLine([0, 105.13], %, $rectangleSegmentA001)

View File

@ -1,5 +1,5 @@
import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { test, expect } from './zoo-test'
import { getUtils, orRunWhenFullSuiteEnabled } from './test-utils'
test.describe('Test toggling perspective', () => {
test('via command palette and toggle', async ({ page, homePage }) => {

View File

@ -1,10 +1,9 @@
import { FILE_EXT } from '@src/lib/constants'
import { bracket } from '@src/lib/exampleKcl'
import { test, expect } from './zoo-test'
import { getUtils } from './test-utils'
import { bracket } from 'lib/exampleKcl'
import * as fsp from 'fs/promises'
import { join } from 'path'
import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { FILE_EXT } from 'lib/constants'
test.describe('Testing in-app sample loading', () => {
/**
@ -47,7 +46,7 @@ test.describe('Testing in-app sample loading', () => {
page.getByRole('option', {
name,
})
const warningText = page.getByText('Overwrite current file with sample?')
const warningText = page.getByText('Overwrite current file and units?')
const confirmButton = page.getByRole('button', { name: 'Submit command' })
await test.step(`Precondition: check the initial code`, async () => {
@ -111,9 +110,11 @@ test.describe('Testing in-app sample loading', () => {
const commandMethodOption = page.getByRole('option', {
name: 'Overwrite',
})
const newFileWarning = page.getByText('Create a new file from sample?')
const newFileWarning = page.getByText(
'Create a new file, overwrite project units?'
)
const overwriteWarning = page.getByText(
'Overwrite current file with sample?'
'Overwrite current file and units?'
)
const confirmButton = page.getByRole('button', { name: 'Submit command' })
const projectMenuButton = page.getByTestId('project-sidebar-toggle')

View File

@ -1,15 +1,15 @@
import type { Page } from '@playwright/test'
import type { LineInputsType } from '@src/lang/std/sketchcombos'
import { uuidv4 } from '@src/lib/utils'
import { Page } from '@playwright/test'
import { test, expect } from './zoo-test'
import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
import {
deg,
getUtils,
orRunWhenFullSuiteEnabled,
wiggleMove,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
orRunWhenFullSuiteEnabled,
} from './test-utils'
import { LineInputsType } from 'lang/std/sketchcombos'
import { uuidv4 } from 'lib/utils'
import { EditorFixture } from './fixtures/editorFixture'
test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
test('Hover over a segment should show its overlay, hovering over the input overlays should show its popover, clicking the input overlay should constrain/unconstrain it:\nfor the following segments', () => {
@ -210,8 +210,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> startProfileAt([5 + 0, 20 + 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -381,8 +380,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yRel001 = -14
`yRel001 = -14
xRel001 = 0.5
angle001 = 3
len001 = 32
@ -461,8 +459,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -593,8 +590,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -755,8 +751,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -836,8 +831,7 @@ test.describe('Testing segment overlays', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
profile001 = startProfileAt([56.37, 120.33], sketch001)
|> line(end = [162.86, 106.48])
|> arcTo({
@ -963,8 +957,7 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> circle(center = [1 + 0, 0], radius = 8)
`
)
@ -1084,8 +1077,7 @@ part001 = startSketchOn(XZ)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|>startProfileAt([0, 0], %)
|> line(end = [0.5, -14 + 0])
|> angledLine({ angle = 3 + 0, length = 32 + 0 }, %)
@ -1359,8 +1351,7 @@ part001 = startSketchOn(XZ)
async ({ lineToBeDeleted, extraLine }) => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> startProfileAt([5, 6], %)
|> ${lineToBeDeleted}
|> line(end = [-10, -15])
@ -1525,8 +1516,7 @@ part001 = startSketchOn(XZ)
async ({ lineToBeDeleted }) => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> startProfileAt([5, 6], %)
|> ${lineToBeDeleted}
|> line(end = [-10, -15])

View File

@ -1,13 +1,9 @@
import type { Coords2d } from '@src/lang/std/sketch'
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
import { uuidv4 } from '@src/lib/utils'
import { test, expect } from './zoo-test'
import {
commonPoints,
getUtils,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { commonPoints, getUtils, orRunWhenFullSuiteEnabled } from './test-utils'
import { Coords2d } from 'lang/std/sketch'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import { uuidv4 } from 'lib/utils'
test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
test.setTimeout(90_000)
@ -72,20 +68,20 @@ test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)`
`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)`
)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${commonPoints.startAt}, sketch001)
|> xLine(length = ${commonPoints.num1})`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1})
@ -93,7 +89,7 @@ test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
.toHaveText(`sketch001 = startSketchOn(XZ)profile001 = startProfileAt(${
commonPoints.startAt
}, sketch001)
|> xLine(length = ${commonPoints.num1})
@ -264,8 +260,7 @@ test.describe('Testing selections', { tag: ['@skipWin'] }, () => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([-79.26, 95.04], %)
|> line(end = [112.54, 127.64], tag = $seg02)
|> line(end = [170.36, -121.61], tag = $seg01)
@ -533,8 +528,7 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
part001 = startSketchOn(XZ)
`part001 = startSketchOn(XZ)
|> startProfileAt([20, 0], %)
|> line(end = [7.13, 4 + 0])
|> angledLine({ angle = 3 + 0, length = 3.14 + 0 }, %)
@ -753,8 +747,7 @@ part001 = startSketchOn(XZ)
await page.waitForTimeout(200)
await u.removeCurrentCode()
await u.codeLocator.fill(`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
await u.codeLocator.fill(`sketch001 = startSketchOn(XZ)
|> startProfileAt([75.8, 317.2], %) // [$startCapTag, $EndCapTag]
|> angledLine([0, 268.43], %, $rectangleSegmentA001)
|> angledLine([
@ -972,8 +965,7 @@ part001 = startSketchOn(XZ)
async ({ cases }) => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
yo = 79
`yo = 79
part001 = startSketchOn(XZ)
|> startProfileAt([-7.54, -26.74], %)
|> ${cases[0].expectedCode}
@ -1028,8 +1020,7 @@ part001 = startSketchOn(XZ)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([-79.26, 95.04], %)
|> line(end = [112.54, 127.64])
|> line(end = [170.36, -121.61], tag = $seg01)
@ -1262,7 +1253,7 @@ part001 = startSketchOn(XZ)
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)sketch001 = startSketchOn(XZ)`
`sketch001 = startSketchOn(XZ)`
)
await page.waitForTimeout(600)

View File

@ -1,29 +1,24 @@
import {
PROJECT_SETTINGS_FILE_NAME,
SETTINGS_FILE_NAME,
} from '@src/lib/constants'
import type { SettingsLevel } from '@src/lib/settings/settingsTypes'
import type { DeepPartial } from '@src/lib/types'
import { test, expect } from './zoo-test'
import * as fsp from 'fs/promises'
import { join } from 'path'
import type { Settings } from '@rust/kcl-lib/bindings/Settings'
import {
TEST_SETTINGS,
TEST_SETTINGS_CORRUPTED,
TEST_SETTINGS_DEFAULT_THEME,
TEST_SETTINGS_KEY,
} from '@e2e/playwright/storageStates'
import {
TEST_COLORS,
createProject,
executorInputPath,
getUtils,
orRunWhenFullSuiteEnabled,
executorInputPath,
createProject,
tomlToSettings,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
TEST_COLORS,
orRunWhenFullSuiteEnabled,
} from './test-utils'
import { SettingsLevel } from 'lib/settings/settingsTypes'
import { SETTINGS_FILE_NAME, PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
import {
TEST_SETTINGS_KEY,
TEST_SETTINGS_CORRUPTED,
TEST_SETTINGS,
TEST_SETTINGS_DEFAULT_THEME,
} from './storageStates'
import { DeepPartial } from 'lib/types'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
test.describe('Testing settings', () => {
test('Stored settings are validated and fall back to defaults', async ({
@ -50,12 +45,12 @@ test.describe('Testing settings', () => {
)
)
expect(storedSettings.settings?.app?.appearance?.theme).toBe('dark')
expect(storedSettings.settings?.app?.theme).toBe('dark')
// Check that the invalid settings were changed to good defaults
expect(storedSettings.settings?.modeling?.base_unit).toBe('in')
expect(storedSettings.settings?.modeling?.mouse_controls).toBe('zoo')
expect(storedSettings.settings?.project?.directory).toBe('')
expect(storedSettings.settings?.app?.project_directory).toBe('')
expect(storedSettings.settings?.project?.default_project_name).toBe(
'project-$nnn'
)
@ -276,7 +271,7 @@ test.describe('Testing settings', () => {
const bracketDir = join(dir, projectName)
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
executorInputPath('focusrite_scarlett_mounting_braket.kcl'),
join(bracketDir, 'main.kcl')
)
}
@ -386,9 +381,7 @@ test.describe('Testing settings', () => {
}
await tronApp.cleanProjectDir({
app: {
appearance: {
color: 259,
},
theme_color: '259',
},
})
@ -420,12 +413,9 @@ test.describe('Testing settings', () => {
await tronApp.cleanProjectDir({
app: {
appearance: {
// Doesn't matter what you set it to. It will
// default to 264.5
color: 0,
},
// Doesn't matter what you set it to. It will
// default to 264.5
theme_color: '0',
},
})
@ -709,19 +699,19 @@ test.describe('Testing settings', () => {
name: 'Current units are: ',
})
await gizmo.click()
const button = page.locator('ul').getByRole('button', {
const button = page.getByRole('button', {
name: copy,
exact: true,
})
await button.click()
const toastMessage = page.getByText(
`Updated per-file units to ${unitOfMeasure}`
`Set default unit to "${unitOfMeasure}" for this project`
)
await expect(toastMessage).toBeVisible()
}
await changeUnitOfMeasureInGizmo('ft', 'Feet')
await changeUnitOfMeasureInGizmo('in', 'Inches')
await changeUnitOfMeasureInGizmo('ft', 'Feet')
await changeUnitOfMeasureInGizmo('yd', 'Yards')
await changeUnitOfMeasureInGizmo('mm', 'Millimeters')
await changeUnitOfMeasureInGizmo('cm', 'Centimeters')
@ -961,9 +951,9 @@ test.describe('Testing settings', () => {
)
})
await test.step(`Initial units from settings are ignored`, async () => {
await test.step(`Initial units from settings`, async () => {
await homePage.openProject('project-000')
await expect(unitsIndicator).toHaveText('Current units are: mm')
await expect(unitsIndicator).toHaveText('Current units are: in')
})
await test.step(`Manually write inline settings`, async () => {

View File

@ -1,13 +1,12 @@
import type { Page } from '@playwright/test'
import fs from 'fs'
import { join } from 'path'
import { Page } from '@playwright/test'
import { test, expect } from './zoo-test'
import {
createProject,
getUtils,
createProject,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
import { join } from 'path'
import fs from 'fs'
test.describe('Text-to-CAD tests', { tag: ['@skipWin'] }, () => {
test('basic lego happy case', async ({ page, homePage }) => {

View File

@ -1,10 +1,11 @@
import { test, expect } from './zoo-test'
import {
doExport,
getUtils,
makeTemplate,
orRunWhenFullSuiteEnabled,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
} from './test-utils'
test('Units menu', async ({ page, homePage }) => {
test.fixme(orRunWhenFullSuiteEnabled())
@ -66,11 +67,11 @@ part001 = startSketchOn(-XZ)
|> xLine(endAbsolute = totalLen, tag = $seg03)
|> yLine(length = -armThick, tag = $seg01)
|> angledLineThatIntersects({
angle = turns::HALF_TURN,
angle = HALF_TURN,
offset = -armThick,
intersectTag = seg04
}, %)
|> angledLineToY([segAng(seg04) + 180, turns::ZERO], %)
|> angledLineToY([segAng(seg04) + 180, ZERO], %)
|> angledLineToY({
angle = -bottomAng,
to = -totalHeightHalf - armThick,
@ -78,12 +79,12 @@ part001 = startSketchOn(-XZ)
|> xLine(endAbsolute = segEndX(seg03) + 0)
|> yLine(length = -segLen(seg01))
|> angledLineThatIntersects({
angle = turns::HALF_TURN,
angle = HALF_TURN,
offset = -armThick,
intersectTag = seg02
}, %)
|> angledLineToY([segAng(seg02) + 180, -baseHeight], %)
|> xLine(endAbsolute = turns::ZERO)
|> xLine(endAbsolute = ZERO)
|> close()
|> extrude(length = 4)`
)
@ -482,8 +483,7 @@ test('Sketch on face', async ({ page, homePage, scene, cmdBar, toolbar }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
`sketch001 = startSketchOn(XZ)
|> startProfileAt([3.29, 7.86], %)
|> line(end = [2.48, 2.44])
|> line(end = [2.66, 1.17])

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