Compare commits
35 Commits
pierremtb/
...
nightly-v2
Author | SHA1 | Date | |
---|---|---|---|
5f14023404 | |||
9a3ac64603 | |||
67e60cb832 | |||
110037df79 | |||
30b1dae38a | |||
f20fc5b467 | |||
1bfc3a0a3c | |||
f6e975db84 | |||
b82eec85fd | |||
5dc4213295 | |||
61807e7629 | |||
357bbffce5 | |||
6ac9c49773 | |||
020497cde2 | |||
688852a5df | |||
6c635bd70d | |||
1c0a38a1e2 | |||
019cb815f9 | |||
c8653beae7 | |||
9ea3cb51ba | |||
e0de0493ab | |||
11cac0c30e | |||
4de50edf5a | |||
bebace193d | |||
f4d5578faf | |||
fed922cfb8 | |||
2b7325655b | |||
d3b02b8c5b | |||
9008fb636f | |||
eb4048cd16 | |||
c30b161e95 | |||
0e68d03612 | |||
95fd14eedc | |||
3c367426c6 | |||
a277cce636 |
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
@ -9,7 +9,7 @@ Just like patternTransform, but works on 2D sketches not 3D solids.
|
|||||||
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
patternTransform2d(total_instances: integer, transform_function: FunctionParam, solid_set: SketchSet) -> [Sketch]
|
patternTransform2d(total_instances: integer, transform_function: FunctionParam, solid_set: SketchSet, use_original?: bool) -> [Sketch]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ patternTransform2d(total_instances: integer, transform_function: FunctionParam,
|
|||||||
| `total_instances` | `integer` | | Yes |
|
| `total_instances` | `integer` | | Yes |
|
||||||
| `transform_function` | `FunctionParam` | | Yes |
|
| `transform_function` | `FunctionParam` | | Yes |
|
||||||
| `solid_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
|
| `solid_set` | [`SketchSet`](/docs/kcl/types/SketchSet) | A sketch or a group of sketches. | Yes |
|
||||||
|
| `use_original` | `bool` | | No |
|
||||||
|
|
||||||
### Returns
|
### Returns
|
||||||
|
|
||||||
|
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
29948
docs/kcl/std.json
29948
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
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`)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -20,5 +20,6 @@ Data for a circular pattern on a 2D sketch.
|
|||||||
| `center` |`[number, number]`| The center about which to make the pattern. This is a 2D vector. | No |
|
| `center` |`[number, number]`| The center about which to make the pattern. This is a 2D vector. | No |
|
||||||
| `arcDegrees` |`number`| The arc angle (in degrees) to place the repetitions. Must be greater than 0. | No |
|
| `arcDegrees` |`number`| The arc angle (in degrees) to place the repetitions. Must be greater than 0. | No |
|
||||||
| `rotateDuplicates` |`boolean`| Whether or not to rotate the duplicates as they are copied. | No |
|
| `rotateDuplicates` |`boolean`| Whether or not to rotate the duplicates as they are copied. | No |
|
||||||
|
| `useOriginal` |`boolean`| If the target being patterned is itself a pattern, then, should you use the original solid, or the pattern? | No |
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,5 +21,6 @@ Data for a circular pattern on a 3D model.
|
|||||||
| `center` |`[number, number, number]`| The center about which to make the pattern. This is a 3D vector. | No |
|
| `center` |`[number, number, number]`| The center about which to make the pattern. This is a 3D vector. | No |
|
||||||
| `arcDegrees` |`number`| The arc angle (in degrees) to place the repetitions. Must be greater than 0. | No |
|
| `arcDegrees` |`number`| The arc angle (in degrees) to place the repetitions. Must be greater than 0. | No |
|
||||||
| `rotateDuplicates` |`boolean`| Whether or not to rotate the duplicates as they are copied. | No |
|
| `rotateDuplicates` |`boolean`| Whether or not to rotate the duplicates as they are copied. | No |
|
||||||
|
| `useOriginal` |`boolean`| If the target being patterned is itself a pattern, then, should you use the original solid, or the pattern? | No |
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ A face.
|
|||||||
| Property | Type | Description | Required |
|
| Property | Type | Description | Required |
|
||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `id` |`string`| The id of the 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 |
|
| `value` |`string`| The tag of the face. | No |
|
||||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face’s X axis be? | 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 |
|
| `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 |
|
| Property | Type | Description | Required |
|
||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `value` |`string`| The id of the helix. | No |
|
| `value` |`string`| The id of the helix. | No |
|
||||||
|
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||||
| `revolutions` |`number`| Number of revolutions. | No |
|
| `revolutions` |`number`| Number of revolutions. | No |
|
||||||
| `angleStart` |`number`| Start angle (in degrees). | No |
|
| `angleStart` |`number`| Start angle (in degrees). | No |
|
||||||
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | 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 |
|
| Property | Type | Description | Required |
|
||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `value` |`string`| The id of the helix. | No |
|
| `value` |`string`| The id of the helix. | No |
|
||||||
|
| `artifactId` |[`ArtifactId`](/docs/kcl/types/ArtifactId)| The artifact ID. | No |
|
||||||
| `revolutions` |`number`| Number of revolutions. | No |
|
| `revolutions` |`number`| Number of revolutions. | No |
|
||||||
| `angleStart` |`number`| Start angle (in degrees). | No |
|
| `angleStart` |`number`| Start angle (in degrees). | No |
|
||||||
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
|
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
|
||||||
|
@ -17,6 +17,7 @@ A plane.
|
|||||||
| Property | Type | Description | Required |
|
| Property | Type | Description | Required |
|
||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `id` |`string`| The id of the 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 plane. | No |
|
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| A plane. | No |
|
||||||
| `origin` |[`Point3d`](/docs/kcl/types/Point3d)| Origin of the 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 |
|
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the plane’s X axis be? | No |
|
||||||
|
@ -21,6 +21,8 @@ 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 |
|
| `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 |
|
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
|
||||||
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | 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 |
|
||||||
|
| `originalId` |`string`| | No |
|
||||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch is a collection of paths. | No |
|
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch is a collection of paths. | No |
|
||||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
|
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
|
||||||
|
|
||||||
|
@ -30,6 +30,8 @@ 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 |
|
| `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 |
|
| `start` |[`BasePath`](/docs/kcl/types/BasePath)| The starting path. | No |
|
||||||
| `tags` |`object`| Tag identifiers that have been declared in this sketch. | 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 |
|
||||||
|
| `originalId` |`string`| | No |
|
||||||
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch or a group of sketches. | No |
|
| `units` |[`UnitLen`](/docs/kcl/types/UnitLen)| A sketch or a group of sketches. | No |
|
||||||
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
|
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| Metadata. | No |
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ A plane.
|
|||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `type` |enum: `plane`| | No |
|
| `type` |enum: `plane`| | No |
|
||||||
| `id` |`string`| The id of the 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 |
|
| `value` |[`PlaneType`](/docs/kcl/types/PlaneType)| A sketch type. | No |
|
||||||
| `origin` |[`Point3d`](/docs/kcl/types/Point3d)| Origin of the 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 |
|
| `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 |
|
| `type` |enum: `face`| | No |
|
||||||
| `id` |`string`| The id of the 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 |
|
| `value` |`string`| The tag of the face. | No |
|
||||||
| `xAxis` |[`Point3d`](/docs/kcl/types/Point3d)| What should the face’s X axis be? | 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 |
|
| `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 |
|
| Property | Type | Description | Required |
|
||||||
|----------|------|-------------|----------|
|
|----------|------|-------------|----------|
|
||||||
| `id` |`string`| The id of the 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 |
|
| `value` |`[` [`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface) `]`| The extrude surfaces. | No |
|
||||||
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
|
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
|
||||||
| `height` |`number`| The height of the solid. | 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 |
|
| `type` |enum: `solid`| | No |
|
||||||
| `id` |`string`| The id of the 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 |
|
| `value` |`[` [`ExtrudeSurface`](/docs/kcl/types/ExtrudeSurface) `]`| The extrude surfaces. | No |
|
||||||
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
|
| `sketch` |[`Sketch`](/docs/kcl/types/Sketch)| The sketch. | No |
|
||||||
| `height` |`number`| The height of the solid. | 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
@ -35,6 +35,30 @@ sketch002 = startSketchOn(plane001)
|
|||||||
extrude001 = extrude(sketch002, length = 10)
|
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.describe('Feature Tree pane', () => {
|
||||||
test(
|
test(
|
||||||
'User can go to definition and go to function definition',
|
'User can go to definition and go to function definition',
|
||||||
@ -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],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -26,11 +26,18 @@ type CmdBarSerialised =
|
|||||||
export class CmdBarFixture {
|
export class CmdBarFixture {
|
||||||
public page: Page
|
public page: Page
|
||||||
cmdBarOpenBtn!: Locator
|
cmdBarOpenBtn!: Locator
|
||||||
|
cmdBarElement!: Locator
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page
|
this.page = page
|
||||||
this.cmdBarOpenBtn = page.getByTestId('command-bar-open-button')
|
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) => {
|
reConstruct = (page: Page) => {
|
||||||
this.page = page
|
this.page = page
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,10 @@ export class SceneFixture {
|
|||||||
public page: Page
|
public page: Page
|
||||||
public streamWrapper!: Locator
|
public streamWrapper!: Locator
|
||||||
public loadingIndicator!: Locator
|
public loadingIndicator!: Locator
|
||||||
private exeIndicator!: Locator
|
|
||||||
|
get exeIndicator() {
|
||||||
|
return this.page.getByTestId('model-state-indicator-execution-done')
|
||||||
|
}
|
||||||
|
|
||||||
constructor(page: Page) {
|
constructor(page: Page) {
|
||||||
this.page = page
|
this.page = page
|
||||||
@ -64,7 +67,6 @@ export class SceneFixture {
|
|||||||
reConstruct = (page: Page) => {
|
reConstruct = (page: Page) => {
|
||||||
this.page = page
|
this.page = page
|
||||||
|
|
||||||
this.exeIndicator = page.getByTestId('model-state-indicator-execution-done')
|
|
||||||
this.streamWrapper = page.getByTestId('stream')
|
this.streamWrapper = page.getByTestId('stream')
|
||||||
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
|
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ export class ToolbarFixture {
|
|||||||
shellButton!: Locator
|
shellButton!: Locator
|
||||||
revolveButton!: Locator
|
revolveButton!: Locator
|
||||||
offsetPlaneButton!: Locator
|
offsetPlaneButton!: Locator
|
||||||
|
helixButton!: Locator
|
||||||
startSketchBtn!: Locator
|
startSketchBtn!: Locator
|
||||||
lineBtn!: Locator
|
lineBtn!: Locator
|
||||||
rectangleBtn!: Locator
|
rectangleBtn!: Locator
|
||||||
@ -29,7 +30,6 @@ export class ToolbarFixture {
|
|||||||
createFileBtn!: Locator
|
createFileBtn!: Locator
|
||||||
fileCreateToast!: Locator
|
fileCreateToast!: Locator
|
||||||
filePane!: Locator
|
filePane!: Locator
|
||||||
exeIndicator!: Locator
|
|
||||||
treeInputField!: Locator
|
treeInputField!: Locator
|
||||||
/** The sidebar button for the Feature Tree pane */
|
/** The sidebar button for the Feature Tree pane */
|
||||||
featureTreeId = 'feature-tree' as const
|
featureTreeId = 'feature-tree' as const
|
||||||
@ -50,6 +50,7 @@ export class ToolbarFixture {
|
|||||||
this.shellButton = page.getByTestId('shell')
|
this.shellButton = page.getByTestId('shell')
|
||||||
this.revolveButton = page.getByTestId('revolve')
|
this.revolveButton = page.getByTestId('revolve')
|
||||||
this.offsetPlaneButton = page.getByTestId('plane-offset')
|
this.offsetPlaneButton = page.getByTestId('plane-offset')
|
||||||
|
this.helixButton = page.getByTestId('helix')
|
||||||
this.startSketchBtn = page.getByTestId('sketch')
|
this.startSketchBtn = page.getByTestId('sketch')
|
||||||
this.lineBtn = page.getByTestId('line')
|
this.lineBtn = page.getByTestId('line')
|
||||||
this.rectangleBtn = page.getByTestId('corner-rectangle')
|
this.rectangleBtn = page.getByTestId('corner-rectangle')
|
||||||
@ -62,15 +63,16 @@ export class ToolbarFixture {
|
|||||||
this.filePane = page.locator('#files-pane')
|
this.filePane = page.locator('#files-pane')
|
||||||
this.featureTreePane = page.locator('#feature-tree-pane')
|
this.featureTreePane = page.locator('#feature-tree-pane')
|
||||||
this.fileCreateToast = page.getByText('Successfully created')
|
this.fileCreateToast = page.getByText('Successfully created')
|
||||||
this.exeIndicator = page.getByTestId(
|
|
||||||
'model-state-indicator-receive-reliable'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get logoLink() {
|
get logoLink() {
|
||||||
return this.page.getByTestId('app-logo')
|
return this.page.getByTestId('app-logo')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get exeIndicator() {
|
||||||
|
return this.page.getByTestId('model-state-indicator-receive-reliable')
|
||||||
|
}
|
||||||
|
|
||||||
startSketchPlaneSelection = async () =>
|
startSketchPlaneSelection = async () =>
|
||||||
doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500)
|
doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500)
|
||||||
|
|
||||||
@ -139,7 +141,8 @@ export class ToolbarFixture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a specific operation button from the Feature Tree pane
|
* Get a specific operation button from the Feature Tree pane.
|
||||||
|
* Index is 0-based.
|
||||||
*/
|
*/
|
||||||
async getFeatureTreeOperation(operationName: string, operationIndex: number) {
|
async getFeatureTreeOperation(operationName: string, operationIndex: number) {
|
||||||
await this.openFeatureTreePane()
|
await this.openFeatureTreePane()
|
||||||
|
@ -27,7 +27,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
},
|
},
|
||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
async ({ context, page, homePage }) => {
|
async ({ page, homePage }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
@ -68,7 +68,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
},
|
},
|
||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
async ({ page, homePage }, testInfo) => {
|
async ({ page }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
|
|
||||||
const viewportSize = { width: 1200, height: 500 }
|
const viewportSize = { width: 1200, height: 500 }
|
||||||
@ -154,7 +154,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
'Click through each onboarding step',
|
'Click through each onboarding step and back',
|
||||||
{
|
{
|
||||||
appSettings: {
|
appSettings: {
|
||||||
app: {
|
app: {
|
||||||
@ -187,15 +187,21 @@ test.describe('Onboarding tests', () => {
|
|||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
|
|
||||||
const nextButton = page.getByTestId('onboarding-next')
|
const nextButton = page.getByTestId('onboarding-next')
|
||||||
|
const prevButton = page.getByTestId('onboarding-prev')
|
||||||
|
|
||||||
while ((await nextButton.innerText()) !== 'Finish') {
|
while ((await nextButton.innerText()) !== 'Finish') {
|
||||||
await nextButton.hover()
|
await nextButton.hover()
|
||||||
await nextButton.click()
|
await nextButton.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish the onboarding
|
while ((await prevButton.innerText()) !== 'Dismiss') {
|
||||||
await nextButton.hover()
|
await prevButton.hover()
|
||||||
await nextButton.click()
|
await prevButton.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dismiss the onboarding
|
||||||
|
await prevButton.hover()
|
||||||
|
await prevButton.click()
|
||||||
|
|
||||||
// Test that the onboarding pane is gone
|
// Test that the onboarding pane is gone
|
||||||
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
|
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
|
||||||
@ -269,7 +275,7 @@ test.describe('Onboarding tests', () => {
|
|||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
async ({ context, page, homePage }) => {
|
async ({ page, homePage }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
const badCode = `// This is bad code we shouldn't see`
|
const badCode = `// This is bad code we shouldn't see`
|
||||||
|
|
||||||
@ -336,10 +342,10 @@ test.describe('Onboarding tests', () => {
|
|||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
|
|
||||||
// Test that the text in this step is correct
|
// Test that the text in this step is correct
|
||||||
const avatarLocator = await page
|
const avatarLocator = page
|
||||||
.getByTestId('user-sidebar-toggle')
|
.getByTestId('user-sidebar-toggle')
|
||||||
.locator('img')
|
.locator('img')
|
||||||
const onboardingOverlayLocator = await page
|
const onboardingOverlayLocator = page
|
||||||
.getByTestId('onboarding-content')
|
.getByTestId('onboarding-content')
|
||||||
.locator('div')
|
.locator('div')
|
||||||
.nth(1)
|
.nth(1)
|
||||||
@ -447,7 +453,7 @@ test.fixme(
|
|||||||
},
|
},
|
||||||
cleanProjectDir: true,
|
cleanProjectDir: true,
|
||||||
},
|
},
|
||||||
async ({ context, page, homePage }, testInfo) => {
|
async ({ context, page }) => {
|
||||||
await context.folderSetupFn(async (dir) => {
|
await context.folderSetupFn(async (dir) => {
|
||||||
const routerTemplateDir = join(dir, 'router-template-slate')
|
const routerTemplateDir = join(dir, 'router-template-slate')
|
||||||
await fsp.mkdir(routerTemplateDir, { recursive: true })
|
await fsp.mkdir(routerTemplateDir, { recursive: true })
|
||||||
@ -486,10 +492,6 @@ test.fixme(
|
|||||||
})
|
})
|
||||||
|
|
||||||
await test.step('Navigate into project', async () => {
|
await test.step('Navigate into project', async () => {
|
||||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
|
||||||
|
|
||||||
page.on('console', console.log)
|
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('heading', { name: 'Your Projects' })
|
page.getByRole('heading', { name: 'Your Projects' })
|
||||||
).toBeVisible()
|
).toBeVisible()
|
||||||
|
@ -775,6 +775,71 @@ openSketch = startSketchOn('XY')
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('Helix point-and-click', async ({
|
||||||
|
context,
|
||||||
|
page,
|
||||||
|
homePage,
|
||||||
|
scene,
|
||||||
|
editor,
|
||||||
|
toolbar,
|
||||||
|
cmdBar,
|
||||||
|
}) => {
|
||||||
|
// One dumb hardcoded screen pixel value
|
||||||
|
const testPoint = { x: 620, y: 257 }
|
||||||
|
const expectedOutput = `helix001 = helix(revolutions = 1, angleStart = 360, counterClockWise = false, radius = 5, axis = 'X', length = 5)`
|
||||||
|
|
||||||
|
await homePage.goToModelingScene()
|
||||||
|
|
||||||
|
await test.step(`Look for the red of the default plane`, async () => {
|
||||||
|
await scene.expectPixelColor([96, 52, 52], testPoint, 15)
|
||||||
|
})
|
||||||
|
await test.step(`Go through the command bar flow`, async () => {
|
||||||
|
await toolbar.helixButton.click()
|
||||||
|
await cmdBar.expectState({
|
||||||
|
stage: 'arguments',
|
||||||
|
currentArgKey: 'revolutions',
|
||||||
|
currentArgValue: '1',
|
||||||
|
headerArguments: {
|
||||||
|
AngleStart: '',
|
||||||
|
Axis: '',
|
||||||
|
CounterClockWise: '',
|
||||||
|
Length: '',
|
||||||
|
Radius: '',
|
||||||
|
Revolutions: '',
|
||||||
|
},
|
||||||
|
highlightedHeaderArg: 'revolutions',
|
||||||
|
commandName: 'Helix',
|
||||||
|
})
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
await cmdBar.progressCmdBar()
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||||
|
await editor.expectEditor.toContain(expectedOutput)
|
||||||
|
await editor.expectState({
|
||||||
|
diagnostics: [],
|
||||||
|
activeLines: [expectedOutput],
|
||||||
|
highlightedCode: '',
|
||||||
|
})
|
||||||
|
// Red plane is now gone, white helix is there
|
||||||
|
await scene.expectPixelColor([250, 250, 250], testPoint, 15)
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step('Delete offset plane via feature tree selection', async () => {
|
||||||
|
await editor.closePane()
|
||||||
|
const operationButton = await toolbar.getFeatureTreeOperation('Helix', 0)
|
||||||
|
await operationButton.click({ button: 'left' })
|
||||||
|
await page.keyboard.press('Backspace')
|
||||||
|
// Red plane is back
|
||||||
|
await scene.expectPixelColor([96, 52, 52], testPoint, 15)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
const loftPointAndClickCases = [
|
const loftPointAndClickCases = [
|
||||||
{ shouldPreselect: true },
|
{ shouldPreselect: true },
|
||||||
{ shouldPreselect: false },
|
{ shouldPreselect: false },
|
||||||
@ -964,7 +1029,7 @@ sketch002 = startSketchOn('XZ')
|
|||||||
testPoint.x - 50,
|
testPoint.x - 50,
|
||||||
testPoint.y
|
testPoint.y
|
||||||
)
|
)
|
||||||
const sweepDeclaration = 'sweep001 = sweep({ path = sketch002 }, sketch001)'
|
const sweepDeclaration = 'sweep001 = sweep(sketch001, path = sketch002)'
|
||||||
|
|
||||||
await test.step(`Look for sketch001`, async () => {
|
await test.step(`Look for sketch001`, async () => {
|
||||||
await toolbar.closePane('code')
|
await toolbar.closePane('code')
|
||||||
@ -1890,7 +1955,7 @@ chamfer04 = chamfer({ length = 5, tags = [getOppositeEdge(seg02)]}, extrude001
|
|||||||
const testPoint = { x: 575, y: 200 }
|
const testPoint = { x: 575, y: 200 }
|
||||||
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||||
const shellDeclaration =
|
const shellDeclaration =
|
||||||
"shell001 = shell({ faces = ['end'], thickness = 5 }, extrude001)"
|
"shell001 = shell(extrude001, faces = ['end'], thickness = 5)"
|
||||||
|
|
||||||
await test.step(`Look for the grey of the shape`, async () => {
|
await test.step(`Look for the grey of the shape`, async () => {
|
||||||
await scene.expectPixelColor([127, 127, 127], testPoint, 15)
|
await scene.expectPixelColor([127, 127, 127], testPoint, 15)
|
||||||
@ -1990,8 +2055,7 @@ extrude001 = extrude(sketch001, length = 40)
|
|||||||
const [clickOnWall] = scene.makeMouseHelpers(testPoint.x, testPoint.y + 70)
|
const [clickOnWall] = scene.makeMouseHelpers(testPoint.x, testPoint.y + 70)
|
||||||
const mutatedCode = 'xLine(-40, %, $seg01)'
|
const mutatedCode = 'xLine(-40, %, $seg01)'
|
||||||
const shellDeclaration =
|
const shellDeclaration =
|
||||||
"shell001 = shell({ faces = ['end', seg01], thickness = 5}, extrude001)"
|
"shell001 = shell(extrude001, faces = ['end', seg01], thickness = 5)"
|
||||||
const formattedOutLastLine = '}, extrude001)'
|
|
||||||
|
|
||||||
await test.step(`Look for the grey of the shape`, async () => {
|
await test.step(`Look for the grey of the shape`, async () => {
|
||||||
await scene.expectPixelColor([99, 99, 99], testPoint, 15)
|
await scene.expectPixelColor([99, 99, 99], testPoint, 15)
|
||||||
@ -2034,7 +2098,7 @@ extrude001 = extrude(sketch001, length = 40)
|
|||||||
await editor.expectEditor.toContain(shellDeclaration)
|
await editor.expectEditor.toContain(shellDeclaration)
|
||||||
await editor.expectState({
|
await editor.expectState({
|
||||||
diagnostics: [],
|
diagnostics: [],
|
||||||
activeLines: [formattedOutLastLine],
|
activeLines: [shellDeclaration],
|
||||||
highlightedCode: '',
|
highlightedCode: '',
|
||||||
})
|
})
|
||||||
await scene.expectPixelColor([49, 49, 49], testPoint, 15)
|
await scene.expectPixelColor([49, 49, 49], testPoint, 15)
|
||||||
@ -2088,9 +2152,8 @@ extrude002 = extrude(sketch002, length = 50)
|
|||||||
// One dumb hardcoded screen pixel value
|
// One dumb hardcoded screen pixel value
|
||||||
const testPoint = { x: 550, y: 295 }
|
const testPoint = { x: 550, y: 295 }
|
||||||
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
const [clickOnCap] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||||
const shellDeclaration = `shell001 = shell({ faces = ['end'], thickness = 5 }, ${
|
const shellTarget = hasExtrudesInPipe ? 'sketch002' : 'extrude002'
|
||||||
hasExtrudesInPipe ? 'sketch002' : 'extrude002'
|
const shellDeclaration = `shell001 = shell(${shellTarget}, faces = ['end'], thickness = 5)`
|
||||||
})`
|
|
||||||
|
|
||||||
await test.step(`Look for the grey of the shape`, async () => {
|
await test.step(`Look for the grey of the shape`, async () => {
|
||||||
await toolbar.closePane('code')
|
await toolbar.closePane('code')
|
||||||
@ -2158,7 +2221,7 @@ extrude002 = extrude(sketch002, length = 50)
|
|||||||
sketch002 = startSketchOn('XZ')
|
sketch002 = startSketchOn('XZ')
|
||||||
|> startProfileAt([0, 0], %)
|
|> startProfileAt([0, 0], %)
|
||||||
|> xLine(-2000, %)
|
|> xLine(-2000, %)
|
||||||
sweep001 = sweep({ path = sketch002 }, sketch001)
|
sweep001 = sweep(sketch001, path = sketch002)
|
||||||
`
|
`
|
||||||
await context.addInitScript((initialCode) => {
|
await context.addInitScript((initialCode) => {
|
||||||
localStorage.setItem('persistCode', initialCode)
|
localStorage.setItem('persistCode', initialCode)
|
||||||
|
@ -35,106 +35,108 @@ sketch003 = startSketchOn('XY')
|
|||||||
extrude003 = extrude(sketch003, length = 20)
|
extrude003 = extrude(sketch003, length = 20)
|
||||||
`
|
`
|
||||||
|
|
||||||
test.fixme('Check the happy path, for basic changing color', () => {
|
test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||||
const cases = [
|
test.fixme('Check the happy path, for basic changing color', () => {
|
||||||
{
|
const cases = [
|
||||||
desc: 'User accepts change',
|
{
|
||||||
shouldReject: false,
|
desc: 'User accepts change',
|
||||||
},
|
shouldReject: false,
|
||||||
{
|
},
|
||||||
desc: 'User rejects change',
|
{
|
||||||
shouldReject: true,
|
desc: 'User rejects change',
|
||||||
},
|
shouldReject: true,
|
||||||
] as const
|
},
|
||||||
for (const { desc, shouldReject } of cases) {
|
] as const
|
||||||
test(`${desc}`, async ({
|
for (const { desc, shouldReject } of cases) {
|
||||||
context,
|
test(`${desc}`, async ({
|
||||||
homePage,
|
context,
|
||||||
cmdBar,
|
homePage,
|
||||||
editor,
|
cmdBar,
|
||||||
page,
|
editor,
|
||||||
scene,
|
page,
|
||||||
}) => {
|
scene,
|
||||||
await context.addInitScript((file) => {
|
}) => {
|
||||||
localStorage.setItem('persistCode', file)
|
await context.addInitScript((file) => {
|
||||||
}, file)
|
localStorage.setItem('persistCode', file)
|
||||||
await homePage.goToModelingScene()
|
}, file)
|
||||||
|
await homePage.goToModelingScene()
|
||||||
|
|
||||||
const body1CapCoords = { x: 571, y: 351 }
|
const body1CapCoords = { x: 571, y: 351 }
|
||||||
const greenCheckCoords = { x: 565, y: 345 }
|
const greenCheckCoords = { x: 565, y: 345 }
|
||||||
const body2WallCoords = { x: 609, y: 153 }
|
const body2WallCoords = { x: 609, y: 153 }
|
||||||
const [clickBody1Cap] = scene.makeMouseHelpers(
|
const [clickBody1Cap] = scene.makeMouseHelpers(
|
||||||
body1CapCoords.x,
|
body1CapCoords.x,
|
||||||
body1CapCoords.y
|
body1CapCoords.y
|
||||||
)
|
)
|
||||||
const yellow: [number, number, number] = [179, 179, 131]
|
const yellow: [number, number, number] = [179, 179, 131]
|
||||||
const green: [number, number, number] = [108, 152, 75]
|
const green: [number, number, number] = [108, 152, 75]
|
||||||
const notGreen: [number, number, number] = [132, 132, 132]
|
const notGreen: [number, number, number] = [132, 132, 132]
|
||||||
const body2NotGreen: [number, number, number] = [88, 88, 88]
|
const body2NotGreen: [number, number, number] = [88, 88, 88]
|
||||||
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
|
const submittingToast = page.getByText(
|
||||||
const successToast = page.getByText('Prompt to edit successful')
|
'Submitting to Text-to-CAD API...'
|
||||||
const acceptBtn = page.getByRole('button', { name: 'checkmark Accept' })
|
)
|
||||||
const rejectBtn = page.getByRole('button', { name: 'close Reject' })
|
const successToast = page.getByText('Prompt to edit successful')
|
||||||
|
const acceptBtn = page.getByRole('button', { name: 'checkmark Accept' })
|
||||||
|
const rejectBtn = page.getByRole('button', { name: 'close Reject' })
|
||||||
|
|
||||||
await test.step('wait for scene to load select body and check selection came through', async () => {
|
await test.step('wait for scene to load select body and check selection came through', async () => {
|
||||||
await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15)
|
await scene.expectPixelColor([134, 134, 134], body1CapCoords, 15)
|
||||||
await clickBody1Cap()
|
await clickBody1Cap()
|
||||||
await scene.expectPixelColor(yellow, body1CapCoords, 20)
|
await scene.expectPixelColor(yellow, body1CapCoords, 20)
|
||||||
await editor.expectState({
|
await editor.expectState({
|
||||||
highlightedCode: '',
|
highlightedCode: '',
|
||||||
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],
|
activeLines: ['|>startProfileAt([-73.64,-42.89],%)'],
|
||||||
diagnostics: [],
|
diagnostics: [],
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
await test.step('fire off edit prompt', async () => {
|
await test.step('fire off edit prompt', async () => {
|
||||||
await cmdBar.openCmdBar('promptToEdit')
|
await cmdBar.openCmdBar('promptToEdit')
|
||||||
// being specific about the color with a hex means asserting pixel color is more stable
|
// being specific about the color with a hex means asserting pixel color is more stable
|
||||||
await page
|
await page
|
||||||
.getByTestId('cmd-bar-arg-value')
|
.getByTestId('cmd-bar-arg-value')
|
||||||
.fill('make this neon green please, use #39FF14')
|
.fill('make this neon green please, use #39FF14')
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await cmdBar.progressCmdBar()
|
await cmdBar.progressCmdBar()
|
||||||
await expect(submittingToast).toBeVisible()
|
await expect(submittingToast).toBeVisible()
|
||||||
await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000 }) // can take a while
|
await expect(submittingToast).not.toBeVisible({ timeout: 2 * 60_000 }) // can take a while
|
||||||
await expect(successToast).toBeVisible()
|
await expect(successToast).toBeVisible()
|
||||||
})
|
})
|
||||||
|
|
||||||
await test.step('verify initial change', async () => {
|
|
||||||
await scene.expectPixelColor(green, greenCheckCoords, 15)
|
|
||||||
await scene.expectPixelColor(body2NotGreen, body2WallCoords, 15)
|
|
||||||
await editor.expectEditor.toContain('appearance({')
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!shouldReject) {
|
|
||||||
await test.step('check accept works and can be "undo"ed', async () => {
|
|
||||||
await acceptBtn.click()
|
|
||||||
await expect(successToast).not.toBeVisible()
|
|
||||||
|
|
||||||
|
await test.step('verify initial change', async () => {
|
||||||
await scene.expectPixelColor(green, greenCheckCoords, 15)
|
await scene.expectPixelColor(green, greenCheckCoords, 15)
|
||||||
await editor.expectEditor.toContain('appearance({')
|
await scene.expectPixelColor(body2NotGreen, body2WallCoords, 15)
|
||||||
|
await editor.expectEditor.toContain('appearance(')
|
||||||
// ctrl-z works after accepting
|
|
||||||
await page.keyboard.down('ControlOrMeta')
|
|
||||||
await page.keyboard.press('KeyZ')
|
|
||||||
await page.keyboard.up('ControlOrMeta')
|
|
||||||
await editor.expectEditor.not.toContain('appearance({')
|
|
||||||
await scene.expectPixelColor(notGreen, greenCheckCoords, 15)
|
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
await test.step('check reject works', async () => {
|
|
||||||
await rejectBtn.click()
|
|
||||||
await expect(successToast).not.toBeVisible()
|
|
||||||
|
|
||||||
await scene.expectPixelColor(notGreen, greenCheckCoords, 15)
|
if (!shouldReject) {
|
||||||
await editor.expectEditor.not.toContain('appearance({')
|
await test.step('check accept works and can be "undo"ed', async () => {
|
||||||
})
|
await acceptBtn.click()
|
||||||
}
|
await expect(successToast).not.toBeVisible()
|
||||||
})
|
|
||||||
}
|
await scene.expectPixelColor(green, greenCheckCoords, 15)
|
||||||
})
|
await editor.expectEditor.toContain('appearance(')
|
||||||
|
|
||||||
|
// ctrl-z works after accepting
|
||||||
|
await page.keyboard.down('ControlOrMeta')
|
||||||
|
await page.keyboard.press('KeyZ')
|
||||||
|
await page.keyboard.up('ControlOrMeta')
|
||||||
|
await editor.expectEditor.not.toContain('appearance(')
|
||||||
|
await scene.expectPixelColor(notGreen, greenCheckCoords, 15)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await test.step('check reject works', async () => {
|
||||||
|
await rejectBtn.click()
|
||||||
|
await expect(successToast).not.toBeVisible()
|
||||||
|
|
||||||
|
await scene.expectPixelColor(notGreen, greenCheckCoords, 15)
|
||||||
|
await editor.expectEditor.not.toContain('appearance(')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
test.describe('bad path', { tag: ['@skipWin'] }, () => {
|
|
||||||
test(`bad edit prompt`, async ({
|
test(`bad edit prompt`, async ({
|
||||||
context,
|
context,
|
||||||
homePage,
|
homePage,
|
||||||
|
@ -253,7 +253,7 @@ extrude001 = extrude(sketch001, length = 50)
|
|||||||
|>
|
|>
|
||||||
|
|
||||||
example = extrude(exampleSketch, length = 5)
|
example = extrude(exampleSketch, length = 5)
|
||||||
shell({ faces: ['end'], thickness: 0.25 }, exampleSketch)`
|
shell(exampleSketch, faces = ['end'], thickness = 0.25)`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -314,6 +314,7 @@ extrude001 = extrude(sketch001, length = 50)
|
|||||||
)
|
)
|
||||||
|
|
||||||
test('when engine fails export we handle the failure and alert the user', async ({
|
test('when engine fails export we handle the failure and alert the user', async ({
|
||||||
|
scene,
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
}) => {
|
}) => {
|
||||||
@ -383,10 +384,7 @@ extrude001 = extrude(sketch001, length = 50)
|
|||||||
await page.keyboard.press('End')
|
await page.keyboard.press('End')
|
||||||
await page.keyboard.press('Enter')
|
await page.keyboard.press('Enter')
|
||||||
|
|
||||||
// wait for execution done
|
await scene.waitForExecutionDone()
|
||||||
await u.openDebugPanel()
|
|
||||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
|
||||||
await u.closeDebugPanel()
|
|
||||||
|
|
||||||
// Now try exporting
|
// Now try exporting
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user