-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to open KCL samples in-app (#3912)
* Add a shell script to get the list of KCL samples into the app * Add support for overwriting current file with sample * Move these KCL commands down into FileMachineProvider * Add support for creating a new file on desktop * Make it so these files aren't set to "renaming mode" right away * Add support for initializing default values that are functions * Add E2E tests * Add a code menu item to load a sample * Fix tsc issues * Remove `yarn fetch:samples` from `yarn postinstall` * Remove change to arg initialization logic, I was holding it wrong * Switch to use new manifest file from kcl-samples repo * Update tests now that we use proper sample titles * Remove double-load from units menu test * @jtran feedback * Don't encode `https://` that's silly * fmt * Update e2e/playwright/testing-samples-loading.spec.ts Co-authored-by: Kurt Hutten <[email protected]> * Test feedback * Add a test step to actually check the file contents were written to (@Irev-Dev feedback) --------- Co-authored-by: Kurt Hutten <[email protected]>
- Loading branch information
1 parent
1d1bb8c
commit aee1d66
Showing
21 changed files
with
692 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
import { test, expect } from '@playwright/test' | ||
import { getUtils, setup, setupElectron, tearDown } from './test-utils' | ||
import { bracket } from 'lib/exampleKcl' | ||
import * as fsp from 'fs/promises' | ||
import { join } from 'path' | ||
import { FILE_EXT } from 'lib/constants' | ||
|
||
test.beforeEach(async ({ context, page }, testInfo) => { | ||
await setup(context, page, testInfo) | ||
}) | ||
|
||
test.afterEach(async ({ page }, testInfo) => { | ||
await tearDown(page, testInfo) | ||
}) | ||
|
||
test.describe('Testing in-app sample loading', () => { | ||
/** | ||
* Note this test implicitly depends on the KCL sample "flange-with-patterns.kcl" | ||
* and its title. https://github.com/KittyCAD/kcl-samples/blob/main/flange-with-patterns/flange-with-patterns.kcl | ||
*/ | ||
test('Web: should overwrite current code, cannot create new file', async ({ | ||
page, | ||
}) => { | ||
const u = await getUtils(page) | ||
|
||
await test.step(`Test setup`, async () => { | ||
await page.addInitScript((code) => { | ||
window.localStorage.setItem('persistCode', code) | ||
}, bracket) | ||
await page.setViewportSize({ width: 1200, height: 500 }) | ||
await u.waitForAuthSkipAppStart() | ||
}) | ||
|
||
// Locators and constants | ||
const newSample = { | ||
file: 'flange-with-patterns' + FILE_EXT, | ||
title: 'Flange', | ||
} | ||
const commandBarButton = page.getByRole('button', { name: 'Commands' }) | ||
const samplesCommandOption = page.getByRole('option', { | ||
name: 'Open Sample', | ||
}) | ||
const commandSampleOption = page.getByRole('option', { | ||
name: newSample.title, | ||
exact: true, | ||
}) | ||
const commandMethodArgButton = page.getByRole('button', { | ||
name: 'Method', | ||
}) | ||
const commandMethodOption = (name: 'Overwrite' | 'Create new file') => | ||
page.getByRole('option', { | ||
name, | ||
}) | ||
const warningText = page.getByText('Overwrite current file?') | ||
const confirmButton = page.getByRole('button', { name: 'Submit command' }) | ||
const codeLocator = page.locator('.cm-content') | ||
|
||
await test.step(`Precondition: check the initial code`, async () => { | ||
await u.openKclCodePanel() | ||
await expect(codeLocator).toContainText(bracket.split('\n')[0]) | ||
}) | ||
|
||
await test.step(`Load a KCL sample with the command palette`, async () => { | ||
await commandBarButton.click() | ||
await samplesCommandOption.click() | ||
await commandSampleOption.click() | ||
await commandMethodArgButton.click() | ||
await expect(commandMethodOption('Create new file')).not.toBeVisible() | ||
await commandMethodOption('Overwrite').click() | ||
await expect(warningText).toBeVisible() | ||
await confirmButton.click() | ||
|
||
await expect(codeLocator).toContainText('// ' + newSample.title) | ||
}) | ||
}) | ||
|
||
/** | ||
* Note this test implicitly depends on the KCL samples: | ||
* "flange-with-patterns.kcl": https://github.com/KittyCAD/kcl-samples/blob/main/flange-with-patterns/flange-with-patterns.kcl | ||
* "gear-rack.kcl": https://github.com/KittyCAD/kcl-samples/blob/main/gear-rack/gear-rack.kcl | ||
*/ | ||
test( | ||
'Desktop: should create new file by default, optionally overwrite', | ||
{ tag: '@electron' }, | ||
async ({ browserName: _ }, testInfo) => { | ||
const { electronApp, page, dir } = await setupElectron({ | ||
testInfo, | ||
folderSetupFn: async (dir) => { | ||
const bracketDir = join(dir, 'bracket') | ||
await fsp.mkdir(bracketDir, { recursive: true }) | ||
await fsp.writeFile(join(bracketDir, 'main.kcl'), bracket, { | ||
encoding: 'utf-8', | ||
}) | ||
}, | ||
}) | ||
const u = await getUtils(page) | ||
|
||
// Locators and constants | ||
const sampleOne = { | ||
file: 'flange-with-patterns' + FILE_EXT, | ||
title: 'Flange', | ||
} | ||
const sampleTwo = { | ||
file: 'gear-rack' + FILE_EXT, | ||
title: '100mm Gear Rack', | ||
} | ||
const projectCard = page.getByRole('link', { name: 'bracket' }) | ||
const commandBarButton = page.getByRole('button', { name: 'Commands' }) | ||
const commandOption = page.getByRole('option', { name: 'Open Sample' }) | ||
const commandSampleOption = (name: string) => | ||
page.getByRole('option', { | ||
name, | ||
exact: true, | ||
}) | ||
const commandMethodArgButton = page.getByRole('button', { | ||
name: 'Method', | ||
}) | ||
const commandMethodOption = page.getByRole('option', { | ||
name: 'Overwrite', | ||
}) | ||
const newFileWarning = page.getByText( | ||
'Create a new file with the example code?' | ||
) | ||
const overwriteWarning = page.getByText('Overwrite current file?') | ||
const confirmButton = page.getByRole('button', { name: 'Submit command' }) | ||
const projectMenuButton = page.getByTestId('project-sidebar-toggle') | ||
const newlyCreatedFile = (name: string) => | ||
page.getByRole('listitem').filter({ | ||
has: page.getByRole('button', { name }), | ||
}) | ||
const codeLocator = page.locator('.cm-content') | ||
|
||
await test.step(`Test setup`, async () => { | ||
await page.setViewportSize({ width: 1200, height: 500 }) | ||
await projectCard.click() | ||
await u.waitForPageLoad() | ||
}) | ||
|
||
await test.step(`Precondition: check the initial code`, async () => { | ||
await u.openKclCodePanel() | ||
await expect(codeLocator).toContainText(bracket.split('\n')[0]) | ||
await u.openFilePanel() | ||
|
||
await expect(projectMenuButton).toContainText('main.kcl') | ||
await expect(newlyCreatedFile(sampleOne.file)).not.toBeVisible() | ||
}) | ||
|
||
await test.step(`Load a KCL sample with the command palette`, async () => { | ||
await commandBarButton.click() | ||
await commandOption.click() | ||
await commandSampleOption(sampleOne.title).click() | ||
await expect(overwriteWarning).not.toBeVisible() | ||
await expect(newFileWarning).toBeVisible() | ||
await confirmButton.click() | ||
}) | ||
|
||
await test.step(`Ensure we made and opened a new file`, async () => { | ||
await expect(codeLocator).toContainText('// ' + sampleOne.title) | ||
await expect(newlyCreatedFile(sampleOne.file)).toBeVisible() | ||
await expect(projectMenuButton).toContainText(sampleOne.file) | ||
}) | ||
|
||
await test.step(`Now overwrite the current file`, async () => { | ||
await commandBarButton.click() | ||
await commandOption.click() | ||
await commandSampleOption(sampleTwo.title).click() | ||
await commandMethodArgButton.click() | ||
await commandMethodOption.click() | ||
await expect(commandMethodArgButton).toContainText('overwrite') | ||
await expect(newFileWarning).not.toBeVisible() | ||
await expect(overwriteWarning).toBeVisible() | ||
await confirmButton.click() | ||
}) | ||
|
||
await test.step(`Ensure we overwrote the current file without navigating`, async () => { | ||
await expect(codeLocator).toContainText('// ' + sampleTwo.title) | ||
await test.step(`Check actual file contents`, async () => { | ||
await expect | ||
.poll(async () => { | ||
return await fsp.readFile( | ||
join(dir, 'bracket', sampleOne.file), | ||
'utf-8' | ||
) | ||
}) | ||
.toContain('// ' + sampleTwo.title) | ||
}) | ||
await expect(newlyCreatedFile(sampleOne.file)).toBeVisible() | ||
await expect(newlyCreatedFile(sampleTwo.file)).not.toBeVisible() | ||
await expect(projectMenuButton).toContainText(sampleOne.file) | ||
}) | ||
|
||
await electronApp.close() | ||
} | ||
) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
[ | ||
{ | ||
"file": "80-20-rail.kcl", | ||
"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": "a-parametric-bearing-pillow-block.kcl", | ||
"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": "ball-bearing.kcl", | ||
"title": "Ball Bearing", | ||
"description": "A ball bearing is a type of rolling-element bearing that uses balls to maintain the separation between the bearing races. The primary purpose of a ball bearing is to reduce rotational friction and support radial and axial loads." | ||
}, | ||
{ | ||
"file": "bracket.kcl", | ||
"title": "Shelf Bracket", | ||
"description": "This is a bracket that holds a shelf. It is made of aluminum and is designed to hold a force of 300 lbs. The bracket is 6 inches wide and the force is applied at the end of the shelf, 12 inches from the wall. The bracket has a factor of safety of 1.2. The legs of the bracket are 5 inches and 2 inches long. The thickness of the bracket is calculated from the constraints provided." | ||
}, | ||
{ | ||
"file": "brake-caliper.kcl", | ||
"title": "Brake Caliper", | ||
"description": "Brake calipers are used to squeeze the brake pads against the rotor, causing larger and larger amounts of friction depending on how hard the brakes are pressed." | ||
}, | ||
{ | ||
"file": "car-wheel.kcl", | ||
"title": "Car Wheel", | ||
"description": "A sports car wheel with a circular lug pattern and spokes." | ||
}, | ||
{ | ||
"file": "car-wheel-assembly.kcl", | ||
"title": "Car Wheel Assembly", | ||
"description": "A car wheel assembly with a rotor, tire, and lug nuts." | ||
}, | ||
{ | ||
"file": "enclosure.kcl", | ||
"title": "Enclosure", | ||
"description": "An enclosure body and sealing lid for storing items" | ||
}, | ||
{ | ||
"file": "flange-with-patterns.kcl", | ||
"title": "Flange", | ||
"description": "A flange is a flat rim, collar, or rib, typically forged or cast, that is used to strengthen an object, guide it, or attach it to another object. Flanges are known for their use in various applications, including piping, plumbing, and mechanical engineering, among others." | ||
}, | ||
{ | ||
"file": "flange-xy.kcl", | ||
"title": "Flange with XY coordinates", | ||
"description": "A flange is a flat rim, collar, or rib, typically forged or cast, that is used to strengthen an object, guide it, or attach it to another object. Flanges are known for their use in various applications, including piping, plumbing, and mechanical engineering, among others." | ||
}, | ||
{ | ||
"file": "focusrite-scarlett-mounting-bracket.kcl", | ||
"title": "A mounting bracket for the Focusrite Scarlett Solo audio interface", | ||
"description": "This is a bracket that holds an audio device underneath a desk or shelf. The audio device has dimensions of 144mm wide, 80mm length and 45mm depth with fillets of 6mm. This mounting bracket is designed to be 3D printed with PLA material" | ||
}, | ||
{ | ||
"file": "french-press.kcl", | ||
"title": "French Press", | ||
"description": "A french press immersion coffee maker" | ||
}, | ||
{ | ||
"file": "gear.kcl", | ||
"title": "Gear", | ||
"description": "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." | ||
}, | ||
{ | ||
"file": "gear-rack.kcl", | ||
"title": "100mm Gear Rack", | ||
"description": "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." | ||
}, | ||
{ | ||
"file": "hex-nut.kcl", | ||
"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." | ||
}, | ||
{ | ||
"file": "kitt.kcl", | ||
"title": "Kitt", | ||
"description": "The beloved KittyCAD mascot in a voxelized style." | ||
}, | ||
{ | ||
"file": "lego.kcl", | ||
"title": "Lego Brick", | ||
"description": "A standard Lego brick. This is a small, plastic construction block toy that can be interlocked with other blocks to build various structures, models, and figures. There are a lot of hacks used in this code." | ||
}, | ||
{ | ||
"file": "lug-nut.kcl", | ||
"title": "Lug Nut", | ||
"description": "lug Nuts are essential components used to create secure connections, whether for electrical purposes, like terminating wires or grounding, or for mechanical purposes, such as providing mounting points or reinforcing structural joints." | ||
}, | ||
{ | ||
"file": "mounting-plate.kcl", | ||
"title": "Mounting Plate", | ||
"description": "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." | ||
}, | ||
{ | ||
"file": "multi-axis-robot.kcl", | ||
"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": "pipe.kcl", | ||
"title": "Pipe", | ||
"description": "A tubular section or hollow cylinder, usually but not necessarily of circular cross-section, used mainly to convey substances that can flow." | ||
}, | ||
{ | ||
"file": "pipe-flange-assembly.kcl", | ||
"title": "Pipe and Flange Assembly", | ||
"description": "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." | ||
}, | ||
{ | ||
"file": "poopy-shoe.kcl", | ||
"title": "Poopy Shoe", | ||
"description": "poop shute for bambu labs printer - optimized for printing." | ||
}, | ||
{ | ||
"file": "router-template-cross-bar.kcl", | ||
"title": "Router template for a cross bar", | ||
"description": "A guide for routing a notch into a cross bar." | ||
}, | ||
{ | ||
"file": "router-template-slate.kcl", | ||
"title": "Router template for a slate", | ||
"description": "A guide for routing a slate for a cross bar." | ||
}, | ||
{ | ||
"file": "sheet-metal-bracket.kcl", | ||
"title": "Sheet Metal Bracket", | ||
"description": "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." | ||
}, | ||
{ | ||
"file": "socket-head-cap-screw.kcl", | ||
"title": "Socket Head Cap Screw", | ||
"description": "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." | ||
}, | ||
{ | ||
"file": "tire.kcl", | ||
"title": "Tire", | ||
"description": "A tire is a critical component of a vehicle that provides the necessary traction and grip between the car and the road. It supports the vehicle's weight and absorbs shocks from road irregularities." | ||
}, | ||
{ | ||
"file": "washer.kcl", | ||
"title": "Washer", | ||
"description": "A small, typically disk-shaped component with a hole in the middle, used in a wide range of applications, primarily in conjunction with fasteners like bolts and screws. Washers distribute the load of a fastener across a broader area. This is especially important when the fastening surface is soft or uneven, as it helps to prevent damage to the surface and ensures the load is evenly distributed, reducing the risk of the fastener becoming loose over time." | ||
}, | ||
{ | ||
"file": "wheel-rotor.kcl", | ||
"title": "Wheel rotor", | ||
"description": "A component of a disc brake system. It provides a surface for brake pads to press against, generating the friction needed to slow or stop the vehicle." | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.