| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  | import fs from 'node:fs/promises' | 
					
						
							|  |  |  | import path from 'node:path' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-01 23:54:26 -07:00
										 |  |  | import { expect, test } from '@e2e/playwright/zoo-test' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  | test.describe('Point and click for boolean workflows', () => { | 
					
						
							|  |  |  |   // Boolean operations to test
 | 
					
						
							|  |  |  |   const booleanOperations = [ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       name: 'union', | 
					
						
							|  |  |  |       code: 'union([extrude001, extrude006])', | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       name: 'subtract', | 
					
						
							| 
									
										
										
										
											2025-06-26 16:43:53 -04:00
										 |  |  |       code: 'subtract(extrude001, tools = extrude006)', | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  |     }, | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       name: 'intersect', | 
					
						
							|  |  |  |       code: 'intersect([extrude001, extrude006])', | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   ] as const | 
					
						
							|  |  |  |   for (let i = 0; i < booleanOperations.length; i++) { | 
					
						
							|  |  |  |     const operation = booleanOperations[i] | 
					
						
							|  |  |  |     const operationName = operation.name | 
					
						
							|  |  |  |     const commandName = `Boolean ${ | 
					
						
							|  |  |  |       operationName.charAt(0).toUpperCase() + operationName.slice(1) | 
					
						
							|  |  |  |     }`
 | 
					
						
							|  |  |  |     test(`Create boolean operation -- ${operationName}`, async ({ | 
					
						
							|  |  |  |       context, | 
					
						
							|  |  |  |       homePage, | 
					
						
							|  |  |  |       cmdBar, | 
					
						
							|  |  |  |       editor, | 
					
						
							|  |  |  |       toolbar, | 
					
						
							|  |  |  |       scene, | 
					
						
							|  |  |  |       page, | 
					
						
							|  |  |  |     }) => { | 
					
						
							|  |  |  |       const file = await fs.readFile( | 
					
						
							|  |  |  |         path.resolve( | 
					
						
							|  |  |  |           __dirname, | 
					
						
							|  |  |  |           '../../', | 
					
						
							| 
									
										
										
										
											2025-04-09 01:41:48 +10:00
										 |  |  |           './rust/kcl-lib/e2e/executor/inputs/boolean-setup-with-sketch-on-faces.kcl' | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  |         ), | 
					
						
							|  |  |  |         'utf-8' | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |       await context.addInitScript((file) => { | 
					
						
							|  |  |  |         localStorage.setItem('persistCode', file) | 
					
						
							|  |  |  |       }, file) | 
					
						
							|  |  |  |       await homePage.goToModelingScene() | 
					
						
							|  |  |  |       await scene.settled(cmdBar) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Test coordinates for selection - these might need adjustment based on actual scene layout
 | 
					
						
							|  |  |  |       const cylinderPoint = { x: 592, y: 174 } | 
					
						
							|  |  |  |       const secondObjectPoint = { x: 683, y: 273 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Create mouse helpers for selecting objects
 | 
					
						
							|  |  |  |       const [clickFirstObject] = scene.makeMouseHelpers( | 
					
						
							|  |  |  |         cylinderPoint.x, | 
					
						
							|  |  |  |         cylinderPoint.y, | 
					
						
							|  |  |  |         { steps: 10 } | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |       const [clickSecondObject] = scene.makeMouseHelpers( | 
					
						
							|  |  |  |         secondObjectPoint.x, | 
					
						
							|  |  |  |         secondObjectPoint.y, | 
					
						
							|  |  |  |         { steps: 10 } | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       await test.step(`Test ${operationName} operation`, async () => { | 
					
						
							|  |  |  |         // Click the boolean operation button in the toolbar
 | 
					
						
							|  |  |  |         await toolbar.selectBoolean(operationName) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Verify command bar is showing the right command
 | 
					
						
							|  |  |  |         await expect(cmdBar.page.getByTestId('command-name')).toContainText( | 
					
						
							|  |  |  |           commandName | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Select first object in the scene, expect there to be a pixel diff from the selection color change
 | 
					
						
							|  |  |  |         await clickFirstObject({ pixelDiff: 50 }) | 
					
						
							| 
									
										
										
										
											2025-04-07 07:08:31 -04:00
										 |  |  |         await page.waitForTimeout(1000) | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // For subtract, we need to proceed to the next step before selecting the second object
 | 
					
						
							|  |  |  |         if (operationName !== 'subtract') { | 
					
						
							|  |  |  |           // should down shift key to select multiple objects
 | 
					
						
							|  |  |  |           await page.keyboard.down('Shift') | 
					
						
							| 
									
										
										
										
											2025-06-26 16:43:53 -04:00
										 |  |  |         } else { | 
					
						
							|  |  |  |           await cmdBar.progressCmdBar() | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Select second object
 | 
					
						
							|  |  |  |         await clickSecondObject({ pixelDiff: 50 }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-07 07:08:31 -04:00
										 |  |  |         await page.waitForTimeout(1000) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  |         // Confirm the operation in the command bar
 | 
					
						
							|  |  |  |         await cmdBar.progressCmdBar() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (operationName === 'union' || operationName === 'intersect') { | 
					
						
							|  |  |  |           await cmdBar.expectState({ | 
					
						
							|  |  |  |             stage: 'review', | 
					
						
							|  |  |  |             headerArguments: { | 
					
						
							|  |  |  |               Solids: '2 paths', | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             commandName, | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |         } else if (operationName === 'subtract') { | 
					
						
							|  |  |  |           await cmdBar.expectState({ | 
					
						
							|  |  |  |             stage: 'review', | 
					
						
							|  |  |  |             headerArguments: { | 
					
						
							| 
									
										
										
										
											2025-06-26 16:43:53 -04:00
										 |  |  |               Solids: '1 path', | 
					
						
							|  |  |  |               Tools: '1 path', | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  |             }, | 
					
						
							|  |  |  |             commandName, | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await cmdBar.submit() | 
					
						
							| 
									
										
										
										
											2025-05-02 15:34:21 -04:00
										 |  |  |         await scene.settled(cmdBar) | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  |         await editor.expectEditor.toContain(operation.code) | 
					
						
							|  |  |  |       }) | 
					
						
							| 
									
										
										
										
											2025-05-02 15:34:21 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       await test.step(`Delete ${operationName} operation via feature tree selection`, async () => { | 
					
						
							|  |  |  |         await toolbar.openPane('feature-tree') | 
					
						
							|  |  |  |         const op = await toolbar.getFeatureTreeOperation(operationName, 0) | 
					
						
							|  |  |  |         await op.click({ button: 'right' }) | 
					
						
							|  |  |  |         await page.getByTestId('context-menu-delete').click() | 
					
						
							|  |  |  |         await scene.settled(cmdBar) | 
					
						
							|  |  |  |         await toolbar.closePane('feature-tree') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Expect changes in ft and code
 | 
					
						
							|  |  |  |         await toolbar.openPane('code') | 
					
						
							|  |  |  |         await editor.expectEditor.not.toContain(operation.code) | 
					
						
							|  |  |  |         await expect( | 
					
						
							|  |  |  |           await toolbar.getFeatureTreeOperation(operationName, 0) | 
					
						
							|  |  |  |         ).not.toBeVisible() | 
					
						
							|  |  |  |       }) | 
					
						
							| 
									
										
										
										
											2025-03-28 14:56:48 +11:00
										 |  |  |     }) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }) |