mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-12 02:19:43 +00:00
chore: Fix flakes in unit tests around monorepo (#32099)
This commit is contained in:
@@ -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)', () => {
|
||||
|
||||
+10
-1
@@ -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>(
|
||||
|
||||
Reference in New Issue
Block a user