Skip to content

Commit

Permalink
Fix reading files from WebAssembly (#4183)
Browse files Browse the repository at this point in the history
  • Loading branch information
jtran authored Oct 18, 2024
1 parent 5332ddd commit 19ffa22
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 9 deletions.
92 changes: 91 additions & 1 deletion e2e/playwright/editor-tests.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { test, expect } from '@playwright/test'
import fsp from 'fs/promises'
import { uuidv4 } from 'lib/utils'
import { getUtils, setup, tearDown } from './test-utils'
import {
darkModeBgColor,
darkModePlaneColorXZ,
executorInputPath,
getUtils,
setup,
setupElectron,
tearDown,
} from './test-utils'
import { join } from 'path'

test.beforeEach(async ({ context, page }, testInfo) => {
await setup(context, page, testInfo)
Expand Down Expand Up @@ -974,4 +984,84 @@ test.describe('Editor tests', () => {
|> close(%)
|> extrude(5, %)`)
})

test(
`Can use the import stdlib function on a local OBJ file`,
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
const bracketDir = join(dir, 'cube')
await fsp.mkdir(bracketDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cube.obj'),
join(bracketDir, 'cube.obj')
)
await fsp.writeFile(join(bracketDir, 'main.kcl'), '')
},
})
const viewportSize = { width: 1200, height: 500 }
await page.setViewportSize(viewportSize)

// Locators and constants
const u = await getUtils(page)
const projectLink = page.getByRole('link', { name: 'cube' })
const gizmo = page.locator('[aria-label*=gizmo]')
const resetCameraButton = page.getByRole('button', { name: 'Reset view' })
const locationToHavColor = async (
position: { x: number; y: number },
color: [number, number, number]
) => {
return u.getGreatestPixDiff(position, color)
}
const notTheOrigin = {
x: viewportSize.width * 0.55,
y: viewportSize.height * 0.3,
}
const origin = { x: viewportSize.width / 2, y: viewportSize.height / 2 }
const errorIndicators = page.locator('.cm-lint-marker-error')

await test.step(`Open the empty file, see the default planes`, async () => {
await projectLink.click()
await u.waitForPageLoad()
await expect
.poll(
async () => locationToHavColor(notTheOrigin, darkModePlaneColorXZ),
{
timeout: 5000,
message: 'XZ plane color is visible',
}
)
.toBeLessThan(15)
})
await test.step(`Write the import function line`, async () => {
await u.codeLocator.fill(`import('cube.obj')`)
await page.waitForTimeout(800)
})
await test.step(`Reset the camera before checking`, async () => {
await u.doAndWaitForCmd(async () => {
await gizmo.click({ button: 'right' })
await resetCameraButton.click()
}, 'zoom_to_fit')
})
await test.step(`Verify that we see the imported geometry and no errors`, async () => {
await expect(errorIndicators).toHaveCount(0)
await expect
.poll(async () => locationToHavColor(origin, darkModePlaneColorXZ), {
timeout: 3000,
message: 'Plane color should not be visible',
})
.toBeGreaterThan(15)
await expect
.poll(async () => locationToHavColor(origin, darkModeBgColor), {
timeout: 3000,
message: 'Background color should not be visible',
})
.toBeGreaterThan(15)
})

await electronApp.close()
}
)
})
8 changes: 8 additions & 0 deletions e2e/playwright/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ export const commonPoints = {
num2: 14.44,
}

/** A semi-reliable color to check the default XZ plane on
* in dark mode in the default camera position
*/
export const darkModePlaneColorXZ: [number, number, number] = [50, 50, 99]

/** A semi-reliable color to check the default dark mode bg color against */
export const darkModeBgColor: [number, number, number] = [27, 27, 27]

export const editorSelector = '[role="textbox"][data-language="kcl"]'
type PaneId = 'variables' | 'code' | 'files' | 'logs'

Expand Down
2 changes: 1 addition & 1 deletion interface.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export interface IElectronAPI {
key: string,
callback: (eventType: string, path: string) => void
) => void
readFile: typeof fs.readFile
watchFileOff: (path: string, key: string) => void
readFile: (path: string) => ReturnType<fs.readFile>
writeFile: (
path: string,
data: string | Uint8Array
Expand Down
2 changes: 1 addition & 1 deletion src/components/FileTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ const FileTreeItem = ({
async (eventType, path) => {
// Don't try to read a file that was removed.
if (isCurrentFile && eventType !== 'unlink') {
let code = await window.electron.readFile(path)
let code = await window.electron.readFile(path, { encoding: 'utf-8' })
code = normalizeLineEndings(code)
codeManager.updateCodeStateEditor(code)
}
Expand Down
2 changes: 1 addition & 1 deletion src/lang/std/fileSystemManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class FileSystemManager {
return Promise.resolve(window.electron.path.join(dir, path))
}

async readFile(path: string): Promise<Uint8Array | void> {
async readFile(path: string): Promise<Uint8Array> {
// Using local file system only works from desktop.
if (!isDesktop()) {
return Promise.reject(
Expand Down
12 changes: 9 additions & 3 deletions src/lib/desktop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,9 @@ export const readProjectSettingsFile = async (
}
}

const configToml = await window.electron.readFile(settingsPath)
const configToml = await window.electron.readFile(settingsPath, {
encoding: 'utf-8',
})
const configObj = parseProjectSettings(configToml)
if (err(configObj)) {
return Promise.reject(configObj)
Expand All @@ -467,7 +469,9 @@ export const readAppSettingsFile = async () => {

// The file exists, read it and parse it.
if (window.electron.exists(settingsPath)) {
const configToml = await window.electron.readFile(settingsPath)
const configToml = await window.electron.readFile(settingsPath, {
encoding: 'utf-8',
})
const parsedAppConfig = parseAppSettings(configToml)
if (err(parsedAppConfig)) {
return Promise.reject(parsedAppConfig)
Expand Down Expand Up @@ -527,7 +531,9 @@ export const readTokenFile = async () => {
let settingsPath = await getTokenFilePath()

if (window.electron.exists(settingsPath)) {
const token: string = await window.electron.readFile(settingsPath)
const token: string = await window.electron.readFile(settingsPath, {
encoding: 'utf-8',
})
if (!token) return ''

return token
Expand Down
4 changes: 3 additions & 1 deletion src/lib/routeLoaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ export const fileLoader: LoaderFunction = async (
)
}

code = await window.electron.readFile(currentFilePath)
code = await window.electron.readFile(currentFilePath, {
encoding: 'utf-8',
})
code = normalizeLineEndings(code)

// Update both the state and the editor's code.
Expand Down
2 changes: 1 addition & 1 deletion src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const watchFileOff = (path: string, key: string) => {
fsWatchListeners.set(path, watchers)
}
}
const readFile = (path: string) => fs.readFile(path, 'utf-8')
const readFile = fs.readFile
// It seems like from the node source code this does not actually block but also
// don't trust me on that (jess).
const exists = (path: string) => fsSync.existsSync(path)
Expand Down

0 comments on commit 19ffa22

Please sign in to comment.