* expand xstate unit tests
* remove .only 🙄
* add tests for remove constraints (with todos)
* expand to invididual constraints too
* re-organise
* fix tests
* fmt
* remove log
* clean up
* type clean up
* add delete tests too
* remove redundant tests<
* fix e2e
* lints
1302 lines
43 KiB
TypeScript
1302 lines
43 KiB
TypeScript
import {
|
|
modelingMachine,
|
|
modelingMachineDefaultContext,
|
|
} from '@src/machines/modelingMachine'
|
|
import { createActor } from 'xstate'
|
|
import { vi } from 'vitest'
|
|
import { assertParse, recast, type CallExpressionKw } from '@src/lang/wasm'
|
|
import { initPromise } from '@src/lang/wasmUtils'
|
|
import {
|
|
codeManager,
|
|
engineCommandManager,
|
|
kclManager,
|
|
} from '@src/lib/singletons'
|
|
import { VITE_KC_DEV_TOKEN } from '@src/env'
|
|
import { getConstraintInfoKw } from '@src/lang/std/sketch'
|
|
import { getNodeFromPath } from '@src/lang/queryAst'
|
|
import type { Node } from '@rust/kcl-lib/bindings/Node'
|
|
import { err } from '@src/lib/trap'
|
|
import {
|
|
createIdentifier,
|
|
createLiteral,
|
|
createVariableDeclaration,
|
|
} from '@src/lang/create'
|
|
import { ARG_END_ABSOLUTE, ARG_INTERIOR_ABSOLUTE } from '@src/lang/constants'
|
|
import { removeSingleConstraintInfo } from '@src/lang/modifyAst'
|
|
|
|
// Store original method to restore in afterAll
|
|
|
|
beforeAll(async () => {
|
|
await initPromise
|
|
|
|
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
|
|
await new Promise((resolve) => {
|
|
engineCommandManager.start({
|
|
token: VITE_KC_DEV_TOKEN,
|
|
width: 256,
|
|
height: 256,
|
|
setMediaStream: () => {},
|
|
setIsStreamReady: () => {},
|
|
callbackOnEngineLiteConnect: () => {
|
|
resolve(true)
|
|
},
|
|
})
|
|
})
|
|
}, 30_000)
|
|
|
|
afterAll(() => {
|
|
// Restore the original method
|
|
|
|
engineCommandManager.tearDown()
|
|
})
|
|
|
|
// Define mock implementations that will be referenced in vi.mock calls
|
|
vi.mock('@src/components/SetHorVertDistanceModal', () => ({
|
|
createInfoModal: vi.fn(() => ({
|
|
open: vi.fn().mockResolvedValue({
|
|
value: '10',
|
|
segName: 'test',
|
|
valueNode: {},
|
|
newVariableInsertIndex: 0,
|
|
sign: 1,
|
|
}),
|
|
})),
|
|
GetInfoModal: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('@src/components/SetAngleLengthModal', () => ({
|
|
createSetAngleLengthModal: vi.fn(() => ({
|
|
open: vi.fn().mockResolvedValue({
|
|
value: '45',
|
|
segName: 'test',
|
|
valueNode: {},
|
|
newVariableInsertIndex: 0,
|
|
sign: 1,
|
|
}),
|
|
})),
|
|
SetAngleLengthModal: vi.fn(),
|
|
}))
|
|
|
|
// Add this function before the test cases
|
|
// Utility function to wait for a condition to be met
|
|
const waitForCondition = async (
|
|
condition: () => boolean,
|
|
timeout = 5000,
|
|
interval = 100
|
|
) => {
|
|
const startTime = Date.now()
|
|
|
|
while (Date.now() - startTime < timeout) {
|
|
try {
|
|
if (condition()) {
|
|
return true
|
|
}
|
|
} catch {
|
|
// Ignore errors, keep polling
|
|
}
|
|
|
|
// Wait for the next interval
|
|
await new Promise((resolve) => setTimeout(resolve, interval))
|
|
}
|
|
|
|
// Last attempt before failing
|
|
return condition()
|
|
}
|
|
|
|
describe('modelingMachine - XState', () => {
|
|
describe('when initialized', () => {
|
|
it('should start in the idle state', () => {
|
|
const actor = createActor(modelingMachine, {
|
|
input: modelingMachineDefaultContext,
|
|
}).start()
|
|
const state = actor.getSnapshot().value
|
|
|
|
// The machine should start in the idle state
|
|
expect(state).toEqual({ idle: 'hidePlanes' })
|
|
})
|
|
})
|
|
|
|
const makeStraightSegmentSnippet = (line: string) => ({
|
|
code: `testVar1 = 55
|
|
testVar2 = 66
|
|
testVar3 = 77
|
|
testVar4 = 88
|
|
sketch001 = startSketchOn(XZ)
|
|
profile001 = startProfile(sketch001, at = [2263.04, -2721.2])
|
|
|> line(end = [78, 19])
|
|
|> ${line}
|
|
|> line(end = [75.72, 18.41])`,
|
|
searchText: line,
|
|
})
|
|
const makeCircSnippet = (line: string) => ({
|
|
code: `testVar1 = 55
|
|
testVar2 = 66
|
|
testVar3 = 77
|
|
testVar4 = 88
|
|
testVar5 = 99
|
|
testVar6 = 11
|
|
sketch001 = startSketchOn(YZ)
|
|
profile001 = ${line}
|
|
`,
|
|
searchText: line,
|
|
})
|
|
const threePointCirceCode = `circleThreePoint(
|
|
sketch001,
|
|
p1 = [testVar1, testVar2],
|
|
p2 = [testVar3, testVar4],
|
|
p3 = [testVar5, testVar6],
|
|
)`
|
|
const threePointCirceCodeLiterals = `circleThreePoint(
|
|
sketch001,
|
|
p1 = [281.18, 215.74],
|
|
p2 = [295.39, 269.96],
|
|
p3 = [342.51, 216.38],
|
|
)`
|
|
|
|
type TestDetails = {
|
|
name: string
|
|
code: string
|
|
searchText: string
|
|
constraintIndex: number
|
|
expectedResult: string
|
|
filter?: string
|
|
}
|
|
|
|
const cases: {
|
|
[strLibName: string]: {
|
|
namedConstantConstraint: TestDetails[]
|
|
removeAllConstraintsCases: TestDetails[]
|
|
removeIndividualConstraintsCases: TestDetails[]
|
|
deleteSegment: Omit<TestDetails, 'expectedResult' | 'constraintIndex'>[]
|
|
}
|
|
} = {
|
|
line: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain line x value',
|
|
...makeStraightSegmentSnippet('line(end = [16.27, 73.81])'),
|
|
constraintIndex: 0,
|
|
expectedResult: 'line(end = [test_variable,',
|
|
},
|
|
{
|
|
name: 'should constrain line y value',
|
|
...makeStraightSegmentSnippet('line(end = [16.27, 73.81])'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [16.27, test_variable]',
|
|
},
|
|
{
|
|
name: 'should constrain line absolute x value',
|
|
...makeStraightSegmentSnippet('line(endAbsolute = [16.27, 73.81])'),
|
|
constraintIndex: 0,
|
|
expectedResult: 'line(endAbsolute = [test_variable, 73.81]',
|
|
},
|
|
{
|
|
name: 'should constrain line absolute y value',
|
|
...makeStraightSegmentSnippet('line(endAbsolute = [16.27, 73.81])'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(endAbsolute = [16.27, test_variable]',
|
|
},
|
|
],
|
|
removeAllConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain rel-line',
|
|
...makeStraightSegmentSnippet('line(end = [testVar1, testVar2])'),
|
|
constraintIndex: 0,
|
|
expectedResult: 'line(end = [55, 66])',
|
|
},
|
|
{
|
|
name: 'should un-constrain abs-line',
|
|
...makeStraightSegmentSnippet(
|
|
'line(endAbsolute = [testVar1, testVar2])'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult: 'line(end = [-2286.04, 2768.2]',
|
|
// TODO un-constrains to relative line when it should not, expectedResult should be the following
|
|
// expectedResult: 'line(endAbsolute = [55, 66]',
|
|
},
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain line x value',
|
|
...makeStraightSegmentSnippet('line(end = [testVar1, testVar2])'),
|
|
constraintIndex: 0,
|
|
expectedResult: 'line(end = [55, testVar2]',
|
|
},
|
|
{
|
|
name: 'should un-constrain line y value',
|
|
...makeStraightSegmentSnippet('line(end = [testVar1, testVar2])'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [testVar1, 66]',
|
|
},
|
|
{
|
|
name: 'should un-constrain line absolute x value',
|
|
...makeStraightSegmentSnippet(
|
|
'line(endAbsolute = [testVar1, testVar2])'
|
|
),
|
|
constraintIndex: 0,
|
|
// expectedResult: 'line(end = [-2286.04, testVar2])',
|
|
// // TODO should not swap from abs to relative, expected should be
|
|
expectedResult: 'line(endAbsolute = [55, testVar2]',
|
|
},
|
|
{
|
|
name: 'should un-constrain line absolute y value',
|
|
...makeStraightSegmentSnippet(
|
|
'line(endAbsolute = [testVar1, testVar2])'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(endAbsolute = [testVar1, 66])',
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
{
|
|
name: 'should delete rel-line',
|
|
...makeStraightSegmentSnippet('line(end = [testVar1, testVar2])'),
|
|
},
|
|
{
|
|
name: 'should delete abs-line',
|
|
...makeStraightSegmentSnippet(
|
|
'line(endAbsolute = [testVar1, testVar2])'
|
|
),
|
|
},
|
|
],
|
|
},
|
|
xLine: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain xLine x value',
|
|
...makeStraightSegmentSnippet('xLine(length = 15)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'xLine(length = test_variable)',
|
|
},
|
|
{
|
|
name: 'should constrain xLine x absolute value',
|
|
...makeStraightSegmentSnippet('xLine(endAbsolute = 15)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'xLine(endAbsolute = test_variable)',
|
|
},
|
|
],
|
|
removeAllConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain xLine',
|
|
...makeStraightSegmentSnippet('xLine(length = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [55, 0])',
|
|
},
|
|
{
|
|
name: 'should un-constrain xLine absolute value',
|
|
...makeStraightSegmentSnippet('xLine(endAbsolute = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [-2286.04, 0])',
|
|
// TODO un-constrains to relative line when it should not, expectedResult should be the following
|
|
// expectedResult: 'line(endAbsolute = [55, 0])',
|
|
},
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain xLine x value',
|
|
...makeStraightSegmentSnippet('xLine(length = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'xLine(length = 55)',
|
|
},
|
|
{
|
|
name: 'should un-constrain xLine x absolute value',
|
|
...makeStraightSegmentSnippet('xLine(endAbsolute = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'xLine(endAbsolute = 55)',
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
{
|
|
name: 'should delete xLine',
|
|
...makeStraightSegmentSnippet('xLine(length = 15)'),
|
|
},
|
|
{
|
|
name: 'should delete xLine',
|
|
...makeStraightSegmentSnippet('xLine(endAbsolute = 15)'),
|
|
},
|
|
],
|
|
},
|
|
yLine: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain yLine y value',
|
|
...makeStraightSegmentSnippet('yLine(length = 15)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'yLine(length = test_variable)',
|
|
},
|
|
{
|
|
name: 'should constrain yLine y absolute value',
|
|
...makeStraightSegmentSnippet('yLine(endAbsolute = 15)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'yLine(endAbsolute = test_variable)',
|
|
},
|
|
],
|
|
removeAllConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain yLine value',
|
|
...makeStraightSegmentSnippet('yLine(length = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [0, 55])',
|
|
},
|
|
{
|
|
name: 'should un-constrain yLine absolute value',
|
|
...makeStraightSegmentSnippet('yLine(endAbsolute = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [0, 2757.2])',
|
|
// TODO un-constrains to relative line when it should not, expectedResult should be the following
|
|
// expectedResult: 'line(endAbsolute = [0, 55])',
|
|
},
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain yLine y value',
|
|
...makeStraightSegmentSnippet('yLine(length = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'yLine(length = 55)',
|
|
},
|
|
{
|
|
name: 'should un-constrain yLine y absolute value',
|
|
...makeStraightSegmentSnippet('yLine(endAbsolute = testVar1)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'yLine(endAbsolute = 55)',
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
{
|
|
name: 'should delete yLine',
|
|
...makeStraightSegmentSnippet('yLine(length = 15)'),
|
|
},
|
|
{
|
|
name: 'should delete yLine abs',
|
|
...makeStraightSegmentSnippet('yLine(endAbsolute = 15)'),
|
|
},
|
|
],
|
|
},
|
|
angledLine: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain angledLine, angle value',
|
|
...makeStraightSegmentSnippet('angledLine(angle = 45, length = 100)'),
|
|
constraintIndex: 0,
|
|
expectedResult: 'angledLine(angle = test_variable, length = 100)',
|
|
},
|
|
{
|
|
name: 'should constrain angledLine, length value',
|
|
...makeStraightSegmentSnippet('angledLine(angle = 45, length = 100)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = 45, length = test_variable)',
|
|
},
|
|
{
|
|
name: 'should constrain angledLine, endAbsoluteY value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = 45, endAbsoluteY = 5)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult:
|
|
'angledLine(angle = 45, endAbsoluteY = test_variable)',
|
|
},
|
|
{
|
|
name: 'should constrain angledLine, endAbsoluteX value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = 45, endAbsoluteX = 5)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult:
|
|
'angledLine(angle = 45, endAbsoluteX = test_variable)',
|
|
},
|
|
{
|
|
name: 'should constrain angledLine, lengthY value',
|
|
...makeStraightSegmentSnippet('angledLine(angle = 45, lengthY = 5)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = 45, lengthY = test_variable)',
|
|
},
|
|
{
|
|
name: 'should constrain angledLine, lengthX value',
|
|
...makeStraightSegmentSnippet('angledLine(angle = 45, lengthX = 5)'),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = 45, lengthX = test_variable)',
|
|
},
|
|
],
|
|
removeAllConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain angledLine',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, length = testVar2)'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult: 'line(end = [37.86, 54.06]',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, endAbsoluteY',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, endAbsoluteY = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [1938.31, 2768.2])',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, endAbsoluteX',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, endAbsoluteX = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [-2275.04, -3249.09])',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, lengthY',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, lengthY = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [46.21, 66])',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, lengthX',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, lengthX = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'line(end = [66, 94.26])',
|
|
},
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain angledLine, angle value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, length = testVar2)'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult: 'angledLine(angle = 55, length = testVar2)',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, length value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, length = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = testVar1, length = 66)',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, endAbsoluteY value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, endAbsoluteY = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = testVar1, endAbsoluteY = 66)',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, endAbsoluteX value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, endAbsoluteX = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = testVar1, endAbsoluteX = 66)',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, lengthY value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, lengthY = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = testVar1, lengthY = 66)',
|
|
},
|
|
{
|
|
name: 'should un-constrain angledLine, lengthX value',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = testVar1, lengthX = testVar2)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'angledLine(angle = testVar1, lengthX = 66)',
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
{
|
|
name: 'should delete angledLine, angle length',
|
|
...makeStraightSegmentSnippet('angledLine(angle = 45, length = 100)'),
|
|
},
|
|
{
|
|
name: 'should delete angledLine, endAbsoluteY',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = 45, endAbsoluteY = 5)'
|
|
),
|
|
},
|
|
{
|
|
name: 'should delete angledLine, endAbsoluteX',
|
|
...makeStraightSegmentSnippet(
|
|
'angledLine(angle = 45, endAbsoluteX = 5)'
|
|
),
|
|
},
|
|
{
|
|
name: 'should delete angledLine, lengthY',
|
|
...makeStraightSegmentSnippet('angledLine(angle = 45, lengthY = 5)'),
|
|
},
|
|
{
|
|
name: 'should delete angledLine, lengthX',
|
|
...makeStraightSegmentSnippet('angledLine(angle = 45, lengthX = 5)'),
|
|
},
|
|
],
|
|
},
|
|
circle: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain circle, radius value',
|
|
...makeCircSnippet(
|
|
'circle(sketch001, center = [140.82, 183.92], radius = 74.18)'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult:
|
|
'circle(sketch001, center = [140.82, 183.92], radius = test_variable)',
|
|
},
|
|
{
|
|
name: 'should constrain circle, center x value',
|
|
...makeCircSnippet(
|
|
'circle(sketch001, center = [140.82, 183.92], radius = 74.18)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult:
|
|
'circle(sketch001, center = [test_variable, 183.92], radius = 74.18)',
|
|
},
|
|
{
|
|
name: 'should constrain circle, center y value',
|
|
...makeCircSnippet(
|
|
'circle(sketch001, center = [140.82, 183.92], radius = 74.18)'
|
|
),
|
|
constraintIndex: 2,
|
|
expectedResult:
|
|
'circle(sketch001, center = [140.82, test_variable], radius = 74.18)',
|
|
},
|
|
],
|
|
removeAllConstraintsCases: [
|
|
// TODO circle when remove all is working
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain circle, radius value',
|
|
...makeCircSnippet(
|
|
'circle(sketch001, center = [140.82, 183.92], radius = testVar1)'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult:
|
|
'circle(sketch001, center = [140.82, 183.92], radius = 55)',
|
|
},
|
|
{
|
|
name: 'should un-constrain circle, center x value',
|
|
...makeCircSnippet(
|
|
'circle(sketch001, center = [testVar1, testVar2], radius = 74.18)'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult:
|
|
'circle(sketch001, center = [55, testVar2], radius = 74.18)',
|
|
},
|
|
{
|
|
name: 'should un-constrain circle, center y value',
|
|
...makeCircSnippet(
|
|
'circle(sketch001, center = [testVar1, testVar2], radius = 74.18)'
|
|
),
|
|
constraintIndex: 2,
|
|
expectedResult:
|
|
'circle(sketch001, center = [testVar1, 66], radius = 74.18)',
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
/** TODO once circle has delete implemented */
|
|
],
|
|
},
|
|
circleThreePoint: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain circleThreePoint, p1 x value',
|
|
...makeCircSnippet(threePointCirceCodeLiterals),
|
|
constraintIndex: 0,
|
|
expectedResult: 'p1 = [test_variable, 215.74]',
|
|
filter: 'p1',
|
|
},
|
|
{
|
|
name: 'should constrain circleThreePoint, p1 y value',
|
|
...makeCircSnippet(threePointCirceCodeLiterals),
|
|
constraintIndex: 1,
|
|
expectedResult: 'p1 = [281.18, test_variable]',
|
|
filter: 'p1',
|
|
},
|
|
{
|
|
name: 'should constrain circleThreePoint, p2 x value',
|
|
...makeCircSnippet(threePointCirceCodeLiterals),
|
|
constraintIndex: 0,
|
|
expectedResult: 'p2 = [test_variable, 269.96]',
|
|
filter: 'p2',
|
|
},
|
|
{
|
|
name: 'should constrain circleThreePoint, p2 y value',
|
|
...makeCircSnippet(threePointCirceCodeLiterals),
|
|
constraintIndex: 1,
|
|
expectedResult: 'p2 = [295.39, test_variable]',
|
|
filter: 'p2',
|
|
},
|
|
{
|
|
name: 'should constrain circleThreePoint, p3 x value',
|
|
...makeCircSnippet(threePointCirceCodeLiterals),
|
|
constraintIndex: 0,
|
|
expectedResult: 'p3 = [test_variable, 216.38]',
|
|
filter: 'p3',
|
|
},
|
|
{
|
|
name: 'should constrain circleThreePoint, p3 y value',
|
|
...makeCircSnippet(threePointCirceCodeLiterals),
|
|
constraintIndex: 1,
|
|
expectedResult: 'p3 = [342.51, test_variable]',
|
|
filter: 'p3',
|
|
},
|
|
],
|
|
removeAllConstraintsCases: [
|
|
// TODO circleThreePoint when remove all is working
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain circleThreePoint, p1 x value',
|
|
...makeCircSnippet(threePointCirceCode),
|
|
constraintIndex: 0,
|
|
expectedResult: 'p1 = [55, testVar2]',
|
|
filter: 'p1',
|
|
},
|
|
{
|
|
name: 'should un-constrain circleThreePoint, p1 y value',
|
|
...makeCircSnippet(threePointCirceCode),
|
|
constraintIndex: 1,
|
|
expectedResult: 'p1 = [testVar1, 66]',
|
|
filter: 'p1',
|
|
},
|
|
{
|
|
name: 'should un-constrain circleThreePoint, p2 x value',
|
|
...makeCircSnippet(threePointCirceCode),
|
|
constraintIndex: 0,
|
|
expectedResult: 'p2 = [77, testVar4]',
|
|
filter: 'p2',
|
|
},
|
|
{
|
|
name: 'should un-constrain circleThreePoint, p2 y value',
|
|
...makeCircSnippet(threePointCirceCode),
|
|
constraintIndex: 1,
|
|
expectedResult: 'p2 = [testVar3, 88]',
|
|
filter: 'p2',
|
|
},
|
|
{
|
|
name: 'should un-constrain circleThreePoint, p3 x value',
|
|
...makeCircSnippet(threePointCirceCode),
|
|
constraintIndex: 0,
|
|
expectedResult: 'p3 = [99, testVar6]',
|
|
filter: 'p3',
|
|
},
|
|
{
|
|
name: 'should un-constrain circleThreePoint, p3 y value',
|
|
...makeCircSnippet(threePointCirceCode),
|
|
constraintIndex: 1,
|
|
expectedResult: 'p3 = [testVar5, 11]',
|
|
filter: 'p3',
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
/**TODO once three point circle has delete implemented */
|
|
],
|
|
},
|
|
tangentialArc: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain tangentialArc absolute x value',
|
|
...makeStraightSegmentSnippet(
|
|
'tangentialArc(endAbsolute = [176.11, 19.49])'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'endAbsolute = [test_variable, 19.49]',
|
|
},
|
|
{
|
|
name: 'should constrain tangentialArc absolute y value',
|
|
...makeStraightSegmentSnippet(
|
|
'tangentialArc(endAbsolute = [176.11, 19.49])'
|
|
),
|
|
constraintIndex: 2,
|
|
expectedResult: 'endAbsolute = [176.11, test_variable]',
|
|
},
|
|
// TODO tangentialArc relative when that's working
|
|
],
|
|
removeAllConstraintsCases: [
|
|
// TODO tangentialArc when remove all is working
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain tangentialArc absolute x value',
|
|
...makeStraightSegmentSnippet(
|
|
'tangentialArc(endAbsolute = [testVar1, testVar2])'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'endAbsolute = [55, testVar2]',
|
|
},
|
|
{
|
|
name: 'should un-constrain tangentialArc absolute y value',
|
|
...makeStraightSegmentSnippet(
|
|
'tangentialArc(endAbsolute = [testVar1, testVar2])'
|
|
),
|
|
constraintIndex: 2,
|
|
expectedResult: 'endAbsolute = [testVar1, 66]',
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
{
|
|
name: 'should delete tangentialArc absolute',
|
|
...makeStraightSegmentSnippet(
|
|
'tangentialArc(endAbsolute = [176.11, 19.49])'
|
|
),
|
|
},
|
|
],
|
|
},
|
|
arc: {
|
|
namedConstantConstraint: [
|
|
{
|
|
name: 'should constrain threePoint Arc interior x value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [379.93, 103.92], endAbsolute = [386.2, 162.89])'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult: 'interiorAbsolute = [test_variable, 103.92]',
|
|
filter: ARG_INTERIOR_ABSOLUTE,
|
|
},
|
|
{
|
|
name: 'should constrain threePoint Arc interior y value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [379.93, 103.92], endAbsolute = [386.2, 162.89])'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'interiorAbsolute = [379.93, test_variable]',
|
|
filter: ARG_INTERIOR_ABSOLUTE,
|
|
},
|
|
{
|
|
name: 'should constrain threePoint Arc end x value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [379.93, 103.92], endAbsolute = [386.2, 162.89])'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult: 'endAbsolute = [test_variable, 162.89]',
|
|
filter: ARG_END_ABSOLUTE,
|
|
},
|
|
{
|
|
name: 'should constrain threePoint Arc end y value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [379.93, 103.92], endAbsolute = [386.2, 162.89])'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'endAbsolute = [386.2, test_variable]',
|
|
filter: ARG_END_ABSOLUTE,
|
|
},
|
|
// TODO do other kwargs for arc
|
|
],
|
|
removeAllConstraintsCases: [
|
|
// TODO arc when remove all is working
|
|
],
|
|
removeIndividualConstraintsCases: [
|
|
{
|
|
name: 'should un-constrain threePoint Arc interior x value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [testVar1, testVar2], endAbsolute = [testVar3, testVar4])'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult: 'interiorAbsolute = [55, testVar2]',
|
|
filter: ARG_INTERIOR_ABSOLUTE,
|
|
},
|
|
{
|
|
name: 'should un-constrain threePoint Arc interior y value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [testVar1, testVar2], endAbsolute = [testVar3, testVar4])'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'interiorAbsolute = [testVar1, 66]',
|
|
filter: ARG_INTERIOR_ABSOLUTE,
|
|
},
|
|
{
|
|
name: 'should un-constrain threePoint Arc end x value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [testVar1, testVar2], endAbsolute = [testVar3, testVar4])'
|
|
),
|
|
constraintIndex: 0,
|
|
expectedResult: 'endAbsolute = [77, testVar4]',
|
|
filter: ARG_END_ABSOLUTE,
|
|
},
|
|
{
|
|
name: 'should un-constrain threePoint Arc end y value',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [testVar1, testVar2], endAbsolute = [testVar3, testVar4])'
|
|
),
|
|
constraintIndex: 1,
|
|
expectedResult: 'endAbsolute = [testVar3, 88]',
|
|
filter: ARG_END_ABSOLUTE,
|
|
},
|
|
],
|
|
deleteSegment: [
|
|
{
|
|
name: 'should delete threePoint Arc (interior, end)',
|
|
...makeStraightSegmentSnippet(
|
|
'arc(interiorAbsolute = [379.93, 103.92], endAbsolute = [386.2, 162.89])'
|
|
),
|
|
},
|
|
],
|
|
},
|
|
}
|
|
|
|
describe('Deleting segment with three dot menu', () => {
|
|
const namedConstantConstraintCases = Object.values(cases).flatMap(
|
|
(caseGroup) => caseGroup.deleteSegment
|
|
)
|
|
namedConstantConstraintCases.forEach(
|
|
({ name, code, searchText, filter }) => {
|
|
it(name, async () => {
|
|
const indexOfInterest = code.indexOf(searchText)
|
|
|
|
const ast = assertParse(code)
|
|
|
|
await kclManager.executeAst({ ast })
|
|
|
|
expect(kclManager.errors).toEqual([])
|
|
|
|
// segment artifact with that source range
|
|
const artifact = [...kclManager.artifactGraph].find(
|
|
([_, artifact]) =>
|
|
artifact?.type === 'segment' &&
|
|
artifact.codeRef.range[0] <= indexOfInterest &&
|
|
indexOfInterest <= artifact.codeRef.range[1]
|
|
)?.[1]
|
|
if (!artifact || !('codeRef' in artifact)) {
|
|
throw new Error('Artifact not found or invalid artifact structure')
|
|
}
|
|
|
|
const actor = createActor(modelingMachine, {
|
|
input: modelingMachineDefaultContext,
|
|
}).start()
|
|
|
|
// Send event to transition to sketch mode
|
|
actor.send({
|
|
type: 'Set selection',
|
|
data: {
|
|
selectionType: 'mirrorCodeMirrorSelections',
|
|
selection: {
|
|
graphSelections: [
|
|
{
|
|
artifact: artifact,
|
|
codeRef: artifact.codeRef,
|
|
},
|
|
],
|
|
otherSelections: [],
|
|
},
|
|
},
|
|
})
|
|
actor.send({ type: 'Enter sketch' })
|
|
|
|
// Check that we're in the sketch state
|
|
let state = actor.getSnapshot()
|
|
expect(state.value).toBe('animating to existing sketch')
|
|
|
|
// wait for it to transition
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
return snapshot.value !== 'animating to existing sketch'
|
|
}, 5000)
|
|
|
|
// After the condition is met, do the actual assertion
|
|
expect(actor.getSnapshot().value).toEqual({
|
|
Sketch: { SketchIdle: 'scene drawn' },
|
|
})
|
|
|
|
const callExp = getNodeFromPath<Node<CallExpressionKw>>(
|
|
kclManager.ast,
|
|
artifact.codeRef.pathToNode,
|
|
'CallExpressionKw'
|
|
)
|
|
if (err(callExp)) {
|
|
throw new Error('Failed to get CallExpressionKw node')
|
|
}
|
|
const constraintInfo = getConstraintInfoKw(
|
|
callExp.node,
|
|
codeManager.code,
|
|
artifact.codeRef.pathToNode,
|
|
filter
|
|
)
|
|
const constraint = constraintInfo[0]
|
|
|
|
// Now that we're in sketchIdle state, test the "Constrain with named value" event
|
|
actor.send({
|
|
type: 'Delete segment',
|
|
data: constraint.pathToNode,
|
|
})
|
|
|
|
// Wait for the state to change in response to the constraint
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
// Check if we've transitioned to a different state
|
|
return (
|
|
JSON.stringify(snapshot.value) !==
|
|
JSON.stringify({
|
|
Sketch: { SketchIdle: 'set up segments' },
|
|
})
|
|
)
|
|
}, 5000)
|
|
|
|
const startTime = Date.now()
|
|
while (
|
|
codeManager.code.includes(searchText) &&
|
|
Date.now() - startTime < 5000
|
|
) {
|
|
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
}
|
|
expect(codeManager.code).not.toContain(searchText)
|
|
}, 10_000)
|
|
}
|
|
)
|
|
})
|
|
describe('Adding segment overlay constraints', () => {
|
|
const namedConstantConstraintCases = Object.values(cases).flatMap(
|
|
(caseGroup) => caseGroup.namedConstantConstraint
|
|
)
|
|
namedConstantConstraintCases.forEach(
|
|
({ name, code, searchText, constraintIndex, expectedResult, filter }) => {
|
|
it(name, async () => {
|
|
const indexOfInterest = code.indexOf(searchText)
|
|
|
|
const ast = assertParse(code)
|
|
|
|
await kclManager.executeAst({ ast })
|
|
|
|
expect(kclManager.errors).toEqual([])
|
|
|
|
// segment artifact with that source range
|
|
const artifact = [...kclManager.artifactGraph].find(
|
|
([_, artifact]) =>
|
|
artifact?.type === 'segment' &&
|
|
artifact.codeRef.range[0] <= indexOfInterest &&
|
|
indexOfInterest <= artifact.codeRef.range[1]
|
|
)?.[1]
|
|
if (!artifact || !('codeRef' in artifact)) {
|
|
throw new Error('Artifact not found or invalid artifact structure')
|
|
}
|
|
|
|
const actor = createActor(modelingMachine, {
|
|
input: modelingMachineDefaultContext,
|
|
}).start()
|
|
|
|
// Send event to transition to sketch mode
|
|
actor.send({
|
|
type: 'Set selection',
|
|
data: {
|
|
selectionType: 'mirrorCodeMirrorSelections',
|
|
selection: {
|
|
graphSelections: [
|
|
{
|
|
artifact: artifact,
|
|
codeRef: artifact.codeRef,
|
|
},
|
|
],
|
|
otherSelections: [],
|
|
},
|
|
},
|
|
})
|
|
actor.send({ type: 'Enter sketch' })
|
|
|
|
// Check that we're in the sketch state
|
|
let state = actor.getSnapshot()
|
|
expect(state.value).toBe('animating to existing sketch')
|
|
|
|
// wait for it to transition
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
return snapshot.value !== 'animating to existing sketch'
|
|
}, 5000)
|
|
|
|
// After the condition is met, do the actual assertion
|
|
expect(actor.getSnapshot().value).toEqual({
|
|
Sketch: { SketchIdle: 'scene drawn' },
|
|
})
|
|
|
|
const callExp = getNodeFromPath<Node<CallExpressionKw>>(
|
|
kclManager.ast,
|
|
artifact.codeRef.pathToNode,
|
|
'CallExpressionKw'
|
|
)
|
|
if (err(callExp)) {
|
|
throw new Error('Failed to get CallExpressionKw node')
|
|
}
|
|
const constraintInfo = getConstraintInfoKw(
|
|
callExp.node,
|
|
codeManager.code,
|
|
artifact.codeRef.pathToNode,
|
|
filter
|
|
)
|
|
const constraint = constraintInfo[constraintIndex]
|
|
|
|
// Now that we're in sketchIdle state, test the "Constrain with named value" event
|
|
actor.send({
|
|
type: 'Constrain with named value',
|
|
data: {
|
|
currentValue: {
|
|
valueText: constraint.value,
|
|
pathToNode: constraint.pathToNode,
|
|
variableName: 'test_variable',
|
|
},
|
|
// Use type assertion to mock the complex type
|
|
namedValue: {
|
|
valueText: '20',
|
|
variableName: 'test_variable',
|
|
insertIndex: 0,
|
|
valueCalculated: '20',
|
|
variableDeclarationAst: createVariableDeclaration(
|
|
'test_variable',
|
|
createLiteral('20')
|
|
),
|
|
variableIdentifierAst: createIdentifier('test_variable') as any,
|
|
valueAst: createLiteral('20'),
|
|
},
|
|
},
|
|
})
|
|
|
|
// Wait for the state to change in response to the constraint
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
// Check if we've transitioned to a different state
|
|
return (
|
|
JSON.stringify(snapshot.value) !==
|
|
JSON.stringify({
|
|
Sketch: { SketchIdle: 'set up segments' },
|
|
})
|
|
)
|
|
}, 5000)
|
|
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
// Check if we've transitioned to a different state
|
|
return (
|
|
JSON.stringify(snapshot.value) !==
|
|
JSON.stringify({ Sketch: 'Converting to named value' })
|
|
)
|
|
}, 5000)
|
|
expect(codeManager.code).toContain(expectedResult)
|
|
}, 10_000)
|
|
}
|
|
)
|
|
})
|
|
describe('removing individual constraints with segment overlay events', () => {
|
|
const removeIndividualConstraintsCases = Object.values(cases).flatMap(
|
|
(caseGroup) => caseGroup.removeIndividualConstraintsCases
|
|
)
|
|
|
|
removeIndividualConstraintsCases.forEach(
|
|
({ name, code, searchText, constraintIndex, expectedResult, filter }) => {
|
|
it(name, async () => {
|
|
const indexOfInterest = code.indexOf(searchText)
|
|
|
|
const ast = assertParse(code)
|
|
|
|
await kclManager.executeAst({ ast })
|
|
|
|
expect(kclManager.errors).toEqual([])
|
|
|
|
// segment artifact with that source range
|
|
const artifact = [...kclManager.artifactGraph].find(
|
|
([_, artifact]) =>
|
|
artifact?.type === 'segment' &&
|
|
artifact.codeRef.range[0] <= indexOfInterest &&
|
|
indexOfInterest <= artifact.codeRef.range[1]
|
|
)?.[1]
|
|
if (!artifact || !('codeRef' in artifact)) {
|
|
throw new Error('Artifact not found or invalid artifact structure')
|
|
}
|
|
|
|
const actor = createActor(modelingMachine, {
|
|
input: modelingMachineDefaultContext,
|
|
}).start()
|
|
|
|
// Send event to transition to sketch mode
|
|
actor.send({
|
|
type: 'Set selection',
|
|
data: {
|
|
selectionType: 'mirrorCodeMirrorSelections',
|
|
selection: {
|
|
graphSelections: [
|
|
{
|
|
artifact: artifact,
|
|
codeRef: artifact.codeRef,
|
|
},
|
|
],
|
|
otherSelections: [],
|
|
},
|
|
},
|
|
})
|
|
actor.send({ type: 'Enter sketch' })
|
|
|
|
// Check that we're in the sketch state
|
|
let state = actor.getSnapshot()
|
|
expect(state.value).toBe('animating to existing sketch')
|
|
|
|
// wait for it to transition
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
return snapshot.value !== 'animating to existing sketch'
|
|
}, 5000)
|
|
|
|
// After the condition is met, do the actual assertion
|
|
expect(actor.getSnapshot().value).toEqual({
|
|
Sketch: { SketchIdle: 'scene drawn' },
|
|
})
|
|
|
|
const callExp = getNodeFromPath<Node<CallExpressionKw>>(
|
|
kclManager.ast,
|
|
artifact.codeRef.pathToNode,
|
|
'CallExpressionKw'
|
|
)
|
|
if (err(callExp)) {
|
|
throw new Error('Failed to get CallExpressionKw node')
|
|
}
|
|
const constraintInfo = getConstraintInfoKw(
|
|
callExp.node,
|
|
codeManager.code,
|
|
artifact.codeRef.pathToNode,
|
|
filter
|
|
)
|
|
const constraint = constraintInfo[constraintIndex]
|
|
console.log('constraint', constraint)
|
|
if (!constraint.argPosition) {
|
|
throw new Error(
|
|
`Constraint at index ${constraintIndex} does not have argPosition`
|
|
)
|
|
}
|
|
|
|
const mod = removeSingleConstraintInfo(
|
|
constraint.pathToNode,
|
|
constraint.argPosition,
|
|
ast,
|
|
kclManager.variables
|
|
)
|
|
if (!mod) {
|
|
throw new Error('Failed to remove constraint info')
|
|
}
|
|
const codeRecast = recast(mod.modifiedAst)
|
|
|
|
expect(codeRecast).toContain(expectedResult)
|
|
}, 10_000)
|
|
}
|
|
)
|
|
})
|
|
describe('Removing segment overlay constraints', () => {
|
|
const removeAllConstraintsCases = Object.values(cases).flatMap(
|
|
(caseGroup) => caseGroup.removeAllConstraintsCases
|
|
)
|
|
|
|
removeAllConstraintsCases.forEach(
|
|
({ name, code, searchText, constraintIndex, expectedResult, filter }) => {
|
|
it(name, async () => {
|
|
const indexOfInterest = code.indexOf(searchText)
|
|
|
|
const ast = assertParse(code)
|
|
|
|
await kclManager.executeAst({ ast })
|
|
|
|
expect(kclManager.errors).toEqual([])
|
|
|
|
// segment artifact with that source range
|
|
const artifact = [...kclManager.artifactGraph].find(
|
|
([_, artifact]) =>
|
|
artifact?.type === 'segment' &&
|
|
artifact.codeRef.range[0] <= indexOfInterest &&
|
|
indexOfInterest <= artifact.codeRef.range[1]
|
|
)?.[1]
|
|
if (!artifact || !('codeRef' in artifact)) {
|
|
throw new Error('Artifact not found or invalid artifact structure')
|
|
}
|
|
|
|
const actor = createActor(modelingMachine, {
|
|
input: modelingMachineDefaultContext,
|
|
}).start()
|
|
|
|
// Send event to transition to sketch mode
|
|
actor.send({
|
|
type: 'Set selection',
|
|
data: {
|
|
selectionType: 'mirrorCodeMirrorSelections',
|
|
selection: {
|
|
graphSelections: [
|
|
{
|
|
artifact: artifact,
|
|
codeRef: artifact.codeRef,
|
|
},
|
|
],
|
|
otherSelections: [],
|
|
},
|
|
},
|
|
})
|
|
actor.send({ type: 'Enter sketch' })
|
|
|
|
// Check that we're in the sketch state
|
|
let state = actor.getSnapshot()
|
|
expect(state.value).toBe('animating to existing sketch')
|
|
|
|
// wait for it to transition
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
return snapshot.value !== 'animating to existing sketch'
|
|
}, 5000)
|
|
|
|
// After the condition is met, do the actual assertion
|
|
expect(actor.getSnapshot().value).toEqual({
|
|
Sketch: { SketchIdle: 'scene drawn' },
|
|
})
|
|
|
|
const callExp = getNodeFromPath<Node<CallExpressionKw>>(
|
|
kclManager.ast,
|
|
artifact.codeRef.pathToNode,
|
|
'CallExpressionKw'
|
|
)
|
|
if (err(callExp)) {
|
|
throw new Error('Failed to get CallExpressionKw node')
|
|
}
|
|
const constraintInfo = getConstraintInfoKw(
|
|
callExp.node,
|
|
codeManager.code,
|
|
artifact.codeRef.pathToNode,
|
|
filter
|
|
)
|
|
const constraint = constraintInfo[constraintIndex]
|
|
|
|
// Now that we're in sketchIdle state, test the "Constrain with named value" event
|
|
actor.send({
|
|
type: 'Constrain remove constraints',
|
|
data: constraint.pathToNode,
|
|
})
|
|
|
|
// Wait for the state to change in response to the constraint
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
// Check if we've transitioned to a different state
|
|
return (
|
|
JSON.stringify(snapshot.value) !==
|
|
JSON.stringify({
|
|
Sketch: { SketchIdle: 'set up segments' },
|
|
})
|
|
)
|
|
}, 5000)
|
|
|
|
await waitForCondition(() => {
|
|
const snapshot = actor.getSnapshot()
|
|
// Check if we've transitioned to a different state
|
|
return (
|
|
JSON.stringify(snapshot.value) !==
|
|
JSON.stringify({ Sketch: 'Constrain remove constraints' })
|
|
)
|
|
}, 5000)
|
|
const startTime = Date.now()
|
|
while (
|
|
!codeManager.code.includes(expectedResult) &&
|
|
Date.now() - startTime < 5000
|
|
) {
|
|
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
}
|
|
expect(codeManager.code).toContain(expectedResult)
|
|
}, 10_000)
|
|
}
|
|
)
|
|
})
|
|
})
|