Compare commits
55 Commits
jess/chang
...
lee-at-zoo
Author | SHA1 | Date | |
---|---|---|---|
2342d04fe2 | |||
ddac107dc1 | |||
313a21e82a | |||
b9875bb8cf | |||
8940f9b214 | |||
0af99af15e | |||
7f18aef49b | |||
062495c02d | |||
767fde869c | |||
49fcbdddba | |||
e06f76a6bb | |||
e98a957553 | |||
25af691911 | |||
cdc0fa4ed9 | |||
4d06a917f2 | |||
682fa50c1a | |||
496522e27d | |||
4c57cea22d | |||
70f9c8edf1 | |||
9de37879e5 | |||
91b5549a06 | |||
3471f73479 | |||
277c489e38 | |||
00122aae5e | |||
65adfd4497 | |||
8d0343c946 | |||
4c564bf332 | |||
ed1e2aedfd | |||
992fec6afb | |||
62a18dd2b3 | |||
2c673fba82 | |||
635314bb8d | |||
c75aafa60d | |||
fb192ee213 | |||
9e19d131eb | |||
81f70251e1 | |||
74f9afb2ca | |||
d03343d97d | |||
6c8a525762 | |||
c8177564e1 | |||
12bf41ab7e | |||
fbefff490c | |||
4c9851efbf | |||
2cca1376e2 | |||
c32a3edb39 | |||
955a2ffaf9 | |||
6bc8e45aa7 | |||
be0fdc53b5 | |||
cfbe805e14 | |||
2a60efc5ab | |||
deb83cf62c | |||
e3705bf7df | |||
ff887af540 | |||
1e4b6ce701 | |||
e642731529 |
8
.github/workflows/e2e-tests.yml
vendored
@ -281,7 +281,7 @@ jobs:
|
||||
os:
|
||||
- "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
|
||||
- namespace-profile-macos-8-cores
|
||||
- windows-latest-8-cores
|
||||
- windows-latest
|
||||
shardIndex: [1, 2, 3, 4]
|
||||
shardTotal: [4]
|
||||
# Disable macos and windows tests on hourly e2e tests since we only care
|
||||
@ -292,7 +292,7 @@ jobs:
|
||||
exclude:
|
||||
- os: namespace-profile-macos-8-cores
|
||||
isScheduled: true
|
||||
- os: windows-latest-8-cores
|
||||
- os: windows-latest
|
||||
isScheduled: true
|
||||
# TODO: add ref here for main and latest release tag
|
||||
runs-on: ${{ matrix.os }}
|
||||
@ -370,8 +370,8 @@ jobs:
|
||||
with:
|
||||
shell: bash
|
||||
command: .github/ci-cd-scripts/playwright-electron.sh ${{matrix.shardIndex}} ${{matrix.shardTotal}} ${{ env.OS_NAME }}
|
||||
timeout_minutes: 30
|
||||
max_attempts: 9
|
||||
timeout_minutes: 45
|
||||
max_attempts: 15
|
||||
env:
|
||||
FAIL_ON_CONSOLE_ERRORS: true
|
||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||
|
@ -46,8 +46,6 @@ test.describe('Point and click for boolean workflows', () => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Test coordinates for selection - these might need adjustment based on actual scene layout
|
||||
@ -77,6 +75,7 @@ test.describe('Point and click for boolean workflows', () => {
|
||||
|
||||
// Select first object in the scene, expect there to be a pixel diff from the selection color change
|
||||
await clickFirstObject({ pixelDiff: 50 })
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// For subtract, we need to proceed to the next step before selecting the second object
|
||||
if (operationName !== 'subtract') {
|
||||
@ -87,6 +86,8 @@ test.describe('Point and click for boolean workflows', () => {
|
||||
// Select second object
|
||||
await clickSecondObject({ pixelDiff: 50 })
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Confirm the operation in the command bar
|
||||
await cmdBar.progressCmdBar()
|
||||
|
||||
|
@ -4,6 +4,7 @@ import { uuidv4 } from '@src/lib/utils'
|
||||
|
||||
import type { HomePageFixture } from '@e2e/playwright/fixtures/homePageFixture'
|
||||
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
|
||||
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
|
||||
import { getUtils } from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
@ -15,6 +16,7 @@ test.describe(
|
||||
page: Page,
|
||||
homePage: HomePageFixture,
|
||||
scene: SceneFixture,
|
||||
toolbar: ToolbarFixture,
|
||||
plane: string,
|
||||
clickCoords: { x: number; y: number }
|
||||
) => {
|
||||
@ -59,9 +61,12 @@ test.describe(
|
||||
await u.sendCustomCmd(updateCamCommand)
|
||||
|
||||
await u.closeDebugPanel()
|
||||
|
||||
await page.mouse.click(clickCoords.x, clickCoords.y)
|
||||
await page.waitForTimeout(600) // wait for animation
|
||||
|
||||
await toolbar.waitUntilSketchingReady()
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'line Line', exact: true })
|
||||
).toBeVisible()
|
||||
@ -117,11 +122,12 @@ test.describe(
|
||||
]
|
||||
|
||||
for (const config of planeConfigs) {
|
||||
test(config.plane, async ({ page, homePage, scene }) => {
|
||||
test(config.plane, async ({ page, homePage, scene, toolbar }) => {
|
||||
await sketchOnPlaneAndBackSideTest(
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
toolbar,
|
||||
config.plane,
|
||||
config.coords
|
||||
)
|
||||
|
@ -15,6 +15,7 @@ test.describe('Code pane and errors', { tag: ['@skipWin'] }, () => {
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
|
||||
@ -36,7 +37,7 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Ensure no badge is present
|
||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
||||
@ -171,6 +172,8 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
context,
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
// Load the app with the working starter code
|
||||
await context.addInitScript((code) => {
|
||||
@ -180,9 +183,7 @@ extrude001 = extrude(sketch001, length = 5)`
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
// FIXME: await scene.waitForExecutionDone() does not work. It still fails.
|
||||
// I needed to increase this timeout to get this to pass.
|
||||
await page.waitForTimeout(10000)
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Ensure badge is present
|
||||
const codePaneButtonHolder = page.locator('#code-button-holder')
|
||||
|
@ -317,9 +317,13 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
|
||||
test('Can switch between sketch tools via command bar', async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
toolbar,
|
||||
}) => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const sketchButton = page.getByRole('button', { name: 'Start Sketch' })
|
||||
const cmdBarButton = page.getByRole('button', { name: 'Commands' })
|
||||
@ -343,7 +347,9 @@ test.describe('Command bar tests', { tag: ['@skipWin'] }, () => {
|
||||
|
||||
// Start a sketch
|
||||
await sketchButton.click()
|
||||
|
||||
await page.mouse.click(700, 200)
|
||||
await toolbar.waitUntilSketchingReady()
|
||||
|
||||
// Switch between sketch tools via the command bar
|
||||
await expect(lineToolButton).toHaveAttribute('aria-pressed', 'true')
|
||||
|
@ -11,7 +11,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
test(
|
||||
'export works on the first try',
|
||||
{ tag: ['@electron', '@skipLocalEngine'] },
|
||||
async ({ page, context, scene, tronApp }, testInfo) => {
|
||||
async ({ page, context, scene, tronApp, cmdBar }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
@ -32,44 +32,54 @@ test(
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await test.step('on open of project', async () => {
|
||||
// Open the project
|
||||
const projectName = page.getByText(`bracket`)
|
||||
await expect(projectName).toBeVisible()
|
||||
await projectName.click()
|
||||
await scene.waitForExecutionDone()
|
||||
await page.waitForTimeout(1_000) // wait for panel buttons to be available
|
||||
page.on('console', console.log)
|
||||
|
||||
// Expect zero errors in gutter
|
||||
await test.step('on open of project', async () => {
|
||||
await expect(page.getByText(`bracket`)).toBeVisible()
|
||||
|
||||
// open the project
|
||||
await page.getByText(`bracket`).click()
|
||||
|
||||
// expect zero errors in guter
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
// Click the export button
|
||||
// export the model
|
||||
const exportButton = page.getByTestId('export-pane-button')
|
||||
await expect(exportButton).toBeVisible()
|
||||
await exportButton.click()
|
||||
await page.waitForTimeout(1_000) // wait for export options to be available
|
||||
|
||||
// Select the first format option
|
||||
// Wait for the model to finish loading
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const gltfOption = page.getByText('glTF')
|
||||
const exportFileName = `main.gltf` // source file is named `main.kcl`
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
// The open file's name is `main.kcl`, so the export file name should be `main.gltf`
|
||||
const exportFileName = `main.gltf`
|
||||
|
||||
// Click the export button
|
||||
await exportButton.click()
|
||||
|
||||
await expect(gltfOption).toBeVisible()
|
||||
await expect(page.getByText('STL')).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Expect it to succeed
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
// Expect it to succeed.
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
@ -77,7 +87,6 @@ test(
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Check for the exported file
|
||||
const firstFileFullPath = path.resolve(
|
||||
getPlaywrightDownloadDir(tronApp.projectDirName),
|
||||
exportFileName
|
||||
@ -104,53 +113,59 @@ test(
|
||||
const u = await getUtils(page)
|
||||
await u.openFilePanel()
|
||||
|
||||
// Click on the other file
|
||||
const otherKclButton = page.getByRole('button', { name: 'other.kcl' })
|
||||
|
||||
// Click the file
|
||||
await otherKclButton.click()
|
||||
|
||||
// Close the file pane
|
||||
await u.closeFilePanel()
|
||||
await scene.waitForExecutionDone()
|
||||
await page.waitForTimeout(1_000) // wait for panel buttons to be available
|
||||
|
||||
// Expect zero errors in gutter
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// expect zero errors in guter
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
// Click the export button
|
||||
// export the model
|
||||
const exportButton = page.getByTestId('export-pane-button')
|
||||
await expect(exportButton).toBeVisible()
|
||||
await exportButton.click()
|
||||
await page.waitForTimeout(1_000) // wait for export options to be available
|
||||
|
||||
// Select the first format option
|
||||
const gltfOption = page.getByText('glTF')
|
||||
const exportFileName = `other.gltf` // source file is named `other.kcl`
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
// The open file's name is `other.kcl`, so the export file name should be `other.gltf`
|
||||
const exportFileName = `other.gltf`
|
||||
|
||||
// Click the export button
|
||||
await exportButton.click()
|
||||
|
||||
await expect(gltfOption).toBeVisible()
|
||||
await expect(page.getByText('STL')).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
await expect(submitButton).toBeVisible()
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Expect it to succeed
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
const successToastMessage = page.getByText(`Exported successfully`)
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
await test.step('Check the success toast message shows and nothing else', async () =>
|
||||
Promise.all([
|
||||
expect(alreadyExportingToastMessage).not.toBeVisible(),
|
||||
expect(errorToastMessage).not.toBeVisible(),
|
||||
expect(engineErrorToastMessage).not.toBeVisible(),
|
||||
expect(successToastMessage).toBeVisible(),
|
||||
expect(exportingToastMessage).not.toBeVisible(),
|
||||
]))
|
||||
|
||||
// Check for the exported file=
|
||||
const secondFileFullPath = path.resolve(
|
||||
getPlaywrightDownloadDir(tronApp.projectDirName),
|
||||
exportFileName
|
||||
|
@ -78,12 +78,14 @@ sketch001 = startSketchOn(XY)
|
||||
|
||||
// Ensure we execute the first time.
|
||||
await u.openDebugPanel()
|
||||
await expect(
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]')
|
||||
).toHaveCount(1)
|
||||
await expect(
|
||||
page.locator('[data-message-type="execution-done"]')
|
||||
).toHaveCount(2)
|
||||
await expect
|
||||
.poll(() =>
|
||||
page.locator('[data-receive-command-type="scene_clear_all"]').count()
|
||||
)
|
||||
.toBe(1)
|
||||
await expect
|
||||
.poll(() => page.locator('[data-message-type="execution-done"]').count())
|
||||
.toBe(2)
|
||||
|
||||
// Add whitespace to the end of the code.
|
||||
await u.codeLocator.click()
|
||||
@ -110,12 +112,14 @@ sketch001 = startSketchOn(XY)
|
||||
test('ensure we use the cache, and do not clear on append', async ({
|
||||
homePage,
|
||||
page,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await u.codeLocator.click()
|
||||
await page.keyboard.type(`sketch001 = startSketchOn(XY)
|
||||
@ -499,7 +503,7 @@ sketch_001 = startSketchOn(XY)
|
||||
await page.keyboard.press('ArrowLeft')
|
||||
await page.keyboard.press('ArrowRight')
|
||||
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// error in guter
|
||||
await expect(page.locator('.cm-lint-marker-info').first()).toBeVisible()
|
||||
@ -1315,38 +1319,4 @@ sketch001 = startSketchOn(XZ)
|
||||
const element = page.locator('[data-overlay-index="1"]')
|
||||
await expect(element).toHaveAttribute('data-overlay-visible', 'true')
|
||||
})
|
||||
|
||||
test(`Only show axis planes when there are no errors`, async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
profile001 = circle(sketch001, center = [-100.0, -100.0], radius = 50.0)
|
||||
|
||||
sketch002 = startSketchOn(XZ)
|
||||
profile002 = circle(sketch002, center = [-100.0, 100.0], radius = 50.0)
|
||||
extrude001 = extrude(profile002, length = 0)` // length = 0 is causing the error
|
||||
)
|
||||
})
|
||||
|
||||
const viewportSize = { width: 1200, height: 800 }
|
||||
await page.setBodyDimensions(viewportSize)
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await scene.expectPixelColor(
|
||||
TEST_COLORS.DARK_MODE_BKGD,
|
||||
// This is a position where the blue part of the axis plane is visible if its rendered
|
||||
{ x: viewportSize.width * 0.75, y: viewportSize.height * 0.2 },
|
||||
15
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -64,7 +64,7 @@ test.describe('Feature Tree pane', () => {
|
||||
test(
|
||||
'User can go to definition and go to function definition',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, homePage, scene, editor, toolbar }) => {
|
||||
async ({ context, homePage, scene, editor, toolbar, cmdBar, page }) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'test-sample')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -86,9 +86,13 @@ test.describe('Feature Tree pane', () => {
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await editor.closePane()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await toolbar.openFeatureTreePane()
|
||||
await expect
|
||||
.poll(() => page.getByText('Feature tree').count())
|
||||
.toBeGreaterThan(1)
|
||||
})
|
||||
|
||||
async function testViewSource({
|
||||
@ -254,7 +258,7 @@ test.describe('Feature Tree pane', () => {
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
await toolbar.openFeatureTreePane()
|
||||
})
|
||||
|
||||
@ -339,7 +343,7 @@ test.describe('Feature Tree pane', () => {
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
await toolbar.openFeatureTreePane()
|
||||
})
|
||||
|
||||
@ -414,8 +418,7 @@ profile003 = startProfileAt([0, -4.93], sketch001)
|
||||
const planeColor: [number, number, number] = [74, 74, 74]
|
||||
|
||||
await homePage.openProject('test-sample')
|
||||
// FIXME: @lf94 has a better way to verify execution completion, in a PR rn
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await test.step(`Verify we see the sketch`, async () => {
|
||||
await scene.expectPixelColor(sketchColor, testPoint, 10)
|
||||
|
@ -47,6 +47,7 @@ test.describe('integrations tests', () => {
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
await clickObj()
|
||||
await page.waitForTimeout(1000)
|
||||
await scene.moveNoWhere()
|
||||
await editor.expectState({
|
||||
activeLines: [
|
||||
@ -72,11 +73,11 @@ test.describe('integrations tests', () => {
|
||||
})
|
||||
await test.step('setup for next assertion', async () => {
|
||||
await toolbar.openFile('main.kcl')
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.waitForTimeout(1000)
|
||||
await clickObj()
|
||||
await page.waitForTimeout(1000)
|
||||
await scene.moveNoWhere()
|
||||
await page.waitForTimeout(1000)
|
||||
await editor.expectState({
|
||||
activeLines: [
|
||||
'|>startProfileAt([75.8,317.2],%)//[$startCapTag,$EndCapTag]',
|
||||
@ -89,7 +90,7 @@ test.describe('integrations tests', () => {
|
||||
await toolbar.expectFileTreeState(['main.kcl', fileName])
|
||||
})
|
||||
await test.step('check sketch mode is exited when opening a different file', async () => {
|
||||
await toolbar.openFile(fileName, { wait: false })
|
||||
await toolbar.openFile(fileName)
|
||||
|
||||
// check we're out of sketch mode
|
||||
await expect(toolbar.exitSketchBtn).not.toBeVisible()
|
||||
|
@ -112,22 +112,16 @@ export class CmdBarFixture {
|
||||
* and assumes we are past the `pickCommand` step.
|
||||
*/
|
||||
progressCmdBar = async (shouldFuzzProgressMethod = true) => {
|
||||
// FIXME: Progressing the command bar is a race condition. We have an async useEffect that reports the final state via useCalculateKclExpression. If this does not run quickly enough, it will not "fail" the continue because you can press continue if the state is not ready. E2E tests do not know this.
|
||||
// Wait 1250ms to assume the await executeAst of the KCL input field is finished
|
||||
await this.page.waitForTimeout(1250)
|
||||
if (shouldFuzzProgressMethod || Math.random() > 0.5) {
|
||||
const arrowButton = this.page.getByRole('button', {
|
||||
name: 'arrow right Continue',
|
||||
})
|
||||
if (await arrowButton.isVisible()) {
|
||||
await arrowButton.click()
|
||||
} else {
|
||||
await this.page
|
||||
.getByRole('button', { name: 'checkmark Submit command' })
|
||||
.click()
|
||||
}
|
||||
await this.page.waitForTimeout(2000)
|
||||
const arrowButton = this.page.getByRole('button', {
|
||||
name: 'arrow right Continue',
|
||||
})
|
||||
if (await arrowButton.isVisible()) {
|
||||
await arrowButton.click()
|
||||
} else {
|
||||
await this.page.keyboard.press('Enter')
|
||||
await this.page
|
||||
.getByRole('button', { name: 'checkmark Submit command' })
|
||||
.click()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,8 @@ export class AuthenticatedApp {
|
||||
}
|
||||
|
||||
async initialise(code = '') {
|
||||
await setup(this.context, this.page, this.testInfo)
|
||||
const testDir = this.testInfo.outputPath('electron-test-projects-dir')
|
||||
await setup(this.context, this.page, testDir, this.testInfo)
|
||||
const u = await getUtils(this.page)
|
||||
|
||||
await this.page.addInitScript(async (code) => {
|
||||
@ -102,11 +103,11 @@ export class ElectronZoo {
|
||||
return resolve(undefined)
|
||||
}
|
||||
|
||||
if (Date.now() - timeA > 10000) {
|
||||
if (Date.now() - timeA > 3000) {
|
||||
return resolve(undefined)
|
||||
}
|
||||
|
||||
setTimeout(checkDisconnected, 0)
|
||||
setTimeout(checkDisconnected, 1)
|
||||
}
|
||||
checkDisconnected()
|
||||
})
|
||||
@ -128,11 +129,9 @@ export class ElectronZoo {
|
||||
const that = this
|
||||
|
||||
const options = {
|
||||
timeout: 120000,
|
||||
args: ['.', '--no-sandbox'],
|
||||
env: {
|
||||
...process.env,
|
||||
TEST_SETTINGS_FILE_KEY: this.projectDirName,
|
||||
IS_PLAYWRIGHT: 'true',
|
||||
},
|
||||
...(process.env.ELECTRON_OVERRIDE_DIST_PATH
|
||||
@ -155,6 +154,7 @@ export class ElectronZoo {
|
||||
if (!this.electron) {
|
||||
this.electron = await electron.launch(options)
|
||||
|
||||
this.page = await this.electron.firstWindow()
|
||||
// Mac takes quite a long time to create the first window in CI.
|
||||
// Turns out we can't trust firstWindow() either. So loop.
|
||||
let timeoutId: ReturnType<typeof setTimeout>
|
||||
@ -200,7 +200,14 @@ export class ElectronZoo {
|
||||
|
||||
await this.context.tracing.startChunk()
|
||||
|
||||
await setup(this.context, this.page, testInfo)
|
||||
// THIS IS ABSOLUTELY NECESSARY TO CHANGE THE PROJECT DIRECTORY BETWEEN
|
||||
// TESTS BECAUSE OF THE ELECTRON INSTANCE REUSE.
|
||||
await this.electron?.evaluate(({ app }, projectDirName) => {
|
||||
// @ts-ignore can't declaration merge see main.ts
|
||||
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
|
||||
}, this.projectDirName)
|
||||
|
||||
await setup(this.context, this.page, this.projectDirName, testInfo)
|
||||
|
||||
await this.cleanProjectDir()
|
||||
|
||||
@ -250,11 +257,6 @@ export class ElectronZoo {
|
||||
// return app.reuseWindowForTest();
|
||||
// });
|
||||
|
||||
await this.electron?.evaluate(({ app }, projectDirName) => {
|
||||
// @ts-ignore can't declaration merge see main.ts
|
||||
app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName
|
||||
}, this.projectDirName)
|
||||
|
||||
// Always start at the root view
|
||||
await this.page.goto(this.firstUrl)
|
||||
|
||||
@ -278,8 +280,9 @@ export class ElectronZoo {
|
||||
// Not a problem if it already exists.
|
||||
}
|
||||
|
||||
const tempSettingsFilePath = path.join(
|
||||
const tempSettingsFilePath = path.resolve(
|
||||
this.projectDirName,
|
||||
'..',
|
||||
SETTINGS_FILE_NAME
|
||||
)
|
||||
|
||||
|
@ -43,21 +43,13 @@ type DragFromHandler = (
|
||||
export class SceneFixture {
|
||||
public page: Page
|
||||
public streamWrapper!: Locator
|
||||
public loadingIndicator!: Locator
|
||||
public networkToggleConnected!: Locator
|
||||
public startEditSketchBtn!: Locator
|
||||
|
||||
get exeIndicator() {
|
||||
return this.page
|
||||
.getByTestId('model-state-indicator-execution-done')
|
||||
.or(this.page.getByTestId('model-state-indicator-receive-reliable'))
|
||||
}
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page
|
||||
this.streamWrapper = page.getByTestId('stream')
|
||||
this.networkToggleConnected = page.getByTestId('network-toggle-ok')
|
||||
this.loadingIndicator = this.streamWrapper.getByTestId('loading')
|
||||
this.startEditSketchBtn = page
|
||||
.getByRole('button', { name: 'Start Sketch' })
|
||||
.or(page.getByRole('button', { name: 'Edit Sketch' }))
|
||||
@ -231,10 +223,6 @@ export class SceneFixture {
|
||||
}
|
||||
}
|
||||
|
||||
waitForExecutionDone = async () => {
|
||||
await expect(this.exeIndicator).toBeVisible({ timeout: 30000 })
|
||||
}
|
||||
|
||||
connectionEstablished = async () => {
|
||||
const timeout = 30000
|
||||
await expect(this.networkToggleConnected).toBeVisible({ timeout })
|
||||
@ -243,6 +231,9 @@ export class SceneFixture {
|
||||
settled = async (cmdBar: CmdBarFixture) => {
|
||||
const u = await getUtils(this.page)
|
||||
|
||||
await expect(this.startEditSketchBtn).not.toBeDisabled()
|
||||
await expect(this.startEditSketchBtn).toBeVisible()
|
||||
|
||||
await cmdBar.openCmdBar()
|
||||
await cmdBar.chooseCommand('Settings · app · show debug panel')
|
||||
await cmdBar.selectOption({ name: 'on' }).click()
|
||||
@ -250,10 +241,6 @@ export class SceneFixture {
|
||||
await u.openDebugPanel()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.closeDebugPanel()
|
||||
|
||||
await this.waitForExecutionDone()
|
||||
await expect(this.startEditSketchBtn).not.toBeDisabled()
|
||||
await expect(this.startEditSketchBtn).toBeVisible()
|
||||
}
|
||||
|
||||
expectPixelColor = async (
|
||||
|
@ -84,12 +84,6 @@ export class ToolbarFixture {
|
||||
return this.page.getByTestId('app-logo')
|
||||
}
|
||||
|
||||
get exeIndicator() {
|
||||
return this.page
|
||||
.getByTestId('model-state-indicator-receive-reliable')
|
||||
.or(this.page.getByTestId('model-state-indicator-execution-done'))
|
||||
}
|
||||
|
||||
startSketchPlaneSelection = async () =>
|
||||
doAndWaitForImageDiff(this.page, () => this.startSketchBtn.click(), 500)
|
||||
|
||||
@ -165,16 +159,10 @@ export class ToolbarFixture {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Opens file by it's name and waits for execution to finish
|
||||
* Opens file by it's name
|
||||
*/
|
||||
openFile = async (
|
||||
fileName: string,
|
||||
{ wait }: { wait?: boolean } = { wait: true }
|
||||
) => {
|
||||
openFile = async (fileName: string) => {
|
||||
await this.filePane.getByText(fileName).click()
|
||||
if (wait) {
|
||||
await expect(this.exeIndicator).toBeVisible({ timeout: 15_000 })
|
||||
}
|
||||
}
|
||||
selectCenterRectangle = async () => {
|
||||
await this.page
|
||||
|
@ -10,6 +10,7 @@ test.describe('Import UI tests', () => {
|
||||
toolbar,
|
||||
scene,
|
||||
editor,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const projectDir = path.join(dir, 'import-test')
|
||||
@ -61,7 +62,7 @@ sketch002 = startSketchOn(extrude001, seg01)`
|
||||
})
|
||||
|
||||
await homePage.openProject('import-test')
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await scene.moveCameraTo(
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
test(
|
||||
'When machine-api server not found butt is disabled and shows the reason',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -23,10 +23,7 @@ test(
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const notFoundText = 'Machine API server was not discovered'
|
||||
await expect(page.getByText(notFoundText).first()).not.toBeVisible()
|
||||
@ -47,7 +44,7 @@ test(
|
||||
test(
|
||||
'When machine-api server not found home screen & project status shows the reason',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -71,10 +68,7 @@ test(
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(page.getByText(notFoundText).nth(1)).not.toBeVisible()
|
||||
|
||||
|
@ -88,7 +88,7 @@ test.describe('Named view tests', () => {
|
||||
|
||||
// Create and load project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Create named view
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
@ -110,14 +110,17 @@ test.describe('Named view tests', () => {
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
await expect(async () => {
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
}).toPass()
|
||||
})
|
||||
test('Verify named view gets deleted', async ({
|
||||
cmdBar,
|
||||
@ -130,7 +133,7 @@ test.describe('Named view tests', () => {
|
||||
|
||||
// Create project and go into the project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Create a new named view
|
||||
await cmdBar.openCmdBar()
|
||||
@ -152,14 +155,16 @@ test.describe('Named view tests', () => {
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
await expect(async () => {
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
}).toPass()
|
||||
|
||||
// Delete a named view
|
||||
await cmdBar.openCmdBar()
|
||||
@ -167,14 +172,16 @@ test.describe('Named view tests', () => {
|
||||
cmdBar.selectOption({ name: myNamedView2 })
|
||||
await cmdBar.progressCmdBar(false)
|
||||
|
||||
// Read project.toml into memory again since we deleted a named view
|
||||
tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
await expect(async () => {
|
||||
// Read project.toml into memory again since we deleted a named view
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// // Write the entire tomlString to a snapshot.
|
||||
// // There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted')
|
||||
// // Write the entire tomlString to a snapshot.
|
||||
// // There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-deleted')
|
||||
}).toPass()
|
||||
})
|
||||
test('Verify named view gets loaded', async ({
|
||||
cmdBar,
|
||||
@ -186,7 +193,7 @@ test.describe('Named view tests', () => {
|
||||
|
||||
// Create project and go into the project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Create a new named view
|
||||
await cmdBar.openCmdBar()
|
||||
@ -208,14 +215,16 @@ test.describe('Named view tests', () => {
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
await expect(async () => {
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-named-view-gets-created')
|
||||
}).toPass()
|
||||
|
||||
// Create a load a named view
|
||||
await cmdBar.openCmdBar()
|
||||
@ -239,7 +248,7 @@ test.describe('Named view tests', () => {
|
||||
|
||||
// Create and load project
|
||||
await createProject({ name: projectName, page })
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Create named view
|
||||
const projectDirName = testInfo.outputPath('electron-test-projects-dir')
|
||||
@ -282,13 +291,15 @@ test.describe('Named view tests', () => {
|
||||
expect(exists).toBe(true)
|
||||
}).toPass()
|
||||
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
await expect(async () => {
|
||||
// Read project.toml into memory
|
||||
let tomlString = await fsp.readFile(tempProjectSettingsFilePath, 'utf-8')
|
||||
// Rewrite the uuids in the named views to match snapshot otherwise they will be randomly generated from rust and break
|
||||
tomlString = tomlStringOverWriteNamedViewUuids(tomlString)
|
||||
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-two-named-view-gets-created')
|
||||
// Write the entire tomlString to a snapshot.
|
||||
// There are many key/value pairs to check this is a safer match.
|
||||
expect(tomlString).toMatchSnapshot('verify-two-named-view-gets-created')
|
||||
}).toPass()
|
||||
})
|
||||
})
|
||||
|
@ -12,13 +12,21 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const newProject =
|
||||
app.applicationMenu.getMenuItemById('File.New project')
|
||||
if (!newProject) fail()
|
||||
newProject.click()
|
||||
})
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const newProject =
|
||||
app.applicationMenu.getMenuItemById('File.New project')
|
||||
if (!newProject) return false
|
||||
newProject.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
.toBe(true)
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
@ -32,13 +40,21 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const openProject =
|
||||
app.applicationMenu.getMenuItemById('File.Open project')
|
||||
if (!openProject) fail()
|
||||
openProject.click()
|
||||
})
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const openProject =
|
||||
app.applicationMenu.getMenuItemById('File.Open project')
|
||||
if (!openProject) {
|
||||
return false
|
||||
}
|
||||
openProject.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
.toBe(true)
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
@ -56,14 +72,23 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const userSettings = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.User settings'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
console.log(app)
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const userSettings = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.User settings'
|
||||
)
|
||||
if (!userSettings) return false
|
||||
userSettings.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!userSettings) fail()
|
||||
userSettings.click()
|
||||
})
|
||||
.toBe(true)
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
// You are viewing the user tab
|
||||
@ -77,17 +102,27 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
cmdBar,
|
||||
page,
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const keybindings = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Keybindings'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const keybindings = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Keybindings'
|
||||
)
|
||||
if (!keybindings) {
|
||||
return false
|
||||
}
|
||||
keybindings.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!keybindings) fail()
|
||||
keybindings.click()
|
||||
})
|
||||
.toBe(true)
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
// You are viewing the keybindings tab
|
||||
@ -102,14 +137,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.User default units'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.User default units'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
const defaultUnit = settings.locator('#defaultUnit')
|
||||
@ -119,14 +162,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Theme'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Theme'
|
||||
)
|
||||
if (!menu) {
|
||||
return false
|
||||
}
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
// Check that the command bar is opened
|
||||
await expect(cmdBar.cmdBarElement).toBeVisible()
|
||||
// Check the placeholder project name exists
|
||||
@ -144,14 +195,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Theme color'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'File.Preferences.Theme color'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
const defaultUnit = settings.locator('#themeColor')
|
||||
@ -165,13 +224,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById('File.Sign out')
|
||||
if (!menu) fail()
|
||||
// FIXME: Add back when you can actually sign out
|
||||
// menu.click()
|
||||
})
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu =
|
||||
app.applicationMenu.getMenuItemById('File.Sign out')
|
||||
if (!menu) {
|
||||
return false
|
||||
}
|
||||
// FIXME: Add back when you can actually sign out
|
||||
// menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
.toBe(true)
|
||||
// FIXME: When signing out during E2E the page is not bound correctly.
|
||||
// It cannot find the button
|
||||
// const signIn = page.getByTestId('sign-in-button')
|
||||
@ -184,14 +252,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Rename project'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Rename project'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
@ -203,20 +279,27 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Delete project'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Delete project'
|
||||
)
|
||||
if (!menu) {
|
||||
return false
|
||||
}
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
// Check the placeholder project name exists
|
||||
const actual = await cmdBar.cmdBarElement
|
||||
.getByTestId('command-name')
|
||||
.textContent()
|
||||
const actual = async () =>
|
||||
cmdBar.cmdBarElement.getByTestId('command-name').textContent()
|
||||
const expected = 'Delete project'
|
||||
expect(actual).toBe(expected)
|
||||
await expect.poll(async () => await actual()).toBe(expected)
|
||||
})
|
||||
test('Home.Edit.Change project directory', async ({
|
||||
tronApp,
|
||||
@ -226,14 +309,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Change project directory'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Edit.Change project directory'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
const settings = page.getByTestId('settings-dialog-panel')
|
||||
await expect(settings).toBeVisible()
|
||||
const projectDirectory = settings.locator('#projectDirectory')
|
||||
@ -249,14 +340,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'View.Command Palette...'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'View.Command Palette...'
|
||||
)
|
||||
if (!menu) {
|
||||
return false
|
||||
}
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
// Check the placeholder project name exists
|
||||
const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search')
|
||||
await expect(actual).toBeVisible()
|
||||
@ -267,14 +366,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Show all commands'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Show all commands'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
// Check the placeholder project name exists
|
||||
const actual = cmdBar.cmdBarElement.getByTestId('cmd-bar-search')
|
||||
await expect(actual).toBeVisible()
|
||||
@ -283,13 +390,21 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.KCL code samples'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.KCL code samples'
|
||||
)
|
||||
if (!menu) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
})
|
||||
.toBe(true)
|
||||
})
|
||||
test('Home.Help.Refresh and report a bug', async ({
|
||||
tronApp,
|
||||
@ -299,14 +414,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Refresh and report a bug'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
return false
|
||||
}
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Refresh and report a bug'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
// Core dump and refresh magic number timeout
|
||||
await page.waitForTimeout(7000)
|
||||
const actual = page.getByText(
|
||||
@ -318,14 +441,22 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
if (!tronApp) fail()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Reset onboarding'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Reset onboarding'
|
||||
)
|
||||
if (!menu) {
|
||||
return false
|
||||
}
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
|
||||
const actual = page.getByText(
|
||||
`This is a hardware design tool that lets you edit visually, with code, or both. It's powered by the KittyCAD Design API, the first API created for anyone to build hardware design tools.`
|
||||
@ -345,7 +476,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
}) => {
|
||||
if (!tronApp) fail()
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -377,7 +508,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -413,7 +544,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -450,7 +581,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -487,7 +618,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -523,7 +654,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -560,7 +691,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -596,7 +727,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -630,7 +761,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -663,7 +794,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -700,7 +831,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -733,21 +864,28 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
throw new Error('app or app.applicationMenu is missing')
|
||||
}
|
||||
const menu = app.applicationMenu.getMenuItemById('File.Sign out')
|
||||
if (!menu) {
|
||||
throw new Error('File.Sign out')
|
||||
}
|
||||
// FIXME: Add back when you can actually sign out
|
||||
// menu.click()
|
||||
})
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) {
|
||||
throw new Error('app or app.applicationMenu is missing')
|
||||
}
|
||||
const menu =
|
||||
app.applicationMenu.getMenuItemById('File.Sign out')
|
||||
if (!menu) {
|
||||
throw new Error('File.Sign out')
|
||||
}
|
||||
// FIXME: Add back when you can actually sign out
|
||||
// menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
.toBe(true)
|
||||
// FIXME: When signing out during E2E the page is not bound correctly.
|
||||
// It cannot find the button
|
||||
// const signIn = page.getByTestId('sign-in-button')
|
||||
@ -767,7 +905,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -802,7 +940,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -837,7 +975,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -867,7 +1005,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -902,7 +1040,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -937,7 +1075,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
@ -971,7 +1109,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1003,7 +1141,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1039,7 +1177,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1075,7 +1213,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1112,7 +1250,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1141,7 +1279,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1170,7 +1308,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1199,7 +1337,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1228,7 +1366,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1257,7 +1395,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1286,7 +1424,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1315,7 +1453,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1344,7 +1482,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1381,7 +1519,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1418,7 +1556,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1455,7 +1593,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1488,7 +1626,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1521,7 +1659,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1554,7 +1692,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1587,7 +1725,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1621,7 +1759,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1658,7 +1796,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1695,7 +1833,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1733,7 +1871,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1770,7 +1908,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1807,7 +1945,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1844,7 +1982,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1881,7 +2019,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1918,7 +2056,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1956,7 +2094,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -1994,7 +2132,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -2032,7 +2170,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -2071,7 +2209,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -2099,7 +2237,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
@ -2124,20 +2262,26 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) fail()
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Refresh and report a bug'
|
||||
await expect
|
||||
.poll(
|
||||
async () =>
|
||||
await tronApp.electron.evaluate(async ({ app }) => {
|
||||
if (!app || !app.applicationMenu) return false
|
||||
const menu = app.applicationMenu.getMenuItemById(
|
||||
'Help.Refresh and report a bug'
|
||||
)
|
||||
if (!menu) return false
|
||||
menu.click()
|
||||
return true
|
||||
})
|
||||
)
|
||||
if (!menu) fail()
|
||||
menu.click()
|
||||
})
|
||||
.toBe(true)
|
||||
// Core dump and refresh magic number timeout
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
await expect(toolbar.startSketchBtn).toBeVisible()
|
||||
})
|
||||
test('Modeling.Help.Reset onboarding', async ({
|
||||
@ -2152,7 +2296,7 @@ test.describe('Native file menu', { tag: ['@electron'] }, () => {
|
||||
return
|
||||
}
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Run electron snippet to find the Menu!
|
||||
await page.waitForTimeout(100) // wait for createModelingPageMenu() to run
|
||||
|
@ -5,13 +5,14 @@ import path from 'node:path'
|
||||
import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
|
||||
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
|
||||
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
|
||||
import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
|
||||
import { orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
// test file is for testing point an click code gen functionality that's not sketch mode related
|
||||
|
||||
test.describe('Point-and-click tests', () => {
|
||||
test('verify extruding circle works', async ({
|
||||
page,
|
||||
context,
|
||||
homePage,
|
||||
cmdBar,
|
||||
@ -30,8 +31,9 @@ test.describe('Point-and-click tests', () => {
|
||||
await context.addInitScript((file) => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
const [clickCircle, moveToCircle] = scene.makeMouseHelpers(582, 217)
|
||||
|
||||
@ -72,7 +74,6 @@ test.describe('Point-and-click tests', () => {
|
||||
|
||||
await test.step('do extrude flow and check extrude code is added to editor', async () => {
|
||||
await toolbar.extrudeButton.click()
|
||||
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'distance',
|
||||
@ -186,6 +187,7 @@ test.describe('Point-and-click tests', () => {
|
||||
editor,
|
||||
toolbar,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const file = await fs.readFile(
|
||||
path.resolve(
|
||||
@ -200,9 +202,7 @@ test.describe('Point-and-click tests', () => {
|
||||
}, file)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await expect(
|
||||
page.getByTestId('model-state-indicator-receive-reliable')
|
||||
).toBeVisible()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene)
|
||||
|
||||
@ -377,6 +377,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
editor,
|
||||
toolbar,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const file = await fs.readFile(
|
||||
path.resolve(
|
||||
@ -392,7 +393,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const sketchOnAChamfer = _sketchOnAChamfer(page, editor, toolbar, scene)
|
||||
|
||||
@ -479,6 +480,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
await page.setBodyDimensions(viewPortSize)
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Constants and locators
|
||||
// These are mappings from screenspace to KCL coordinates,
|
||||
@ -537,8 +539,7 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
await toolbar.startSketchPlaneSelection()
|
||||
await moveToXzPlane()
|
||||
await clickOnXzPlane()
|
||||
// timeout wait for engine animation is unavoidable
|
||||
await page.waitForTimeout(600)
|
||||
await toolbar.waitUntilSketchingReady()
|
||||
await editor.expectEditor.toContain(expectedCodeSnippets.sketchOnXzPlane)
|
||||
})
|
||||
await test.step(`Place a point a few pixels off the middle, verify it still snaps to 0,0`, async () => {
|
||||
@ -580,9 +581,8 @@ profile001 = startProfileAt([205.96, 254.59], sketch002)
|
||||
editor,
|
||||
toolbar,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
|
||||
const initialCode = `closedSketch = startSketchOn(XZ)
|
||||
|> circle(center = [8, 5], radius = 2)
|
||||
openSketch = startSketchOn(XY)
|
||||
@ -599,8 +599,6 @@ openSketch = startSketchOn(XY)
|
||||
}, initialCode)
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
const pointInsideCircle = {
|
||||
x: viewPortSize.width * 0.63,
|
||||
@ -625,15 +623,16 @@ openSketch = startSketchOn(XY)
|
||||
const exitSketch = async () => {
|
||||
await test.step(`Exit sketch mode`, async () => {
|
||||
await toolbar.exitSketchBtn.click()
|
||||
await expect(toolbar.exitSketchBtn).not.toBeVisible()
|
||||
await expect(toolbar.startSketchBtn).toBeEnabled()
|
||||
})
|
||||
}
|
||||
|
||||
await test.step(`Double-click on the closed sketch`, async () => {
|
||||
await scene.settled(cmdBar)
|
||||
await moveToCircle()
|
||||
await page.waitForTimeout(1000)
|
||||
await dblClickCircle()
|
||||
await expect(toolbar.startSketchBtn).not.toBeVisible()
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(toolbar.exitSketchBtn).toBeVisible()
|
||||
await editor.expectState({
|
||||
activeLines: [`|>circle(center=[8,5],radius=2)`],
|
||||
@ -670,7 +669,6 @@ openSketch = startSketchOn(XY)
|
||||
// There is a full execution after exiting sketch that clears the scene.
|
||||
await page.waitForTimeout(500)
|
||||
await dblClickOpenPath()
|
||||
await expect(toolbar.startSketchBtn).not.toBeVisible()
|
||||
await expect(toolbar.exitSketchBtn).toBeVisible()
|
||||
// Wait for enter sketch mode to complete
|
||||
await page.waitForTimeout(500)
|
||||
@ -1031,6 +1029,9 @@ openSketch = startSketchOn(XY)
|
||||
})
|
||||
await test.step(`Go through the command bar flow`, async () => {
|
||||
await toolbar.offsetPlaneButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'plane',
|
||||
@ -1088,6 +1089,7 @@ openSketch = startSketchOn(XY)
|
||||
const expectedLine = `axis=X,`
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
await test.step(`Go through the command bar flow`, async () => {
|
||||
await toolbar.helixButton.click()
|
||||
@ -1106,6 +1108,7 @@ openSketch = startSketchOn(XY)
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await expect.poll(() => page.getByText('Axis').count()).toBe(6)
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -1233,6 +1236,7 @@ openSketch = startSketchOn(XY)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await test.step(`Go through the command bar flow`, async () => {
|
||||
await toolbar.closePane('code')
|
||||
@ -1252,15 +1256,22 @@ openSketch = startSketchOn(XY)
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.selectOption({ name: 'Edge' }).click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await clickOnEdge()
|
||||
await page.waitForTimeout(1000)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(1000)
|
||||
await cmdBar.argumentInput.focus()
|
||||
await page.waitForTimeout(1000)
|
||||
await page.keyboard.insertText('20')
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.keyboard.insertText('0')
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.keyboard.insertText('1')
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.keyboard.insertText('100')
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
@ -1274,6 +1285,7 @@ openSketch = startSketchOn(XY)
|
||||
commandName: 'Helix',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||
@ -1369,7 +1381,7 @@ extrude001 = extrude(profile001, length = 100)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 620, y: 257 }
|
||||
@ -1530,6 +1542,9 @@ extrude001 = extrude(profile001, length = 100)
|
||||
if (!shouldPreselect) {
|
||||
await test.step(`Go through the command bar flow without preselected sketches`, async () => {
|
||||
await toolbar.loftButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
@ -1579,6 +1594,7 @@ extrude001 = extrude(profile001, length = 100)
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const initialCode = `sketch001 = startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = 30)
|
||||
@ -1592,7 +1608,7 @@ loft001 = loft([sketch001, sketch002])
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 575, y: 200 }
|
||||
@ -1687,7 +1703,7 @@ sketch002 = startSketchOn(XZ)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
|
||||
@ -1707,6 +1723,9 @@ sketch002 = startSketchOn(XZ)
|
||||
|
||||
await test.step(`Go through the command bar flow`, async () => {
|
||||
await toolbar.sweepButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Sweep',
|
||||
currentArgKey: 'target',
|
||||
@ -1826,7 +1845,7 @@ sketch002 = startSketchOn(XZ)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 700, y: 250 }
|
||||
@ -1843,6 +1862,9 @@ sketch002 = startSketchOn(XZ)
|
||||
|
||||
await test.step(`Go through the command bar flow and fail validation with a toast`, async () => {
|
||||
await toolbar.sweepButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Sweep',
|
||||
currentArgKey: 'target',
|
||||
@ -2059,6 +2081,9 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
await test.step(`Open fillet UI without selecting edges`, async () => {
|
||||
await page.waitForTimeout(100)
|
||||
await toolbar.filletButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
@ -2184,6 +2209,7 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
homePage,
|
||||
scene,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const initialCode = `sketch001 = startSketchOn(XY)
|
||||
profile001 = circle(
|
||||
@ -2200,7 +2226,7 @@ fillet001 = fillet(extrude001, radius = 5, tags = [getOppositeEdge(seg01)])
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await test.step('Double-click in feature tree and expect error toast', async () => {
|
||||
await toolbar.openPane('feature-tree')
|
||||
@ -2521,7 +2547,7 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
// Test 1: Command bar flow with preselected edges
|
||||
@ -2554,6 +2580,7 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
stage: 'arguments',
|
||||
})
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(1000)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Chamfer',
|
||||
highlightedHeaderArg: 'length',
|
||||
@ -2565,7 +2592,10 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
},
|
||||
stage: 'arguments',
|
||||
})
|
||||
await cmdBar.argumentInput.focus()
|
||||
await page.waitForTimeout(1000)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(1000)
|
||||
await cmdBar.expectState({
|
||||
commandName: 'Chamfer',
|
||||
headerArguments: {
|
||||
@ -2649,6 +2679,9 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
await test.step(`Open chamfer UI without selecting edges`, async () => {
|
||||
await page.waitForTimeout(100)
|
||||
await toolbar.chamferButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
@ -2771,6 +2804,7 @@ extrude001 = extrude(sketch001, length = -12)
|
||||
scene,
|
||||
editor,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
}) => {
|
||||
// Code samples
|
||||
const initialCode = `@settings(defaultLengthUnit = in)
|
||||
@ -2814,7 +2848,7 @@ chamfer04 = chamfer(extrude001, length = 5, tags = [getOppositeEdge(seg02)])
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// verify modeling scene is loaded
|
||||
await scene.expectPixelColor(
|
||||
@ -2936,9 +2970,11 @@ extrude001 = extrude(sketch001, length = 30)
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
}, initialCode)
|
||||
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 575, y: 200 }
|
||||
@ -2955,6 +2991,9 @@ extrude001 = extrude(sketch001, length = 30)
|
||||
if (!shouldPreselect) {
|
||||
await test.step(`Go through the command bar flow without preselected faces`, async () => {
|
||||
await toolbar.shellButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
@ -3015,7 +3054,6 @@ extrude001 = extrude(sketch001, length = 30)
|
||||
})
|
||||
|
||||
await test.step('Edit shell via feature tree selection works', async () => {
|
||||
await toolbar.closePane('code')
|
||||
await toolbar.openPane('feature-tree')
|
||||
const operationButton = await toolbar.getFeatureTreeOperation(
|
||||
'Shell',
|
||||
@ -3044,7 +3082,6 @@ extrude001 = extrude(sketch001, length = 30)
|
||||
await cmdBar.progressCmdBar()
|
||||
await toolbar.closePane('feature-tree')
|
||||
await scene.expectPixelColor([150, 150, 150], testPoint, 15)
|
||||
await toolbar.openPane('code')
|
||||
await editor.expectEditor.toContain(editedShellDeclaration)
|
||||
await editor.expectState({
|
||||
diagnostics: [],
|
||||
@ -3079,7 +3116,7 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 580, y: 180 }
|
||||
@ -3097,6 +3134,9 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
|
||||
await test.step(`Go through the command bar flow, selecting a wall and keeping default thickness`, async () => {
|
||||
await toolbar.shellButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
@ -3108,6 +3148,9 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
highlightedHeaderArg: 'selection',
|
||||
commandName: 'Shell',
|
||||
})
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await clickOnCap()
|
||||
await page.keyboard.down('Shift')
|
||||
await clickOnWall()
|
||||
@ -3116,6 +3159,7 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
@ -3124,7 +3168,9 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
},
|
||||
commandName: 'Shell',
|
||||
})
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(500)
|
||||
})
|
||||
|
||||
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
|
||||
@ -3139,7 +3185,6 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
})
|
||||
|
||||
await test.step('Edit shell via feature tree selection works', async () => {
|
||||
await editor.closePane()
|
||||
const operationButton = await toolbar.getFeatureTreeOperation('Shell', 0)
|
||||
await operationButton.dblclick({ button: 'left' })
|
||||
await cmdBar.expectState({
|
||||
@ -3154,6 +3199,7 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
})
|
||||
await page.keyboard.insertText('1')
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
@ -3164,7 +3210,6 @@ extrude001 = extrude(sketch001, length = 40)
|
||||
await cmdBar.progressCmdBar()
|
||||
await toolbar.closePane('feature-tree')
|
||||
await scene.expectPixelColor([150, 150, 150], testPoint, 15)
|
||||
await toolbar.openPane('code')
|
||||
await editor.expectEditor.toContain(editedShellDeclaration)
|
||||
await editor.expectState({
|
||||
diagnostics: [],
|
||||
@ -3218,7 +3263,7 @@ extrude002 = extrude(sketch002, length = 50)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 580, y: 320 }
|
||||
@ -3243,12 +3288,13 @@ extrude002 = extrude(sketch002, length = 50)
|
||||
highlightedHeaderArg: 'selection',
|
||||
commandName: 'Shell',
|
||||
})
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await clickOnCap()
|
||||
await page.waitForTimeout(500)
|
||||
await page.waitForTimeout(1000)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.progressCmdBar()
|
||||
await page.waitForTimeout(500)
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
@ -3306,7 +3352,7 @@ profile001 = startProfileAt([-20, 20], sketch001)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
await toolbar.openPane('feature-tree')
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
@ -3386,7 +3432,7 @@ sweep001 = sweep(sketch001, path = sketch002)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 500, y: 250 }
|
||||
@ -3399,6 +3445,9 @@ sweep001 = sweep(sketch001, path = sketch002)
|
||||
|
||||
await test.step(`Go through the Shell flow and fail validation with a toast`, async () => {
|
||||
await toolbar.shellButton.click()
|
||||
await expect
|
||||
.poll(() => page.getByText('Please select one').count())
|
||||
.toBe(1)
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'selection',
|
||||
@ -3462,12 +3511,13 @@ segAng(rectangleSegmentA002),
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// select line of code
|
||||
const codeToSelecton = `segAng(rectangleSegmentA002) - 90,`
|
||||
const codeToSelection = `segAng(rectangleSegmentA002) - 90,`
|
||||
// revolve
|
||||
await page.getByText(codeToSelecton).click()
|
||||
await editor.scrollToText(codeToSelection)
|
||||
await page.getByText(codeToSelection).click()
|
||||
await toolbar.revolveButton.click()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -3541,15 +3591,17 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// select line of code
|
||||
const codeToSelecton = `center = [-11.34, 10.0]`
|
||||
const codeToSelection = `center = [-11.34, 10.0]`
|
||||
// revolve
|
||||
await page.getByText(codeToSelecton).click()
|
||||
await editor.scrollToText(codeToSelection)
|
||||
await page.getByText(codeToSelection).click()
|
||||
await toolbar.revolveButton.click()
|
||||
await page.getByText('Edge', { exact: true }).click()
|
||||
const lineCodeToSelection = `|> angledLine([0, 202.6], %, $rectangleSegmentA001)`
|
||||
const lineCodeToSelection = `angledLine([0, 202.6], %, $rectangleSegmentA001)`
|
||||
await page.getByText(lineCodeToSelection).click()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -3595,6 +3647,7 @@ sketch002 = startSketchOn(extrude001, rectangleSegmentA001)
|
||||
await editor.expectEditor.toContain(
|
||||
newCodeToFind.replace('angle = 360', 'angle = angle001')
|
||||
)
|
||||
expect(editor.expectEditor.toContain(newCodeToFind)).toBeTruthy()
|
||||
})
|
||||
test('revolve sketch circle around line segment from startProfileAt sketch', async ({
|
||||
context,
|
||||
@ -3628,15 +3681,20 @@ sketch003 = startSketchOn(extrude001, 'START')
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// select line of code
|
||||
const codeToSelecton = `center = [-0.69, 0.56]`
|
||||
const codeToSelection = `center = [-0.69, 0.56]`
|
||||
// revolve
|
||||
await page.getByText(codeToSelecton).click()
|
||||
await toolbar.revolveButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await editor.scrollToText(codeToSelection)
|
||||
await page.getByText(codeToSelection).click()
|
||||
await expect.poll(() => page.getByText('AxisOrEdge').count()).toBe(2)
|
||||
await page.getByText('Edge', { exact: true }).click()
|
||||
const lineCodeToSelection = `|> xLine(length = 2.6)`
|
||||
const lineCodeToSelection = `length = 2.6`
|
||||
await editor.scrollToText(lineCodeToSelection)
|
||||
await page.getByText(lineCodeToSelection).click()
|
||||
await cmdBar.progressCmdBar()
|
||||
await cmdBar.progressCmdBar()
|
||||
@ -3703,7 +3761,7 @@ extrude001 = extrude(profile001, length = 100)
|
||||
}, initialCode)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// One dumb hardcoded screen pixel value
|
||||
const testPoint = { x: 500, y: 250 }
|
||||
|
@ -83,7 +83,7 @@ test(
|
||||
test(
|
||||
'click help/keybindings from project page',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -95,17 +95,11 @@ test(
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
page.on('console', console.log)
|
||||
|
||||
// expect to see the text bracket
|
||||
await expect(page.getByText('bracket')).toBeVisible()
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// click ? button
|
||||
await page.getByTestId('help-button').click()
|
||||
@ -120,7 +114,7 @@ test(
|
||||
test(
|
||||
'open a file in a project works and renders, open another file in different project with errors, it should clear the scene',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page, editor }, testInfo) => {
|
||||
async ({ scene, cmdBar, context, page, editor }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -149,24 +143,7 @@ test(
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).toBeEnabled({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [110, 110, 110]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(20)
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
await test.step('Clicking the logo takes us back to the projects page / home', async () => {
|
||||
@ -209,7 +186,7 @@ test(
|
||||
test(
|
||||
'open a file in a project works and renders, open another file in different project that is empty, it should clear the scene',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = path.join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -235,24 +212,7 @@ test(
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).toBeEnabled({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(15)
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
await test.step('Clicking the logo takes us back to the projects page / home', async () => {
|
||||
@ -352,7 +312,7 @@ test(
|
||||
test(
|
||||
'open a file in a project works and renders, open another file in the same project with errors, it should clear the scene',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
if (runningOnWindows()) {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
}
|
||||
@ -380,10 +340,7 @@ test(
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
@ -443,10 +400,10 @@ test(
|
||||
await expect(page.getByText('broken-code')).toBeVisible()
|
||||
await page.getByText('broken-code').click()
|
||||
|
||||
// Gotcha: You can not use scene.waitForExecutionDone() since the KCL code is going to fail
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
// Gotcha: You can not use scene.settled() since the KCL code is going to fail
|
||||
await expect(
|
||||
page.getByTestId('model-state-indicator-playing')
|
||||
).toBeAttached()
|
||||
|
||||
// Gotcha: Scroll to the text content in code mirror because CodeMirror lazy loads DOM content
|
||||
await editor.scrollToText(
|
||||
@ -469,7 +426,7 @@ test.describe('Can export from electron app', () => {
|
||||
test(
|
||||
`Can export using ${method}`,
|
||||
{ tag: ['@electron', '@skipLocalEngine'] },
|
||||
async ({ context, page, tronApp }, testInfo) => {
|
||||
async ({ scene, cmdBar, context, page, tronApp }, testInfo) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
}
|
||||
@ -499,10 +456,7 @@ test.describe('Can export from electron app', () => {
|
||||
|
||||
await page.getByText('bracket').click()
|
||||
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
@ -812,7 +766,7 @@ test.describe(`Project management commands`, () => {
|
||||
test(
|
||||
`Rename from project page`,
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_rename`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
|
||||
@ -821,7 +775,6 @@ test.describe(`Project management commands`, () => {
|
||||
`${dir}/${projectName}/main.kcl`
|
||||
)
|
||||
})
|
||||
const u = await getUtils(page)
|
||||
|
||||
// Constants and locators
|
||||
const projectHomeLink = page.getByTestId('project-link')
|
||||
@ -843,7 +796,7 @@ test.describe(`Project management commands`, () => {
|
||||
page.on('console', console.log)
|
||||
|
||||
await projectHomeLink.click()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
await test.step(`Run rename command via command palette`, async () => {
|
||||
@ -882,7 +835,6 @@ test.describe(`Project management commands`, () => {
|
||||
`${dir}/${projectName}/main.kcl`
|
||||
)
|
||||
})
|
||||
const u = await getUtils(page)
|
||||
|
||||
// Constants and locators
|
||||
const projectHomeLink = page.getByTestId('project-link')
|
||||
@ -900,9 +852,9 @@ test.describe(`Project management commands`, () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
page.on('console', console.log)
|
||||
|
||||
await page.waitForTimeout(3000)
|
||||
|
||||
await projectHomeLink.click()
|
||||
await u.waitForPageLoad()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
@ -926,7 +878,7 @@ test.describe(`Project management commands`, () => {
|
||||
test(
|
||||
`Rename from home page`,
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page, homePage }, testInfo) => {
|
||||
async ({ context, page, homePage, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_rename`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
|
||||
@ -982,7 +934,7 @@ test.describe(`Project management commands`, () => {
|
||||
test(
|
||||
`Delete from home page`,
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
const projectName = `my_project_to_delete`
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(`${dir}/${projectName}`, { recursive: true })
|
||||
@ -1033,6 +985,7 @@ test.describe(`Project management commands`, () => {
|
||||
homePage,
|
||||
toolbar,
|
||||
cmdBar,
|
||||
scene,
|
||||
}) => {
|
||||
const projectName = 'test-project'
|
||||
await test.step(`Setup`, async () => {
|
||||
@ -1072,10 +1025,11 @@ test.describe(`Project management commands`, () => {
|
||||
})
|
||||
await cmdBar.argumentInput.fill(projectName)
|
||||
await cmdBar.progressCmdBar()
|
||||
await scene.settled(cmdBar)
|
||||
await toolbar.logoLink.click()
|
||||
})
|
||||
|
||||
await test.step(`Check the project was created with a non-colliding name`, async () => {
|
||||
await toolbar.logoLink.click()
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
{
|
||||
@ -1106,10 +1060,11 @@ test.describe(`Project management commands`, () => {
|
||||
})
|
||||
await cmdBar.argumentInput.fill(projectName)
|
||||
await cmdBar.progressCmdBar()
|
||||
await scene.settled(cmdBar)
|
||||
await toolbar.logoLink.click()
|
||||
})
|
||||
|
||||
await test.step(`Check the second project was created with a non-colliding name`, async () => {
|
||||
await toolbar.logoLink.click()
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
{
|
||||
@ -1195,7 +1150,7 @@ test(
|
||||
test(
|
||||
'Nested directories in project without main.kcl do not create main.kcl',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
let testDir: string | undefined
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(path.join(dir, 'router-template-slate', 'nested'), {
|
||||
@ -1218,10 +1173,7 @@ test(
|
||||
|
||||
await test.step('Open the project', async () => {
|
||||
await page.getByText('router-template-slate').click()
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// It actually loads.
|
||||
await expect(u.codeLocator).toContainText('mounting bracket')
|
||||
@ -1334,7 +1286,7 @@ test(
|
||||
test(
|
||||
'Can load a file with CRLF line endings',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ context, page, scene, cmdBar }, testInfo) => {
|
||||
if (runningOnWindows()) {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
}
|
||||
@ -1357,13 +1309,8 @@ test(
|
||||
const u = await getUtils(page)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
page.on('console', console.log)
|
||||
|
||||
await page.getByText('router-template-slate').click()
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(u.codeLocator).toContainText('routerDiameter')
|
||||
await expect(u.codeLocator).toContainText('templateGap')
|
||||
@ -1578,7 +1525,7 @@ extrude001 = extrude(sketch001, length = 200)`)
|
||||
test(
|
||||
'Opening a project should successfully load the stream, (regression test that this also works when switching between projects)',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page, cmdBar, homePage }, testInfo) => {
|
||||
async ({ context, page, cmdBar, homePage, scene }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
await fsp.mkdir(path.join(dir, 'router-template-slate'), {
|
||||
recursive: true,
|
||||
@ -1607,13 +1554,10 @@ test(
|
||||
path.join(dir, 'bracket', 'main.kcl')
|
||||
)
|
||||
})
|
||||
const u = await getUtils(page)
|
||||
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
page.on('console', console.log)
|
||||
|
||||
const pointOnModel = { x: 630, y: 280 }
|
||||
|
||||
await test.step('Opening the bracket project via command palette should load the stream', async () => {
|
||||
await homePage.expectState({
|
||||
projectCards: [
|
||||
@ -1647,15 +1591,7 @@ test(
|
||||
stage: 'commandBarClosed',
|
||||
})
|
||||
|
||||
await u.waitForPageLoad()
|
||||
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [85, 85, 85]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(15)
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
await test.step('Clicking the logo takes us back to the projects page / home', async () => {
|
||||
@ -1672,15 +1608,7 @@ test(
|
||||
|
||||
await page.getByText('router-template-slate').click()
|
||||
|
||||
await u.waitForPageLoad()
|
||||
|
||||
// gray at this pixel means the stream has loaded in the most
|
||||
// user way we can verify it (pixel color)
|
||||
await expect
|
||||
.poll(() => u.getGreatestPixDiff(pointOnModel, [143, 143, 143]), {
|
||||
timeout: 10_000,
|
||||
})
|
||||
.toBeLessThan(15)
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
await test.step('The projects on the home page should still be normal', async () => {
|
||||
@ -1733,8 +1661,6 @@ test(
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
page.on('console', console.log)
|
||||
|
||||
// we'll grab this from the settings on screen before we switch
|
||||
let originalProjectDirName: string
|
||||
const newProjectDirName = testInfo.outputPath(
|
||||
@ -1875,7 +1801,7 @@ test(
|
||||
test(
|
||||
'file pane is scrollable when there are many files',
|
||||
{ tag: '@electron' },
|
||||
async ({ context, page }, testInfo) => {
|
||||
async ({ scene, cmdBar, context, page }, testInfo) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const testDir = path.join(dir, 'testProject')
|
||||
await fsp.mkdir(testDir, { recursive: true })
|
||||
@ -1954,10 +1880,8 @@ test(
|
||||
|
||||
await test.step('setup, open file pane', async () => {
|
||||
await page.getByText('testProject').click()
|
||||
await expect(page.getByTestId('loading')).toBeAttached()
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByTestId('files-pane-button').click()
|
||||
})
|
||||
|
@ -63,7 +63,7 @@ test.describe('edit with AI example snapshots', () => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const body1CapCoords = { x: 571, y: 351 }
|
||||
const [clickBody1Cap] = scene.makeMouseHelpers(
|
||||
|
@ -61,7 +61,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const body1CapCoords = { x: 571, y: 311 }
|
||||
const greenCheckCoords = { x: 565, y: 305 }
|
||||
@ -156,7 +156,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const body1CapCoords = { x: 571, y: 311 }
|
||||
const [clickBody1Cap] = scene.makeMouseHelpers(
|
||||
@ -212,7 +212,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
|
||||
const successToast = page.getByText('Prompt to edit successful')
|
||||
@ -281,7 +281,7 @@ test.describe('Prompt-to-edit tests', { tag: '@skipWin' }, () => {
|
||||
localStorage.setItem('persistCode', file)
|
||||
}, file)
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const submittingToast = page.getByText('Submitting to Text-to-CAD API...')
|
||||
const successToast = page.getByText('Prompt to edit successful')
|
||||
|
@ -689,6 +689,7 @@ extrude002 = extrude(profile002, length = 150)
|
||||
homePage,
|
||||
scene,
|
||||
toolbar,
|
||||
viewport,
|
||||
}) => {
|
||||
await context.folderSetupFn(async (dir) => {
|
||||
const legoDir = path.join(dir, 'lego')
|
||||
@ -703,8 +704,8 @@ extrude002 = extrude(profile002, length = 150)
|
||||
await homePage.openProject('lego')
|
||||
await toolbar.closePane('code')
|
||||
})
|
||||
await test.step(`Waiting for the loading spinner to disappear`, async () => {
|
||||
await scene.loadingIndicator.waitFor({ state: 'detached' })
|
||||
await test.step(`Waiting for scene to settle`, async () => {
|
||||
await scene.connectionEstablished()
|
||||
})
|
||||
await test.step(`The part should start loading quickly, not waiting until execution is complete`, async () => {
|
||||
// TODO: use the viewport size to pick the center point, but the `viewport` fixture's values were wrong.
|
||||
@ -762,7 +763,7 @@ plane002 = offsetPlane(XZ, offset = -2 * x)`
|
||||
)
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
await expect(toolbar.startSketchBtn).toBeEnabled({ timeout: 20_000 })
|
||||
const operationButton = await toolbar.getFeatureTreeOperation(
|
||||
'Offset Plane',
|
||||
|
@ -22,6 +22,7 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
|
||||
context,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
const selectionsSnippets = {
|
||||
@ -82,7 +83,7 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// wait for execution done
|
||||
await u.openDebugPanel()
|
||||
@ -108,6 +109,7 @@ test.describe('Sketch tests', { tag: ['@skipWin'] }, () => {
|
||||
page,
|
||||
scene,
|
||||
homePage,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async () => {
|
||||
@ -122,7 +124,7 @@ sketch001 = startSketchOn(XZ)
|
||||
})
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await scene.expectPixelColor(TEST_COLORS.WHITE, { x: 587, y: 270 }, 15)
|
||||
|
||||
@ -673,6 +675,7 @@ sketch001 = startSketchOn(XZ)
|
||||
homePage,
|
||||
scene,
|
||||
editor,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async () => {
|
||||
@ -689,7 +692,7 @@ sketch001 = startSketchOn(XZ)
|
||||
})
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
@ -1614,7 +1617,7 @@ profile002 = startProfileAt([117.2, 56.08], sketch001)
|
||||
test(
|
||||
`snapToProfile start only works for current profile`,
|
||||
{ tag: ['@skipWin'] },
|
||||
async ({ context, page, scene, toolbar, editor, homePage }) => {
|
||||
async ({ context, page, scene, toolbar, editor, homePage, cmdBar }) => {
|
||||
// We seed the scene with a single offset plane
|
||||
await context.addInitScript(() => {
|
||||
localStorage.setItem(
|
||||
@ -1630,6 +1633,8 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
|
||||
})
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
@ -1651,9 +1656,13 @@ profile003 = startProfileAt([206.63, -56.73], sketch001)
|
||||
const codeFromTangentialArc = ` |> tangentialArcTo([39.49, 88.22], %)`
|
||||
await test.step('check that tangential tool does not snap to other profile starts', async () => {
|
||||
await toolbar.tangentialArcBtn.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await endOfLowerSegMove()
|
||||
await page.waitForTimeout(1000)
|
||||
await endOfLowerSegClick()
|
||||
await page.waitForTimeout(1000)
|
||||
await profileStartOfHigherSegClick()
|
||||
await page.waitForTimeout(1000)
|
||||
await editor.expectEditor.toContain(codeFromTangentialArc)
|
||||
await editor.expectEditor.not.toContain(
|
||||
`[profileStartX(%), profileStartY(%)]`
|
||||
@ -2242,8 +2251,9 @@ profile004 = circleThreePoint(sketch001, p1 = [13.44, -6.8], p2 = [13.39, -2.07]
|
||||
|
||||
await test.step('enter sketch and setup', async () => {
|
||||
await moveToClearToolBarPopover()
|
||||
await page.waitForTimeout(1000)
|
||||
await pointOnSegment({ shouldDbClick: true })
|
||||
await page.waitForTimeout(600)
|
||||
await page.waitForTimeout(2000)
|
||||
|
||||
await toolbar.lineBtn.click()
|
||||
await page.waitForTimeout(100)
|
||||
@ -2359,7 +2369,7 @@ profile003 = circle(sketch001, center = [6.92, -4.2], radius = 3.16)
|
||||
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).not.toBeDisabled()
|
||||
@ -2965,6 +2975,7 @@ test.describe(`Click based selection don't brick the app when clicked out of ran
|
||||
toolbar,
|
||||
editor,
|
||||
homePage,
|
||||
cmdBar,
|
||||
}) => {
|
||||
// We seed the scene with a single offset plane
|
||||
await context.addInitScript(() => {
|
||||
@ -2982,7 +2993,7 @@ test.describe(`Click based selection don't brick the app when clicked out of ran
|
||||
})
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await test.step(`format the code`, async () => {
|
||||
// doesn't contain condensed version
|
||||
@ -3047,6 +3058,7 @@ test.describe('Redirecting to home page and back to the original file should cle
|
||||
toolbar,
|
||||
editor,
|
||||
homePage,
|
||||
cmdBar,
|
||||
}) => {
|
||||
// We seed the scene with a single offset plane
|
||||
await context.addInitScript(() => {
|
||||
@ -3059,7 +3071,7 @@ test.describe('Redirecting to home page and back to the original file should cle
|
||||
)
|
||||
})
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const [objClick] = scene.makeMouseHelpers(634, 274)
|
||||
await objClick()
|
||||
|
@ -103,7 +103,6 @@ part001 = startSketchOn(-XZ)
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
const axisDirectionPair: Models['AxisDirectionPair_type'] = {
|
||||
@ -369,7 +368,6 @@ const extrudeDefaultPlane = async (
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(page).toHaveScreenshot({
|
||||
@ -421,8 +419,6 @@ test(
|
||||
const PUR = 400 / 37.5 //pixeltoUnitRatio
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
|
||||
const startXPx = 600
|
||||
const [endOfTangentClk, endOfTangentMv] = scene.makeMouseHelpers(
|
||||
startXPx + PUR * 30,
|
||||
@ -551,8 +547,6 @@ test(
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// click on "Start Sketch" button
|
||||
await u.doAndWaitForImageDiff(
|
||||
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
|
||||
@ -598,8 +592,6 @@ test(
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
|
||||
await u.doAndWaitForImageDiff(
|
||||
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
|
||||
200
|
||||
@ -650,8 +642,6 @@ test.describe(
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
|
||||
await u.doAndWaitForImageDiff(
|
||||
() => page.getByRole('button', { name: 'Start Sketch' }).click(),
|
||||
200
|
||||
@ -744,7 +734,6 @@ test.describe(
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await u.doAndWaitForImageDiff(
|
||||
@ -846,7 +835,6 @@ part002 = startSketchOn(part001, seg01)
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Wait for the second extrusion to appear
|
||||
@ -902,7 +890,6 @@ test(
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Wait for the second extrusion to appear
|
||||
@ -943,7 +930,6 @@ test(
|
||||
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Wait for the second extrusion to appear
|
||||
@ -976,7 +962,6 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
await page.goto('/')
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await u.closeKclCodePanel()
|
||||
@ -1041,7 +1026,6 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
await page.goto('/')
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await u.closeKclCodePanel()
|
||||
@ -1086,7 +1070,6 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
|
||||
await page.goto('/')
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await u.closeKclCodePanel()
|
||||
@ -1205,7 +1188,6 @@ sweepSketch = startSketchOn(XY)
|
||||
await page.setViewportSize({ width: 1200, height: 1000 })
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(page, 'expect small color widget').toHaveScreenshot({
|
||||
@ -1255,7 +1237,6 @@ sweepSketch = startSketchOn(XY)
|
||||
await page.setViewportSize({ width: 1200, height: 1000 })
|
||||
await u.waitForAuthSkipAppStart()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await expect(page.locator('.cm-css-color-picker-wrapper')).toBeVisible()
|
||||
|
@ -80,8 +80,7 @@ export const TEST_SETTINGS_CORRUPTED = {
|
||||
},
|
||||
} satisfies Partial<SaveSettingsPayload>
|
||||
|
||||
export const TEST_CODE_GIZMO = `@settings(defaultLengthUnit = in)
|
||||
part001 = startSketchOn(XZ)
|
||||
export const TEST_CODE_GIZMO = `part001 = startSketchOn(XZ)
|
||||
|> startProfileAt([20, 0], %)
|
||||
|> line(end = [7.13, 4 + 0])
|
||||
|> angledLine({ angle: 3 + 0, length: 3.14 + 0 }, %)
|
||||
|
@ -89,7 +89,7 @@ test.describe('Test network and connection issues', () => {
|
||||
test(
|
||||
'Engine disconnect & reconnect in sketch mode',
|
||||
{ tag: '@skipLocalEngine' },
|
||||
async ({ page, homePage, toolbar }) => {
|
||||
async ({ page, homePage, toolbar, scene, cmdBar }) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
const networkToggle = page.getByTestId('network-toggle')
|
||||
|
||||
@ -169,7 +169,7 @@ test.describe('Test network and connection issues', () => {
|
||||
|
||||
// Expect the network to be up
|
||||
await expect(networkToggle).toContainText('Connected')
|
||||
await expect(page.getByTestId('loading-stream')).not.toBeAttached()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
// Click off the code pane.
|
||||
await page.mouse.click(100, 100)
|
||||
|
@ -74,7 +74,10 @@ async function waitForPageLoadWithRetry(page: Page) {
|
||||
await expect(async () => {
|
||||
await page.goto('/')
|
||||
const errorMessage = 'App failed to load - 🔃 Retrying ...'
|
||||
await expect(page.getByTestId('loading'), errorMessage).not.toBeAttached({
|
||||
await expect(
|
||||
page.getByTestId('model-state-indicator-playing'),
|
||||
errorMessage
|
||||
).toBeAttached({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
@ -87,9 +90,10 @@ async function waitForPageLoadWithRetry(page: Page) {
|
||||
}).toPass({ timeout: 70_000, intervals: [1_000] })
|
||||
}
|
||||
|
||||
// lee: This needs to be replaced by scene.settled() eventually.
|
||||
async function waitForPageLoad(page: Page) {
|
||||
// wait for all spinners to be gone
|
||||
await expect(page.getByTestId('loading')).not.toBeAttached({
|
||||
await expect(page.getByTestId('model-state-indicator-playing')).toBeVisible({
|
||||
timeout: 20_000,
|
||||
})
|
||||
|
||||
@ -871,9 +875,10 @@ export async function tearDown(page: Page, testInfo: TestInfo) {
|
||||
export async function setup(
|
||||
context: BrowserContext,
|
||||
page: Page,
|
||||
testDir: string,
|
||||
testInfo?: TestInfo
|
||||
) {
|
||||
await context.addInitScript(
|
||||
await page.addInitScript(
|
||||
async ({
|
||||
token,
|
||||
settingsKey,
|
||||
@ -914,7 +919,7 @@ export async function setup(
|
||||
},
|
||||
}),
|
||||
IS_PLAYWRIGHT_KEY,
|
||||
PLAYWRIGHT_TEST_DIR: TEST_SETTINGS.project?.directory || '',
|
||||
PLAYWRIGHT_TEST_DIR: testDir,
|
||||
PERSIST_MODELING_CONTEXT,
|
||||
}
|
||||
)
|
||||
@ -934,7 +939,7 @@ export async function setup(
|
||||
await page.emulateMedia({ reducedMotion: 'reduce' })
|
||||
|
||||
// Trigger a navigation, since loading file:// doesn't.
|
||||
// await page.reload()
|
||||
await page.reload()
|
||||
}
|
||||
|
||||
function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
|
||||
|
@ -5,12 +5,18 @@ import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test.describe('Testing Camera Movement', { tag: ['@skipWin'] }, () => {
|
||||
test('Can move camera reliably', async ({ page, context, homePage }) => {
|
||||
test('Can move camera reliably', async ({
|
||||
page,
|
||||
context,
|
||||
homePage,
|
||||
scene,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
await u.openAndClearDebugPanel()
|
||||
await u.closeKclCodePanel()
|
||||
|
||||
|
@ -77,7 +77,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
})
|
||||
.toBe(false)
|
||||
})
|
||||
test(`Remove constraints`, async ({ page, homePage }) => {
|
||||
test(`Remove constraints`, async ({ page, homePage, scene, cmdBar }) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -101,7 +101,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4], tag = $seg01)').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -142,7 +142,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
},
|
||||
] as const
|
||||
for (const { testName, offset } of cases) {
|
||||
test(`${testName}`, async ({ page, homePage }) => {
|
||||
test(`${testName}`, async ({ page, homePage, scene, cmdBar }) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -166,7 +166,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4], tag = $seg01)').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -250,7 +250,12 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
},
|
||||
] as const
|
||||
for (const { testName, value, constraint } of cases) {
|
||||
test(`${constraint} - ${testName}`, async ({ page, homePage }) => {
|
||||
test(`${constraint} - ${testName}`, async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -274,7 +279,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -361,7 +366,12 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
},
|
||||
] as const
|
||||
for (const { testName, addVariable, value, constraint } of cases) {
|
||||
test(`${constraint} - ${testName}`, async ({ page, homePage }) => {
|
||||
test(`${constraint} - ${testName}`, async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -385,7 +395,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -475,7 +485,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
},
|
||||
] as const
|
||||
for (const { testName, addVariable, value, axisSelect } of cases) {
|
||||
test(`${testName}`, async ({ page, homePage }) => {
|
||||
test(`${testName}`, async ({ page, homePage, scene, cmdBar }) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -499,7 +509,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -578,7 +588,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
},
|
||||
] as const
|
||||
for (const { testName, addVariable, value, constraint } of cases) {
|
||||
test(`${testName}`, async ({ page, homePage }) => {
|
||||
test(`${testName}`, async ({ page, homePage, scene, cmdBar }) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -602,7 +612,7 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -655,7 +665,14 @@ test.describe('Testing constraints', { tag: ['@skipWin'] }, () => {
|
||||
},
|
||||
] as const
|
||||
for (const { testName, addVariable, value, constraint } of cases) {
|
||||
test(`${testName}`, async ({ context, homePage, page, editor }) => {
|
||||
test(`${testName}`, async ({
|
||||
context,
|
||||
homePage,
|
||||
page,
|
||||
editor,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
// constants and locators
|
||||
const cmdBarKclInput = page
|
||||
.getByTestId('cmd-bar-arg-value')
|
||||
@ -689,7 +706,7 @@ part002 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await editor.scrollToText('line(end = [74.36, 130.4])', true)
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
@ -746,7 +763,7 @@ part002 = startSketchOn(XZ)
|
||||
},
|
||||
] as const
|
||||
for (const { codeAfter, constraintName } of cases) {
|
||||
test(`${constraintName}`, async ({ page, homePage }) => {
|
||||
test(`${constraintName}`, async ({ page, homePage, scene, cmdBar }) => {
|
||||
await page.addInitScript(async (customCode) => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -770,7 +787,7 @@ part002 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -848,7 +865,7 @@ part002 = startSketchOn(XZ)
|
||||
},
|
||||
] as const
|
||||
for (const { codeAfter, constraintName } of cases) {
|
||||
test(`${constraintName}`, async ({ page, homePage }) => {
|
||||
test(`${constraintName}`, async ({ page, homePage, scene, cmdBar }) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -871,7 +888,7 @@ part002 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -930,7 +947,7 @@ part002 = startSketchOn(XZ)
|
||||
},
|
||||
] as const
|
||||
for (const { codeAfter, constraintName, axisClick } of cases) {
|
||||
test(`${constraintName}`, async ({ page, homePage }) => {
|
||||
test(`${constraintName}`, async ({ page, homePage, scene, cmdBar }) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
@ -953,7 +970,7 @@ part002 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [74.36, 130.4])').click()
|
||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||
@ -994,6 +1011,8 @@ part002 = startSketchOn(XZ)
|
||||
test('Horizontally constrained line remains selected after applying constraint', async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
test.setTimeout(70_000)
|
||||
@ -1010,7 +1029,7 @@ part002 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await page.getByText('line(end = [3.79, 2.68], tag = $seg01)').click()
|
||||
await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeEnabled(
|
||||
@ -1129,7 +1148,7 @@ test.describe('Electron constraint tests', () => {
|
||||
sortBy: 'last-modified-desc',
|
||||
})
|
||||
await homePage.openProject('test-sample')
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
async function clickOnFirstSegmentLabel() {
|
||||
|
@ -8,37 +8,37 @@ test.describe('Testing Gizmo', { tag: ['@skipWin'] }, () => {
|
||||
const cases = [
|
||||
{
|
||||
testDescription: 'top view',
|
||||
clickPosition: { x: 951, y: 385 },
|
||||
clickPosition: { x: 951, y: 347 },
|
||||
expectedCameraPosition: { x: 800, y: -152, z: 4886.02 },
|
||||
expectedCameraTarget: { x: 800, y: -152, z: 26 },
|
||||
},
|
||||
{
|
||||
testDescription: 'bottom view',
|
||||
clickPosition: { x: 951, y: 429 },
|
||||
clickPosition: { x: 951, y: 391 },
|
||||
expectedCameraPosition: { x: 800, y: -152, z: -4834.02 },
|
||||
expectedCameraTarget: { x: 800, y: -152, z: 26 },
|
||||
},
|
||||
{
|
||||
testDescription: 'right view',
|
||||
clickPosition: { x: 929, y: 417 },
|
||||
clickPosition: { x: 929, y: 379 },
|
||||
expectedCameraPosition: { x: 5660.02, y: -152, z: 26 },
|
||||
expectedCameraTarget: { x: 800, y: -152, z: 26 },
|
||||
},
|
||||
{
|
||||
testDescription: 'left view',
|
||||
clickPosition: { x: 974, y: 397 },
|
||||
clickPosition: { x: 974, y: 359 },
|
||||
expectedCameraPosition: { x: -4060.02, y: -152, z: 26 },
|
||||
expectedCameraTarget: { x: 800, y: -152, z: 26 },
|
||||
},
|
||||
{
|
||||
testDescription: 'back view',
|
||||
clickPosition: { x: 967, y: 421 },
|
||||
clickPosition: { x: 967, y: 383 },
|
||||
expectedCameraPosition: { x: 800, y: 4708.02, z: 26 },
|
||||
expectedCameraTarget: { x: 800, y: -152, z: 26 },
|
||||
},
|
||||
{
|
||||
testDescription: 'front view',
|
||||
clickPosition: { x: 935, y: 393 },
|
||||
clickPosition: { x: 935, y: 355 },
|
||||
expectedCameraPosition: { x: 800, y: -5012.02, z: 26 },
|
||||
expectedCameraTarget: { x: 800, y: -152, z: 26 },
|
||||
},
|
||||
|
@ -2,11 +2,7 @@ import { getUtils, orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
|
||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test.describe('Test toggling perspective', () => {
|
||||
test('via command palette and toggle', async ({
|
||||
page,
|
||||
homePage,
|
||||
toolbar,
|
||||
}) => {
|
||||
test('via command palette and toggle', async ({ page, homePage }) => {
|
||||
test.fixme(orRunWhenFullSuiteEnabled())
|
||||
const u = await getUtils(page)
|
||||
|
||||
@ -18,7 +14,7 @@ test.describe('Test toggling perspective', () => {
|
||||
y: screenHeight * 0.2,
|
||||
}
|
||||
const backgroundColor: [number, number, number] = [29, 29, 29]
|
||||
const xzPlaneColor: [number, number, number] = [72, 55, 96]
|
||||
const xzPlaneColor: [number, number, number] = [82, 55, 96]
|
||||
const locationToHaveColor = async (color: [number, number, number]) => {
|
||||
return u.getGreatestPixDiff(checkedScreenLocation, color)
|
||||
}
|
||||
@ -30,29 +26,9 @@ test.describe('Test toggling perspective', () => {
|
||||
const commandToast = page.getByText(
|
||||
`Set camera projection to "orthographic"`
|
||||
)
|
||||
|
||||
const checkSettingValue = async () => {
|
||||
const settingsButton = page.getByRole('link', {
|
||||
name: 'Settings',
|
||||
exact: false,
|
||||
})
|
||||
|
||||
let settingValue: string | null = null
|
||||
|
||||
await test.step(`Check the setting value`, async () => {
|
||||
await settingsButton.click()
|
||||
const userTab = page.getByRole('radio', { name: 'User' })
|
||||
await userTab.click()
|
||||
await expect(userTab).toBeChecked()
|
||||
const setting = page.locator('#cameraProjection').first()
|
||||
await expect(setting).toBeAttached()
|
||||
await setting.scrollIntoViewIfNeeded()
|
||||
settingValue = await setting.getByRole('combobox').inputValue()
|
||||
await page.getByTestId('settings-close-button').click()
|
||||
})
|
||||
|
||||
return settingValue
|
||||
}
|
||||
const projectionToggle = page.getByRole('switch', {
|
||||
name: 'Camera projection: ',
|
||||
})
|
||||
|
||||
await test.step('Setup', async () => {
|
||||
await page.setBodyDimensions({ width: screenWidth, height: screenHeight })
|
||||
@ -63,8 +39,8 @@ test.describe('Test toggling perspective', () => {
|
||||
timeout: 5000,
|
||||
message: 'This spot should have the background color',
|
||||
})
|
||||
.toBeLessThan(30)
|
||||
expect(await checkSettingValue()).toBe('perspective')
|
||||
.toBeLessThan(15)
|
||||
await expect(projectionToggle).toHaveAttribute('aria-checked', 'true')
|
||||
})
|
||||
|
||||
// Extremely wild note: flicking between ortho and persp actually changes
|
||||
@ -83,22 +59,33 @@ test.describe('Test toggling perspective', () => {
|
||||
timeout: 5000,
|
||||
message: 'This spot should have the XZ plane color',
|
||||
})
|
||||
.toBeLessThan(30)
|
||||
expect(await checkSettingValue()).toBe('orthographic')
|
||||
.toBeLessThan(15)
|
||||
await expect(projectionToggle).toHaveAttribute('aria-checked', 'false')
|
||||
})
|
||||
|
||||
await test.step(`Refresh the page and ensure the stream is loaded in ortho`, async () => {
|
||||
await page.reload()
|
||||
await expect(toolbar.startSketchBtn).toBeEnabled({ timeout: 15_000 })
|
||||
await page.waitForTimeout(1000)
|
||||
await u.closeKclCodePanel()
|
||||
await expect
|
||||
.poll(async () => locationToHaveColor(xzPlaneColor), {
|
||||
timeout: 5000,
|
||||
message: 'This spot should have the XZ plane color',
|
||||
})
|
||||
.toBeLessThan(30)
|
||||
.toBeLessThan(15)
|
||||
await expect(commandToast).not.toBeVisible()
|
||||
expect(await checkSettingValue()).toBe('orthographic')
|
||||
await expect(projectionToggle).toHaveAttribute('aria-checked', 'false')
|
||||
})
|
||||
|
||||
await test.step(`Switch to perspective via toggle`, async () => {
|
||||
await projectionToggle.click()
|
||||
await expect(projectionToggle).toHaveAttribute('aria-checked', 'true')
|
||||
await expect
|
||||
.poll(async () => locationToHaveColor(backgroundColor), {
|
||||
timeout: 5000,
|
||||
message: 'This spot should have the background color',
|
||||
})
|
||||
.toBeLessThan(15)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -8,10 +8,11 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test.describe('Testing in-app sample loading', () => {
|
||||
/**
|
||||
* Note this test implicitly depends on the KCL sample "parametric-bearing-pillow-block",
|
||||
* its title, and its units settings. https://github.com/KittyCAD/kcl-samples/blob/main/parametric-bearing-pillow-block/main.kcl
|
||||
* Note this test implicitly depends on the KCL sample "a-parametric-bearing-pillow-block",
|
||||
* its title, and its units settings. https://github.com/KittyCAD/kcl-samples/blob/main/a-parametric-bearing-pillow-block/main.kcl
|
||||
*/
|
||||
test('Web: should overwrite current code, cannot create new file', async ({
|
||||
// We have no more web tests
|
||||
test.skip('Web: should overwrite current code, cannot create new file', async ({
|
||||
editor,
|
||||
context,
|
||||
page,
|
||||
@ -29,8 +30,8 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
// Locators and constants
|
||||
const newSample = {
|
||||
file: 'parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'Parametric Bearing Pillow Block',
|
||||
file: 'a-parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'A Parametric Bearing Pillow Block',
|
||||
}
|
||||
const commandBarButton = page.getByRole('button', { name: 'Commands' })
|
||||
const samplesCommandOption = page.getByRole('option', {
|
||||
@ -72,13 +73,13 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
/**
|
||||
* Note this test implicitly depends on the KCL samples:
|
||||
* "parametric-bearing-pillow-block": https://github.com/KittyCAD/kcl-samples/blob/main/parametric-bearing-pillow-block/main.kcl
|
||||
* "a-parametric-bearing-pillow-block": https://github.com/KittyCAD/kcl-samples/blob/main/a-parametric-bearing-pillow-block/main.kcl
|
||||
* "gear-rack": https://github.com/KittyCAD/kcl-samples/blob/main/gear-rack/main.kcl
|
||||
*/
|
||||
test(
|
||||
'Desktop: should create new file by default, optionally overwrite',
|
||||
{ tag: '@electron' },
|
||||
async ({ editor, context, page }, testInfo) => {
|
||||
async ({ editor, context, page, scene, cmdBar }, testInfo) => {
|
||||
const { dir } = await context.folderSetupFn(async (dir) => {
|
||||
const bracketDir = join(dir, 'bracket')
|
||||
await fsp.mkdir(bracketDir, { recursive: true })
|
||||
@ -90,8 +91,8 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
// Locators and constants
|
||||
const sampleOne = {
|
||||
file: 'parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'Parametric Bearing Pillow Block',
|
||||
file: 'a-parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'A Parametric Bearing Pillow Block',
|
||||
}
|
||||
const sampleTwo = {
|
||||
file: 'gear-rack' + FILE_EXT,
|
||||
@ -125,7 +126,7 @@ test.describe('Testing in-app sample loading', () => {
|
||||
await test.step(`Test setup`, async () => {
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await projectCard.click()
|
||||
await u.waitForPageLoad()
|
||||
await scene.settled(cmdBar)
|
||||
})
|
||||
|
||||
await test.step(`Precondition: check the initial code`, async () => {
|
||||
@ -140,11 +141,14 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
await test.step(`Load a KCL sample with the command palette`, async () => {
|
||||
await commandBarButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandOption.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandSampleOption(sampleOne.title).click()
|
||||
await expect(overwriteWarning).not.toBeVisible()
|
||||
await expect(newFileWarning).toBeVisible()
|
||||
await confirmButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
await test.step(`Ensure we made and opened a new file`, async () => {
|
||||
@ -155,14 +159,20 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
await test.step(`Now overwrite the current file`, async () => {
|
||||
await commandBarButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandOption.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandSampleOption(sampleTwo.title).click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandMethodArgButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await commandMethodOption.click()
|
||||
await page.waitForTimeout(1000)
|
||||
await expect(commandMethodArgButton).toContainText('overwrite')
|
||||
await expect(newFileWarning).not.toBeVisible()
|
||||
await expect(overwriteWarning).toBeVisible()
|
||||
await confirmButton.click()
|
||||
await page.waitForTimeout(1000)
|
||||
})
|
||||
|
||||
await test.step(`Ensure we overwrote the current file without navigating`, async () => {
|
||||
|
@ -1520,6 +1520,8 @@ part001 = startSketchOn(XZ)
|
||||
page,
|
||||
editor,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await page.addInitScript(
|
||||
async ({ lineToBeDeleted }) => {
|
||||
@ -1541,7 +1543,8 @@ part001 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await u.waitForPageLoad()
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
await page.waitForTimeout(300)
|
||||
|
||||
await page.getByText(before).click()
|
||||
|
@ -528,6 +528,8 @@ profile001 = startProfileAt([7.49, 9.96], sketch001)
|
||||
test('Hovering over 3d features highlights code, clicking puts the cursor in the right place and sends selection id to engine', async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const u = await getUtils(page)
|
||||
await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
|
||||
@ -779,11 +781,7 @@ part001 = startSketchOn(XZ)
|
||||
)
|
||||
`)
|
||||
|
||||
await expect(
|
||||
page
|
||||
.getByTestId('model-state-indicator-receive-reliable')
|
||||
.or(page.getByTestId('model-state-indicator-execution-done'))
|
||||
).toBeVisible()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await u.openAndClearDebugPanel()
|
||||
await u.sendCustomCmd({
|
||||
@ -953,6 +951,7 @@ part001 = startSketchOn(XZ)
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
const cases = [
|
||||
{
|
||||
@ -989,7 +988,7 @@ part001 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
await u.openAndClearDebugPanel()
|
||||
|
||||
await u.sendCustomCmd({
|
||||
@ -1024,6 +1023,7 @@ part001 = startSketchOn(XZ)
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
@ -1043,7 +1043,7 @@ part001 = startSketchOn(XZ)
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
await scene.waitForExecutionDone()
|
||||
await scene.settled(cmdBar)
|
||||
await u.openAndClearDebugPanel()
|
||||
|
||||
await u.sendCustomCmd({
|
||||
|
@ -55,7 +55,8 @@ test.describe('Testing settings', () => {
|
||||
// Check that the invalid settings were changed to good defaults
|
||||
expect(storedSettings.settings?.modeling?.base_unit).toBe('in')
|
||||
expect(storedSettings.settings?.modeling?.mouse_controls).toBe('zoo')
|
||||
expect(storedSettings.settings?.project?.directory).toBe('')
|
||||
// Commenting this out because tests need this to be set to work properly.
|
||||
// expect(storedSettings.settings?.app?.project_directory).toBe('')
|
||||
expect(storedSettings.settings?.project?.default_project_name).toBe(
|
||||
'untitled'
|
||||
)
|
||||
@ -865,6 +866,8 @@ test.describe('Testing settings', () => {
|
||||
page,
|
||||
homePage,
|
||||
tronApp,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
if (!tronApp) {
|
||||
fail()
|
||||
@ -886,6 +889,7 @@ test.describe('Testing settings', () => {
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
await homePage.goToModelingScene()
|
||||
await scene.connectionEstablished()
|
||||
|
||||
// Constants and locators
|
||||
const resizeHandle = page.locator('.sidebar-resize-handles > div.block')
|
||||
@ -897,6 +901,7 @@ test.describe('Testing settings', () => {
|
||||
|
||||
async function setShowDebugPanelTo(value: 'On' | 'Off') {
|
||||
await commandsButton.click()
|
||||
await debugPaneOption.scrollIntoViewIfNeeded()
|
||||
await debugPaneOption.click()
|
||||
await page.getByRole('option', { name: value }).click()
|
||||
await expect(
|
||||
|
@ -17,7 +17,6 @@ declare module '@playwright/test' {
|
||||
}
|
||||
interface Page {
|
||||
dir: string
|
||||
TEST_SETTINGS_FILE_KEY?: string
|
||||
setBodyDimensions: (dims: {
|
||||
width: number
|
||||
height: number
|
||||
|
@ -4,7 +4,6 @@ directories:
|
||||
buildResources: assets
|
||||
files:
|
||||
- .vite/**
|
||||
- "!node_modules/win-ca/pem/**"
|
||||
mac:
|
||||
category: public.app-category.developer-tools
|
||||
artifactName: "${productName}-${version}-${arch}-${os}.${ext}"
|
||||
|
1
interface.d.ts
vendored
@ -72,7 +72,6 @@ export interface IElectronAPI {
|
||||
process: {
|
||||
env: {
|
||||
BASE_URL: string
|
||||
TEST_SETTINGS_FILE_KEY: string
|
||||
IS_PLAYWRIGHT: string
|
||||
VITE_KC_DEV_TOKEN: string
|
||||
VITE_KC_API_WS_MODELING_URL: string
|
||||
|
@ -4,10 +4,10 @@ $ dpdm --no-warning --no-tree -T --skip-dynamic-imports=circular src/index.tsx
|
||||
02) src/lang/std/sketch.ts -> src/lang/modifyAst.ts
|
||||
03) src/lang/std/sketch.ts -> src/lang/modifyAst.ts -> src/lang/std/sketchcombos.ts
|
||||
04) src/lib/singletons.ts -> src/editor/manager.ts -> src/lib/selections.ts
|
||||
05) src/lib/singletons.ts -> src/lang/KclSingleton.ts
|
||||
06) src/lib/singletons.ts -> src/lang/codeManager.ts
|
||||
07) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts -> src/components/Toolbar/angleLengthInfo.ts
|
||||
08) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts -> src/machines/commandBarMachine.ts -> src/lib/commandBarConfigs/authCommandConfig.ts -> src/machines/appMachine.ts -> src/machines/settingsMachine.ts
|
||||
09) src/machines/commandBarMachine.ts -> src/lib/commandBarConfigs/authCommandConfig.ts -> src/machines/appMachine.ts -> src/machines/settingsMachine.ts
|
||||
05) src/lib/singletons.ts -> src/editor/manager.ts -> src/lib/selections.ts -> src/machines/appMachine.ts -> src/machines/engineStreamMachine.ts
|
||||
06) src/lib/singletons.ts -> src/editor/manager.ts -> src/lib/selections.ts -> src/machines/appMachine.ts -> src/machines/settingsMachine.ts
|
||||
07) src/machines/appMachine.ts -> src/machines/settingsMachine.ts -> src/machines/commandBarMachine.ts -> src/lib/commandBarConfigs/authCommandConfig.ts
|
||||
08) src/lib/singletons.ts -> src/lang/codeManager.ts
|
||||
09) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts -> src/components/Toolbar/angleLengthInfo.ts
|
||||
10) src/hooks/useModelingContext.ts -> src/components/ModelingMachineProvider.tsx -> src/components/Toolbar/Intersect.tsx -> src/components/SetHorVertDistanceModal.tsx -> src/lib/useCalculateKclExpression.ts
|
||||
11) src/routes/Onboarding/index.tsx -> src/routes/Onboarding/Camera.tsx -> src/routes/Onboarding/utils.tsx
|
||||
|
@ -66,7 +66,6 @@
|
||||
"vscode-languageserver-protocol": "^3.17.5",
|
||||
"vscode-uri": "^3.1.0",
|
||||
"web-vitals": "^3.5.2",
|
||||
"win-ca": "^3.5.1",
|
||||
"xstate": "^5.19.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
@ -234,7 +233,7 @@
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.26.1",
|
||||
"vite": "^5.4.17",
|
||||
"vite": "^5.4.16",
|
||||
"vite-plugin-package-version": "^1.1.0",
|
||||
"vite-plugin-top-level-await": "^1.5.0",
|
||||
"vite-tsconfig-paths": "^4.3.2",
|
||||
|
@ -683,9 +683,9 @@ vite-tsconfig-paths@^4.3.2:
|
||||
tsconfck "^3.0.3"
|
||||
|
||||
vite@^5.0.0:
|
||||
version "5.4.17"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.17.tgz#4bf61dd4cdbf64b0d6661f5dba76954cc81d5082"
|
||||
integrity sha512-5+VqZryDj4wgCs55o9Lp+p8GE78TLVg0lasCH5xFZ4jacZjtqZa6JUw9/p0WeAojaOfncSM6v77InkFPGnvPvg==
|
||||
version "5.4.16"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.16.tgz#471983257a890ef33f2700cbbbc2134f2d08abf1"
|
||||
integrity sha512-Y5gnfp4NemVfgOTDQAunSD4346fal44L9mszGGY/e+qxsRT5y1sMlS/8tiQ8AFAp+MFgYNSINdfEchJiPm41vQ==
|
||||
dependencies:
|
||||
esbuild "^0.21.3"
|
||||
postcss "^8.4.43"
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Create a function to make the 80-20 rail
|
||||
// Define function
|
||||
fn rail8020(originStart, railHeight, railLength) {
|
||||
// Sketch side 1 of profile
|
||||
sketch001 = startSketchOn(-XZ)
|
||||
|
@ -25,6 +25,8 @@ When you submit a PR to add or modify KCL samples, images and STEP files will be
|
||||
---
|
||||
#### [80-20-rail](80-20-rail/main.kcl) ([screenshot](screenshots/80-20-rail.png))
|
||||
[](80-20-rail/main.kcl)
|
||||
#### [a-parametric-bearing-pillow-block](a-parametric-bearing-pillow-block/main.kcl) ([screenshot](screenshots/a-parametric-bearing-pillow-block.png))
|
||||
[](a-parametric-bearing-pillow-block/main.kcl)
|
||||
#### [ball-bearing](ball-bearing/main.kcl) ([screenshot](screenshots/ball-bearing.png))
|
||||
[](ball-bearing/main.kcl)
|
||||
#### [bench](bench/main.kcl) ([screenshot](screenshots/bench.png))
|
||||
@ -81,8 +83,6 @@ When you submit a PR to add or modify KCL samples, images and STEP files will be
|
||||
[](mounting-plate/main.kcl)
|
||||
#### [multi-axis-robot](multi-axis-robot/main.kcl) ([screenshot](screenshots/multi-axis-robot.png))
|
||||
[](multi-axis-robot/main.kcl)
|
||||
#### [parametric-bearing-pillow-block](parametric-bearing-pillow-block/main.kcl) ([screenshot](screenshots/parametric-bearing-pillow-block.png))
|
||||
[](parametric-bearing-pillow-block/main.kcl)
|
||||
#### [pipe](pipe/main.kcl) ([screenshot](screenshots/pipe.png))
|
||||
[](pipe/main.kcl)
|
||||
#### [pipe-flange-assembly](pipe-flange-assembly/main.kcl) ([screenshot](screenshots/pipe-flange-assembly.png))
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Parametric Bearing Pillow Block
|
||||
// A Parametric Bearing Pillow Block
|
||||
// A bearing pillow block, also known as a plummer block or pillow block bearing, is a pedestal used to provide support for a rotating shaft with the help of compatible bearings and various accessories. Housing a bearing, the pillow block provides a secure and stable foundation that allows the shaft to rotate smoothly within its machinery setup. These components are essential in a wide range of mechanical systems and machinery, playing a key role in reducing friction and supporting radial and axial loads.
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants such as length, width, height, counter-bore depth and diameter, bearing diameter, hole location padding, and more
|
||||
length = 6
|
||||
width = 4
|
||||
height = 1
|
||||
@ -14,15 +14,15 @@ holeDia = .375
|
||||
padding = 1.5
|
||||
bearingDia = 3
|
||||
|
||||
// Sketch the block body
|
||||
body = startSketchOn(XY)
|
||||
// (Needs to be updated). Sketch the block and extrude up to where the counterbore diameter starts.
|
||||
extrude001 = startSketchOn(XY)
|
||||
|> startProfileAt([-width / 2, -length / 2], %)
|
||||
|> line(endAbsolute = [width / 2, -length / 2])
|
||||
|> line(endAbsolute = [width / 2, length / 2])
|
||||
|> line(endAbsolute = [-width / 2, length / 2])
|
||||
|> close()
|
||||
|> extrude(length = height)
|
||||
counterBoreHoles = startSketchOn(body, 'end')
|
||||
extrude002 = startSketchOn(extrude001, 'end')
|
||||
|> circle(
|
||||
center = [
|
||||
-(width / 2 - (padding / 2)),
|
||||
@ -34,7 +34,7 @@ counterBoreHoles = startSketchOn(body, 'end')
|
||||
|> patternLinear2d(instances = 2, distance = width - padding, axis = [1, 0])
|
||||
|> extrude(%, length = -cbDepth)
|
||||
|
||||
boltHoles = startSketchOn(body, 'start')
|
||||
extrude003 = startSketchOn(extrude001, 'start')
|
||||
|> circle(
|
||||
center = [
|
||||
-(width / 2 - (padding / 2)),
|
||||
@ -46,6 +46,6 @@ boltHoles = startSketchOn(body, 'start')
|
||||
|> patternLinear2d(instances = 2, distance = width - padding, axis = [1, 0])
|
||||
|> extrude(length = -height + cbDepth)
|
||||
|
||||
centerHole = startSketchOn(body, 'end')
|
||||
extrude004 = startSketchOn(extrude001, 'end')
|
||||
|> circle(center = [0, 0], radius = bearingDia / 2)
|
||||
|> extrude(length = -height)
|
@ -4,7 +4,7 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants like ball diameter, inside diamter, overhange length, and thickness
|
||||
outsideDiameter = 1.625
|
||||
sphereDia = 0.25
|
||||
shaftDia = 0.75
|
||||
@ -95,3 +95,5 @@ outsideWallSketch = startSketchOn(offsetPlane(XY, offset = -overallThickness / 2
|
||||
|> hole(circle(center = [0, 0], radius = shaftDia / 2 + wallThickness + sphereDia), %)
|
||||
|
||||
outsideWall = extrude(outsideWallSketch, length = overallThickness)
|
||||
|
||||
// https://www.mcmaster.com/60355K185/
|
||||
|
@ -4,8 +4,8 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import caliperTolerance, caliperPadLength, caliperThickness, caliperOuterEdgeRadius, caliperInnerEdgeRadius, rotorDiameter, rotorTotalThickness, yAxisOffset from "parameters.kcl"
|
||||
// Import Constants
|
||||
import caliperTolerance, caliperPadLength, caliperThickness, caliperOuterEdgeRadius, caliperInnerEdgeRadius, rotorDiameter, rotorTotalThickness, yAxisOffset from "globals.kcl"
|
||||
|
||||
// Sketch the brake caliper profile
|
||||
brakeCaliperSketch = startSketchOn(XY)
|
||||
|
@ -4,8 +4,8 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import rotorDiameter, rotorInnerDiameter, rotorSinglePlateThickness, rotorInnerDiameterThickness, lugHolePatternDia, lugSpacing, rotorTotalThickness, spacerPatternDiameter, spacerDiameter, spacerLength, spacerCount, wheelDiameter, lugCount, yAxisOffset, drillAndSlotCount from "parameters.kcl"
|
||||
// Import Constants
|
||||
import rotorDiameter, rotorInnerDiameter, rotorSinglePlateThickness, rotorInnerDiameterThickness, lugHolePatternDia, lugSpacing, rotorTotalThickness, spacerPatternDiameter, spacerDiameter, spacerLength, spacerCount, wheelDiameter, lugCount, yAxisOffset, drillAndSlotCount from "globals.kcl"
|
||||
|
||||
rotorSketch = startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = rotorDiameter / 2)
|
||||
|
@ -4,8 +4,8 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import tireInnerDiameter, tireOuterDiameter, tireDepth, bendRadius, tireTreadWidth, tireTreadDepth, tireTreadOffset from "parameters.kcl"
|
||||
// Import Constants
|
||||
import tireInnerDiameter, tireOuterDiameter, tireDepth, bendRadius, tireTreadWidth, tireTreadDepth, tireTreadOffset from "globals.kcl"
|
||||
|
||||
// Create the sketch of the tire
|
||||
tireSketch = startSketchOn(XY)
|
||||
|
@ -4,8 +4,8 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import lugCount, lugSpacing, offset, backSpacing, wheelWidth, wheelDiameter, spokeCount, spokeGap, spokeAngle, spokeThickness from "parameters.kcl"
|
||||
// Import Constants
|
||||
import lugCount, lugSpacing, offset, backSpacing, wheelWidth, wheelDiameter, spokeCount, spokeGap, spokeAngle, spokeThickness from "globals.kcl"
|
||||
|
||||
// Create the wheel center
|
||||
lugBase = startSketchOn(XZ)
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Car wheel assembly parameters
|
||||
// Car wheel assembly global constants
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Car wheel
|
||||
// Car Wheel
|
||||
export lugCount = 5
|
||||
export lugSpacing = 114.3 * mm()
|
||||
export offset = -35 * mm()
|
||||
@ -22,7 +22,7 @@ export lugThreadDiameter = lugDiameter / 2 * .85
|
||||
export lugLength = 30 * mm()
|
||||
export lugThreadDepth = lugLength - (12.7 * mm())
|
||||
|
||||
// Car rotor
|
||||
// Car Rotor
|
||||
export rotorDiameter = 12
|
||||
export rotorInnerDiameter = 6
|
||||
export rotorSinglePlateThickness = 0.25
|
||||
@ -36,7 +36,7 @@ export spacerCount = 16
|
||||
export yAxisOffset = 0.5
|
||||
export drillAndSlotCount = 5
|
||||
|
||||
// Car tire
|
||||
// Car Tire
|
||||
export tireInnerDiameter = 19
|
||||
export tireOuterDiameter = 24
|
||||
export tireDepth = 11.02
|
||||
@ -45,7 +45,7 @@ export tireTreadWidth = 0.39
|
||||
export tireTreadDepth = 0.39
|
||||
export tireTreadOffset = 3.15
|
||||
|
||||
// Brake caliper
|
||||
// Brake Caliper
|
||||
export caliperTolerance = 0.050
|
||||
export caliperPadLength = 1.6
|
||||
export caliperThickness = 0.39
|
@ -4,8 +4,8 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import lugDiameter, lugHeadLength, lugThreadDiameter, lugLength, lugThreadDepth, lugSpacing from "parameters.kcl"
|
||||
// Import Constants
|
||||
import lugDiameter, lugHeadLength, lugThreadDiameter, lugLength, lugThreadDepth, lugSpacing from "globals.kcl"
|
||||
|
||||
customPlane = {
|
||||
plane = {
|
||||
|
@ -4,24 +4,16 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parts
|
||||
import "car-wheel.kcl" as carWheel
|
||||
import "car-rotor.kcl" as carRotor
|
||||
import "brake-caliper.kcl" as brakeCaliper
|
||||
import "lug-nut.kcl" as lugNut
|
||||
import "car-tire.kcl" as carTire
|
||||
import lugCount from "globals.kcl"
|
||||
|
||||
// Import parameters
|
||||
import * from "parameters.kcl"
|
||||
|
||||
// Place the car rotor
|
||||
carRotor
|
||||
|> translate(x = 0, y = 0.5, z = 0)
|
||||
|
||||
// Place the car wheel
|
||||
carWheel
|
||||
|
||||
// Place the lug nuts
|
||||
lugNut
|
||||
|> patternCircular3d(
|
||||
arcDegrees = 360,
|
||||
@ -30,10 +22,6 @@ lugNut
|
||||
instances = lugCount,
|
||||
rotateDuplicates = false,
|
||||
)
|
||||
|
||||
// Place the brake caliper
|
||||
brakeCaliper
|
||||
|> translate(x = 0, y = 0.5, z = 0)
|
||||
|
||||
// Place the car tire
|
||||
carTire
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Color Cube
|
||||
// This is a color cube centered about the origin. It is used to help determine orientation in the scene.
|
||||
|
||||
// Set units
|
||||
// Set unit
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Parameters referenced in drawRectangle
|
||||
// Globals referenced in drawRectangle
|
||||
size = 100
|
||||
halfSize = size / 2
|
||||
extrudeLength = 1.0
|
||||
|
@ -1,10 +1,9 @@
|
||||
// Cycloidal Gear
|
||||
// A cycloidal gear is a gear with a continuous, curved tooth profile. They are used in watchmaking and high precision robotics actuation
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Create a function for the cycloidal gear
|
||||
fn cycloidalGear(gearPitch, gearHeight, holeDiameter, helixAngle) {
|
||||
// Create a function to draw the gear profile as a sketch. Rotate each profile about the gear's axis by an helix angle proportional to the total gear height
|
||||
fn gearSketch(gHeight) {
|
||||
@ -45,5 +44,4 @@ fn cycloidalGear(gearPitch, gearHeight, holeDiameter, helixAngle) {
|
||||
return gearLoft
|
||||
}
|
||||
|
||||
// Call the cycloidal gear function
|
||||
cycloidalGear(.3, 1.5, 0.297, -80)
|
||||
|
@ -9,19 +9,19 @@
|
||||
circR = 25
|
||||
|
||||
// Calculated parameters
|
||||
// Thickness of the dodecahedron
|
||||
// thickness of the dodecahedron
|
||||
wallThickness = circR * 0.2
|
||||
|
||||
// Angle between faces in radians
|
||||
// angle between faces in radians
|
||||
dihedral = acos(-(sqrt(5) / 5))
|
||||
|
||||
// Inscribed radius
|
||||
// inscribed radius
|
||||
inscR = circR / 15 * sqrt(75 + 30 * sqrt(5))
|
||||
|
||||
// Pentagon edge length
|
||||
// pentagon edge length
|
||||
edgeL = 4 * circR / (sqrt(3) * (1 + sqrt(5)))
|
||||
|
||||
// Pentagon radius
|
||||
// pentagon radius
|
||||
pentR = edgeL / 2 / sin(toRadians(36))
|
||||
|
||||
// Define a plane for the bottom angled face
|
||||
@ -69,7 +69,7 @@ bottomBowl = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Pattern the bottom to create the top face
|
||||
// pattern the bottom to create the top face
|
||||
patternCircular3d(
|
||||
bottom,
|
||||
instances = 2,
|
||||
@ -79,7 +79,7 @@ patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Pattern the bottom angled faces to create the top
|
||||
// pattern the bottom angled faces to create the top
|
||||
patternCircular3d(
|
||||
bottomBowl,
|
||||
instances = 2,
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Dual-Basin Utility Sink
|
||||
// A stainless steel sink unit with dual rectangular basins and six under-counter storage compartments.
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// globals
|
||||
tableHeight = 850
|
||||
tableWidth = 3400
|
||||
tableDepth = 400
|
||||
|
@ -4,7 +4,6 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
length = 175
|
||||
width = 125
|
||||
height = 70
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Exhaust Manifold
|
||||
// A welded exhaust header for an inline 4-cylinder engine
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define Constants
|
||||
primaryTubeDiameter = 1.625
|
||||
wallThickness = 0.080
|
||||
plateHeight = 0.125
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
mountingHoleDia = .625
|
||||
baseDia = 4.625
|
||||
pipeDia = 1.25
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// define parameters
|
||||
// define constants in mm
|
||||
radius = 6.0
|
||||
width = 144.0
|
||||
length = 80.0
|
||||
@ -15,7 +15,7 @@ tabLength = 25
|
||||
tabWidth = 12
|
||||
tabThk = 4
|
||||
|
||||
// Define a rectangular shape func
|
||||
// define a rectangular shape func
|
||||
fn rectShape(pos, w, l) {
|
||||
rr = startSketchOn('xy')
|
||||
|> startProfileAt([pos[0] - (w / 2), pos[1] - (l / 2)], %)
|
||||
@ -26,7 +26,7 @@ fn rectShape(pos, w, l) {
|
||||
return rr
|
||||
}
|
||||
|
||||
// Define the bracket plane
|
||||
// define the bracket plane
|
||||
bracketPlane = {
|
||||
plane = {
|
||||
origin = { x = 0, y = length / 2 + thk, z = 0 },
|
||||
@ -36,7 +36,7 @@ bracketPlane = {
|
||||
}
|
||||
}
|
||||
|
||||
// Build the bracket sketch around the body
|
||||
// build the bracket sketch around the body
|
||||
fn bracketSketch(w, d, t) {
|
||||
s = startSketchOn(bracketPlane)
|
||||
|> startProfileAt([-w / 2 - t, d + t], %)
|
||||
@ -51,7 +51,7 @@ fn bracketSketch(w, d, t) {
|
||||
return s
|
||||
}
|
||||
|
||||
// Build the body of the bracket
|
||||
// build the body of the bracket
|
||||
bs = bracketSketch(width, depth, thk)
|
||||
bracketBody = bs
|
||||
|> extrude(length = length + 2 * thk)
|
||||
@ -65,7 +65,7 @@ bracketBody = bs
|
||||
],
|
||||
)
|
||||
|
||||
// Define the tab plane
|
||||
// define the tab plane
|
||||
tabPlane = {
|
||||
plane = {
|
||||
origin = { x = 0, y = 0, z = depth + thk },
|
||||
@ -75,7 +75,7 @@ tabPlane = {
|
||||
}
|
||||
}
|
||||
|
||||
// Build the tabs of the mounting bracket (right side)
|
||||
// build the tabs of the mounting bracket (right side)
|
||||
tabsR = startSketchOn(tabPlane)
|
||||
|> startProfileAt([width / 2 + thk, length / 2 + thk], %)
|
||||
|> line(end = [tabWidth, -tabLength / 3], tag = $edge11)
|
||||
@ -99,7 +99,7 @@ tabsR = startSketchOn(tabPlane)
|
||||
)
|
||||
|> patternLinear3d(axis = [0, -1, 0], instances = 2, distance = length + 2 * thk - (tabLength * 4 / 3))
|
||||
|
||||
// Build the tabs of the mounting bracket (left side)
|
||||
// build the tabs of the mounting bracket (left side)
|
||||
tabsL = startSketchOn(tabPlane)
|
||||
|> startProfileAt([-width / 2 - thk, length / 2 + thk], %)
|
||||
|> line(end = [-tabWidth, -tabLength / 3], tag = $edge21)
|
||||
@ -123,7 +123,7 @@ tabsL = startSketchOn(tabPlane)
|
||||
)
|
||||
|> patternLinear3d(axis = [0, -1, 0], instances = 2, distance = length + 2 * thk - (tabLength * 4 / 3))
|
||||
|
||||
// Define a plane for retention bumps
|
||||
// define a plane for retention bumps
|
||||
retPlane = {
|
||||
plane = {
|
||||
origin = { x = -width / 2 + 20, y = 0, z = 0 },
|
||||
@ -133,7 +133,7 @@ retPlane = {
|
||||
}
|
||||
}
|
||||
|
||||
// Build the retention bump in the front
|
||||
// build the retention bump in the front
|
||||
retFront = startSketchOn(retPlane)
|
||||
|> startProfileAt([-length / 2 - thk, 0], %)
|
||||
|> line(end = [0, thk])
|
||||
@ -141,7 +141,7 @@ retFront = startSketchOn(retPlane)
|
||||
|> close()
|
||||
|> extrude(length = width - 40)
|
||||
|
||||
// Build the retention bump in the back
|
||||
// build the retention bump in the back
|
||||
retBack = startSketchOn(retPlane)
|
||||
|> startProfileAt([length / 2 + thk, 0], %)
|
||||
|> line(end = [0, thk])
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// Define constants in millimeters (mm)
|
||||
flipperThickness = 3.5
|
||||
flipperLength = 70.0
|
||||
handleWidth = 15.0
|
||||
@ -16,7 +16,7 @@ gripHeight = 20.0
|
||||
gripFilletRadius = 3.0
|
||||
gripSlotWidth = 8.0
|
||||
|
||||
// Function for drawing slots on a sketch given the start and end points as well as a width
|
||||
// function for drawing slots on a sketch given the start and end points as well as a width
|
||||
fn slot(sketch1, start, end, width) {
|
||||
angle = if start[0] == end[0] {
|
||||
if end[1] > start[1] {
|
||||
@ -43,10 +43,10 @@ fn slot(sketch1, start, end, width) {
|
||||
return slotSketch
|
||||
}
|
||||
|
||||
// Create a sketch on the "XY" plane
|
||||
// create a sketch on the "XY" plane
|
||||
sketch000 = startSketchOn(XY)
|
||||
|
||||
// Create a profile of the flipper
|
||||
// create a profile of the flipper
|
||||
flipperProfile = startProfileAt([-flipperLength, -32.0], sketch000)
|
||||
|> line(end = [flipperLength, 2.0])
|
||||
|> yLine(length = 60.0, tag = $backEdge)
|
||||
@ -58,25 +58,25 @@ flipperProfile = startProfileAt([-flipperLength, -32.0], sketch000)
|
||||
}, %)
|
||||
|> close()
|
||||
|
||||
// Create a profile of the middle
|
||||
// create a profile of the middle
|
||||
slotProfile000 = slot(sketch000, [-25, 0], [-55, 0], flipperSlotWidth)
|
||||
|
||||
// Create a profile of the top slot
|
||||
// create a profile of the top slot
|
||||
slotProfile001 = slot(sketch000, [-25, 18], [-55, 19], flipperSlotWidth)
|
||||
|
||||
// Create a profile of the bottom slot
|
||||
// create a profile of the bottom slot
|
||||
slotProfile002 = slot(sketch000, [-25, -18], [-55, -19], flipperSlotWidth)
|
||||
|
||||
// Create a profile with slots for the spatula
|
||||
// create a profile with slots for the spatula
|
||||
spatulaProfile = flipperProfile
|
||||
|> hole(slotProfile000, %)
|
||||
|> hole(slotProfile001, %)
|
||||
|> hole(slotProfile002, %)
|
||||
|
||||
// Extrude the profile to create the spatula flipper
|
||||
// extrude the profile to create the spatula flipper
|
||||
flipper = extrude(spatulaProfile, length = flipperThickness)
|
||||
|
||||
// Fillet the edges of the flipper
|
||||
// fillet the edges of the flipper
|
||||
fillet(
|
||||
flipper,
|
||||
radius = flipperFilletRadius,
|
||||
@ -86,10 +86,10 @@ fillet(
|
||||
],
|
||||
)
|
||||
|
||||
// Create a sketch on the "XZ" plane offset by half the thickness
|
||||
// create a sketch on the "XZ" plane offset by half the thickness
|
||||
sketch001 = startSketchOn(offsetPlane(XZ, offset = -handleWidth / 2))
|
||||
|
||||
// Create a profile of the spatula handle
|
||||
// create a profile of the spatula handle
|
||||
handleProfile = startProfileAt([0.0, flipperThickness], sketch001)
|
||||
|> line(end = [31.819805, 31.819805], tag = $handleBottomEdge)
|
||||
|> line(end = [140.953893, 51.303021])
|
||||
@ -99,10 +99,10 @@ handleProfile = startProfileAt([0.0, flipperThickness], sketch001)
|
||||
|> xLine(length = 7.071068)
|
||||
|> close()
|
||||
|
||||
// Create an extrusion extrude001
|
||||
// create an extrusion extrude001
|
||||
handle = extrude(handleProfile, length = handleWidth)
|
||||
|
||||
// Fillet the bend of the spatula handle
|
||||
// fillet the bend of the spatula handle
|
||||
fillet(
|
||||
handle,
|
||||
radius = 4,
|
||||
@ -112,7 +112,7 @@ fillet(
|
||||
],
|
||||
)
|
||||
|
||||
// Define a plane which is at the end of the handle
|
||||
// define a plane which is at the end of the handle
|
||||
handlePlane = {
|
||||
plane = {
|
||||
origin = [208.593833, 0.0, 75.921946],
|
||||
@ -122,10 +122,10 @@ handlePlane = {
|
||||
}
|
||||
}
|
||||
|
||||
// Create a sketch on the handle plane
|
||||
// create a sketch on the handle plane
|
||||
sketch002 = startSketchOn(handlePlane)
|
||||
|
||||
// Create a profile of the grip
|
||||
// create a profile of the grip
|
||||
gripProfile = startProfileAt([-26.806746, -10.0], sketch002)
|
||||
|> xLine(length = gripWidth - (2 * gripFilletRadius))
|
||||
|> arc({
|
||||
@ -153,14 +153,14 @@ gripProfile = startProfileAt([-26.806746, -10.0], sketch002)
|
||||
}, %)
|
||||
|> close()
|
||||
|
||||
// Extrude the grip profile to create the grip
|
||||
// extrude the grip profile to create the grip
|
||||
grip = extrude(gripProfile, length = -gripLength)
|
||||
|
||||
// Create a sketch on the grip for the hole
|
||||
// create a sketch on the grip for the hole
|
||||
sketch003 = startSketchOn(grip, gripEdgeTop)
|
||||
|
||||
// Create a profile for the grip hole
|
||||
// create a profile for the grip hole
|
||||
gripHoleProfile = slot(sketch003, [0, 200], [0, 210], gripSlotWidth)
|
||||
|
||||
// Cut a hole in the grip
|
||||
// cut a hole in the grip
|
||||
extrude(gripHoleProfile, length = -gripWidth - 20)
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
carafeDiameter = 4.41
|
||||
carafeHeight = 7.32
|
||||
handleThickness = 0.65
|
||||
|
@ -1,10 +1,10 @@
|
||||
// 100mm Gear Rack
|
||||
// A flat bar or rail that is engraved with teeth along its length. These teeth are designed to mesh with the teeth of a gear, known as a pinion. When the pinion, a small cylindrical gear, rotates, its teeth engage with the teeth on the rack, causing the rack to move linearly. Conversely, linear motion applied to the rack will cause the pinion to rotate.
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
length = 100
|
||||
pitchHeight = 11.5
|
||||
width = 5
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Spur Gear
|
||||
// A rotating machine part having cut teeth or, in the case of a cogwheel, inserted teeth (called cogs), which mesh with another toothed part to transmit torque. Geared devices can change the speed, torque, and direction of a power source. The two elements that define a gear are its circular shape and the teeth that are integrated into its outer edge, which are designed to fit into the teeth of another gear.
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
nTeeth = 21
|
||||
module = 0.5
|
||||
pitchDiameter = module * nTeeth
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units in millimeters (mm)
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
binLength = 42.0
|
||||
cornerRadius = 4.0
|
||||
firstStep = 0.7
|
||||
@ -21,7 +21,7 @@ countBinLength = 3
|
||||
// The total height of the baseplate is a summation of the vertical heights of the baseplate steps
|
||||
height = firstStep + secondStep + thirdStep
|
||||
|
||||
// Define a function which builds the profile of the baseplate bin
|
||||
// define a function which builds the profile of the baseplate bin
|
||||
fn face(plane) {
|
||||
faceSketch = startSketchOn(plane)
|
||||
|> startProfileAt([0, 0], %)
|
||||
@ -33,10 +33,10 @@ fn face(plane) {
|
||||
return faceSketch
|
||||
}
|
||||
|
||||
// Extrude a single side of the bin
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// Create the other sides of the bin by using a circular pattern
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
singleSide,
|
||||
arcDegrees = 360,
|
||||
@ -46,16 +46,16 @@ sides = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Define an axis axis000
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
direction = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
|
||||
// Create a single corner of the bin
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
||||
|
||||
// Create the corners of the bin
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
singleCorner,
|
||||
arcDegrees = 360,
|
||||
@ -65,7 +65,7 @@ corners = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the baseplate by patterning sides
|
||||
// create the baseplate by patterning sides
|
||||
basePlateSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -74,7 +74,7 @@ basePlateSides = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// Create the corners of the baseplate by patterning the corners
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
basePlateCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -83,7 +83,7 @@ basePlateCorners = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// Create the center cutout for the magnet profile
|
||||
// create the center cutout for the magnet profile
|
||||
fn magnetCenterCutout(plane) {
|
||||
magnetSketch = startSketchOn(plane)
|
||||
|> startProfileAt([
|
||||
@ -126,7 +126,7 @@ fn magnetCenterCutout(plane) {
|
||||
return magnetSketch
|
||||
}
|
||||
|
||||
// Create the outside profile of the magnets
|
||||
// create the outside profile of the magnets
|
||||
fn magnetBase(plane) {
|
||||
magnetBaseSketch = startSketchOn(plane)
|
||||
|> startProfileAt([0, 0], %)
|
||||
@ -138,7 +138,7 @@ fn magnetBase(plane) {
|
||||
return magnetBaseSketch
|
||||
}
|
||||
|
||||
// Create sketch profile sketch000Profile002
|
||||
// create sketch profile sketch000Profile002
|
||||
magnetsSketch = startSketchOn(XY)
|
||||
|> circle(center = [cornerRadius * 2, cornerRadius * 2], radius = magOuterDiam / 2)
|
||||
|> patternCircular2d(
|
||||
@ -148,14 +148,14 @@ magnetsSketch = startSketchOn(XY)
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create a profile with holes for the magnets
|
||||
// create a profile with holes for the magnets
|
||||
magnetProfile = magnetBase(XY)
|
||||
|> hole(magnetsSketch, %)
|
||||
|
||||
// Create an extrusion of the magnet cutout with holes
|
||||
// create an extrusion of the magnet cutout with holes
|
||||
magnetHolesExtrude = extrude(magnetProfile, length = -magDepth)
|
||||
|
||||
// Add a fillet to the extrusion
|
||||
// add a fillet to the extrusion
|
||||
magnetHolesExtrudeFillets = fillet(
|
||||
magnetHolesExtrude,
|
||||
radius = cornerRadius,
|
||||
@ -167,13 +167,13 @@ magnetHolesExtrudeFillets = fillet(
|
||||
],
|
||||
)
|
||||
|
||||
// Create a profile without the holes for the magnets
|
||||
// create a profile without the holes for the magnets
|
||||
magnetProfileNoMagnets = magnetBase(offsetPlane(XY, offset = -magDepth))
|
||||
|
||||
// Create an extrusion of the magnet cutout without holes
|
||||
// create an extrusion of the magnet cutout without holes
|
||||
magnetCutoutExtrude = extrude(magnetProfileNoMagnets, length = -magDepth)
|
||||
|
||||
// Add a fillet to the extrusion
|
||||
// add a fillet to the extrusion
|
||||
magnetCutoutExtrudeFillets = fillet(
|
||||
magnetCutoutExtrude,
|
||||
radius = cornerRadius,
|
||||
@ -185,7 +185,7 @@ magnetCutoutExtrudeFillets = fillet(
|
||||
],
|
||||
)
|
||||
|
||||
// Pattern the magnet cutouts with holes
|
||||
// pattern the magnet cutouts with holes
|
||||
patternLinear3d(
|
||||
magnetHolesExtrudeFillets,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -194,7 +194,7 @@ patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// Pattern the magnet cutouts without holes
|
||||
// pattern the magnet cutouts without holes
|
||||
patternLinear3d(
|
||||
magnetCutoutExtrudeFillets,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units in millimeters (mm)
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
binLength = 42.0
|
||||
cornerRadius = 4.0
|
||||
firstStep = 0.7
|
||||
@ -18,7 +18,7 @@ countBinLength = 3
|
||||
// The total height of the baseplate is a summation of the vertical heights of the baseplate steps
|
||||
height = firstStep + secondStep + thirdStep
|
||||
|
||||
// Define a function which builds the profile of the baseplate bin
|
||||
// define a function which builds the profile of the baseplate bin
|
||||
fn face(plane) {
|
||||
faceSketch = startSketchOn(plane)
|
||||
|> startProfileAt([0, 0], %)
|
||||
@ -30,10 +30,10 @@ fn face(plane) {
|
||||
return faceSketch
|
||||
}
|
||||
|
||||
// Extrude a single side of the bin
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// Create the other sides of the bin by using a circular pattern
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
singleSide,
|
||||
arcDegrees = 360,
|
||||
@ -43,16 +43,16 @@ sides = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Define an axis axis000
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
direction = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
|
||||
// Create a single corner of the bin
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius)), angle = -90, axis = axis000)
|
||||
|
||||
// Create the corners of the bin
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
singleCorner,
|
||||
arcDegrees = 360,
|
||||
@ -62,7 +62,7 @@ corners = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the baseplate by patterning sides
|
||||
// create the baseplate by patterning sides
|
||||
basePlateSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -71,7 +71,7 @@ basePlateSides = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength)
|
||||
|
||||
// Create the corners of the baseplate by patterning the corners
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
basePlateCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units in millimeters (mm)
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
binLength = 41.5
|
||||
binHeight = 7.0
|
||||
binBaseLength = 2.95
|
||||
@ -33,7 +33,7 @@ countBinHeight = 1
|
||||
height = firstStep + secondStep + thirdStep
|
||||
lipHeight = lipStep1 + lipStep2 + lipStep3 + lipStep4 + lipStep5
|
||||
|
||||
// Define a function which builds the profile of the baseplate bin
|
||||
// define a function which builds the profile of the baseplate bin
|
||||
fn face(plane) {
|
||||
faceSketch = startSketchOn(plane)
|
||||
|> startProfileAt([binBaseLength + binTol, 0], %)
|
||||
@ -46,10 +46,10 @@ fn face(plane) {
|
||||
return faceSketch
|
||||
}
|
||||
|
||||
// Extrude a single side of the bin
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius + binTol)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// Create the other sides of the bin by using a circular pattern
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
singleSide,
|
||||
arcDegrees = 360,
|
||||
@ -63,7 +63,7 @@ sides = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Define an axis axis000
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
direction = [0.0, 1.0],
|
||||
origin = [
|
||||
@ -72,10 +72,10 @@ axis000 = {
|
||||
]
|
||||
}
|
||||
|
||||
// Create a single corner of the bin
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||
|
||||
// Create the corners of the bin
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
singleCorner,
|
||||
arcDegrees = 360,
|
||||
@ -128,7 +128,7 @@ magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
)
|
||||
|> extrude(length = -magDepth)
|
||||
|
||||
// Create the baseplate by patterning sides
|
||||
// create the baseplate by patterning sides
|
||||
binSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -137,7 +137,7 @@ binSides = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// Create the corners of the baseplate by patterning the corners
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
binCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -146,7 +146,7 @@ binCorners = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// Create the fill of the bin by patterning the corners
|
||||
// create the fill of the bin by patterning the corners
|
||||
binFill = patternLinear3d(
|
||||
singleBinFill,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -155,6 +155,7 @@ binFill = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
//
|
||||
binTop = startSketchOn(offsetPlane(XY, offset = height))
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = (binLength + 2 * binTol) * countBinWidth, tag = $line010)
|
||||
@ -173,7 +174,7 @@ binTop = startSketchOn(offsetPlane(XY, offset = height))
|
||||
)
|
||||
|> shell(faces = ["end"], thickness = binThk)
|
||||
|
||||
// Define a function which builds the profile of the baseplate bin
|
||||
// define a function which builds the profile of the baseplate bin
|
||||
fn lipFace(plane) {
|
||||
faceSketch = startSketchOn(plane)
|
||||
|> startProfileAt([0, 0], %)
|
||||
@ -233,13 +234,13 @@ plane002 = {
|
||||
}
|
||||
}
|
||||
|
||||
// Extrude a single side of the lip of the bin
|
||||
// extrude a single side of the lip of the bin
|
||||
lipSingleLength = extrude(lipFace(plane000), length = binLength * countBinWidth - (2 * cornerRadius) + 2 * binTol * countBinWidth)
|
||||
|
||||
// Extrude a single side of the lip of the bin
|
||||
// extrude a single side of the lip of the bin
|
||||
lipSingleWidth = extrude(lipFace(plane001), length = binLength * countBinLength - (2 * cornerRadius) + 2 * binTol * countBinLength)
|
||||
|
||||
// Create the other sides of the lips by using a circular pattern
|
||||
// create the other sides of the lips by using a circular pattern
|
||||
lipLengths = patternCircular3d(
|
||||
lipSingleLength,
|
||||
arcDegrees = 360,
|
||||
@ -253,7 +254,7 @@ lipLengths = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the other sides of the lips by using a circular pattern
|
||||
// create the other sides of the lips by using a circular pattern
|
||||
lipWidths = patternCircular3d(
|
||||
lipSingleWidth,
|
||||
arcDegrees = 360,
|
||||
@ -267,19 +268,19 @@ lipWidths = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Define an axis axis000
|
||||
// define an axis axis000
|
||||
axis001 = {
|
||||
direction = [0.0, 1.0],
|
||||
origin = [cornerRadius, cornerRadius]
|
||||
}
|
||||
|
||||
// Create a single corner of the bin
|
||||
// create a single corner of the bin
|
||||
lipSingleLengthCorner = revolve(lipFace(plane000), angle = -90, axis = axis001)
|
||||
|
||||
// Create a single corner of the bin
|
||||
// create a single corner of the bin
|
||||
lipSingleWidthCorner = revolve(lipFace(plane002), angle = 90, axis = axis001)
|
||||
|
||||
// Create the corners of the bin
|
||||
// create the corners of the bin
|
||||
lipCorners000 = patternCircular3d(
|
||||
lipSingleLengthCorner,
|
||||
arcDegrees = 360,
|
||||
@ -293,7 +294,7 @@ lipCorners000 = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Create the corners of the bin
|
||||
// create the corners of the bin
|
||||
lipCorners001 = patternCircular3d(
|
||||
lipSingleWidthCorner,
|
||||
arcDegrees = 360,
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Set units in millimeters (mm)
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
binLength = 41.5
|
||||
binHeight = 7.0
|
||||
binBaseLength = 2.95
|
||||
@ -26,7 +26,7 @@ countBinHeight = 2
|
||||
// The total height of the baseplate is a summation of the vertical heights of the baseplate steps
|
||||
height = firstStep + secondStep + thirdStep
|
||||
|
||||
// Define a function which builds the profile of the baseplate bin
|
||||
// define a function which builds the profile of the baseplate bin
|
||||
fn face(plane) {
|
||||
faceSketch = startSketchOn(plane)
|
||||
|> startProfileAt([binBaseLength + binTol, 0], %)
|
||||
@ -39,10 +39,10 @@ fn face(plane) {
|
||||
return faceSketch
|
||||
}
|
||||
|
||||
// Extrude a single side of the bin
|
||||
// extrude a single side of the bin
|
||||
singleSide = extrude(face(offsetPlane(YZ, offset = cornerRadius + binTol)), length = binLength - (cornerRadius * 2))
|
||||
|
||||
// Create the other sides of the bin by using a circular pattern
|
||||
// create the other sides of the bin by using a circular pattern
|
||||
sides = patternCircular3d(
|
||||
singleSide,
|
||||
arcDegrees = 360,
|
||||
@ -56,7 +56,7 @@ sides = patternCircular3d(
|
||||
rotateDuplicates = true,
|
||||
)
|
||||
|
||||
// Define an axis axis000
|
||||
// define an axis axis000
|
||||
axis000 = {
|
||||
direction = [0.0, 1.0],
|
||||
origin = [
|
||||
@ -65,10 +65,10 @@ axis000 = {
|
||||
]
|
||||
}
|
||||
|
||||
// Create a single corner of the bin
|
||||
// create a single corner of the bin
|
||||
singleCorner = revolve(face(offsetPlane(YZ, offset = cornerRadius + binTol)), angle = -90, axis = axis000)
|
||||
|
||||
// Create the corners of the bin
|
||||
// create the corners of the bin
|
||||
corners = patternCircular3d(
|
||||
singleCorner,
|
||||
arcDegrees = 360,
|
||||
@ -121,7 +121,7 @@ magCutout000 = startSketchOn(singleBinFill, "start")
|
||||
)
|
||||
|> extrude(length = -magDepth)
|
||||
|
||||
// Create the baseplate by patterning sides
|
||||
// create the baseplate by patterning sides
|
||||
binSides = patternLinear3d(
|
||||
sides,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -130,7 +130,7 @@ binSides = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// Create the corners of the baseplate by patterning the corners
|
||||
// create the corners of the baseplate by patterning the corners
|
||||
binCorners = patternLinear3d(
|
||||
corners,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -139,7 +139,7 @@ binCorners = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// Create the fill of the bin by patterning the corners
|
||||
// create the fill of the bin by patterning the corners
|
||||
binFill = patternLinear3d(
|
||||
singleBinFill,
|
||||
axis = [1.0, 0.0, 0.0],
|
||||
@ -148,7 +148,7 @@ binFill = patternLinear3d(
|
||||
)
|
||||
|> patternLinear3d(axis = [0.0, 1.0, 0.0], instances = countBinLength, distance = binLength + binTol * 2)
|
||||
|
||||
// Create the top of the bin
|
||||
// create the top of the bin
|
||||
binTop = startSketchOn(offsetPlane(XY, offset = height))
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> xLine(length = (binLength + 2 * binTol) * countBinWidth, tag = $line010)
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Hex Nut
|
||||
// Hex nut
|
||||
// A hex nut is a type of fastener with a threaded hole and a hexagonal outer shape, used in a wide variety of applications to secure parts together. The hexagonal shape allows for a greater torque to be applied with wrenches or tools, making it one of the most common nut types in hardware.
|
||||
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters (5/16" - 24 thread size)
|
||||
// Define constants (5/16" - 24 thread size)
|
||||
wallToWallLength = 0.5
|
||||
thickness = 0.266
|
||||
diameter = 0.3125
|
||||
|
@ -1,10 +1,10 @@
|
||||
// I-beam
|
||||
// A structural metal beam with an I shaped cross section. Often used in construction and architecture
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define Beam Dimensions
|
||||
beamLength = 6 * ft()
|
||||
beamHeight = 4
|
||||
flangeWidth = 2.663
|
||||
@ -13,7 +13,7 @@ webThickness = 0.193
|
||||
rootRadius = 0.457
|
||||
|
||||
// Sketch a quadrant of the beam cross section, then mirror for symmetry across each axis. Extrude to the appropriate length
|
||||
iBeam = startSketchOn(-XZ)
|
||||
sketch001 = startSketchOn(-XZ)
|
||||
|> startProfileAt([0, beamHeight / 2], %)
|
||||
|> xLine(length = flangeWidth / 2)
|
||||
|> yLine(length = -flangeThickness)
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Zoo Keyboard
|
||||
// A custom keyboard with Zoo brand lettering
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
baseColor = "#0f0f0f"
|
||||
highlightColor1 = "#b0b0b0"
|
||||
highlightColor2 = "#23af93"
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Kitt
|
||||
// The beloved KittyCAD mascot in a voxelized style.
|
||||
|
||||
// Pixel box function
|
||||
// pixel box function
|
||||
fn pixelBox(kitExtrude, extrudeTag, positionY, positionZ, width, height, depth) {
|
||||
pixelBoxBody = startSketchOn(kitExtrude, extrudeTag)
|
||||
|> startProfileAt([positionY, positionZ], %)
|
||||
|
@ -4,8 +4,8 @@
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
lbumps = 3 // number of bumps long
|
||||
// Define constants
|
||||
lbumps = 4 // number of bumps long
|
||||
wbumps = 2 // number of bumps wide
|
||||
pitch = 8.0
|
||||
clearance = 0.1
|
||||
|
@ -1,19 +1,19 @@
|
||||
// Makeup Mirror
|
||||
// A circular vanity mirror mounted on a swiveling arm with pivot joints, used for personal grooming.
|
||||
|
||||
// Set units
|
||||
// Settings
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Hinge parameters
|
||||
// hinge
|
||||
hingeRadius = 8
|
||||
hingeHeight = hingeRadius * 3
|
||||
hingeGap = 0.5
|
||||
|
||||
// Arm parameters
|
||||
// arm
|
||||
armLength = 170
|
||||
armRadius = 5
|
||||
|
||||
// Mirror parameters
|
||||
// mirror
|
||||
mirrorRadius = 170 / 2
|
||||
mirrorThickness = 10
|
||||
archToMirrorGap = 5
|
||||
@ -21,7 +21,7 @@ archThickness = 1
|
||||
archRadius = mirrorRadius + archToMirrorGap
|
||||
|
||||
// Geometry
|
||||
// Add a function to create the hinge
|
||||
// hinge
|
||||
fn hingeFn(x, y, z) {
|
||||
hingeBody = startSketchOn(offsetPlane(XY, offset = z))
|
||||
|> circle(center = [x, y], radius = hingeRadius)
|
||||
@ -39,7 +39,7 @@ hingePartB3 = hingeFn(armLength, 0, hingeHeight * 2 + hingeGap * 2)
|
||||
hingePartC2 = hingeFn(armLength, -armLength, hingeHeight * 2 + hingeGap * 2)
|
||||
hingePartC3 = hingeFn(armLength, -armLength, hingeHeight * 3 + hingeGap * 3)
|
||||
|
||||
// Add a function to create the arm
|
||||
// arm
|
||||
fn armFn(plane, offset, altitude) {
|
||||
armBody = startSketchOn(plane)
|
||||
|> circle(center = [offset, altitude], radius = armRadius)
|
||||
@ -50,7 +50,7 @@ fn armFn(plane, offset, altitude) {
|
||||
armPartA = armFn(YZ, 0, hingeHeight * 1.5 + hingeGap)
|
||||
armPartB = armFn(XZ, armLength, hingeHeight * 2.5 + hingeGap * 2)
|
||||
|
||||
// Add a function to create the mirror
|
||||
// mirror
|
||||
fn mirrorFn(plane, offsetX, offsetY, altitude, radius, tiefe, gestellR, gestellD) {
|
||||
armPlane = startSketchOn( offsetPlane(plane, offset = offsetY - (tiefe / 2)))
|
||||
armBody = circle(armPlane, center = [offsetX, altitude], radius = radius)
|
||||
|
@ -6,6 +6,13 @@
|
||||
"title": "80/20 Rail",
|
||||
"description": "An 80/20 extruded aluminum linear rail. T-slot profile adjustable by profile height, rail length, and origin position"
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "a-parametric-bearing-pillow-block/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "A Parametric Bearing Pillow Block",
|
||||
"description": "A bearing pillow block, also known as a plummer block or pillow block bearing, is a pedestal used to provide support for a rotating shaft with the help of compatible bearings and various accessories. Housing a bearing, the pillow block provides a secure and stable foundation that allows the shaft to rotate smoothly within its machinery setup. These components are essential in a wide range of mechanical systems and machinery, playing a key role in reducing friction and supporting radial and axial loads."
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "ball-bearing/main.kcl",
|
||||
@ -150,7 +157,7 @@
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "hex-nut/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Hex Nut",
|
||||
"title": "Hex nut",
|
||||
"description": "A hex nut is a type of fastener with a threaded hole and a hexagonal outer shape, used in a wide variety of applications to secure parts together. The hexagonal shape allows for a greater torque to be applied with wrenches or tools, making it one of the most common nut types in hardware."
|
||||
},
|
||||
{
|
||||
@ -202,19 +209,12 @@
|
||||
"title": "Robot Arm",
|
||||
"description": "A 4 axis robotic arm for industrial use. These machines can be used for assembly, packaging, organization of goods, and quality inspection processes"
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "parametric-bearing-pillow-block/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Parametric Bearing Pillow Block",
|
||||
"description": "A bearing pillow block, also known as a plummer block or pillow block bearing, is a pedestal used to provide support for a rotating shaft with the help of compatible bearings and various accessories. Housing a bearing, the pillow block provides a secure and stable foundation that allows the shaft to rotate smoothly within its machinery setup. These components are essential in a wide range of mechanical systems and machinery, playing a key role in reducing friction and supporting radial and axial loads."
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "pipe/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Pipe",
|
||||
"description": "Piping for the pipe flange assembly"
|
||||
"description": "A tubular section or hollow cylinder, usually but not necessarily of circular cross-section, used mainly to convey substances that can flow."
|
||||
},
|
||||
{
|
||||
"file": "main.kcl",
|
||||
@ -248,7 +248,7 @@
|
||||
"file": "main.kcl",
|
||||
"pathFromProjectDirectoryToFirstFile": "router-template-slate/main.kcl",
|
||||
"multipleFiles": false,
|
||||
"title": "Router Template for a Slate",
|
||||
"title": "Router template for a slate",
|
||||
"description": "A guide for routing a slate for a cross bar."
|
||||
},
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Mounting Plate
|
||||
// A flat piece of material, often metal or plastic, that serves as a support or base for attaching, securing, or mounting various types of equipment, devices, or components.
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
plateLength = 10
|
||||
plateWidth = 6
|
||||
filletRadius = 0.5
|
||||
|
@ -4,7 +4,6 @@
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parts
|
||||
import "robot-arm-base.kcl" as robotArmBase
|
||||
import "robot-rotating-base.kcl" as rotatingBase
|
||||
import "robot-arm-j2.kcl" as j2RobotArm
|
||||
|
@ -1,23 +1,25 @@
|
||||
// Pipe
|
||||
// Piping for the pipe flange assembly
|
||||
// piping for the pipe flange assembly
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import pipeInnerDiameter, pipeOuterDiameter, pipeLength from "parameters.kcl"
|
||||
// import constants
|
||||
import pipeInnerDiameter, pipeOuterDiameter, pipeLength from "globals.kcl"
|
||||
|
||||
// Create a function to make the pipe. Export
|
||||
// create a function to make the pipe
|
||||
export fn pipe() {
|
||||
// Create the pipe base
|
||||
// create the pipe base
|
||||
pipeBase = startSketchOn(XZ)
|
||||
|> circle(%, center = [0, 0], radius = pipeOuterDiameter / 2)
|
||||
|> extrude(%, length = pipeLength)
|
||||
|
||||
// Extrude a hole through the length of the pipe
|
||||
// extrude a hole through the length of the pipe
|
||||
pipe = startSketchOn(pipeBase, 'end')
|
||||
|> circle(center = [0, 0], radius = pipeInnerDiameter / 2)
|
||||
|> extrude(%, length = -pipeLength)
|
||||
|> appearance(color = "#a24ed0")
|
||||
return pipe
|
||||
}
|
||||
|
||||
// https://www.mcmaster.com/1120T74/
|
||||
|
@ -1,15 +1,15 @@
|
||||
// Flange
|
||||
// Flange used for mating two pipes together in the pipe flange assembly.
|
||||
// 68095k348 flange
|
||||
// flange used for mating two pipes together in the pipe flange assembly.
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import pipeDiameter, mountingHoleDiameter, mountingHolePlacementDiameter, flangeDiameter, flangeTotalThickness, flangeBackHeight, flangeFrontHeight, flangeBaseThickness, flangeBackDiameter, flangeFrontDiameter from "parameters.kcl"
|
||||
// import constants
|
||||
import pipeDiameter, mountingHoleDiameter, mountingHolePlacementDiameter, flangeDiameter, flangeTotalThickness, flangeBackHeight, flangeFrontHeight, flangeBaseThickness, flangeBackDiameter, flangeFrontDiameter from "globals.kcl"
|
||||
|
||||
// Create a function to create the flange. We must create a function since we are using multiple flanges.
|
||||
// create a function to create the flange
|
||||
export fn flange() {
|
||||
// Sketch the mounting hole pattern
|
||||
// sketch the mounting hole pattern
|
||||
mountingHoles = startSketchOn(XY)
|
||||
|> circle(%, center = [0, mountingHolePlacementDiameter / 2], radius = mountingHoleDiameter / 2)
|
||||
|> patternCircular2d(
|
||||
@ -20,13 +20,13 @@ export fn flange() {
|
||||
rotateDuplicates = false,
|
||||
)
|
||||
|
||||
// Create the flange base
|
||||
// create the flange base
|
||||
flangeBase = startSketchOn(XY)
|
||||
|> circle(%, center = [0, 0], radius = flangeDiameter / 2)
|
||||
|> hole(mountingHoles, %)
|
||||
|> extrude(%, length = flangeBaseThickness)
|
||||
|
||||
// Create both the raised portions on the front and back of the flange base
|
||||
// create both the raised portions on the front and back of the flange base
|
||||
flangeBack = startSketchOn(flangeBase, 'start')
|
||||
|> circle(%, center = [0, 0], radius = flangeBackDiameter / 2)
|
||||
|> extrude(%, length = flangeBackHeight)
|
||||
@ -34,7 +34,7 @@ export fn flange() {
|
||||
|> circle(%, center = [0, 0], radius = flangeFrontDiameter / 2)
|
||||
|> extrude(%, length = flangeFrontHeight)
|
||||
|
||||
// Create the circular cut in the center for the pipe
|
||||
// create the circular cut in the center for the pipe
|
||||
pipeCut = startSketchOn(flangeFront, 'end')
|
||||
|> circle(%, center = [0, 0], radius = pipeDiameter / 2)
|
||||
|> extrude(%, length = -flangeTotalThickness)
|
||||
@ -42,3 +42,5 @@ export fn flange() {
|
||||
|
||||
return pipeCut
|
||||
}
|
||||
|
||||
// https://www.mcmaster.com/68095K348/
|
||||
|
@ -1,13 +1,13 @@
|
||||
// Socket Head Cap Screw
|
||||
// 91251A404 Socket Head Cap Screw
|
||||
// screw for mating the flanges together in the pipe flange assembly
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import boltDiameter, boltLength, boltHeadLength, boltHeadDiameter, boltHexDrive, boltHexFlatLength, boltThreadLength from "parameters.kcl"
|
||||
// import constants
|
||||
import boltDiameter, boltLength, boltHeadLength, boltHeadDiameter, boltHexDrive, boltHexFlatLength, boltThreadLength from "globals.kcl"
|
||||
|
||||
// Create a function to make a the bolt
|
||||
// create a function to make a the bolt
|
||||
export fn bolt() {
|
||||
// Create the head of the cap screw
|
||||
boltHead = startSketchOn(XZ)
|
||||
@ -52,3 +52,5 @@ export fn bolt() {
|
||||
|
||||
return boltBody
|
||||
}
|
||||
|
||||
// https://www.mcmaster.com/91251a404/
|
||||
|
@ -1,19 +1,26 @@
|
||||
// Gasket
|
||||
// Gasket for the pipe flange assembly. A gasket is a mechanical seal that fills the space between two or more mating surfaces, preventing leaks of liquids or gases under compression
|
||||
// 9472K188 Gasket
|
||||
// gasket for the pipe flange assembly. A gasket is a mechanical seal that fills the space between two or more mating surfaces, preventing leaks of liquids or gases under compression
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import gasketOutsideDiameter, gasketInnerDiameter, gasketThickness from "parameters.kcl"
|
||||
// import constants
|
||||
import gasketOutsideDiameter, gasketInnerDiameter, gasketThickness from "globals.kcl"
|
||||
|
||||
// Create the base of the gasket
|
||||
gasketBase = startSketchOn(XY)
|
||||
|> circle(%, center = [0, 0], radius = gasketOutsideDiameter / 2)
|
||||
|> extrude(%, length = gasketThickness)
|
||||
// create a function to make the gasket
|
||||
export fn gasket() {
|
||||
// create the base of the gasket
|
||||
gasketBase = startSketchOn(XY)
|
||||
|> circle(%, center = [0, 0], radius = gasketOutsideDiameter / 2)
|
||||
|> extrude(%, length = gasketThickness)
|
||||
|
||||
// Extrude a circular hole through the gasket base
|
||||
startSketchOn(gasketBase, 'end')
|
||||
|> circle(%, center = [0, 0], radius = gasketInnerDiameter / 2)
|
||||
|> extrude(%, length = -gasketThickness)
|
||||
|> appearance(%, color = "#d0cb3e")
|
||||
// extrude a circular hole through the gasket base
|
||||
gasket = startSketchOn(gasketBase, 'end')
|
||||
|> circle(%, center = [0, 0], radius = gasketInnerDiameter / 2)
|
||||
|> extrude(%, length = -gasketThickness)
|
||||
|> appearance(%, color = "#d0cb3e")
|
||||
|
||||
return gasket
|
||||
}
|
||||
|
||||
// https://www.mcmaster.com/9472K616/
|
||||
|
@ -1,15 +1,15 @@
|
||||
// Hex Nut
|
||||
// Hex nut for the screws in the pipe flange assembly.
|
||||
// 95479A127 Hex Nut
|
||||
// hex nut for the screws in the pipe flange assembly.
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import hexNutDiameter, hexNutFlatToFlat, hexNutThickness, hexNutFlatLength from "parameters.kcl"
|
||||
// import constants
|
||||
import hexNutDiameter, hexNutFlatToFlat, hexNutThickness, hexNutFlatLength from "globals.kcl"
|
||||
|
||||
// Create a function to make the hex nut. Must be a function since multiple hex nuts are used
|
||||
// create a function to make the hex nut
|
||||
export fn hexNut() {
|
||||
// Create the base of the hex nut
|
||||
// create the base of the hex nut
|
||||
hexNutBase = startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
hexNutFlatToFlat / 2,
|
||||
@ -38,7 +38,7 @@ export fn hexNut() {
|
||||
|> close()
|
||||
|> extrude(length = hexNutThickness)
|
||||
|
||||
// Create the hole in the center of the hex nut
|
||||
// create the hole in the center of the hex nut
|
||||
hexNut = startSketchOn(hexNutBase, 'end')
|
||||
|> circle(center = [0, 0], radius = hexNutDiameter / 2)
|
||||
|> extrude(%, length = -hexNutThickness)
|
||||
@ -46,3 +46,4 @@ export fn hexNut() {
|
||||
|
||||
return hexNut
|
||||
}
|
||||
// https://www.mcmaster.com/95479A127/
|
||||
|
@ -1,20 +1,20 @@
|
||||
// 98017A257 Washer
|
||||
// Washer for the screws in the pipe flange assembly.
|
||||
// washer for the screws in the pipe flange assembly.
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import washerInnerDia, washerOuterDia, washerThickness from "parameters.kcl"
|
||||
// import constants
|
||||
import washerInnerDia, washerOuterDia, washerThickness from "globals.kcl"
|
||||
|
||||
// Create a function to make the washer. Must be a function since multiple washers are used.
|
||||
// create a function to make the washer
|
||||
export fn washer() {
|
||||
// Create the base of the washer
|
||||
// create the base of the washer
|
||||
washerBase = startSketchOn(XY)
|
||||
|> circle(center = [0, 0], radius = washerOuterDia / 2)
|
||||
|> extrude(length = washerThickness)
|
||||
|
||||
// Extrude a hole through the washer
|
||||
// extrude a hole through the washer
|
||||
washer = startSketchOn(washerBase, 'end')
|
||||
|> circle(center = [0, 0], radius = washerInnerDia / 2)
|
||||
|> extrude(%, length = -washerThickness)
|
||||
@ -22,3 +22,5 @@ export fn washer() {
|
||||
|
||||
return washer
|
||||
}
|
||||
|
||||
// https://www.mcmaster.com/98017A257/
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Parameters
|
||||
// Globals
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Flange (68095K348)
|
||||
// flange (68095K348)
|
||||
export pipeDiameter = 2.440
|
||||
export mountingHoleDiameter = 0.750
|
||||
export mountingHolePlacementDiameter = 4.750
|
||||
@ -17,12 +17,12 @@ export flangeBaseThickness = flangeTotalThickness - flangeBackHeight - flangeFro
|
||||
export flangeBackDiameter = 3.620
|
||||
export flangeFrontDiameter = 3.060
|
||||
|
||||
// Washer (98017A257)
|
||||
// washer (98017A257)
|
||||
export washerInnerDia = 0.640
|
||||
export washerOuterDia = 1.188
|
||||
export washerThickness = 0.032
|
||||
|
||||
// Bolt (91251A404)
|
||||
// bolt (91251A404)
|
||||
export boltDiameter = 0.625
|
||||
export boltLength = 2.500
|
||||
export boltHeadLength = boltDiameter
|
||||
@ -31,18 +31,18 @@ export boltHexDrive = 1 / 2
|
||||
export boltHexFlatLength = boltHexDrive / (2 * cos(toRadians(30)))
|
||||
export boltThreadLength = 1.750
|
||||
|
||||
// Hex nut (95479A127)
|
||||
// hex nut (95479A127)
|
||||
export hexNutDiameter = 5 / 8
|
||||
export hexNutFlatToFlat = 15 / 16
|
||||
export hexNutThickness = 35 / 64
|
||||
export hexNutFlatLength = hexNutFlatToFlat / (2 * cos(toRadians(30)))
|
||||
|
||||
// Gasket (9472K188)
|
||||
// gasket (9472K188)
|
||||
export gasketOutsideDiameter = 4.125
|
||||
export gasketInnerDiameter = 2.375
|
||||
export gasketThickness = 0.031
|
||||
|
||||
// Pipe (1120T74)
|
||||
// pipe (1120T74)
|
||||
export pipeInnerDiameter = 2.0
|
||||
export pipeOuterDiameter = 2.375
|
||||
export pipeLength = 6
|
@ -1,31 +1,31 @@
|
||||
// Pipe and Flange Assembly
|
||||
// A crucial component in various piping systems, designed to facilitate the connection, disconnection, and access to piping for inspection, cleaning, and modifications. This assembly combines pipes (long cylindrical conduits) with flanges (plate-like fittings) to create a secure yet detachable joint.
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import * from "parameters.kcl"
|
||||
// import constants
|
||||
import * from "globals.kcl"
|
||||
|
||||
// Import parts
|
||||
import "9472k188-gasket.kcl" as gasket
|
||||
// import parts
|
||||
import flange from "68095k348-flange.kcl"
|
||||
import gasket from "9472k188-gasket.kcl"
|
||||
import washer from "98017a257-washer.kcl"
|
||||
import bolt from "91251a404-bolt.kcl"
|
||||
import hexNut from "95479a127-hex-nut.kcl"
|
||||
import pipe from "1120t74-pipe.kcl"
|
||||
|
||||
// Place flanges
|
||||
// place flanges
|
||||
flange()
|
||||
flange()
|
||||
|> rotate(axis = [0, 1, 0], angle = 180)
|
||||
|> translate(x = 0, y = 0, z = flangeBackHeight * 2 + gasketThickness)
|
||||
|
||||
// Place gasket between the flanges
|
||||
gasket
|
||||
// place gasket between the flanges
|
||||
gasket()
|
||||
|> translate(x = 0, y = 0, z = -flangeBackHeight - gasketThickness)
|
||||
|
||||
// Place eight washers (four front, four back)
|
||||
// place eight washers (four front, four back)
|
||||
washer()
|
||||
|> translate(x = mountingHolePlacementDiameter / 2, y = 0, z = flangeBaseThickness)
|
||||
|> patternCircular3d(
|
||||
@ -43,7 +43,7 @@ washer()
|
||||
axis = [0, 0, 1],
|
||||
)
|
||||
|
||||
// Place four bolts
|
||||
// place four bolts
|
||||
bolt()
|
||||
|> translate(x = mountingHolePlacementDiameter / 2, y = 0, z = flangeBaseThickness + washerThickness)
|
||||
|> rotate(roll = 90, pitch = 0, yaw = 0)
|
||||
@ -56,7 +56,7 @@ bolt()
|
||||
rotateDuplicates = false,
|
||||
)
|
||||
|
||||
// Place four hex nuts
|
||||
// place four hex nuts
|
||||
hexNut()
|
||||
|> translate(x = mountingHolePlacementDiameter / 2, y = 0, z = -(flangeBackHeight * 2 + gasketThickness + flangeBaseThickness + washerThickness + hexNutThickness))
|
||||
|> patternCircular3d(
|
||||
@ -68,7 +68,7 @@ hexNut()
|
||||
rotateDuplicates = false,
|
||||
)
|
||||
|
||||
// Place both pieces of pipe
|
||||
// place both pieces of pipe
|
||||
pipe()
|
||||
|> rotate(
|
||||
%,
|
||||
|
@ -4,24 +4,24 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
innerDiameter = 10
|
||||
outerDiameter = 20
|
||||
bendRadius = 30
|
||||
bendAngle = 90
|
||||
|
||||
// Create a sketch in the 'XZ' plane
|
||||
// create a sketch in the 'XZ' plane
|
||||
sketch000 = startSketchOn(XZ)
|
||||
|
||||
// Create a profile for the outer diameter
|
||||
// create a profile for the outer diameter
|
||||
outerProfile = circle(sketch000, center = [bendRadius, 0], radius = outerDiameter / 2)
|
||||
|
||||
// Create a profile for the inner diameter
|
||||
// create a profile for the inner diameter
|
||||
innerProfile = circle(sketch000, center = [bendRadius, 0], radius = innerDiameter / 2)
|
||||
|
||||
// Create the profile of the pipe
|
||||
// create the profile of the pipe
|
||||
pipeProfile = outerProfile
|
||||
|> hole(innerProfile, %)
|
||||
|
||||
// Revolve the pipe profile at the desired angle
|
||||
// revolve the pipe profile at the desired angle
|
||||
pipe = revolve(pipeProfile, axis = Y, angle = bendAngle)
|
||||
|
@ -1,21 +1,36 @@
|
||||
// Pipe
|
||||
// Piping for the pipe flange assembly
|
||||
// A tubular section or hollow cylinder, usually but not necessarily of circular cross-section, used mainly to convey substances that can flow.
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
pipeInnerDiameter = 2.0
|
||||
pipeOuterDiameter = 2.375
|
||||
pipeLength = 6
|
||||
// Define constants
|
||||
pipeTotalLength = 20
|
||||
pipeLargeDiaLength = 1
|
||||
pipeLargeDia = 1
|
||||
pipeSmallDia = .75
|
||||
thickness = 0.125
|
||||
pipeTransitionAngle = 60
|
||||
pipeTransitionLength = 0.5
|
||||
pipeSmallDiaLength = pipeTotalLength - pipeTransitionLength - pipeLargeDiaLength
|
||||
|
||||
// Create the pipe base
|
||||
pipeBase = startSketchOn(XZ)
|
||||
|> circle(%, center = [0, 0], radius = pipeOuterDiameter / 2)
|
||||
|> extrude(%, length = pipeLength)
|
||||
// Create the sketch to be revolved around the y-axis. Use the small diameter, large diameter, length, and thickness to define the sketch.
|
||||
pipeSketch = startSketchOn(XY)
|
||||
|> startProfileAt([pipeSmallDia - (thickness / 2), 38], %)
|
||||
|> line(end = [thickness, 0])
|
||||
|> line(end = [0, -pipeSmallDiaLength])
|
||||
|> angledLineOfYLength({
|
||||
angle = -60,
|
||||
length = pipeTransitionLength
|
||||
}, %)
|
||||
|> line(end = [0, -pipeLargeDiaLength])
|
||||
|> xLine(length = -thickness)
|
||||
|> line(end = [0, pipeLargeDiaLength])
|
||||
|> angledLineToX({
|
||||
angle = -pipeTransitionAngle + 180,
|
||||
to = pipeSmallDia - (thickness / 2)
|
||||
}, %)
|
||||
|> close()
|
||||
|
||||
// Extrude a hole through the length of the pipe
|
||||
pipe = startSketchOn(pipeBase, 'end')
|
||||
|> circle(center = [0, 0], radius = pipeInnerDiameter / 2)
|
||||
|> extrude(%, length = -pipeLength)
|
||||
|> appearance(color = "#a24ed0")
|
||||
// Revolve the sketch to create the pipe
|
||||
pipe = revolve(pipeSketch, axis = Y)
|
||||
|
@ -4,7 +4,6 @@
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Define parameters
|
||||
wallThickness = 0.125
|
||||
wallsWidth = 3
|
||||
height = 5.125
|
||||
@ -13,7 +12,6 @@ backLength = 6
|
||||
exitHeight = 1
|
||||
frontLength = 7
|
||||
|
||||
// Create the curved portion that catches the printer poop
|
||||
sketch001 = startSketchOn(-YZ)
|
||||
|> startProfileAt([wallsWidth / 2, 0], %)
|
||||
|> xLine(length = wallThickness / 2)
|
||||
@ -80,7 +78,6 @@ sketch003 = startSketchOn(customPlane)
|
||||
|> close()
|
||||
|> extrude(length = wallThickness)
|
||||
|
||||
// Create the right side wall of the tub
|
||||
sketch004 = startSketchOn(sketch002, 'END')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> yLine(endAbsolute = height)
|
||||
|
@ -1,23 +1,18 @@
|
||||
// Router template for a cross bar
|
||||
// A guide for routing a notch into a cross bar.
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
routerDiameter = 12.7
|
||||
templateDiameter = 11 / 16 * inch()
|
||||
templateGap = (templateDiameter - routerDiameter) / 2 - 0.5
|
||||
slateWidthHalf = 41.5 / 2
|
||||
minClampingDistance = 50 + 30
|
||||
templateThickness = 10
|
||||
radius = 10
|
||||
depth = 30
|
||||
|
||||
// Calculated parameters
|
||||
templateGap = (templateDiameter - routerDiameter) / 2 - 0.5
|
||||
distanceToInsideEdge = slateWidthHalf + templateThickness + templateGap
|
||||
|
||||
// Create the first sketch
|
||||
sketch001 = startSketchOn(XZ)
|
||||
|> startProfileAt([0, depth + templateGap], %)
|
||||
|> xLine(length = slateWidthHalf - radius, tag = $seg01)
|
||||
@ -49,12 +44,9 @@ sketch001 = startSketchOn(XZ)
|
||||
}, %)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
// Extrude the first sketch
|
||||
extrude001 = extrude(sketch001, length = 5)
|
||||
|
||||
// Create the second sketch
|
||||
sketch002 = startSketchOn(extrude001, 'START')
|
||||
sketch003 = startSketchOn(extrude001, 'START')
|
||||
|> startProfileAt([distanceToInsideEdge, 0], %)
|
||||
|> angledLine([180, templateThickness], %, $rectangleSegmentA002)
|
||||
|> angledLine([
|
||||
@ -67,12 +59,9 @@ sketch002 = startSketchOn(extrude001, 'START')
|
||||
], %, $rectangleSegmentC002)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude003 = extrude(sketch003, length = 13)
|
||||
|
||||
// Extrude the second sketch
|
||||
extrude002 = extrude(sketch002, length = 13)
|
||||
|
||||
// Create the third sketch
|
||||
sketch003 = startSketchOn(extrude001, 'START')
|
||||
sketch002 = startSketchOn(extrude001, 'START')
|
||||
|> startProfileAt([-distanceToInsideEdge, 0], %)
|
||||
|> angledLine([0, templateThickness], %, $rectangleSegmentA001)
|
||||
|> angledLine([
|
||||
@ -86,10 +75,8 @@ sketch003 = startSketchOn(extrude001, 'START')
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
// Extrude the third sketch
|
||||
extrude003 = extrude(sketch003, length = 13)
|
||||
extrude002 = extrude(sketch002, length = 13)
|
||||
|
||||
// Create the fourth sketch
|
||||
sketch004 = startSketchOn(extrude002, 'END')
|
||||
|> startProfileAt([-distanceToInsideEdge, 0], %)
|
||||
|> angledLine([0, distanceToInsideEdge * 2], %, $rectangleSegmentA003)
|
||||
@ -103,6 +90,4 @@ sketch004 = startSketchOn(extrude002, 'END')
|
||||
], %, $rectangleSegmentC003)
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
|
||||
// Extrude the fourth sketch
|
||||
extrude004 = extrude(sketch004, length = 4)
|
||||
|
@ -1,20 +1,18 @@
|
||||
// Router Template for a Slate
|
||||
// Router template for a slate
|
||||
// A guide for routing a slate for a cross bar.
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = mm)
|
||||
|
||||
// Define parameters
|
||||
// Define constants
|
||||
routerDiameter = 12.7
|
||||
templateDiameter = 11 / 16 * inch()
|
||||
templateGap = (templateDiameter - routerDiameter) / 2 - 0.5
|
||||
slateWidthHalf = 41.5 / 2
|
||||
minClampingDistance = 50 + 30
|
||||
templateThickness = 10
|
||||
radius = 10
|
||||
depth = 30
|
||||
|
||||
// Calculated parameters
|
||||
templateGap = (templateDiameter - routerDiameter) / 2 - 0.5
|
||||
length001 = slateWidthHalf - radius
|
||||
length002 = depth + minClampingDistance
|
||||
|
||||
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 59 KiB |
@ -1,7 +1,7 @@
|
||||
// Sheet Metal Bracket
|
||||
// A component typically made from flat sheet metal through various manufacturing processes such as bending, punching, cutting, and forming. These brackets are used to support, attach, or mount other hardware components, often providing a structural or functional base for assembly.
|
||||
|
||||
// Set units
|
||||
// Set Units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Input bolt pattern dimensions to mount the bracket
|
||||
@ -14,13 +14,13 @@ componentBoltDiameter = 3 / 16
|
||||
componentBoltPatternX = 2
|
||||
componentBoltPatternY = 3
|
||||
|
||||
// Define bracket parameters such as sheet metal thickness, bend radius, flange length, etc.
|
||||
// Define bracket constants such as sheet metal thickness, bend radius, flange length, etc.
|
||||
hatHeight = 2.5
|
||||
bendAngle = 75
|
||||
thickness = 0.125
|
||||
interiorBendRadius = 0.125
|
||||
|
||||
// Calculate remaining parameters
|
||||
// Calculate Remaining Parameters
|
||||
exteriorBendRadius = interiorBendRadius + thickness
|
||||
overhang = 3 * mountingBoltDiameter
|
||||
flangeLength = 6 * mountingBoltDiameter
|
||||
|
@ -1,53 +1,58 @@
|
||||
// Socket Head Cap Screw
|
||||
// This is for a #10-24 screw that is 1.00 inches long. A socket head cap screw is a type of fastener that is widely used in a variety of applications requiring a high strength fastening solution. It is characterized by its cylindrical head and internal hexagonal drive, which allows for tightening with an Allen wrench or hex key.
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in, defaultAngleUnit = deg)
|
||||
|
||||
// Define parameters
|
||||
boltDiameter = 0.190
|
||||
boltLength = 1.0
|
||||
boltHeadLength = boltDiameter
|
||||
boltHeadDiameter = 0.313
|
||||
boltHexDrive = 5 / 32
|
||||
boltHexFlatLength = boltHexDrive / (2 * cos(toRadians(30)))
|
||||
export boltDiameter = 0.190
|
||||
export boltLength = 1.0
|
||||
export boltHeadLength = boltDiameter
|
||||
export boltHeadDiameter = 0.313
|
||||
export boltHexDrive = 5 / 32
|
||||
export boltHexFlatLength = boltHexDrive / (2 * cos(toRadians(30)))
|
||||
|
||||
// Create the head of the cap screw
|
||||
boltHead = startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = boltHeadDiameter / 2, tag = $topEdge)
|
||||
|> extrude(length = -boltHeadLength)
|
||||
|> fillet(radius = 0.020, tags = [topEdge, getOppositeEdge(topEdge)])
|
||||
export fn bolt() {
|
||||
// Create the head of the cap screw
|
||||
boltHead = startSketchOn(XZ)
|
||||
|> circle(center = [0, 0], radius = boltHeadDiameter / 2, tag = $topEdge)
|
||||
|> extrude(length = -boltHeadLength)
|
||||
|> fillet(radius = 0.020, tags = [topEdge, getOppositeEdge(topEdge)])
|
||||
|
||||
// Define the sketch of the hex pattern on the screw head
|
||||
hexPatternSketch = startSketchOn(boltHead, 'start')
|
||||
|> startProfileAt([
|
||||
boltHexDrive / 2,
|
||||
boltHexFlatLength / 2
|
||||
], %)
|
||||
|> angledLine({
|
||||
angle = 270,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 210,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 150,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 90,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 30,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> close()
|
||||
|> extrude(length = -boltHeadLength * 0.75)
|
||||
boltBody = startSketchOn(boltHead, 'end')
|
||||
|> circle(center = [0, 0], radius = boltDiameter / 2, tag = $filletEdge)
|
||||
|> extrude(length = boltLength)
|
||||
|> fillet(radius = .020, tags = [getOppositeEdge(filletEdge)])
|
||||
|> appearance(color = "#4dd043", metalness = 90, roughness = 90)
|
||||
// Define the sketch of the hex pattern on the screw head
|
||||
hexPatternSketch = startSketchOn(boltHead, 'start')
|
||||
|> startProfileAt([
|
||||
boltHexDrive / 2,
|
||||
boltHexFlatLength / 2
|
||||
], %)
|
||||
|> angledLine({
|
||||
angle = 270,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 210,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 150,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 90,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> angledLine({
|
||||
angle = 30,
|
||||
length = boltHexFlatLength
|
||||
}, %)
|
||||
|> close()
|
||||
|> extrude(length = -boltHeadLength * 0.75)
|
||||
boltBody = startSketchOn(boltHead, 'end')
|
||||
|> circle(center = [0, 0], radius = boltDiameter / 2, tag = $filletEdge)
|
||||
|> extrude(length = boltLength)
|
||||
|> fillet(radius = .020, tags = [getOppositeEdge(filletEdge)])
|
||||
|> appearance(color = "#4dd043", metalness = 90, roughness = 90)
|
||||
|
||||
return boltBody
|
||||
}
|
||||
|
||||
bolt()
|
||||
|
@ -1,32 +1,35 @@
|
||||
// Walkie Talkie Antenna
|
||||
// Antenna for the walkie talkie assembly
|
||||
// Walkie talkie antenna
|
||||
// antenna for the walkie talkie assembly
|
||||
|
||||
// Set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import antennaLength, antennaBaseWidth, antennaBaseHeight, antennaTopWidth, antennaTopHeight from "parameters.kcl"
|
||||
// import constants
|
||||
import antennaLength, antennaBaseWidth, antennaBaseHeight, antennaTopWidth, antennaTopHeight from "globals.kcl"
|
||||
|
||||
// Create the antenna base sketch
|
||||
antennaBaseSketch = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [antennaBaseWidth, 0])
|
||||
|> line(end = [0, -antennaBaseHeight])
|
||||
|> line(end = [-antennaBaseWidth, 0])
|
||||
|> close()
|
||||
export fn antenna() {
|
||||
// Create the antenna base sketch
|
||||
sketch001 = startSketchOn(XY)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line(end = [antennaBaseWidth, 0])
|
||||
|> line(end = [0, -antennaBaseHeight])
|
||||
|> line(end = [-antennaBaseWidth, 0])
|
||||
|> close()
|
||||
|
||||
// Create the antenna top sketch
|
||||
loftPlane = offsetPlane(XY, offset = antennaLength)
|
||||
antennaTopSketch = startSketchOn(loftPlane)
|
||||
|> startProfileAt([
|
||||
(antennaBaseWidth - antennaTopWidth) / 2,
|
||||
(antennaBaseHeight - antennaTopHeight) / 2
|
||||
], %)
|
||||
|> xLine(length = antennaTopWidth)
|
||||
|> yLine(length = -antennaTopHeight)
|
||||
|> xLine(length = -antennaTopWidth)
|
||||
|> close()
|
||||
// Create the antenna top sketch
|
||||
loftPlane = offsetPlane(XY, offset = antennaLength)
|
||||
sketch002 = startSketchOn(loftPlane)
|
||||
|> startProfileAt([
|
||||
(antennaBaseWidth - antennaTopWidth) / 2,
|
||||
(antennaBaseHeight - antennaTopHeight) / 2
|
||||
], %)
|
||||
|> xLine(length = antennaTopWidth)
|
||||
|> yLine(length = -antennaTopHeight)
|
||||
|> xLine(length = -antennaTopWidth)
|
||||
|> close()
|
||||
|
||||
// Create the antenna using a loft
|
||||
loft([antennaBaseSketch, antennaTopSketch])
|
||||
|> appearance(color = "#000000")
|
||||
// Create the antenna using a loft
|
||||
antenna = loft([sketch001, sketch002])
|
||||
|> appearance(color = "#000000")
|
||||
return antenna
|
||||
}
|
||||
|
@ -1,78 +1,84 @@
|
||||
// Walkie Talkie Body
|
||||
// The main body of the walkie talkie assembly
|
||||
// Walkie talkie body
|
||||
// the main body of the walkie talkie assembly
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import height, width, thickness, chamferLength, offset, screenWidth, screenHeight, screenYPosition, screenDepth, speakerBoxWidth, speakerBoxHeight from "parameters.kcl"
|
||||
// import constants
|
||||
import height, width, thickness, chamferLength, offset, screenWidth, screenHeight, screenYPosition, screenDepth, speakerBoxWidth, speakerBoxHeight from "globals.kcl"
|
||||
|
||||
// Sketch and extrude the body of the walkie talkie
|
||||
body = startSketchOn(XZ)
|
||||
|> startProfileAt([-width / 2, height / 2], %)
|
||||
|> xLine(length = width, tag = $chamfer1)
|
||||
|> yLine(length = -height, tag = $chamfer2)
|
||||
|> xLine(length = -width, tag = $chamfer3)
|
||||
|> close(tag = $chamfer4)
|
||||
|> extrude(%, length = thickness)
|
||||
|> chamfer(
|
||||
length = chamferLength,
|
||||
tags = [
|
||||
getNextAdjacentEdge(chamfer1),
|
||||
getNextAdjacentEdge(chamfer2),
|
||||
getNextAdjacentEdge(chamfer3),
|
||||
getNextAdjacentEdge(chamfer4)
|
||||
],
|
||||
)
|
||||
// create a function to define the body
|
||||
export fn body() {
|
||||
// sketch and extrude the body of the walkie talkie
|
||||
bodySketch = startSketchOn(XZ)
|
||||
|> startProfileAt([-width / 2, height / 2], %)
|
||||
|> xLine(length = width, tag = $chamfer1)
|
||||
|> yLine(length = -height, tag = $chamfer2)
|
||||
|> xLine(length = -width, tag = $chamfer3)
|
||||
|> close(tag = $chamfer4)
|
||||
bodyExtrude = extrude(bodySketch, length = thickness)
|
||||
|> chamfer(
|
||||
length = chamferLength,
|
||||
tags = [
|
||||
getNextAdjacentEdge(chamfer1),
|
||||
getNextAdjacentEdge(chamfer2),
|
||||
getNextAdjacentEdge(chamfer3),
|
||||
getNextAdjacentEdge(chamfer4)
|
||||
],
|
||||
)
|
||||
|
||||
// Cut out the indentation for the case
|
||||
caseIndentSketch = startSketchOn(body, 'END')
|
||||
|> startProfileAt([
|
||||
-width / 2 + offset,
|
||||
height / 2 - (chamferLength + offset / 2 * cos(toRadians(45)))
|
||||
], %)
|
||||
|> angledLineToY({ angle = 45, to = height / 2 - offset }, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - (chamferLength + offset / 2 * cos(toRadians(45))),
|
||||
height / 2 - offset
|
||||
])
|
||||
|> angledLineToX({ angle = -45, to = width / 2 - offset }, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - offset,
|
||||
-(height / 2 - (chamferLength + offset / 2 * cos(toRadians(45))))
|
||||
])
|
||||
|> angledLineToY({
|
||||
angle = -135,
|
||||
to = -height / 2 + offset
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
-(width / 2 - (chamferLength + offset / 2 * cos(toRadians(45)))),
|
||||
-height / 2 + offset
|
||||
])
|
||||
|> angledLineToX({
|
||||
angle = -225,
|
||||
to = -width / 2 + offset
|
||||
}, %)
|
||||
|> close()
|
||||
extrude002 = extrude(caseIndentSketch, length = -0.0625)
|
||||
// cut out the indentation for the case
|
||||
sketch002 = startSketchOn(bodyExtrude, 'END')
|
||||
|> startProfileAt([
|
||||
-width / 2 + offset,
|
||||
height / 2 - (chamferLength + offset / 2 * cos(toRadians(45)))
|
||||
], %)
|
||||
|> angledLineToY({ angle = 45, to = height / 2 - offset }, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - (chamferLength + offset / 2 * cos(toRadians(45))),
|
||||
height / 2 - offset
|
||||
])
|
||||
|> angledLineToX({ angle = -45, to = width / 2 - offset }, %)
|
||||
|> line(endAbsolute = [
|
||||
width / 2 - offset,
|
||||
-(height / 2 - (chamferLength + offset / 2 * cos(toRadians(45))))
|
||||
])
|
||||
|> angledLineToY({
|
||||
angle = -135,
|
||||
to = -height / 2 + offset
|
||||
}, %)
|
||||
|> line(endAbsolute = [
|
||||
-(width / 2 - (chamferLength + offset / 2 * cos(toRadians(45)))),
|
||||
-height / 2 + offset
|
||||
])
|
||||
|> angledLineToX({
|
||||
angle = -225,
|
||||
to = -width / 2 + offset
|
||||
}, %)
|
||||
|> close()
|
||||
extrude002 = extrude(sketch002, length = -0.0625)
|
||||
|
||||
// Create the pocket for the screen
|
||||
screenCutout = startSketchOn(extrude002, 'start')
|
||||
|> startProfileAt([-screenWidth / 2, screenYPosition], %)
|
||||
|> xLine(length = screenWidth, tag = $seg01)
|
||||
|> yLine(length = -screenHeight)
|
||||
|> xLine(length = -segLen(seg01))
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude003 = extrude(screenCutout, length = screenDepth)
|
||||
// Create the pocket for the screen
|
||||
sketch003 = startSketchOn(extrude002, 'start')
|
||||
|> startProfileAt([-screenWidth / 2, screenYPosition], %)
|
||||
|> xLine(length = screenWidth, tag = $seg01)
|
||||
|> yLine(length = -screenHeight)
|
||||
|> xLine(length = -segLen(seg01))
|
||||
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
|> close()
|
||||
extrude003 = extrude(sketch003, length = screenDepth)
|
||||
|
||||
// Create the speaker box
|
||||
speakerBox = startSketchOn(extrude002, 'start')
|
||||
|> startProfileAt([-1.25 / 2, -.125], %)
|
||||
|> xLine(length = speakerBoxWidth)
|
||||
|> yLine(length = -speakerBoxHeight)
|
||||
|> xLine(length = -speakerBoxWidth)
|
||||
|> close()
|
||||
// Create the speaker box
|
||||
sketch004 = startSketchOn(extrude002, 'start')
|
||||
|> startProfileAt([-1.25 / 2, -.125], %)
|
||||
|> xLine(length = speakerBoxWidth)
|
||||
|> yLine(length = -speakerBoxHeight)
|
||||
|> xLine(length = -speakerBoxWidth)
|
||||
|> close()
|
||||
|
||||
extrude(speakerBox, length = -.5)
|
||||
|> appearance(color = "#277bb0")
|
||||
body = extrude(sketch004, length = -.5)
|
||||
|> appearance(color = "#277bb0")
|
||||
return body
|
||||
}
|
||||
|
||||
body()
|
||||
|
@ -1,24 +1,21 @@
|
||||
// Walkie Talkie Button
|
||||
// Button for the walkie talkie
|
||||
// Walkie Talkie button
|
||||
|
||||
// Set units
|
||||
// set units
|
||||
@settings(defaultLengthUnit = in)
|
||||
|
||||
// Import parameters
|
||||
import buttonWidth, buttonHeight, buttonThickness from "parameters.kcl"
|
||||
|
||||
// Create a function for the button. We need to create a function to use multiple buttons.
|
||||
|
||||
// import constants
|
||||
import buttonWidth, buttonHeight, buttonThickness from "globals.kcl"
|
||||
|
||||
// create a function to define the button
|
||||
export fn button() {
|
||||
// Sketch the button profile and extrude
|
||||
// sketch the button profile and extrude
|
||||
buttonSketch = startSketchOn(XZ)
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> angledLine({ angle = 180, length = buttonWidth }, %, $tag1)
|
||||
|> angledLine({ angle = 270, length = buttonHeight }, %, $tag2)
|
||||
|> angledLine({ angle = 0, length = buttonWidth }, %)
|
||||
|> close()
|
||||
button = extrude(buttonSketch, length = buttonThickness)
|
||||
buttonExtrude = extrude(buttonSketch, length = buttonThickness)
|
||||
|> chamfer(
|
||||
length = .050,
|
||||
tags = [
|
||||
@ -28,5 +25,5 @@ export fn button() {
|
||||
)
|
||||
|> appearance(color = "#ff0000")
|
||||
|
||||
return button
|
||||
return buttonExtrude
|
||||
}
|
||||
|