fix: resolved main conflicts
This commit is contained in:
@ -29,6 +29,13 @@
|
||||
{
|
||||
"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": [
|
||||
|
16
.github/workflows/e2e-tests.yml
vendored
16
.github/workflows/e2e-tests.yml
vendored
@ -46,7 +46,15 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: check-rust-changes
|
||||
steps:
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
|
||||
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
@ -153,11 +161,11 @@ jobs:
|
||||
continue-on-error: true
|
||||
run: rm -r test-results
|
||||
- name: check for changes
|
||||
if: ${{ matrix.os == 'namespace-profile-ubuntu-8-cores' && matrix.shardIndex == 1 }}
|
||||
if: ${{ matrix.os == 'namespace-profile-ubuntu-8-cores' && matrix.shardIndex == 1 && github.ref != 'refs/heads/main' }}
|
||||
shell: bash
|
||||
id: git-check
|
||||
run: |
|
||||
git add .
|
||||
git add e2e/playwright/snapshot-tests.spec.ts-snapshots
|
||||
if git status | grep -q "Changes to be committed"
|
||||
then echo "modified=true" >> $GITHUB_OUTPUT
|
||||
else echo "modified=false" >> $GITHUB_OUTPUT
|
||||
@ -166,14 +174,14 @@ jobs:
|
||||
if: steps.git-check.outputs.modified == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
git add .
|
||||
git add e2e/playwright/snapshot-tests.spec.ts-snapshots
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
||||
git fetch origin
|
||||
echo ${{ github.head_ref }}
|
||||
git checkout ${{ github.head_ref }}
|
||||
git commit -am "A snapshot a day keeps the bugs away! 📷🐛 (OS: ${{matrix.os}})" || true
|
||||
git commit -m "A snapshot a day keeps the bugs away! 📷🐛 (OS: ${{matrix.os}})" || true
|
||||
git push
|
||||
git push origin ${{ github.head_ref }}
|
||||
# only upload artifacts if there's actually changes
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
7644
docs/kcl/std.json
7644
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -47,21 +47,6 @@ myObj = { a = 0, b = "thing" }
|
||||
We support two different ways of getting properties from objects, you can call
|
||||
`myObj.a` or `myObj["a"]` both work.
|
||||
|
||||
|
||||
## Functions
|
||||
|
||||
We also have support for defining your own functions. Functions can take in any
|
||||
type of argument. Below is an example of the syntax:
|
||||
|
||||
```
|
||||
fn myFn(x) {
|
||||
return x
|
||||
}
|
||||
```
|
||||
|
||||
As you can see above `myFn` just returns whatever it is given.
|
||||
|
||||
|
||||
## Binary expressions
|
||||
|
||||
You can also do math! Let's show an example below:
|
||||
@ -76,6 +61,120 @@ You can nest expressions in parenthesis as well:
|
||||
myMathExpression = 3 + (1 * 2 / (3 - 7))
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
We also have support for defining your own functions. Functions can take in any
|
||||
type of argument. Below is an example of the syntax:
|
||||
|
||||
```
|
||||
fn myFn(x) {
|
||||
return x
|
||||
}
|
||||
```
|
||||
|
||||
As you can see above `myFn` just returns whatever it is given.
|
||||
|
||||
KCL's early drafts used positional arguments, but we now use keyword arguments. If you declare a
|
||||
function like this:
|
||||
|
||||
```
|
||||
fn add(left, right) {
|
||||
return left + right
|
||||
}
|
||||
```
|
||||
|
||||
You can call it like this:
|
||||
|
||||
```
|
||||
total = add(left = 1, right = 2)
|
||||
```
|
||||
|
||||
Functions can also declare one *unlabeled* arg. If you do want to declare an unlabeled arg, it must
|
||||
be the first arg declared.
|
||||
|
||||
```
|
||||
// The @ indicates an argument can be used without a label.
|
||||
// Note that only the first argument can use @.
|
||||
fn increment(@x) {
|
||||
return x + 1
|
||||
}
|
||||
|
||||
fn add(@x, delta) {
|
||||
return x + delta
|
||||
}
|
||||
|
||||
two = increment(1)
|
||||
three = add(1, delta = 2)
|
||||
```
|
||||
|
||||
## Pipelines
|
||||
|
||||
It can be hard to read repeated function calls, because of all the nested brackets.
|
||||
|
||||
```
|
||||
i = 1
|
||||
x = h(g(f(i)))
|
||||
```
|
||||
|
||||
You can make this easier to read by breaking it into many declarations, but that is a bit annoying.
|
||||
|
||||
```
|
||||
i = 1
|
||||
x0 = f(i)
|
||||
x1 = g(x0)
|
||||
x = h(x1)
|
||||
```
|
||||
|
||||
Instead, you can use the pipeline operator (`|>`) to simplify this.
|
||||
|
||||
Basically, `x |> f(%)` is a shorthand for `f(x)`. The left-hand side of the `|>` gets put into
|
||||
the `%` in the right-hand side.
|
||||
|
||||
So, this means `x |> f(%) |> g(%)` is shorthand for `g(f(x))`. The code example above, with its
|
||||
somewhat-clunky `x0` and `x1` constants could be rewritten as
|
||||
|
||||
```
|
||||
i = 1
|
||||
x = i
|
||||
|> f(%)
|
||||
|> g(%)
|
||||
|> h(%)
|
||||
```
|
||||
|
||||
This helps keep your code neat and avoid unnecessary declarations.
|
||||
|
||||
## Pipelines and keyword arguments
|
||||
|
||||
Say you have a long pipeline of sketch functions, like this:
|
||||
|
||||
```
|
||||
startSketch()
|
||||
|> line(%, end = [3, 4])
|
||||
|> line(%, end = [10, 10])
|
||||
|> line(%, end = [-13, -14])
|
||||
|> close(%)
|
||||
```
|
||||
|
||||
In this example, each function call outputs a sketch, and it gets put into the next function call via
|
||||
the `%`, into the first (unlabeled) argument.
|
||||
|
||||
If a function call uses an unlabeled first parameter, it will default to `%` if it's not given. This
|
||||
means that `|> line(%, end = [3, 4])` and `|> line(end = [3, 4])` are equivalent! So the above
|
||||
could be rewritten as
|
||||
|
||||
```
|
||||
startSketch()
|
||||
|> line(end = [3, 4])
|
||||
|> line(end = [10, 10])
|
||||
|> line(end = [-13, -14])
|
||||
|> close()
|
||||
```
|
||||
|
||||
Note that we are still in the process of migrating KCL's standard library to use keyword arguments. So some
|
||||
functions are still unfortunately using positional arguments. We're moving them over, so keep checking back.
|
||||
Some functions like `angledLine`, `startProfileAt` etc are still using the old positional argument syntax.
|
||||
Check the docs page for each function and look at its examples to see.
|
||||
|
||||
## Tags
|
||||
|
||||
Tags are used to give a name (tag) to a specific path.
|
||||
@ -88,17 +187,17 @@ way:
|
||||
```
|
||||
startSketchOn('XZ')
|
||||
|> startProfileAt(origin, %)
|
||||
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
196.99
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|
||||
|> angledLine({
|
||||
angle = segAng(rectangleSegmentA001) - 90,
|
||||
length = 196.99,
|
||||
}, %, $rectangleSegmentB001)
|
||||
|> angledLine({
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001),
|
||||
}, %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
```
|
||||
|
||||
### Tag Identifier
|
||||
@ -121,17 +220,17 @@ However if the code was written like this:
|
||||
fn rect(origin) {
|
||||
return startSketchOn('XZ')
|
||||
|> startProfileAt(origin, %)
|
||||
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
196.99
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|
||||
|> angledLine({
|
||||
angle = segAng(rectangleSegmentA001) - 90,
|
||||
length = 196.99
|
||||
}, %, $rectangleSegmentB001)
|
||||
|> angledLine({
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001)
|
||||
}, %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
}
|
||||
|
||||
rect([0, 0])
|
||||
@ -149,17 +248,17 @@ For example the following code works.
|
||||
fn rect(origin) {
|
||||
return startSketchOn('XZ')
|
||||
|> startProfileAt(origin, %)
|
||||
|> angledLine([0, 191.26], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
196.99
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||
|> close(%)
|
||||
|> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001)
|
||||
|> angledLine({
|
||||
angle = segAng(rectangleSegmentA001) - 90,
|
||||
length = 196.99
|
||||
}, %, $rectangleSegmentB001)
|
||||
|> angledLine({
|
||||
angle = segAng(rectangleSegmentA001),
|
||||
length = -segLen(rectangleSegmentA001)
|
||||
}, %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
}
|
||||
|
||||
rect([0, 0])
|
||||
|
15
docs/kcl/types/ArtifactId.md
Normal file
15
docs/kcl/types/ArtifactId.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "ArtifactId"
|
||||
excerpt: ""
|
||||
layout: manual
|
||||
---
|
||||
|
||||
|
||||
**Type:** `string` (`uuid`)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@ A face.
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `id` |`string`| The id of the face. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |`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 |
|
||||
|
@ -17,6 +17,7 @@ A helix.
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `value` |`string`| The id of the helix. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `revolutions` |`number`| Number of revolutions. | No |
|
||||
| `angleStart` |`number`| Start angle (in degrees). | No |
|
||||
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
|
||||
|
@ -1,26 +0,0 @@
|
||||
---
|
||||
title: "HelixData"
|
||||
excerpt: "Data for a helix."
|
||||
layout: manual
|
||||
---
|
||||
|
||||
Data for a helix.
|
||||
|
||||
**Type:** `object`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `revolutions` |`number`| Number of revolutions. | No |
|
||||
| `angleStart` |`number`| Start angle (in degrees). | No |
|
||||
| `ccw` |`boolean`| Is the helix rotation counter clockwise? The default is `false`. | No |
|
||||
| `length` |`number`| Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used. | No |
|
||||
| `radius` |`number`| Radius of the helix. | No |
|
||||
| `axis` |[`Axis3dOrEdgeReference`](/docs/kcl/types/Axis3dOrEdgeReference)| Axis to use as mirror. | No |
|
||||
|
||||
|
@ -17,6 +17,7 @@ A helix.
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `value` |`string`| The id of the helix. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `revolutions` |`number`| Number of revolutions. | No |
|
||||
| `angleStart` |`number`| Start angle (in degrees). | No |
|
||||
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
|
||||
|
@ -17,6 +17,7 @@ A plane.
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `id` |`string`| The id of the plane. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| 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 |
|
||||
|
@ -21,6 +21,7 @@ A sketch is a collection of paths.
|
||||
| `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No |
|
||||
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
|
||||
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The original id of the sketch. This stays the same even if the sketch is is sketched on face etc. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch is a collection of paths. | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
|
||||
|
||||
|
@ -30,6 +30,7 @@ A sketch is a collection of paths.
|
||||
| `on` |[`SketchSurface`](/docs/kcl/types/SketchSurface)| What the sketch is on (can be a plane or a face). | No |
|
||||
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
|
||||
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The original id of the sketch. This stays the same even if the sketch is is sketched on face etc. | No |
|
||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch or a group of sketches. | No |
|
||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
|
||||
|
||||
|
@ -26,6 +26,7 @@ A plane.
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `plane`| | No |
|
||||
| `id` |`string`| The id of the plane. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| A sketch type. | 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 |
|
||||
@ -50,6 +51,7 @@ A face.
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `face`| | No |
|
||||
| `id` |`string`| The id of the face. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||
| `value` |`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 |
|
||||
|
@ -17,6 +17,7 @@ An solid is a collection of extrude surfaces.
|
||||
| Property | Type | Description | Required |
|
||||
|----------|------|-------------|----------|
|
||||
| `id` |`string`| The id of the solid. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID of the solid. Unlike `id`, this doesn't change. | No |
|
||||
| `value` |`[` [`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface) `]`| The extrude surfaces. | No |
|
||||
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
|
||||
| `height` |`number`| The height of the solid. | No |
|
||||
|
@ -26,6 +26,7 @@ An solid is a collection of extrude surfaces.
|
||||
|----------|------|-------------|----------|
|
||||
| `type` |enum: `solid`| | No |
|
||||
| `id` |`string`| The id of the solid. | No |
|
||||
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID of the solid. Unlike `id`, this doesn't change. | No |
|
||||
| `value` |`[` [`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface) `]`| The extrude surfaces. | No |
|
||||
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
|
||||
| `height` |`number`| The height of the solid. | No |
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -144,7 +144,7 @@ async function doBasicSketch(
|
||||
|> xLine(-segLen(seg01), %)`)
|
||||
}
|
||||
|
||||
test.describe('Basic sketch', () => {
|
||||
test.describe('Basic sketch', { tag: ['@skipWin'] }, () => {
|
||||
test.fixme('code pane open at start', async ({ page, homePage }) => {
|
||||
await doBasicSketch(page, homePage, ['code'])
|
||||
})
|
||||
|
@ -4,7 +4,10 @@ import { getUtils } from './test-utils'
|
||||
import { EngineCommand } from 'lang/std/artifactGraph'
|
||||
import { uuidv4 } from 'lib/utils'
|
||||
|
||||
test.describe('Can create sketches on all planes and their back sides', () => {
|
||||
test.describe(
|
||||
'Can create sketches on all planes and their back sides',
|
||||
{ tag: ['@skipWin'] },
|
||||
() => {
|
||||
const sketchOnPlaneAndBackSideTest = async (
|
||||
page: Page,
|
||||
homePage: HomePageFixture,
|
||||
@ -88,11 +91,17 @@ test.describe('Can create sketches on all planes and their back sides', () => {
|
||||
})
|
||||
|
||||
test('YZ', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, 'YZ', { x: 700, y: 250 }) // green plane
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, 'YZ', {
|
||||
x: 700,
|
||||
y: 250,
|
||||
}) // green plane
|
||||
})
|
||||
|
||||
test('XZ', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, '-XZ', { x: 700, y: 80 }) // blue plane
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, '-XZ', {
|
||||
x: 700,
|
||||
y: 80,
|
||||
}) // blue plane
|
||||
})
|
||||
|
||||
test('-XY', async ({ page, homePage }) => {
|
||||
@ -110,6 +119,10 @@ test.describe('Can create sketches on all planes and their back sides', () => {
|
||||
})
|
||||
|
||||
test('-XZ', async ({ page, homePage }) => {
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, 'XZ', { x: 700, y: 427 }) // back of blue plane
|
||||
await sketchOnPlaneAndBackSideTest(page, homePage, 'XZ', {
|
||||
x: 700,
|
||||
y: 427,
|
||||
}) // back of blue plane
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ 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', () => {
|
||||
test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
|
||||
test('Typing KCL errors induces a badge on the code pane button', async ({
|
||||
page,
|
||||
homePage,
|
||||
|
@ -4,7 +4,7 @@ import { executorInputPath, getUtils } from './test-utils'
|
||||
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
|
||||
import path from 'path'
|
||||
|
||||
test.describe('Command bar tests', () => {
|
||||
test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
|
||||
test('Extrude from command bar selects extrude line after', async ({
|
||||
page,
|
||||
homePage,
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
|
||||
import { join } from 'path'
|
||||
|
||||
test.describe('Editor tests', () => {
|
||||
test.describe('Editor tests', { tag: ['@skipWin'] }, () => {
|
||||
test('can comment out code with ctrl+/', async ({ page, homePage }) => {
|
||||
const u = await getUtils(page)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
@ -35,6 +35,30 @@ sketch002 = startSketchOn(plane001)
|
||||
extrude001 = extrude(sketch002, length = 10)
|
||||
`
|
||||
|
||||
const FEAUTRE_TREE_SKETCH_CODE = `sketch001 = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine([0, 4], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001) - 90,
|
||||
2
|
||||
], %, $rectangleSegmentB001)
|
||||
|> angledLine([
|
||||
segAng(rectangleSegmentA001),
|
||||
-segLen(rectangleSegmentA001)
|
||||
], %, $rectangleSegmentC001)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close(%)
|
||||
extrude001 = extrude(sketch001, length = 10)
|
||||
sketch002 = startSketchOn(extrude001, rectangleSegmentB001)
|
||||
|> circle({
|
||||
center = [-1, 2],
|
||||
radius = .5
|
||||
}, %)
|
||||
plane001 = offsetPlane('XZ', -5)
|
||||
sketch003 = startSketchOn(plane001)
|
||||
|> circle({ center = [0, 0], radius = 5 }, %)
|
||||
`
|
||||
|
||||
test.describe('Feature Tree pane', () => {
|
||||
test(
|
||||
'User can go to definition and go to function definition',
|
||||
@ -124,4 +148,267 @@ test.describe('Feature Tree pane', () => {
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
`User can edit sketch (but not on offset plane yet) from the feature tree`,
|
||||
{ tag: '@electron' },
|
||||
async ({ context, homePage, scene, editor, toolbar, page }) => {
|
||||
const unavailableToastMessage = page.getByText(
|
||||
'Editing sketches on faces or offset planes through the feature tree is not yet supported'
|
||||
)
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'test-sample')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
await fsp.writeFile(
|
||||
join(bracketDir, 'main.kcl'),
|
||||
FEAUTRE_TREE_SKETCH_CODE,
|
||||
'utf-8'
|
||||
)
|
||||
})
|
||||
|
||||
await test.step('setup test', async () => {
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
{
|
||||
title: 'test-sample',
|
||||
fileCount: 1,
|
||||
},
|
||||
],
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await toolbar.openFeatureTreePane()
|
||||
})
|
||||
|
||||
await test.step('On a default plane should work', async () => {
|
||||
await (await toolbar.getFeatureTreeOperation('Sketch', 0)).dblclick()
|
||||
await expect(
|
||||
toolbar.exitSketchBtn,
|
||||
'We should be in sketch mode now'
|
||||
).toBeVisible()
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: ["sketch001 = startSketchOn('XZ')"],
|
||||
})
|
||||
await toolbar.exitSketchBtn.click()
|
||||
})
|
||||
|
||||
await test.step('On an extrude face should *not* work', async () => {
|
||||
// Tooltip is getting in the way of clicking, so I'm first closing the pane
|
||||
await toolbar.closeFeatureTreePane()
|
||||
await (await toolbar.getFeatureTreeOperation('Sketch', 1)).dblclick()
|
||||
await expect(
|
||||
unavailableToastMessage,
|
||||
'We should see a toast message about this'
|
||||
).toBeVisible()
|
||||
await unavailableToastMessage.waitFor({ state: 'detached' })
|
||||
// TODO - turn on once we update the artifactGraph in Rust
|
||||
// to include the proper source location for the extrude face
|
||||
// await expect(
|
||||
// toolbar.exitSketchBtn,
|
||||
// 'We should be in sketch mode now'
|
||||
// ).toBeVisible()
|
||||
// await editor.expectState({
|
||||
// highlightedCode: '',
|
||||
// diagnostics: [],
|
||||
// activeLines: ['|>circle({center=[-1,2],radius=.5},%)'],
|
||||
// })
|
||||
// await toolbar.exitSketchBtn.click()
|
||||
})
|
||||
|
||||
await test.step('On an offset plane should *not* work', async () => {
|
||||
// Tooltip is getting in the way of clicking, so I'm first closing the pane
|
||||
await toolbar.closeFeatureTreePane()
|
||||
await (await toolbar.getFeatureTreeOperation('Sketch', 2)).dblclick()
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: ['|>circle({center=[0,0],radius=5},%)'],
|
||||
})
|
||||
await expect(
|
||||
toolbar.exitSketchBtn,
|
||||
'We should not be in sketch mode now'
|
||||
).not.toBeVisible()
|
||||
await expect(
|
||||
page.getByText(
|
||||
'Editing sketches on faces or offset planes through the feature tree is not yet supported'
|
||||
),
|
||||
'We should see a toast message about this'
|
||||
).toBeVisible()
|
||||
})
|
||||
}
|
||||
)
|
||||
test(`User can edit an extrude operation from the feature tree`, async ({
|
||||
context,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
const initialInput = '23'
|
||||
const initialCode = `sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [0, 0], radius = 5 }, %)
|
||||
renamedExtrude = extrude(sketch001, length = ${initialInput})`
|
||||
const newConstantName = 'distance001'
|
||||
const expectedCode = `sketch001 = startSketchOn('XZ')
|
||||
|> circle({ center = [0, 0], radius = 5 }, %)
|
||||
${newConstantName} = 23
|
||||
renamedExtrude = extrude(sketch001, length = ${newConstantName})`
|
||||
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const testDir = join(dir, 'test-sample')
|
||||
await fsp.mkdir(testDir, { recursive: true })
|
||||
await fsp.writeFile(join(testDir, 'main.kcl'), initialCode, 'utf-8')
|
||||
})
|
||||
|
||||
await test.step('setup test', async () => {
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
{
|
||||
title: 'test-sample',
|
||||
fileCount: 1,
|
||||
},
|
||||
],
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await toolbar.openFeatureTreePane()
|
||||
})
|
||||
|
||||
await test.step('Double click on the extrude operation', async () => {
|
||||
await (await toolbar.getFeatureTreeOperation('Extrude', 0))
|
||||
.first()
|
||||
.dblclick()
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: [
|
||||
`renamedExtrude = extrude(sketch001, length = ${initialInput})`,
|
||||
],
|
||||
})
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Extrude',
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'distance',
|
||||
currentArgValue: initialInput,
|
||||
headerArguments: {
|
||||
Selection: '1 face',
|
||||
Distance: initialInput,
|
||||
},
|
||||
highlightedHeaderArg: 'distance',
|
||||
})
|
||||
})
|
||||
|
||||
await test.step('Add a named constant for distance argument and submit', async () => {
|
||||
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
||||
const addVariableButton = page.getByRole('button', {
|
||||
name: 'Create new variable',
|
||||
})
|
||||
await addVariableButton.click()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Selection: '1 face',
|
||||
// The calculated value is shown in the argument summary
|
||||
Distance: initialInput,
|
||||
},
|
||||
commandName: 'Extrude',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: [
|
||||
`renamedExtrude = extrude(sketch001, length = ${newConstantName})`,
|
||||
],
|
||||
})
|
||||
await editor.expectEditor.toContain(expectedCode, {
|
||||
shouldNormalise: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
test(`User can edit an offset plane operation from the feature tree`, async ({
|
||||
context,
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const testCode = (value: string) => `p = offsetPlane('XY', ${value})`
|
||||
const initialInput = '10'
|
||||
const initialCode = testCode(initialInput)
|
||||
const newInput = '5 + 10'
|
||||
const expectedCode = testCode(newInput)
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const testDir = join(dir, 'test-sample')
|
||||
await fsp.mkdir(testDir, { recursive: true })
|
||||
await fsp.writeFile(join(testDir, 'main.kcl'), initialCode, 'utf-8')
|
||||
})
|
||||
|
||||
await test.step('setup test', async () => {
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
{
|
||||
title: 'test-sample',
|
||||
fileCount: 1,
|
||||
},
|
||||
],
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await toolbar.openFeatureTreePane()
|
||||
})
|
||||
|
||||
await test.step('Double click on the offset plane operation', async () => {
|
||||
await (await toolbar.getFeatureTreeOperation('Offset Plane', 0))
|
||||
.first()
|
||||
.dblclick()
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: [initialCode],
|
||||
})
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Offset plane',
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'distance',
|
||||
currentArgValue: initialInput,
|
||||
headerArguments: {
|
||||
Plane: '1 plane',
|
||||
Distance: initialInput,
|
||||
},
|
||||
highlightedHeaderArg: 'distance',
|
||||
})
|
||||
})
|
||||
|
||||
await test.step('Edit the distance argument and submit', async () => {
|
||||
await expect(cmdBar.currentArgumentInput).toBeVisible()
|
||||
await cmdBar.currentArgumentInput.locator('.cm-content').fill(newInput)
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
Plane: '1 plane',
|
||||
// We show the calculated value in the argument summary
|
||||
Distance: '15',
|
||||
},
|
||||
commandName: 'Offset plane',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await editor.expectState({
|
||||
highlightedCode: '',
|
||||
diagnostics: [],
|
||||
activeLines: [expectedCode],
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1186,4 +1186,56 @@ test.describe('Undo and redo do not keep history when navigating between files',
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
`cloned file has an incremented name and same contents`,
|
||||
{ tag: '@electron' },
|
||||
async ({ page, context, homePage }, testInfo) => {
|
||||
const { panesOpen, createNewFile, cloneFile } = await getUtils(page, test)
|
||||
|
||||
const { dir } = await context.folderSetupFn(async (dir) => {
|
||||
const finalDir = join(dir, 'testDefault')
|
||||
await fsp.mkdir(finalDir, { recursive: true })
|
||||
await fsp.copyFile(
|
||||
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
|
||||
join(finalDir, 'lee.kcl')
|
||||
)
|
||||
})
|
||||
|
||||
const contentOriginal = await fsp.readFile(
|
||||
join(dir, 'testDefault', 'lee.kcl'),
|
||||
'utf-8'
|
||||
)
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
page.on('console', console.log)
|
||||
|
||||
await panesOpen(['files'])
|
||||
await homePage.openProject('testDefault')
|
||||
|
||||
await cloneFile('lee.kcl')
|
||||
await cloneFile('lee-1.kcl')
|
||||
await cloneFile('lee-2.kcl')
|
||||
await cloneFile('lee-3.kcl')
|
||||
await cloneFile('lee-4.kcl')
|
||||
|
||||
await test.step('Postcondition: there are 5 new lee-*.kcl files', async () => {
|
||||
await expect(
|
||||
page
|
||||
.locator('[data-testid="file-pane-scroll-container"] button')
|
||||
.filter({ hasText: /lee[-]?[0-5]?/ })
|
||||
).toHaveCount(5)
|
||||
})
|
||||
|
||||
await test.step('Postcondition: the files have the same contents', async () => {
|
||||
for (let n = 0; n < 5; n += 1) {
|
||||
const content = await fsp.readFile(
|
||||
join(dir, 'testDefault', `lee-${n + 1}.kcl`),
|
||||
'utf-8'
|
||||
)
|
||||
await expect(content).toEqual(contentOriginal)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -26,11 +26,18 @@ type CmdBarSerialised =
|
||||
export class CmdBarFixture {
|
||||
public page: Page
|
||||
cmdBarOpenBtn!: Locator
|
||||
cmdBarElement!: Locator
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.cmdBarOpenBtn = page.getByTestId('command-bar-open-button')
|
||||
this.cmdBarElement = page.getByTestId('command-bar')
|
||||
}
|
||||
|
||||
get currentArgumentInput() {
|
||||
return this.page.getByTestId('cmd-bar-arg-value')
|
||||
}
|
||||
|
||||
reConstruct = (page: Page) => {
|
||||
this.page = page
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user