Files
twenty/packages/twenty-front-component-renderer/jest.config.mjs
T
Raphaël Bosi bb22b216db Fix front components rendering a blank panel in Firefox (#23213)
Fixes #22973

In Firefox, front components rendered a blank panel with only
`DataCloneError: Exception object could not be cloned` in the console.
Accessing `caches` in the opaque-origin sandbox worker throws a Gecko
`Exception` (worker-side CacheStorage code up to v2.22, or any component
code touching it since), and `@quilted/threads` posts thrown values raw
over the MessagePort. Firefox cannot structured-clone these exceptions,
so the error report itself failed and the render promise never settled.

Thread errors are now flattened to clonable payloads and rehydrated on
the other side, so the real error surfaces in the error box instead of
silently hanging the panel. Also makes the CacheStorage guards
exception-safe (v2.23 already moved that code host-side, which removed
the main trigger).

Verified end to end in stock Firefox 149: before, a component touching
`caches` hangs silently; after, render rejects with the full
`NS_ERROR_FAILURE` diagnostic. Chromium behavior unchanged.

```mermaid
sequenceDiagram
    participant Host as Host (React)
    participant Worker as Sandbox worker (null origin)
    participant Threads as @quilted/threads

    rect rgb(250, 235, 235)
    note over Host,Threads: Before — Firefox hangs
    Host->>Worker: render(component)
    Worker->>Worker: throws Gecko Exception<br/>(typeof caches)
    Worker->>Threads: postMessage(rawException)
    Threads--xHost: DataCloneError:<br/>Exception could not be cloned
    note over Host: CALL_RESULT never arrives<br/>render() promise never settles → blank panel
    end

    rect rgb(232, 245, 233)
    note over Host,Threads: After — error surfaces
    Host->>Worker: render(component)
    Worker->>Worker: throws Gecko Exception
    Worker->>Threads: serialize → { name, message, stack }
    Threads->>Host: postMessage(clonable payload)
    Host->>Host: rehydrate → Error, reject render()
    note over Host: error box shows NS_ERROR_FAILURE
    end
```

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23213?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-07-24 13:14:47 +02:00

44 lines
1.3 KiB
JavaScript

import { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
import { pathsToModuleNameMapper } from 'ts-jest';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const tsConfigPath = resolve(__dirname, './tsconfig.json');
const tsConfig = JSON.parse(readFileSync(tsConfigPath, 'utf8'));
const jestConfig = {
displayName: 'twenty-front-component-renderer',
preset: '../../jest.preset.js',
testEnvironment: 'jsdom',
setupFiles: ['<rootDir>/jest.setup.mjs'],
transformIgnorePatterns: ['node_modules/(?!@quilted/)'],
transform: {
'^.+\\.(mjs|[tj]sx?)$': [
'@swc/jest',
{
jsc: {
parser: { syntax: 'typescript', tsx: true },
transform: { react: { runtime: 'automatic' } },
},
},
],
},
moduleNameMapper: {
...pathsToModuleNameMapper(tsConfig.compilerOptions.paths, {
prefix: '<rootDir>/',
}),
'^@quilted/threads$':
'<rootDir>/../../node_modules/@quilted/threads/build/esm/index.mjs',
'^@quilted/events$':
'<rootDir>/../../node_modules/@quilted/events/build/esm/index.mjs',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'mjs'],
extensionsToTreatAsEsm: ['.ts', '.tsx'],
coverageDirectory: './coverage',
};
export default jestConfig;