Compare commits
7 Commits
pierremtb/
...
achalmers-
Author | SHA1 | Date | |
---|---|---|---|
9b29b08f62 | |||
46c613288c | |||
541dcd9a41 | |||
b5bf85d420 | |||
4eee73f471 | |||
7462eee89c | |||
17945cac6d |
@ -112,7 +112,8 @@ test.describe('when using the file tree to', () => {
|
||||
})
|
||||
|
||||
const {
|
||||
panesOpen,
|
||||
openKclCodePanel,
|
||||
openFilePanel,
|
||||
createAndSelectProject,
|
||||
pasteCodeInEditor,
|
||||
createNewFileAndSelect,
|
||||
@ -124,9 +125,9 @@ test.describe('when using the file tree to', () => {
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
page.on('console', console.log)
|
||||
|
||||
await panesOpen(['files', 'code'])
|
||||
|
||||
await createAndSelectProject('project-000')
|
||||
await openKclCodePanel()
|
||||
await openFilePanel()
|
||||
// File the main.kcl with contents
|
||||
const kclCube = await fsp.readFile(
|
||||
'src/wasm-lib/tests/executor/inputs/cube.kcl',
|
||||
|
@ -585,6 +585,15 @@ export async function getUtils(page: Page, test_?: typeof test) {
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated Sorry I don't have time to fix this right now, but runs like
|
||||
* the one linked below show me that setting the open panes in this manner is not reliable.
|
||||
* You can either set `openPanes` as a part of the same initScript we run in setupElectron/setup,
|
||||
* or you can imperatively open the panes with functions like {openKclCodePanel}
|
||||
* (or we can make a general openPane function that takes a paneId).,
|
||||
* but having a separate initScript does not seem to work reliably.
|
||||
* @link https://github.com/KittyCAD/modeling-app/actions/runs/10731890169/job/29762700806?pr=3807#step:20:19553
|
||||
*/
|
||||
panesOpen: async (paneIds: PaneId[]) => {
|
||||
return test?.step(`Setting ${paneIds} panes to be open`, async () => {
|
||||
await page.addInitScript(
|
||||
|
@ -368,10 +368,10 @@ test.describe('Testing settings', () => {
|
||||
})
|
||||
|
||||
const {
|
||||
panesOpen,
|
||||
openKclCodePanel,
|
||||
openFilePanel,
|
||||
createAndSelectProject,
|
||||
pasteCodeInEditor,
|
||||
clickPane,
|
||||
createNewFileAndSelect,
|
||||
editorTextMatches,
|
||||
} = await getUtils(page, test)
|
||||
@ -379,8 +379,6 @@ test.describe('Testing settings', () => {
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
page.on('console', console.log)
|
||||
|
||||
await panesOpen([])
|
||||
|
||||
await test.step('Precondition: No projects exist', async () => {
|
||||
await expect(page.getByTestId('home-section')).toBeVisible()
|
||||
const projectLinksPre = page.getByTestId('project-link')
|
||||
@ -389,14 +387,14 @@ test.describe('Testing settings', () => {
|
||||
|
||||
await createAndSelectProject('project-000')
|
||||
|
||||
await clickPane('code')
|
||||
await openKclCodePanel()
|
||||
const kclCube = await fsp.readFile(
|
||||
'src/wasm-lib/tests/executor/inputs/cube.kcl',
|
||||
'utf-8'
|
||||
)
|
||||
await pasteCodeInEditor(kclCube)
|
||||
|
||||
await clickPane('files')
|
||||
await openFilePanel()
|
||||
await createNewFileAndSelect('2.kcl')
|
||||
|
||||
const kclCylinder = await fsp.readFile(
|
||||
|
@ -690,40 +690,53 @@ test(
|
||||
'Text-to-CAD functionality',
|
||||
{ tag: '@electron' },
|
||||
async ({ browserName }, testInfo) => {
|
||||
const projectName = 'project-000'
|
||||
const prompt = 'lego 2x4'
|
||||
const textToCadFileName = 'lego-2x4.kcl'
|
||||
|
||||
const { electronApp, page, dir } = await setupElectron({ testInfo })
|
||||
const fileExists = () =>
|
||||
fs.existsSync(join(dir, 'project-000', 'lego-2x4.kcl'))
|
||||
fs.existsSync(join(dir, projectName, textToCadFileName))
|
||||
|
||||
const { createAndSelectProject, panesOpen } = await getUtils(page, test)
|
||||
const {
|
||||
createAndSelectProject,
|
||||
openFilePanel,
|
||||
openKclCodePanel,
|
||||
waitForPageLoad,
|
||||
} = await getUtils(page, test)
|
||||
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
|
||||
await panesOpen(['code', 'files'])
|
||||
// Locators
|
||||
const projectMenuButton = page.getByRole('button', { name: projectName })
|
||||
const textToCadFileButton = page.getByRole('listitem').filter({
|
||||
has: page.getByRole('button', { name: textToCadFileName }),
|
||||
})
|
||||
const textToCadComment = page.getByText(
|
||||
`// Generated by Text-to-CAD: ${prompt}`
|
||||
)
|
||||
|
||||
// Create and navigate to the project
|
||||
await createAndSelectProject('project-000')
|
||||
|
||||
// Wait for Start Sketch otherwise you will not have access Text-to-CAD command
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Sketch' })
|
||||
).toBeEnabled({
|
||||
timeout: 20_000,
|
||||
})
|
||||
await waitForPageLoad()
|
||||
await openFilePanel()
|
||||
await openKclCodePanel()
|
||||
|
||||
await test.step(`Test file creation`, async () => {
|
||||
await sendPromptFromCommandBar(page, 'lego 2x4')
|
||||
await sendPromptFromCommandBar(page, prompt)
|
||||
// File is considered created if it shows up in the Project Files pane
|
||||
const file = page.getByRole('button', { name: 'lego-2x4.kcl' })
|
||||
await expect(file).toBeVisible({ timeout: 20_000 })
|
||||
await expect(textToCadFileButton).toBeVisible({ timeout: 20_000 })
|
||||
expect(fileExists()).toBeTruthy()
|
||||
})
|
||||
|
||||
await test.step(`Test file navigation`, async () => {
|
||||
const file = page.getByRole('button', { name: 'lego-2x4.kcl' })
|
||||
await file.click()
|
||||
const kclComment = page.getByText('Lego 2x4 Brick')
|
||||
await expect(projectMenuButton).toContainText('main.kcl')
|
||||
await textToCadFileButton.click()
|
||||
// File can be navigated and loaded assuming a specific KCL comment is loaded into the KCL code pane
|
||||
await expect(kclComment).toBeVisible({ timeout: 20_000 })
|
||||
await expect(textToCadComment).toBeVisible({ timeout: 20_000 })
|
||||
await expect(projectMenuButton).toContainText(textToCadFileName)
|
||||
})
|
||||
|
||||
await test.step(`Test file deletion on rejection`, async () => {
|
||||
@ -737,6 +750,8 @@ test(
|
||||
)
|
||||
await expect(submittingToastMessage).toBeVisible()
|
||||
expect(fileExists()).toBeFalsy()
|
||||
// Confirm we've navigated back to the main.kcl file after deletion
|
||||
await expect(projectMenuButton).toContainText('main.kcl')
|
||||
})
|
||||
|
||||
await electronApp.close()
|
||||
|
@ -1,5 +1,5 @@
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use kcl_lib::test_server;
|
||||
use kcl_lib::{settings::types::UnitLength::Mm, test_server};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
pub fn bench_execute(c: &mut Criterion) {
|
||||
@ -13,26 +13,42 @@ pub fn bench_execute(c: &mut Criterion) {
|
||||
// Configure Criterion.rs to detect smaller differences and increase sample size to improve
|
||||
// precision and counteract the resulting noise.
|
||||
group.sample_size(10);
|
||||
group.bench_with_input(BenchmarkId::new("execute_", name), &code, |b, &s| {
|
||||
group.bench_with_input(BenchmarkId::new("execute", name), &code, |b, &s| {
|
||||
let rt = Runtime::new().unwrap();
|
||||
|
||||
// Spawn a future onto the runtime
|
||||
b.iter(|| {
|
||||
rt.block_on(test_server::execute_and_snapshot(
|
||||
s,
|
||||
kcl_lib::settings::types::UnitLength::Mm,
|
||||
))
|
||||
.unwrap();
|
||||
rt.block_on(test_server::execute_and_snapshot(s, Mm)).unwrap();
|
||||
});
|
||||
});
|
||||
group.finish();
|
||||
}
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_execute);
|
||||
pub fn bench_lego(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("executor_lego_pattern");
|
||||
// Configure Criterion.rs to detect smaller differences and increase sample size to improve
|
||||
// precision and counteract the resulting noise.
|
||||
group.sample_size(10);
|
||||
// Create lego bricks with N x 10 bumps, where N is each element of `sizes`.
|
||||
let sizes = vec![1, 2, 4];
|
||||
for size in sizes {
|
||||
group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| {
|
||||
let rt = Runtime::new().unwrap();
|
||||
let code = LEGO_PROGRAM.replace("{{N}}", &size.to_string());
|
||||
// Spawn a future onto the runtime
|
||||
b.iter(|| {
|
||||
rt.block_on(test_server::execute_and_snapshot(&code, Mm)).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_lego, bench_execute);
|
||||
criterion_main!(benches);
|
||||
|
||||
const KITT_PROGRAM: &str = include_str!("../../tests/executor/inputs/kittycad_svg.kcl");
|
||||
const CUBE_PROGRAM: &str = include_str!("../../tests/executor/inputs/cube.kcl");
|
||||
const SERVER_RACK_HEAVY_PROGRAM: &str = include_str!("../../tests/executor/inputs/server-rack-heavy.kcl");
|
||||
const SERVER_RACK_LITE_PROGRAM: &str = include_str!("../../tests/executor/inputs/server-rack-lite.kcl");
|
||||
const LEGO_PROGRAM: &str = include_str!("../../tests/executor/inputs/slow_lego.kcl.tmpl");
|
||||
|
@ -99,7 +99,7 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args
|
||||
)
|
||||
.await?;
|
||||
|
||||
args.send_modeling_cmd(
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
kittycad::types::ModelingCmd::Extrude {
|
||||
target: sketch_group.id,
|
||||
@ -112,7 +112,7 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args
|
||||
// Disable the sketch mode.
|
||||
args.batch_modeling_cmd(uuid::Uuid::new_v4(), kittycad::types::ModelingCmd::SketchModeDisable {})
|
||||
.await?;
|
||||
extrude_groups.push(do_post_extrude(sketch_group.clone(), length, id, args.clone()).await?);
|
||||
extrude_groups.push(do_post_extrude(sketch_group.clone(), length, args.clone()).await?);
|
||||
}
|
||||
|
||||
Ok(extrude_groups.into())
|
||||
@ -121,7 +121,6 @@ async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args
|
||||
pub(crate) async fn do_post_extrude(
|
||||
sketch_group: SketchGroup,
|
||||
length: f64,
|
||||
id: Uuid,
|
||||
args: Args,
|
||||
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||
// Bring the object to the front of the scene.
|
||||
@ -165,7 +164,7 @@ pub(crate) async fn do_post_extrude(
|
||||
|
||||
let solid3d_info = args
|
||||
.send_modeling_cmd(
|
||||
id,
|
||||
uuid::Uuid::new_v4(),
|
||||
kittycad::types::ModelingCmd::Solid3DGetExtrusionFaceInfo {
|
||||
edge_id,
|
||||
object_id: sketch_group.id,
|
||||
|
@ -170,5 +170,5 @@ async fn inner_loft(
|
||||
.await?;
|
||||
|
||||
// Using the first sketch as the base curve, idk we might want to change this later.
|
||||
do_post_extrude(sketch_groups[0].clone(), 0.0, id, args).await
|
||||
do_post_extrude(sketch_groups[0].clone(), 0.0, args).await
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ async fn inner_revolve(
|
||||
}
|
||||
}
|
||||
|
||||
do_post_extrude(sketch_group, 0.0, id, args).await
|
||||
do_post_extrude(sketch_group, 0.0, args).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
81
src/wasm-lib/tests/executor/inputs/slow_lego.kcl.tmpl
Normal file
81
src/wasm-lib/tests/executor/inputs/slow_lego.kcl.tmpl
Normal file
@ -0,0 +1,81 @@
|
||||
// 2x8 Lego Brick
|
||||
// A standard Lego brick with 2 bumps wide and 8 bumps long.
|
||||
// Define constants
|
||||
const lbumps = 10 // number of bumps long
|
||||
const wbumps = {{N}} // number of bumps wide
|
||||
const pitch = 8.0
|
||||
const clearance = 0.1
|
||||
const bumpDiam = 4.8
|
||||
const bumpHeight = 1.8
|
||||
const height = 9.6
|
||||
const t = (pitch - (2 * clearance) - bumpDiam) / 2.0
|
||||
const totalLength = lbumps * pitch - (2.0 * clearance)
|
||||
const totalWidth = wbumps * pitch - (2.0 * clearance)
|
||||
// Create the plane for the pegs. This is a hack so that the pegs can be patterned along the face of the lego base.
|
||||
const pegFace = {
|
||||
plane: {
|
||||
origin: { x: 0, y: 0, z: height },
|
||||
xAxis: { x: 1, y: 0, z: 0 },
|
||||
yAxis: { x: 0, y: 1, z: 0 },
|
||||
zAxis: { x: 0, y: 0, z: 1 }
|
||||
}
|
||||
}
|
||||
// Create the plane for the tubes underneath the lego. This is a hack so that the tubes can be patterned underneath the lego.
|
||||
const tubeFace = {
|
||||
plane: {
|
||||
origin: { x: 0, y: 0, z: height - t },
|
||||
xAxis: { x: 1, y: 0, z: 0 },
|
||||
yAxis: { x: 0, y: 1, z: 0 },
|
||||
zAxis: { x: 0, y: 0, z: 1 }
|
||||
}
|
||||
}
|
||||
// Make the base
|
||||
const s = startSketchOn('XY')
|
||||
|> startProfileAt([-totalWidth / 2, -totalLength / 2], %)
|
||||
|> line([totalWidth, 0], %)
|
||||
|> line([0, totalLength], %)
|
||||
|> line([-totalWidth, 0], %)
|
||||
|> close(%)
|
||||
|> extrude(height, %)
|
||||
|
||||
// Sketch and extrude a rectangular shape to create the shell underneath the lego. This is a hack until we have a shell function.
|
||||
const shellExtrude = startSketchOn(s, "start")
|
||||
|> startProfileAt([
|
||||
-(totalWidth / 2 - t),
|
||||
-(totalLength / 2 - t)
|
||||
], %)
|
||||
|> line([totalWidth - (2 * t), 0], %)
|
||||
|> line([0, totalLength - (2 * t)], %)
|
||||
|> line([-(totalWidth - (2 * t)), 0], %)
|
||||
|> close(%)
|
||||
|> extrude(-(height - t), %)
|
||||
|
||||
fn tr = (i) => {
|
||||
let j = i + 1
|
||||
let x = (j/wbumps) * pitch
|
||||
let y = (j % wbumps) * pitch
|
||||
return {
|
||||
translate: [x, y, 0],
|
||||
}
|
||||
}
|
||||
|
||||
// Create the pegs on the top of the base
|
||||
const totalBumps = (wbumps * lbumps)-1
|
||||
const peg = startSketchOn(s, 'end')
|
||||
|> circle([
|
||||
-(pitch*(wbumps-1)/2),
|
||||
-(pitch*(lbumps-1)/2)
|
||||
], bumpDiam / 2, %)
|
||||
|> patternLinear2d({
|
||||
axis: [1, 0],
|
||||
repetitions: wbumps-1,
|
||||
distance: pitch
|
||||
}, %)
|
||||
|> patternLinear2d({
|
||||
axis: [0, 1],
|
||||
repetitions: lbumps-1,
|
||||
distance: pitch
|
||||
}, %)
|
||||
|> extrude(bumpHeight, %)
|
||||
// |> patternTransform(int(totalBumps-1), tr, %)
|
||||
|
Reference in New Issue
Block a user