diff --git a/e2e/playwright/projects.spec.ts b/e2e/playwright/projects.spec.ts index cab24566d..3b69e8fe0 100644 --- a/e2e/playwright/projects.spec.ts +++ b/e2e/playwright/projects.spec.ts @@ -297,13 +297,12 @@ test( const pointOnModel = { x: 630, y: 280 } - await test.step('Opening the bracket project should load the stream', async () => { // expect to see the text bracket await expect(page.getByText('bracket')).toBeVisible() await page.getByText('bracket').click() - + await expect( page.getByRole('button', { name: 'Start Sketch' }) ).toBeEnabled({ diff --git a/e2e/playwright/sketch-tests.spec.ts b/e2e/playwright/sketch-tests.spec.ts index 1d439782c..22e2b8fc4 100644 --- a/e2e/playwright/sketch-tests.spec.ts +++ b/e2e/playwright/sketch-tests.spec.ts @@ -388,7 +388,7 @@ test.describe('Sketch tests', () => { const dragPX = 40 await page - .getByText('circle({ center: [4.61, -5.01], radius: 8 }, %)') + .getByText('circle({ center = [4.61, -5.01], radius = 8 }, %)') .click() await expect( page.getByRole('button', { name: 'Edit Sketch' }) diff --git a/e2e/playwright/test-utils.ts b/e2e/playwright/test-utils.ts index e94687961..25ab69d03 100644 --- a/e2e/playwright/test-utils.ts +++ b/e2e/playwright/test-utils.ts @@ -30,103 +30,126 @@ import { reportRejection } from 'lib/trap' // The below is copied from playwright-core because it exports none of them :( import { Env, BrowserContextOptions } from 'playwright-core' -import type * as channels from '@protocol/channels'; +import type * as channels from '@protocol/channels' // Copied from playwright-core -function envObjectToArray(env: Env): { name: string, value: string }[] { - const result: { name: string, value: string }[] = []; +function envObjectToArray(env: Env): { name: string; value: string }[] { + const result: { name: string; value: string }[] = [] for (const name in env) { if (!Object.is(env[name], undefined)) - result.push({ name, value: String(env[name]) }); + result.push({ name, value: String(env[name]) }) } - return result; + return result } // Copied from playwright-core -export async function toClientCertificatesProtocol(certs?: BrowserContextOptions['clientCertificates']): Promise { - if (!certs) - return undefined; +export async function toClientCertificatesProtocol( + certs?: BrowserContextOptions['clientCertificates'] +): Promise { + if (!certs) return undefined - const bufferizeContent = async (value?: Buffer, path?: string): Promise => { - if (value) - return value; - if (path) - return await fs.promises.readFile(path); - }; + const bufferizeContent = async ( + value?: Buffer, + path?: string + ): Promise => { + if (value) return value + if (path) return await fs.promises.readFile(path) + } - return await Promise.all(certs.map(async cert => ({ - origin: cert.origin, - cert: await bufferizeContent(cert.cert, cert.certPath), - key: await bufferizeContent(cert.key, cert.keyPath), - pfx: await bufferizeContent(cert.pfx, cert.pfxPath), - passphrase: cert.passphrase, - }))); + return await Promise.all( + certs.map(async (cert) => ({ + origin: cert.origin, + cert: await bufferizeContent(cert.cert, cert.certPath), + key: await bufferizeContent(cert.key, cert.keyPath), + pfx: await bufferizeContent(cert.pfx, cert.pfxPath), + passphrase: cert.passphrase, + })) + ) } // Copied from playwright-core function toAcceptDownloadsProtocol(acceptDownloads?: boolean) { - if (acceptDownloads === undefined) - return undefined; - if (acceptDownloads) - return 'accept'; - return 'deny'; + if (acceptDownloads === undefined) return undefined + if (acceptDownloads) return 'accept' + return 'deny' } // Copied from playwright-core -function prepareRecordHarOptions(options: BrowserContextOptions['recordHar']): channels.RecordHarOptions | undefined { - if (!options) - return; +function prepareRecordHarOptions( + options: BrowserContextOptions['recordHar'] +): channels.RecordHarOptions | undefined { + if (!options) return return { path: options.path, content: options.content || (options.omitContent ? 'omit' : undefined), urlGlob: isString(options.urlFilter) ? options.urlFilter : undefined, - urlRegexSource: isRegExp(options.urlFilter) ? options.urlFilter.source : undefined, - urlRegexFlags: isRegExp(options.urlFilter) ? options.urlFilter.flags : undefined, - mode: options.mode - }; -} - -// Copied from playwright-core -async function prepareStorageState(options: BrowserContextOptions): Promise { - if (typeof options.storageState !== 'string') - return options.storageState; - try { - return JSON.parse(await fs.promises.readFile(options.storageState, 'utf8')); - } catch (e) { - rewriteErrorMessage(e, `Error reading storage state from ${options.storageState}:\n` + e.message); - throw e; + urlRegexSource: isRegExp(options.urlFilter) + ? options.urlFilter.source + : undefined, + urlRegexFlags: isRegExp(options.urlFilter) + ? options.urlFilter.flags + : undefined, + mode: options.mode, } } // Copied from playwright-core -async function prepareBrowserContextParams(options: BrowserContextOptions): Promise { +async function prepareStorageState( + options: BrowserContextOptions +): Promise { + if (typeof options.storageState !== 'string') return options.storageState + try { + return JSON.parse(await fs.promises.readFile(options.storageState, 'utf8')) + } catch (e) { + rewriteErrorMessage( + e, + `Error reading storage state from ${options.storageState}:\n` + e.message + ) + throw e + } +} + +// Copied from playwright-core +async function prepareBrowserContextParams( + options: BrowserContextOptions +): Promise { if (options.videoSize && !options.videosPath) - throw new Error(`"videoSize" option requires "videosPath" to be specified`); + throw new Error(`"videoSize" option requires "videosPath" to be specified`) if (options.extraHTTPHeaders) - network.validateHeaders(options.extraHTTPHeaders); + network.validateHeaders(options.extraHTTPHeaders) const contextParams: channels.BrowserNewContextParams = { ...options, viewport: options.viewport === null ? undefined : options.viewport, noDefaultViewport: options.viewport === null, - extraHTTPHeaders: options.extraHTTPHeaders ? headersObjectToArray(options.extraHTTPHeaders) : undefined, + extraHTTPHeaders: options.extraHTTPHeaders + ? headersObjectToArray(options.extraHTTPHeaders) + : undefined, storageState: await prepareStorageState(options), serviceWorkers: options.serviceWorkers, recordHar: prepareRecordHarOptions(options.recordHar), - colorScheme: options.colorScheme === null ? 'no-override' : options.colorScheme, - reducedMotion: options.reducedMotion === null ? 'no-override' : options.reducedMotion, - forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors, + colorScheme: + options.colorScheme === null ? 'no-override' : options.colorScheme, + reducedMotion: + options.reducedMotion === null ? 'no-override' : options.reducedMotion, + forcedColors: + options.forcedColors === null ? 'no-override' : options.forcedColors, acceptDownloads: toAcceptDownloadsProtocol(options.acceptDownloads), - clientCertificates: await toClientCertificatesProtocol(options.clientCertificates), - }; + clientCertificates: await toClientCertificatesProtocol( + options.clientCertificates + ), + } if (!contextParams.recordVideo && options.videosPath) { contextParams.recordVideo = { dir: options.videosPath, - size: options.videoSize - }; + size: options.videoSize, + } } if (contextParams.recordVideo && contextParams.recordVideo.dir) - contextParams.recordVideo.dir = path.resolve(process.cwd(), contextParams.recordVideo.dir); - return contextParams; + contextParams.recordVideo.dir = path.resolve( + process.cwd(), + contextParams.recordVideo.dir + ) + return contextParams } const toNormalizedCode = (text: string) => { @@ -973,7 +996,10 @@ export async function setup( localStorage.clear() localStorage.setItem('TOKEN_PERSIST_KEY', token) localStorage.setItem('persistCode', ``) - localStorage.setItem(PERSIST_MODELING_CONTEXT, JSON.stringify({openPanes: ['code']})) + localStorage.setItem( + PERSIST_MODELING_CONTEXT, + JSON.stringify({ openPanes: ['code'] }) + ) localStorage.setItem(settingsKey, settings) localStorage.setItem(IS_PLAYWRIGHT_KEY, 'true') localStorage.setItem('PLAYWRIGHT_TEST_DIR', PLAYWRIGHT_TEST_DIR) diff --git a/e2e/playwright/testing-segment-overlays.spec.ts b/e2e/playwright/testing-segment-overlays.spec.ts index 782b3a6fd..4bc6168b6 100644 --- a/e2e/playwright/testing-segment-overlays.spec.ts +++ b/e2e/playwright/testing-segment-overlays.spec.ts @@ -95,7 +95,9 @@ test.describe('Testing segment overlays', () => { }) .click() await expect(page.locator('.cm-content')).toContainText(expectFinal) - await editor.expectEditor.toContain(expectFinal, { shouldNormalise: true }) + await editor.expectEditor.toContain(expectFinal, { + shouldNormalise: true, + }) await editor.expectEditor.toContain(expectFinal, { shouldNormalise: true, }) diff --git a/e2e/playwright/zoo-test.ts b/e2e/playwright/zoo-test.ts index 591e1f5bf..2470a2db2 100644 --- a/e2e/playwright/zoo-test.ts +++ b/e2e/playwright/zoo-test.ts @@ -223,15 +223,15 @@ export const test = ( if (tronApp instanceof AuthenticatedTronApp) { tronApp.context.folderSetupFn = async function (fn) { return fn(tronApp.dir) - .then(() => tronApp.page.reload()) - .then(() => ({ - dir: tronApp.dir, - })) + .then(() => tronApp.page.reload()) + .then(() => ({ + dir: tronApp.dir, + })) } } if (!firstUrl) { - await tronApp.page.getByText('Your Projects').count(); + await tronApp.page.getByText('Your Projects').count() firstUrl = tronApp.page.url() } @@ -243,7 +243,7 @@ export const test = ( // }); await tronApp.electronApp.evaluate(({ app }, projectDirName) => { - console.log("ABCDEFGHI", app.testProperty['TEST_SETTINGS_FILE_KEY']) + console.log('ABCDEFGHI', app.testProperty['TEST_SETTINGS_FILE_KEY']) app.testProperty['TEST_SETTINGS_FILE_KEY'] = projectDirName }, tronApp.dir) diff --git a/package.json b/package.json index 174b37a2a..90646d067 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "@iarna/toml": "^2.2.5", "@lezer/generator": "^1.7.1", "@nabla/vite-plugin-eslint": "^2.0.5", - "@playwright/test": "^1.46.1", + "@playwright/test": "^1.49.0", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^15.0.2", "@types/d3-force": "^3.0.10", diff --git a/public/kcl-samples-manifest-fallback.json b/public/kcl-samples-manifest-fallback.json index de6867795..db2f0988a 100644 --- a/public/kcl-samples-manifest-fallback.json +++ b/public/kcl-samples-manifest-fallback.json @@ -119,6 +119,11 @@ "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": "pipe-with-bend.kcl", + "title": "Pipe with bend", + "description": "A tubular section or hollow cylinder, usually but not necessarily of circular cross-section, used mainly to convey substances that can flow." + }, { "file": "poopy-shoe.kcl", "title": "Poopy Shoe", diff --git a/src/lib/desktop.ts b/src/lib/desktop.ts index 0d3cd5544..0525655e5 100644 --- a/src/lib/desktop.ts +++ b/src/lib/desktop.ts @@ -391,7 +391,9 @@ const getAppFolderName = () => { export const getAppSettingsFilePath = async () => { const isTestEnv = window.electron.process.env.IS_PLAYWRIGHT === 'true' - const testSettingsPath = await window.electron.getAppTestProperty('TEST_SETTINGS_FILE_KEY') + const testSettingsPath = await window.electron.getAppTestProperty( + 'TEST_SETTINGS_FILE_KEY' + ) const appConfig = await window.electron.getPath('appData') const fullPath = isTestEnv ? testSettingsPath @@ -408,7 +410,9 @@ export const getAppSettingsFilePath = async () => { } const getTokenFilePath = async () => { const isTestEnv = window.electron.process.env.IS_PLAYWRIGHT === 'true' - const testSettingsPath = await window.electron.getAppTestProperty('TEST_SETTINGS_FILE_KEY') + const testSettingsPath = await window.electron.getAppTestProperty( + 'TEST_SETTINGS_FILE_KEY' + ) const appConfig = await window.electron.getPath('appData') const fullPath = isTestEnv ? testSettingsPath diff --git a/src/lib/exportSave.ts b/src/lib/exportSave.ts index 912de324f..54394e4f3 100644 --- a/src/lib/exportSave.ts +++ b/src/lib/exportSave.ts @@ -18,7 +18,9 @@ const save_ = async (file: ModelingAppFile, toastId: string) => { if (window.electron.process.env.IS_PLAYWRIGHT) { // Skip file picker, save to the test dir downloads directory - const testSettingsPath = await window.electron.getAppTestProperty('TEST_SETTINGS_FILE_KEY') + const testSettingsPath = await window.electron.getAppTestProperty( + 'TEST_SETTINGS_FILE_KEY' + ) const downloadDir = window.electron.join( testSettingsPath, 'downloads-during-playwright' diff --git a/src/main.ts b/src/main.ts index eb8e1c8be..d4dd41953 100644 --- a/src/main.ts +++ b/src/main.ts @@ -62,22 +62,26 @@ if (process.defaultApp) { registerStartupListeners() const createWindow = (filePath?: string, reuse?: boolean): BrowserWindow => { - const newWindow = reuse ? mainWindow : new BrowserWindow({ - autoHideMenuBar: true, - show: false, - width: 1800, - height: 1200, - webPreferences: { - nodeIntegration: false, // do not give the application implicit system access - contextIsolation: true, // expose system functions in preload - sandbox: false, // expose nodejs in preload - preload: path.join(__dirname, './preload.js'), - }, - icon: path.resolve(process.cwd(), 'assets', 'icon.png'), - frame: os.platform() !== 'darwin', - titleBarStyle: 'hiddenInset', - backgroundColor: nativeTheme.shouldUseDarkColors ? '#1C1C1C' : '#FCFCFC', - }) + const newWindow = reuse + ? mainWindow + : new BrowserWindow({ + autoHideMenuBar: true, + show: false, + width: 1800, + height: 1200, + webPreferences: { + nodeIntegration: false, // do not give the application implicit system access + contextIsolation: true, // expose system functions in preload + sandbox: false, // expose nodejs in preload + preload: path.join(__dirname, './preload.js'), + }, + icon: path.resolve(process.cwd(), 'assets', 'icon.png'), + frame: os.platform() !== 'darwin', + titleBarStyle: 'hiddenInset', + backgroundColor: nativeTheme.shouldUseDarkColors + ? '#1C1C1C' + : '#FCFCFC', + }) // and load the index.html of the app. if (MAIN_WINDOW_VITE_DEV_SERVER_URL) { diff --git a/src/preload.ts b/src/preload.ts index f999de820..a9e5b1cc9 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -31,7 +31,8 @@ const onUpdateDownloadStart = ( const onUpdateError = (callback: (value: Error) => void) => ipcRenderer.on('update-error', (_event: any, value) => callback(value)) const appRestart = () => ipcRenderer.invoke('app.restart') -const getAppTestProperty = (propertyName: string) => ipcRenderer.invoke('app.testProperty', propertyName) +const getAppTestProperty = (propertyName: string) => + ipcRenderer.invoke('app.testProperty', propertyName) const isMac = os.platform() === 'darwin' const isWindows = os.platform() === 'win32' diff --git a/yarn.lock b/yarn.lock index 82b619785..1a24d4220 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2131,12 +2131,12 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@playwright/test@^1.46.1": - version "1.46.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.46.1.tgz#a8dfdcd623c4c23bb1b7ea588058aad41055c188" - integrity sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA== +"@playwright/test@^1.49.0": + version "1.49.1" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.49.1.tgz#55fa360658b3187bfb6371e2f8a64f50ef80c827" + integrity sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g== dependencies: - playwright "1.46.1" + playwright "1.49.1" "@react-hook/latest@^1.0.2": version "1.0.3" @@ -7506,17 +7506,17 @@ pkg-types@^1.0.3, pkg-types@^1.1.1: mlly "^1.7.1" pathe "^1.1.2" -playwright-core@1.46.1: - version "1.46.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.46.1.tgz#28f3ab35312135dda75b0c92a3e5c0e7edb9cc8b" - integrity sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A== +playwright-core@1.49.1: + version "1.49.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.49.1.tgz#32c62f046e950f586ff9e35ed490a424f2248015" + integrity sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg== -playwright@1.46.1: - version "1.46.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.46.1.tgz#ea562bc48373648e10420a10c16842f0b227c218" - integrity sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng== +playwright@1.49.1: + version "1.49.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.49.1.tgz#830266dbca3008022afa7b4783565db9944ded7c" + integrity sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA== dependencies: - playwright-core "1.46.1" + playwright-core "1.49.1" optionalDependencies: fsevents "2.3.2" @@ -8533,16 +8533,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -8636,14 +8627,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -9500,16 +9484,7 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==