diff --git a/ava.config.js b/ava.config.js index 6d983d59..cb9c7c85 100644 --- a/ava.config.js +++ b/ava.config.js @@ -1,8 +1,10 @@ export default { - // GraphQL schema generation currently uses graphql-compose's process-global - // schemaComposer. Run AVA files serially so schema-building tests do not - // mutate that shared composer concurrently. - concurrency: 1, + // AVA isolates test files in worker processes. Test writers use unique + // mkdtemp directories (including the cwd-relative watcher fixtures), bind + // ephemeral ports, and close their servers; no test changes process.cwd(). + // Four workers provide parallelism without over-subscribing real filesystem + // watchers during the suite's integration tests. + concurrency: 4, files: [ 'packages/**/*.test.(j|t)s', // Codegen + utils use Vitest under src/__tests__. Keep those out of the diff --git a/packages/flatbread/src/graphql/liveServer.ts b/packages/flatbread/src/graphql/liveServer.ts index 00daf4bd..a517f769 100644 --- a/packages/flatbread/src/graphql/liveServer.ts +++ b/packages/flatbread/src/graphql/liveServer.ts @@ -167,19 +167,33 @@ export async function startGraphqlServer( : 'codegen refresh'; console.error(`Flatbread ${label} failed:`, result.error); }); - subscription = await subscribe( - cwd, - (error, events) => { - if (error) { - console.error('Flatbread watcher error:', error); - return; - } - coordinator!.push( - events.map((event) => ({ path: event.path, type: event.type })) + for (let attempt = 0; attempt < 3; attempt++) { + try { + subscription = await subscribe( + cwd, + (error, events) => { + if (error) { + console.error('Flatbread watcher error:', error); + return; + } + coordinator!.push( + events.map((event) => ({ path: event.path, type: event.type })) + ); + }, + { ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**'] } ); - }, - { ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**'] } - ); + break; + } catch (error: unknown) { + const isEnoent = + error instanceof Error && + ((error as NodeJS.ErrnoException).code === 'ENOENT' || + error.message.includes('No such file or directory')); + if (!isEnoent || attempt === 2) throw error; + await new Promise((resolve) => + setTimeout(resolve, 100 * (attempt + 1)) + ); + } + } } return { port,