update cli to reestablish export test (#1523)
* update cli to reestablish export test * update cli v * tweak
This commit is contained in:
2
.github/workflows/playwright.yml
vendored
2
.github/workflows/playwright.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'yarn'
|
||||
- uses: KittyCAD/action-install-cli@v0.2.16
|
||||
- uses: KittyCAD/action-install-cli@v0.2.21
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
- name: Install Playwright Browsers
|
||||
|
||||
@ -120,254 +120,254 @@ test('change camera, show planes', async ({ page, context }) => {
|
||||
})
|
||||
})
|
||||
|
||||
// test('exports of each format should work', async ({ page, context }) => {
|
||||
// // FYI this test doesn't work with only engine running locally
|
||||
// // And you will need to have the KittyCAD CLI installed
|
||||
// const u = getUtils(page)
|
||||
// await context.addInitScript(async () => {
|
||||
// ;(window as any).playwrightSkipFilePicker = true
|
||||
// localStorage.setItem(
|
||||
// 'persistCode',
|
||||
// `const topAng = 25
|
||||
// const bottomAng = 35
|
||||
// const baseLen = 3.5
|
||||
// const baseHeight = 1
|
||||
// const totalHeightHalf = 2
|
||||
// const armThick = 0.5
|
||||
// const totalLen = 9.5
|
||||
// const part001 = startSketchOn('-XZ')
|
||||
// |> startProfileAt([0, 0], %)
|
||||
// |> yLine(baseHeight, %)
|
||||
// |> xLine(baseLen, %)
|
||||
// |> angledLineToY({
|
||||
// angle: topAng,
|
||||
// to: totalHeightHalf,
|
||||
// tag: 'seg04'
|
||||
// }, %)
|
||||
// |> xLineTo({ to: totalLen, tag: 'seg03' }, %)
|
||||
// |> yLine({ length: -armThick, tag: 'seg01' }, %)
|
||||
// |> angledLineThatIntersects({
|
||||
// angle: HALF_TURN,
|
||||
// offset: -armThick,
|
||||
// intersectTag: 'seg04'
|
||||
// }, %)
|
||||
// |> angledLineToY([segAng('seg04', %) + 180, ZERO], %)
|
||||
// |> angledLineToY({
|
||||
// angle: -bottomAng,
|
||||
// to: -totalHeightHalf - armThick,
|
||||
// tag: 'seg02'
|
||||
// }, %)
|
||||
// |> xLineTo(segEndX('seg03', %) + 0, %)
|
||||
// |> yLine(-segLen('seg01', %), %)
|
||||
// |> angledLineThatIntersects({
|
||||
// angle: HALF_TURN,
|
||||
// offset: -armThick,
|
||||
// intersectTag: 'seg02'
|
||||
// }, %)
|
||||
// |> angledLineToY([segAng('seg02', %) + 180, -baseHeight], %)
|
||||
// |> xLineTo(ZERO, %)
|
||||
// |> close(%)
|
||||
// |> extrude(4, %)`
|
||||
// )
|
||||
// })
|
||||
// await page.setViewportSize({ width: 1200, height: 500 })
|
||||
// await page.goto('/')
|
||||
// await u.waitForAuthSkipAppStart()
|
||||
// await u.openDebugPanel()
|
||||
// await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
// await u.waitForCmdReceive('extrude')
|
||||
// await page.waitForTimeout(1000)
|
||||
// await u.clearAndCloseDebugPanel()
|
||||
test('exports of each format should work', async ({ page, context }) => {
|
||||
// FYI this test doesn't work with only engine running locally
|
||||
// And you will need to have the KittyCAD CLI installed
|
||||
const u = getUtils(page)
|
||||
await context.addInitScript(async () => {
|
||||
;(window as any).playwrightSkipFilePicker = true
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`const topAng = 25
|
||||
const bottomAng = 35
|
||||
const baseLen = 3.5
|
||||
const baseHeight = 1
|
||||
const totalHeightHalf = 2
|
||||
const armThick = 0.5
|
||||
const totalLen = 9.5
|
||||
const part001 = startSketchOn('-XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> yLine(baseHeight, %)
|
||||
|> xLine(baseLen, %)
|
||||
|> angledLineToY({
|
||||
angle: topAng,
|
||||
to: totalHeightHalf,
|
||||
tag: 'seg04'
|
||||
}, %)
|
||||
|> xLineTo({ to: totalLen, tag: 'seg03' }, %)
|
||||
|> yLine({ length: -armThick, tag: 'seg01' }, %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: HALF_TURN,
|
||||
offset: -armThick,
|
||||
intersectTag: 'seg04'
|
||||
}, %)
|
||||
|> angledLineToY([segAng('seg04', %) + 180, ZERO], %)
|
||||
|> angledLineToY({
|
||||
angle: -bottomAng,
|
||||
to: -totalHeightHalf - armThick,
|
||||
tag: 'seg02'
|
||||
}, %)
|
||||
|> xLineTo(segEndX('seg03', %) + 0, %)
|
||||
|> yLine(-segLen('seg01', %), %)
|
||||
|> angledLineThatIntersects({
|
||||
angle: HALF_TURN,
|
||||
offset: -armThick,
|
||||
intersectTag: 'seg02'
|
||||
}, %)
|
||||
|> angledLineToY([segAng('seg02', %) + 180, -baseHeight], %)
|
||||
|> xLineTo(ZERO, %)
|
||||
|> close(%)
|
||||
|> extrude(4, %)`
|
||||
)
|
||||
})
|
||||
await page.setViewportSize({ width: 1200, height: 500 })
|
||||
await page.goto('/')
|
||||
await u.waitForAuthSkipAppStart()
|
||||
await u.openDebugPanel()
|
||||
await u.expectCmdLog('[data-message-type="execution-done"]')
|
||||
await u.waitForCmdReceive('extrude')
|
||||
await page.waitForTimeout(1000)
|
||||
await u.clearAndCloseDebugPanel()
|
||||
|
||||
// await page.getByRole('button', { name: APP_NAME }).click()
|
||||
await page.getByRole('button', { name: APP_NAME }).click()
|
||||
|
||||
// interface Paths {
|
||||
// modelPath: string
|
||||
// imagePath: string
|
||||
// outputType: string
|
||||
// }
|
||||
// const doExport = async (
|
||||
// output: Models['OutputFormat_type']
|
||||
// ): Promise<Paths> => {
|
||||
// await page.getByRole('button', { name: 'Export Model' }).click()
|
||||
interface Paths {
|
||||
modelPath: string
|
||||
imagePath: string
|
||||
outputType: string
|
||||
}
|
||||
const doExport = async (
|
||||
output: Models['OutputFormat_type']
|
||||
): Promise<Paths> => {
|
||||
await page.getByRole('button', { name: 'Export Model' }).click()
|
||||
|
||||
// const exportSelect = page.getByTestId('export-type')
|
||||
// await exportSelect.selectOption({ label: output.type })
|
||||
const exportSelect = page.getByTestId('export-type')
|
||||
await exportSelect.selectOption({ label: output.type })
|
||||
|
||||
// if ('storage' in output) {
|
||||
// const storageSelect = page.getByTestId('export-storage')
|
||||
// await storageSelect.selectOption({ label: output.storage })
|
||||
// }
|
||||
if ('storage' in output) {
|
||||
const storageSelect = page.getByTestId('export-storage')
|
||||
await storageSelect.selectOption({ label: output.storage })
|
||||
}
|
||||
|
||||
// const downloadPromise = page.waitForEvent('download')
|
||||
// await page.getByRole('button', { name: 'Export', exact: true }).click()
|
||||
// const download = await downloadPromise
|
||||
// const downloadLocationer = (extra = '', isImage = false) =>
|
||||
// `./e2e/playwright/export-snapshots/${output.type}-${
|
||||
// 'storage' in output ? output.storage : ''
|
||||
// }${extra}.${isImage ? 'png' : output.type}`
|
||||
// const downloadLocation = downloadLocationer()
|
||||
// const downloadLocation2 = downloadLocationer('-2')
|
||||
const downloadPromise = page.waitForEvent('download')
|
||||
await page.getByRole('button', { name: 'Export', exact: true }).click()
|
||||
const download = await downloadPromise
|
||||
const downloadLocationer = (extra = '', isImage = false) =>
|
||||
`./e2e/playwright/export-snapshots/${output.type}-${
|
||||
'storage' in output ? output.storage : ''
|
||||
}${extra}.${isImage ? 'png' : output.type}`
|
||||
const downloadLocation = downloadLocationer()
|
||||
const downloadLocation2 = downloadLocationer('-2')
|
||||
|
||||
// if (output.type === 'gltf' && output.storage === 'standard') {
|
||||
// // wait for second download
|
||||
// const download2 = await page.waitForEvent('download')
|
||||
// await download.saveAs(downloadLocation)
|
||||
// await download2.saveAs(downloadLocation2)
|
||||
if (output.type === 'gltf' && output.storage === 'standard') {
|
||||
// wait for second download
|
||||
const download2 = await page.waitForEvent('download')
|
||||
await download.saveAs(downloadLocation)
|
||||
await download2.saveAs(downloadLocation2)
|
||||
|
||||
// // rewrite uri to reference our file name
|
||||
// const fileContents = await fsp.readFile(downloadLocation, 'utf-8')
|
||||
// const isJson = fileContents.includes('buffers')
|
||||
// let contents = fileContents
|
||||
// let reWriteLocation = downloadLocation
|
||||
// let uri = downloadLocation2.split('/').pop()
|
||||
// if (!isJson) {
|
||||
// contents = await fsp.readFile(downloadLocation2, 'utf-8')
|
||||
// reWriteLocation = downloadLocation2
|
||||
// uri = downloadLocation.split('/').pop()
|
||||
// }
|
||||
// contents = contents.replace(/"uri": ".*"/g, `"uri": "${uri}"`)
|
||||
// await fsp.writeFile(reWriteLocation, contents)
|
||||
// } else {
|
||||
// await download.saveAs(downloadLocation)
|
||||
// }
|
||||
// rewrite uri to reference our file name
|
||||
const fileContents = await fsp.readFile(downloadLocation, 'utf-8')
|
||||
const isJson = fileContents.includes('buffers')
|
||||
let contents = fileContents
|
||||
let reWriteLocation = downloadLocation
|
||||
let uri = downloadLocation2.split('/').pop()
|
||||
if (!isJson) {
|
||||
contents = await fsp.readFile(downloadLocation2, 'utf-8')
|
||||
reWriteLocation = downloadLocation2
|
||||
uri = downloadLocation.split('/').pop()
|
||||
}
|
||||
contents = contents.replace(/"uri": ".*"/g, `"uri": "${uri}"`)
|
||||
await fsp.writeFile(reWriteLocation, contents)
|
||||
} else {
|
||||
await download.saveAs(downloadLocation)
|
||||
}
|
||||
|
||||
// if (output.type === 'step') {
|
||||
// // stable timestamps for step files
|
||||
// const fileContents = await fsp.readFile(downloadLocation, 'utf-8')
|
||||
// const newFileContents = fileContents.replace(
|
||||
// /[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+[0-9]+[0-9]\+[0-9]{2}:[0-9]{2}/g,
|
||||
// '1970-01-01T00:00:00.0+00:00'
|
||||
// )
|
||||
// await fsp.writeFile(downloadLocation, newFileContents)
|
||||
// }
|
||||
// return {
|
||||
// modelPath: downloadLocation,
|
||||
// imagePath: downloadLocationer('', true),
|
||||
// outputType: output.type,
|
||||
// }
|
||||
// }
|
||||
// const axisDirectionPair: Models['AxisDirectionPair_type'] = {
|
||||
// axis: 'z',
|
||||
// direction: 'positive',
|
||||
// }
|
||||
// const sysType: Models['System_type'] = {
|
||||
// forward: axisDirectionPair,
|
||||
// up: axisDirectionPair,
|
||||
// }
|
||||
if (output.type === 'step') {
|
||||
// stable timestamps for step files
|
||||
const fileContents = await fsp.readFile(downloadLocation, 'utf-8')
|
||||
const newFileContents = fileContents.replace(
|
||||
/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]+[0-9]+[0-9]\+[0-9]{2}:[0-9]{2}/g,
|
||||
'1970-01-01T00:00:00.0+00:00'
|
||||
)
|
||||
await fsp.writeFile(downloadLocation, newFileContents)
|
||||
}
|
||||
return {
|
||||
modelPath: downloadLocation,
|
||||
imagePath: downloadLocationer('', true),
|
||||
outputType: output.type,
|
||||
}
|
||||
}
|
||||
const axisDirectionPair: Models['AxisDirectionPair_type'] = {
|
||||
axis: 'z',
|
||||
direction: 'positive',
|
||||
}
|
||||
const sysType: Models['System_type'] = {
|
||||
forward: axisDirectionPair,
|
||||
up: axisDirectionPair,
|
||||
}
|
||||
|
||||
// const exportLocations: Paths[] = []
|
||||
const exportLocations: Paths[] = []
|
||||
|
||||
// // NOTE it was easiest to leverage existing types and have doExport take Models['OutputFormat_type'] as in input
|
||||
// // just note that only `type` and `storage` are used for selecting the drop downs is the app
|
||||
// // the rest are only there to make typescript happy
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'step',
|
||||
// coords: sysType,
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'ply',
|
||||
// coords: sysType,
|
||||
// selection: { type: 'default_scene' },
|
||||
// storage: 'ascii',
|
||||
// units: 'in',
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'ply',
|
||||
// storage: 'binary_little_endian',
|
||||
// coords: sysType,
|
||||
// selection: { type: 'default_scene' },
|
||||
// units: 'in',
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'ply',
|
||||
// storage: 'binary_big_endian',
|
||||
// coords: sysType,
|
||||
// selection: { type: 'default_scene' },
|
||||
// units: 'in',
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'stl',
|
||||
// storage: 'ascii',
|
||||
// coords: sysType,
|
||||
// units: 'in',
|
||||
// selection: { type: 'default_scene' },
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'stl',
|
||||
// storage: 'binary',
|
||||
// coords: sysType,
|
||||
// units: 'in',
|
||||
// selection: { type: 'default_scene' },
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// // obj seems to be a little flaky, times out tests sometimes
|
||||
// type: 'obj',
|
||||
// coords: sysType,
|
||||
// units: 'in',
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'gltf',
|
||||
// storage: 'embedded',
|
||||
// presentation: 'pretty',
|
||||
// })
|
||||
// )
|
||||
// exportLocations.push(
|
||||
// await doExport({
|
||||
// type: 'gltf',
|
||||
// storage: 'binary',
|
||||
// presentation: 'pretty',
|
||||
// })
|
||||
// )
|
||||
// NOTE it was easiest to leverage existing types and have doExport take Models['OutputFormat_type'] as in input
|
||||
// just note that only `type` and `storage` are used for selecting the drop downs is the app
|
||||
// the rest are only there to make typescript happy
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'step',
|
||||
coords: sysType,
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'ply',
|
||||
coords: sysType,
|
||||
selection: { type: 'default_scene' },
|
||||
storage: 'ascii',
|
||||
units: 'in',
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'ply',
|
||||
storage: 'binary_little_endian',
|
||||
coords: sysType,
|
||||
selection: { type: 'default_scene' },
|
||||
units: 'in',
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'ply',
|
||||
storage: 'binary_big_endian',
|
||||
coords: sysType,
|
||||
selection: { type: 'default_scene' },
|
||||
units: 'in',
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'stl',
|
||||
storage: 'ascii',
|
||||
coords: sysType,
|
||||
units: 'in',
|
||||
selection: { type: 'default_scene' },
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'stl',
|
||||
storage: 'binary',
|
||||
coords: sysType,
|
||||
units: 'in',
|
||||
selection: { type: 'default_scene' },
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
// obj seems to be a little flaky, times out tests sometimes
|
||||
type: 'obj',
|
||||
coords: sysType,
|
||||
units: 'in',
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'gltf',
|
||||
storage: 'embedded',
|
||||
presentation: 'pretty',
|
||||
})
|
||||
)
|
||||
exportLocations.push(
|
||||
await doExport({
|
||||
type: 'gltf',
|
||||
storage: 'binary',
|
||||
presentation: 'pretty',
|
||||
})
|
||||
)
|
||||
|
||||
// // TODO: gltfs don't seem to work with snap shots. push onto exportLocations once it's figured out
|
||||
// await doExport({
|
||||
// type: 'gltf',
|
||||
// storage: 'standard',
|
||||
// presentation: 'pretty',
|
||||
// })
|
||||
// TODO: gltfs don't seem to work with snap shots. push onto exportLocations once it's figured out
|
||||
await doExport({
|
||||
type: 'gltf',
|
||||
storage: 'standard',
|
||||
presentation: 'pretty',
|
||||
})
|
||||
|
||||
// // close page to disconnect websocket since we can only have one open atm
|
||||
// await page.close()
|
||||
// close page to disconnect websocket since we can only have one open atm
|
||||
await page.close()
|
||||
|
||||
// // snapshot exports, good compromise to capture that exports are healthy without getting bogged down in "did the formatting change" changes
|
||||
// // context: https://github.com/KittyCAD/modeling-app/issues/1222
|
||||
// for (const { modelPath, imagePath, outputType } of exportLocations) {
|
||||
// const cliCommand = `export KITTYCAD_TOKEN=${secrets.snapshottoken} && kittycad file snapshot --output-format=png --src-format=${outputType} ${modelPath} ${imagePath}`
|
||||
// const child = spawn(cliCommand, { shell: true })
|
||||
// await new Promise((resolve, reject) => {
|
||||
// child.on('error', (code: any, msg: any) => {
|
||||
// console.log('error', code, msg)
|
||||
// reject()
|
||||
// })
|
||||
// child.on('exit', (code, msg) => {
|
||||
// console.log('exit', code, msg)
|
||||
// if (code !== 0) {
|
||||
// reject(`exit code ${code} for model ${modelPath}`)
|
||||
// } else {
|
||||
// resolve(true)
|
||||
// }
|
||||
// })
|
||||
// child.stderr.on('data', (data) => console.log(`stderr: ${data}`))
|
||||
// child.stdout.on('data', (data) => console.log(`stdout: ${data}`))
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// snapshot exports, good compromise to capture that exports are healthy without getting bogged down in "did the formatting change" changes
|
||||
// context: https://github.com/KittyCAD/modeling-app/issues/1222
|
||||
for (const { modelPath, imagePath, outputType } of exportLocations) {
|
||||
const cliCommand = `export ZOO_TOKEN=${secrets.snapshottoken} && zoo file snapshot --output-format=png --src-format=${outputType} ${modelPath} ${imagePath}`
|
||||
const child = spawn(cliCommand, { shell: true })
|
||||
await new Promise((resolve, reject) => {
|
||||
child.on('error', (code: any, msg: any) => {
|
||||
console.log('error', code, msg)
|
||||
reject()
|
||||
})
|
||||
child.on('exit', (code, msg) => {
|
||||
console.log('exit', code, msg)
|
||||
if (code !== 0) {
|
||||
reject(`exit code ${code} for model ${modelPath}`)
|
||||
} else {
|
||||
resolve(true)
|
||||
}
|
||||
})
|
||||
child.stderr.on('data', (data) => console.log(`stderr: ${data}`))
|
||||
child.stdout.on('data', (data) => console.log(`stdout: ${data}`))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('extrude on each default plane should be stable', async ({
|
||||
page,
|
||||
|
||||
Reference in New Issue
Block a user