chore: Fix flakes in unit tests around monorepo (#32099)

This commit is contained in:
Matsu
2026-06-11 12:13:01 +00:00
committed by GitHub
parent 9d8fca8746
commit becb9cffa4
4 changed files with 34 additions and 8 deletions
@@ -1,3 +1,4 @@
import { ensureSyntaxTree } from '@codemirror/language';
import { EditorState } from '@codemirror/state';
import { CompletionContext, CompletionResult, CompletionSource } from '@codemirror/autocomplete';
import { html } from '../dist/index.js';
@@ -6,11 +7,17 @@ import ist from 'ist';
function get(doc: string, conf: { explicit?: boolean } = {}) {
let cur = doc.indexOf('|');
doc = doc.slice(0, cur) + doc.slice(cur + 1);
let state = EditorState.create({
let initialState = EditorState.create({
doc,
selection: { anchor: cur },
extensions: [html()],
});
// `EditorState.create` only parses within a 20ms wall-clock budget, which a
// contended CI runner can starve, leaving a truncated tree with no language
// data so `languageDataAt` returns []. Fully parse and commit the tree into
// the language state field via an empty transaction for determinism.
ensureSyntaxTree(initialState, initialState.doc.length, 1e9);
let state = initialState.update({}).state;
let result = state.languageDataAt<CompletionSource>('autocomplete', cur)[0](
new CompletionContext(state, cur, !!conf.explicit),
);
@@ -11,7 +11,7 @@ function get(doc: string, conf: SQLConfig & { explicit?: boolean } = {}) {
const dialect = conf.dialect || PostgreSQL;
doc = doc.slice(0, cur) + doc.slice(cur + 1);
const state = EditorState.create({
const initialState = EditorState.create({
doc,
selection: { anchor: cur },
extensions: [
@@ -21,7 +21,14 @@ function get(doc: string, conf: SQLConfig & { explicit?: boolean } = {}) {
}),
],
});
ensureSyntaxTree(state, state.doc.length, 1e9);
// `EditorState.create` only parses within a 20ms wall-clock budget, and
// `ensureSyntaxTree` advances a separate context tree rather than the one
// `languageDataAt` reads. Commit the fully-parsed tree into the language
// state field via an empty transaction so the lookup is deterministic
// regardless of host load (contended CI runners can otherwise starve that
// budget and leave a truncated tree with no language data).
ensureSyntaxTree(initialState, initialState.doc.length, 1e9);
const state = initialState.update({}).state;
const result = state.languageDataAt<CompletionSource>('autocomplete', cur)[0](
new CompletionContext(state, cur, !!conf.explicit),
);
@@ -2500,20 +2500,23 @@ export default workflow('same-name-agents', 'Same Name Agents')
});
describe('Codegen Roundtrip with Real Workflows', () => {
// Download fixtures if needed (runs once before all tests in this file)
// Extract fixtures from the committed zip if needed (runs once before all
// tests in this file). Unpacking ~2000 workflow files is IO-bound and can
// take well over the default 10s hook timeout on a contended CI runner, so
// give it a generous budget to avoid flaky "Hook timed out" failures.
beforeAll(() => {
try {
ensureFixtures();
} catch (error) {
if (error instanceof FixtureDownloadError) {
throw new Error(
`Failed to download test fixtures from n8n.io API: ${error.message}. ` +
'Check your network connection and ensure the API is accessible.',
`Failed to prepare test fixtures: ${error.message}. ` +
'Ensure public_published_templates.zip is committed to test-fixtures/real-workflows/.',
);
}
throw error;
}
});
}, 60_000);
if (workflows.length === 0) {
it('should have fixtures available (run tests again after download)', () => {
@@ -14,6 +14,7 @@ import {
import { mockProxy } from './__tests__/mock';
import type { CompletionSource, CompletionResult } from '@codemirror/autocomplete';
import { CompletionContext } from '@codemirror/autocomplete';
import { ensureSyntaxTree } from '@codemirror/language';
import { EditorState } from '@codemirror/state';
import { n8nLang } from '@/features/shared/editors/plugins/codemirror/n8nLang';
import { useExternalSecretsStore } from '@/features/integrations/externalSecrets.ee/externalSecrets.ee.store';
@@ -44,12 +45,20 @@ export async function completions(docWithCursor: string, explicit = false) {
const doc = docWithCursor.slice(0, cursorPosition) + docWithCursor.slice(cursorPosition + 1);
const state = EditorState.create({
const initialState = EditorState.create({
doc,
selection: { anchor: cursorPosition },
extensions: [n8nLang(), WORKFLOW_DOCUMENT_FACET.of('test@latest')],
});
// `EditorState.create` only parses within a 20ms wall-clock budget, which a
// contended CI runner can starve, leaving a truncated tree with no language
// data so `languageDataAt` returns [] and completions silently come back
// empty. Fully parse and commit the tree into the language state field via
// an empty transaction so the lookup is deterministic regardless of load.
ensureSyntaxTree(initialState, initialState.doc.length, 1e9);
const state = initialState.update({}).state;
const context = new CompletionContext(state, cursorPosition, explicit);
for (const completionSource of state.languageDataAt<CompletionSource>(