test: Resolve 43 janitor violations and update baseline (no-changelog) (#28173)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Declan Carroll 2026-04-09 15:34:18 +01:00 committed by GitHub
parent 12e660a1a8
commit bf25fad7df
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 497 additions and 505 deletions

View file

@ -1,14 +1,44 @@
{
"version": 1,
"generated": "2026-04-08T09:41:27.477Z",
"totalViolations": 408,
"generated": "2026-04-08T13:49:08.611Z",
"totalViolations": 405,
"violations": {
"pages/AIAssistantPage.ts": [
{
"rule": "scope-lockdown",
"line": 3,
"message": "AIAssistantPage: Ambiguous page - add a container (for scoped components) or a navigation method (for top-level pages)",
"hash": "5dbc5b92f63b"
"line": 15,
"message": "AIAssistantPage: Unscoped locator - use this.container instead of this.page",
"hash": "0d4d5092768f"
},
{
"rule": "scope-lockdown",
"line": 19,
"message": "AIAssistantPage: Unscoped locator - use this.container instead of this.page",
"hash": "0d4d5092768f"
},
{
"rule": "scope-lockdown",
"line": 61,
"message": "AIAssistantPage: Unscoped locator - use this.container instead of this.page",
"hash": "0d4d5092768f"
},
{
"rule": "scope-lockdown",
"line": 61,
"message": "AIAssistantPage: Unscoped locator - use this.container instead of this.page",
"hash": "0d4d5092768f"
},
{
"rule": "scope-lockdown",
"line": 85,
"message": "AIAssistantPage: Unscoped locator - use this.container instead of this.page",
"hash": "0d4d5092768f"
},
{
"rule": "scope-lockdown",
"line": 109,
"message": "AIAssistantPage: Unscoped locator - use this.container instead of this.page",
"hash": "0d4d5092768f"
}
],
"pages/AIBuilderPage.ts": [
@ -27,14 +57,6 @@
"hash": "02f0790cba2a"
}
],
"pages/KeycloakLoginPage.ts": [
{
"rule": "scope-lockdown",
"line": 9,
"message": "KeycloakLoginPage: Ambiguous page - add a container (for scoped components) or a navigation method (for top-level pages)",
"hash": "0c0162a6f10c"
}
],
"pages/NodeDetailsViewPage.ts": [
{
"rule": "scope-lockdown",
@ -56,219 +78,219 @@
},
{
"rule": "scope-lockdown",
"line": 94,
"line": 114,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 110,
"line": 274,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 265,
"line": 323,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 314,
"line": 327,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 318,
"line": 331,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 322,
"line": 351,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 342,
"line": 355,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 346,
"line": 359,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 350,
"line": 363,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 354,
"line": 367,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 358,
"line": 373,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 364,
"line": 399,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 390,
"line": 435,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 421,
"line": 463,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 449,
"line": 467,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 453,
"line": 467,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 453,
"line": 471,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 457,
"line": 475,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 461,
"line": 493,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 479,
"line": 497,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 483,
"line": 497,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 483,
"line": 508,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 494,
"line": 517,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 503,
"line": 579,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 565,
"line": 624,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 610,
"line": 630,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 616,
"line": 654,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 640,
"line": 654,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 640,
"line": 658,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 644,
"line": 765,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 751,
"line": 810,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 796,
"line": 864,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 842,
"line": 868,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 846,
"line": 877,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 855,
"line": 883,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
},
{
"rule": "scope-lockdown",
"line": 861,
"message": "NodeDetailsViewPage: Unscoped locator - use this.container instead of this.page",
"hash": "4087a9cf20cb"
"rule": "dead-code",
"line": 942,
"message": "Unused method: NodeDetailsViewPage.getAddOptionDropdown()",
"hash": "a3acba0a44bc"
}
],
"pages/NotificationsPage.ts": [
@ -282,17 +304,185 @@
"pages/SidebarPage.ts": [
{
"rule": "scope-lockdown",
"line": 3,
"message": "SidebarPage: Ambiguous page - add a container (for scoped components) or a navigation method (for top-level pages)",
"hash": "367c993c8483"
"line": 31,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 35,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 39,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 44,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 44,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 45,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 45,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 50,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 50,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 51,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 51,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 68,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 72,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 85,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 93,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 101,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
},
{
"rule": "scope-lockdown",
"line": 109,
"message": "SidebarPage: Unscoped locator - use this.container instead of this.page",
"hash": "b15fa9cfe2ac"
}
],
"pages/WorkflowSettingsModal.ts": [
{
"rule": "scope-lockdown",
"line": 5,
"message": "WorkflowSettingsModal: Ambiguous page - add a container (for scoped components) or a navigation method (for top-level pages)",
"hash": "611f1593934a"
"line": 15,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 19,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 55,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 59,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 63,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 71,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 75,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 79,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 83,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 99,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 125,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 141,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
},
{
"rule": "scope-lockdown",
"line": 145,
"message": "WorkflowSettingsModal: Unscoped locator - use this.container instead of this.page",
"hash": "d38a3afc984b"
}
],
"pages/WorkflowSharingModal.ts": [
@ -410,57 +600,21 @@
"tests/e2e/ai/langchain-memory.spec.ts": [
{
"rule": "selector-purity",
"line": 93,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Define below' }).cl...",
"hash": "28c6914ff909"
},
{
"rule": "selector-purity",
"line": 93,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Define below' })",
"hash": "7cd2ac8a0723"
},
{
"rule": "selector-purity",
"line": 94,
"message": "Chained locator call in test: n8n.ndv.getParameterInput('sessionKey').locator('input')",
"hash": "0aaea50f9472"
},
{
"rule": "selector-purity",
"line": 108,
"line": 107,
"message": "Chained locator call in test: n8n.ndv.getAiOutputModeToggle().locator('[role=\"radio\"]')",
"hash": "96a750e297fc"
},
{
"rule": "selector-purity",
"line": 116,
"line": 115,
"message": "Chained locator call in test: n8n.ndv.getOutputPanel().getByTestId('node-error-message')",
"hash": "6534d00a617a"
},
{
"rule": "selector-purity",
"line": 119,
"line": 118,
"message": "Chained locator call in test: n8n.ndv.getOutputPanel().getByTestId('node-error-message')",
"hash": "6534d00a617a"
},
{
"rule": "selector-purity",
"line": 170,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Define below' }).cl...",
"hash": "28c6914ff909"
},
{
"rule": "selector-purity",
"line": 170,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Define below' })",
"hash": "7cd2ac8a0723"
},
{
"rule": "selector-purity",
"line": 171,
"message": "Chained locator call in test: n8n.ndv.getParameterInput('text').locator('textarea')",
"hash": "27b5eb888380"
}
],
"tests/e2e/ai/langchain-vectorstores.spec.ts": [
@ -557,26 +711,6 @@
"hash": "49fec707c0ba"
}
],
"tests/e2e/building-blocks/node-details-configuration.spec.ts": [
{
"rule": "selector-purity",
"line": 63,
"message": "Chained locator call in test: n8n.ndv.getAssignmentName('assignments', 0).getByRole('te...",
"hash": "b9d6b99cecf8"
},
{
"rule": "selector-purity",
"line": 77,
"message": "Chained locator call in test: n8n.ndv.getAssignmentCollectionContainer('assignments').g...",
"hash": "e176317dc9d0"
},
{
"rule": "selector-purity",
"line": 92,
"message": "Chained locator call in test: n8n.ndv.getAssignmentCollectionContainer('assignments').g...",
"hash": "e176317dc9d0"
}
],
"tests/e2e/chat-hub/chat-hub-attachment.spec.ts": [
{
"rule": "selector-purity",
@ -597,14 +731,6 @@
"hash": "140cf31c63ab"
}
],
"tests/e2e/chat-hub/chat-hub-basic.spec.ts": [
{
"rule": "selector-purity",
"line": 35,
"message": "Direct page locator call: n8n.page.getByTestId('editCredential-modal')",
"hash": "48846c7aaefd"
}
],
"tests/e2e/chat-hub/chat-hub-personal-agent.spec.ts": [
{
"rule": "selector-purity",
@ -731,32 +857,6 @@
"hash": "606eea72385e"
}
],
"tests/e2e/nodes/community-nodes.spec.ts": [
{
"rule": "selector-purity",
"line": 86,
"message": "Direct page locator call: n8n.page.getByTestId('editCredential-modal')",
"hash": "42fb46d2503a"
},
{
"rule": "selector-purity",
"line": 100,
"message": "Direct page locator call: n8n.page.getByTestId('editCredential-modal')",
"hash": "42fb46d2503a"
},
{
"rule": "api-purity",
"line": 20,
"message": "Raw API call detected: fetch(",
"hash": "974d7953dd83"
},
{
"rule": "api-purity",
"line": 35,
"message": "Raw API call detected: fetch(",
"hash": "974d7953dd83"
}
],
"tests/e2e/nodes/form-trigger-node.spec.ts": [
{
"rule": "selector-purity",
@ -905,20 +1005,6 @@
"hash": "314e16747365"
}
],
"tests/e2e/nodes/webhook.spec.ts": [
{
"rule": "selector-purity",
"line": 71,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Response Code' }).c...",
"hash": "7ffc37451dd9"
},
{
"rule": "selector-purity",
"line": 71,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Response Code' })",
"hash": "7cf70496b1bc"
}
],
"tests/e2e/projects/folders-basic.spec.ts": [
{
"rule": "selector-purity",
@ -1165,20 +1251,6 @@
"hash": "8f8319b575f7"
}
],
"tests/e2e/regression/SUG-121-fields-reset-after-closing-ndv.spec.ts": [
{
"rule": "selector-purity",
"line": 26,
"message": "Chained locator call in test: n8n.ndv.getParameterByLabel('JavaScript').getByRole('text...",
"hash": "6db6a6135c16"
},
{
"rule": "selector-purity",
"line": 29,
"message": "Chained locator call in test: n8n.ndv.getParameterByLabel('JavaScript').getByRole('text...",
"hash": "6db6a6135c16"
}
],
"tests/e2e/settings/environments/source-control.spec.ts": [
{
"rule": "selector-purity",
@ -1515,44 +1587,6 @@
"hash": "7ae7242bb6f3"
}
],
"tests/e2e/workflows/editor/code/code-node.spec.ts": [
{
"rule": "selector-purity",
"line": 29,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Run Once for Each I...",
"hash": "c8604c7015a0"
},
{
"rule": "selector-purity",
"line": 29,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Run Once for Each I...",
"hash": "c8604c7015a0"
},
{
"rule": "selector-purity",
"line": 36,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Run Once for All It...",
"hash": "0d82b552bdab"
},
{
"rule": "selector-purity",
"line": 36,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Run Once for All It...",
"hash": "0d82b552bdab"
},
{
"rule": "selector-purity",
"line": 51,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Run Once for Each I...",
"hash": "c8604c7015a0"
},
{
"rule": "selector-purity",
"line": 51,
"message": "Direct page locator call: n8n.page.getByRole('option', { name: 'Run Once for Each I...",
"hash": "c8604c7015a0"
}
],
"tests/e2e/workflows/editor/expressions/mapping.spec.ts": [
{
"rule": "selector-purity",
@ -1588,19 +1622,13 @@
"tests/e2e/workflows/editor/expressions/transformation.spec.ts": [
{
"rule": "selector-purity",
"line": 20,
"message": "Chained locator call in test: assignmentValue.locator('text=Expression')",
"hash": "1aef0d70a3e7"
},
{
"rule": "selector-purity",
"line": 115,
"line": 114,
"message": "Chained locator call in test: n8n.ndv.getOutputDataContainer().locator('[class*=value_]')",
"hash": "5ce9a307e353"
},
{
"rule": "selector-purity",
"line": 135,
"line": 134,
"message": "Chained locator call in test: n8n.ndv.getOutputDataContainer().locator('[class*=value_]')",
"hash": "5ce9a307e353"
}
@ -1719,26 +1747,14 @@
{
"rule": "selector-purity",
"line": 121,
"message": "Chained locator call in test: n8n.ndv.getContainer().getByText('Webhook URLs').locator(...",
"hash": "39044cf4addd"
"message": "Chained locator call in test: n8n.ndv.container.getByText('Webhook URLs').locator('..')",
"hash": "2d90b69679a1"
},
{
"rule": "selector-purity",
"line": 121,
"message": "Chained locator call in test: n8n.ndv.getContainer().getByText('Webhook URLs')",
"hash": "f5b7de1ccbfa"
},
{
"rule": "selector-purity",
"line": 178,
"message": "Chained locator call in test: n8n.ndv.getParameterInput('jsCode').locator('.cm-content')",
"hash": "257313c2749b"
},
{
"rule": "selector-purity",
"line": 209,
"message": "Chained locator call in test: n8n.ndv.getParameterInput('jsCode').locator('.cm-content')",
"hash": "257313c2749b"
"message": "Chained locator call in test: n8n.ndv.container.getByText('Webhook URLs')",
"hash": "acfb445f29c7"
}
],
"tests/e2e/workflows/editor/ndv/ndv-data-display.spec.ts": [
@ -1791,20 +1807,6 @@
"hash": "fba81950a906"
}
],
"tests/e2e/workflows/editor/ndv/ndv-parameters.spec.ts": [
{
"rule": "selector-purity",
"line": 123,
"message": "Chained locator call in test: n8n.ndv.getResourceLocatorInput('documentId').locator('in...",
"hash": "6481ee8bad10"
},
{
"rule": "selector-purity",
"line": 184,
"message": "Chained locator call in test: n8n.ndv.getAssignmentValue('assignments').getByText('Expr...",
"hash": "5a6fa331a8a7"
}
],
"tests/e2e/workflows/editor/ndv/paired-item.spec.ts": [
{
"rule": "selector-purity",
@ -1910,42 +1912,12 @@
"message": "Direct page locator call: n8n.page.locator('.el-message-box')",
"hash": "423a23988aea"
},
{
"rule": "selector-purity",
"line": 119,
"message": "Chained locator call in test: n8n.ndv.getResourceLocatorInput('sheetName').locator('inp...",
"hash": "2455d6b2c3e0"
},
{
"rule": "selector-purity",
"line": 128,
"message": "Direct page locator call: n8n.page.getByTestId('rlc-item').first()",
"hash": "fbf0954678ec"
},
{
"rule": "selector-purity",
"line": 128,
"message": "Direct page locator call: n8n.page.getByTestId('rlc-item')",
"hash": "4229ce6e5618"
},
{
"rule": "selector-purity",
"line": 131,
"message": "Chained locator call in test: visiblePopper.getByTestId('rlc-item')",
"hash": "7e16cbf0596b"
},
{
"rule": "selector-purity",
"line": 142,
"message": "Direct page locator call: n8n.page.getByTestId('rlc-item').first()",
"hash": "fbf0954678ec"
},
{
"rule": "selector-purity",
"line": 142,
"message": "Direct page locator call: n8n.page.getByTestId('rlc-item')",
"hash": "4229ce6e5618"
},
{
"rule": "selector-purity",
"line": 145,
@ -1954,24 +1926,6 @@
}
],
"tests/e2e/workflows/editor/subworkflows/workflow-selector.spec.ts": [
{
"rule": "selector-purity",
"line": 63,
"message": "Chained locator call in test: n8n.ndv.getResourceLocatorInput('workflowId').locator('in...",
"hash": "22d4eeb8b861"
},
{
"rule": "selector-purity",
"line": 69,
"message": "Chained locator call in test: n8n.ndv.getResourceLocatorInput('workflowId').locator('a')",
"hash": "fa09a1804e35"
},
{
"rule": "selector-purity",
"line": 78,
"message": "Chained locator call in test: n8n.ndv.getResourceLocatorModeSelector('workflowId').loca...",
"hash": "0084dd471fa9"
},
{
"rule": "selector-purity",
"line": 92,
@ -2419,6 +2373,20 @@
"hash": "cc21f9656cd4"
}
],
"tests/e2e/nodes/community-nodes.spec.ts": [
{
"rule": "api-purity",
"line": 20,
"message": "Raw API call detected: fetch(",
"hash": "974d7953dd83"
},
{
"rule": "api-purity",
"line": 35,
"message": "Raw API call detected: fetch(",
"hash": "974d7953dd83"
}
],
"tests/e2e/sharing/workflow-sharing.spec.ts": [
{
"rule": "api-purity",

View file

@ -1,6 +1,14 @@
import { BasePage } from './BasePage';
export class AIAssistantPage extends BasePage {
// #region Container
get container() {
return this.page.getByTestId('ask-assistant-sidebar');
}
// #endregion
// #region Getters
getAskAssistantFloatingButton() {
@ -12,39 +20,41 @@ export class AIAssistantPage extends BasePage {
}
getAskAssistantChat() {
return this.page.getByTestId('ask-assistant-chat');
return this.container.getByTestId('ask-assistant-chat');
}
getAskAssistantSidebar() {
return this.page.getByTestId('ask-assistant-sidebar');
return this.container;
}
getPlaceholderMessage() {
return this.page.getByTestId('placeholder-message');
return this.container.getByTestId('placeholder-message');
}
getChatInput() {
// Try suggestions input first (shown when suggestions are visible),
// fall back to regular input (shown when there are messages),
// or the mention input (shown when focused nodes feature is enabled)
const suggestionsInput = this.page.getByTestId('chat-suggestions-input').locator('textarea');
const regularInput = this.page.getByTestId('chat-input').locator('textarea');
const mentionInput = this.page.getByTestId('chat-input-with-mention').locator('textarea');
const suggestionsInput = this.container
.getByTestId('chat-suggestions-input')
.locator('textarea');
const regularInput = this.container.getByTestId('chat-input').locator('textarea');
const mentionInput = this.container.getByTestId('chat-input-with-mention').locator('textarea');
// Return the first one that's visible
return suggestionsInput.or(regularInput).or(mentionInput);
}
getSendMessageButton() {
return this.page.getByTestId('send-message-button');
return this.container.getByTestId('send-message-button');
}
getCloseChatButton() {
return this.page.getByTestId('close-chat-button');
return this.container.getByTestId('close-chat-button');
}
getAskAssistantSidebarResizer() {
return this.getAskAssistantSidebar().locator('[class*="_resizer"][data-dir="left"]').first();
return this.container.locator('[class*="_resizer"][data-dir="left"]').first();
}
getNodeErrorViewAssistantButton() {
@ -52,23 +62,23 @@ export class AIAssistantPage extends BasePage {
}
getChatMessagesAll() {
return this.page.locator('[data-test-id^="chat-message"]');
return this.container.locator('[data-test-id^="chat-message"]');
}
getChatMessagesAssistant() {
return this.page.getByTestId('chat-message-assistant');
return this.container.getByTestId('chat-message-assistant');
}
getChatMessagesUser() {
return this.page.getByTestId('chat-message-user');
return this.container.getByTestId('chat-message-user');
}
getChatMessagesSystem() {
return this.page.getByTestId('chat-message-system');
return this.container.getByTestId('chat-message-system');
}
getQuickReplyButtons() {
return this.page.getByTestId('quick-replies').locator('button');
return this.container.getByTestId('quick-replies').locator('button');
}
getNewAssistantSessionModal() {
@ -80,19 +90,19 @@ export class AIAssistantPage extends BasePage {
}
getCodeDiffs() {
return this.page.getByTestId('code-diff-suggestion');
return this.container.getByTestId('code-diff-suggestion');
}
getApplyCodeDiffButtons() {
return this.page.getByTestId('replace-code-button');
return this.container.getByTestId('replace-code-button');
}
getUndoReplaceCodeButtons() {
return this.page.getByTestId('undo-replace-button');
return this.container.getByTestId('undo-replace-button');
}
getCodeReplacedMessage() {
return this.page.getByTestId('code-replaced-message');
return this.container.getByTestId('code-replaced-message');
}
getCredentialEditAssistantButton() {
@ -100,7 +110,7 @@ export class AIAssistantPage extends BasePage {
}
getCodeSnippet() {
return this.page.getByTestId('assistant-code-snippet-content');
return this.container.getByTestId('assistant-code-snippet-content');
}
// #endregion

View file

@ -7,6 +7,10 @@ import { BasePage } from './BasePage';
* Used when testing OIDC authentication flows.
*/
export class KeycloakLoginPage extends BasePage {
async goto() {
await this.page.goto('/signin/oidc');
}
getUsernameField(): Locator {
return this.page.locator('#username');
}

View file

@ -12,8 +12,8 @@ export class NodeDetailsViewPage extends BasePage {
readonly setupHelper: NodeParameterHelper;
readonly editFields: EditFieldsNode;
readonly clipboard: ClipboardHelper;
readonly inputPanel = new RunDataPanel(this.getContainer().getByTestId('ndv-input-panel'));
readonly outputPanel = new RunDataPanel(this.getContainer().getByTestId('output-panel'));
readonly inputPanel = new RunDataPanel(this.container.getByTestId('ndv-input-panel'));
readonly outputPanel = new RunDataPanel(this.container.getByTestId('output-panel'));
constructor(page: Page) {
super(page);
@ -23,11 +23,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getNodeCredentialsSelect() {
return this.getContainer().getByTestId('node-credentials-select');
return this.container.getByTestId('node-credentials-select');
}
getNodeCredentialsEmptyState() {
return this.getContainer().getByTestId('node-credentials-empty-state');
return this.container.getByTestId('node-credentials-empty-state');
}
credentialDropdownCreateNewCredential() {
@ -43,7 +43,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getCredentialSelect() {
return this.getContainer().getByRole('combobox', { name: 'Select Credential' });
return this.container.getByRole('combobox', { name: 'Select Credential' });
}
async clickBackToCanvasButton() {
@ -51,7 +51,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getParameterByLabel(labelName: string) {
return this.getContainer().locator('.parameter-item').filter({ hasText: labelName });
return this.container.locator('.parameter-item').filter({ hasText: labelName });
}
getParameterTextboxByLabel(labelName: string) {
return this.getParameterByLabel(labelName).getByRole('textbox');
}
async fillParameterInput(labelName: string, value: string, index?: number) {
@ -87,23 +91,23 @@ export class NodeDetailsViewPage extends BasePage {
}
getOutputPanel() {
return this.getContainer().getByTestId('output-panel');
return this.container.getByTestId('output-panel');
}
getContainer() {
get container() {
return this.page.getByTestId('ndv');
}
getInputPanel() {
return this.getContainer().getByTestId('ndv-input-panel');
return this.container.getByTestId('ndv-input-panel');
}
getParameterExpressionPreviewValue() {
return this.getContainer().getByTestId('parameter-expression-preview-value');
return this.container.getByTestId('parameter-expression-preview-value');
}
getParameterExpressionPreviewOutput() {
return this.getContainer().getByTestId('parameter-expression-preview-output');
return this.container.getByTestId('parameter-expression-preview-output');
}
getInlineExpressionEditorPreview() {
@ -113,18 +117,18 @@ export class NodeDetailsViewPage extends BasePage {
async activateParameterExpressionEditor(parameterName: string) {
const parameterInput = this.getParameterInput(parameterName);
await parameterInput.click();
await this.getContainer()
await this.container
.getByTestId(`${parameterName}-parameter-input-options-container`)
.getByTestId('radio-button-expression')
.click();
}
getEditPinnedDataButton() {
return this.getContainer().getByTestId('ndv-edit-pinned-data');
return this.container.getByTestId('ndv-edit-pinned-data');
}
getRunDataPaneHeader() {
return this.getContainer().getByTestId('run-data-pane-header');
return this.container.getByTestId('run-data-pane-header');
}
getEditOutputButton() {
@ -152,13 +156,13 @@ export class NodeDetailsViewPage extends BasePage {
}
getAssignmentCollectionAdd(paramName: string) {
return this.getContainer()
return this.container
.getByTestId(`assignment-collection-${paramName}`)
.getByTestId('assignment-collection-drop-area');
}
getAssignmentCollectionDropArea() {
return this.getContainer().getByTestId('assignment-collection-drop-area');
return this.container.getByTestId('assignment-collection-drop-area');
}
async clickAssignmentCollectionDropArea() {
@ -166,13 +170,17 @@ export class NodeDetailsViewPage extends BasePage {
}
getAssignmentValue(paramName: string) {
return this.getContainer()
return this.container
.getByTestId(`assignment-collection-${paramName}`)
.getByTestId('assignment-value');
}
getAssignmentExpressionToggle(paramName: string) {
return this.getAssignmentValue(paramName).getByText('Expression');
}
async clickAssignmentExpressionToggle(paramName: string) {
await this.getAssignmentValue(paramName).getByText('Expression').click();
await this.getAssignmentExpressionToggle(paramName).click();
}
/**
@ -185,15 +193,15 @@ export class NodeDetailsViewPage extends BasePage {
const parameterInput = this.getParameterInput(parameterName);
return parameterInput.getByTestId('inline-expression-editor-input');
}
return this.getContainer().getByTestId('inline-expression-editor-input');
return this.container.getByTestId('inline-expression-editor-input');
}
getNodeParameters() {
return this.getContainer().getByTestId('node-parameters');
return this.container.getByTestId('node-parameters');
}
getParameterInputHint() {
return this.getContainer().getByTestId('parameter-input-hint');
return this.container.getByTestId('parameter-input-hint');
}
getParameterInputHintWithText(text: string) {
@ -201,7 +209,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getInputLabel() {
return this.getContainer().getByTestId('input-label');
return this.container.getByTestId('input-label');
}
getNthParameter(index: number) {
@ -209,7 +217,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getCredentialsLabel() {
return this.getContainer().getByTestId('credentials-label');
return this.container.getByTestId('credentials-label');
}
async makeWebhookRequest(path: string) {
@ -230,10 +238,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getParameterInput(parameterName: string, index?: number) {
return locatorByIndex(
this.getContainer().getByTestId(`parameter-input-${parameterName}`),
index,
);
return locatorByIndex(this.container.getByTestId(`parameter-input-${parameterName}`), index);
}
getParameterInputTextbox(parameterName: string, index?: number) {
@ -249,6 +254,10 @@ export class NodeDetailsViewPage extends BasePage {
return this.getParameterInput(parameterName, index).locator('.cm-content');
}
getParameterTextarea(parameterName: string, index?: number) {
return this.getParameterInput(parameterName, index).locator('textarea');
}
async selectOptionInParameterDropdown(parameterName: string, optionText: string, index = 0) {
await this.clickParameterDropdown(parameterName, index);
await this.selectFromVisibleDropdown(optionText);
@ -256,7 +265,7 @@ export class NodeDetailsViewPage extends BasePage {
async clickParameterDropdown(parameterName: string, index = 0): Promise<void> {
await locatorByIndex(
this.getContainer().getByTestId(`parameter-input-${parameterName}`),
this.container.getByTestId(`parameter-input-${parameterName}`),
index,
).click();
}
@ -272,7 +281,7 @@ export class NodeDetailsViewPage extends BasePage {
}
async clickParameterOptions(): Promise<void> {
await this.getContainer().getByTestId('collection-parameter-add').click();
await this.container.getByTestId('collection-parameter-add').click();
}
async addParameterOptionByName(optionName: string): Promise<void> {
@ -281,7 +290,7 @@ export class NodeDetailsViewPage extends BasePage {
}
async clickFloatingNode(nodeName: string) {
await this.getContainer()
await this.container
.locator(`[data-test-id="floating-node"][data-node-name="${nodeName}"]`)
.click();
}
@ -291,23 +300,23 @@ export class NodeDetailsViewPage extends BasePage {
}
async clickAskAiTab() {
await this.getContainer().locator('#tab-ask-ai').click();
await this.container.locator('#tab-ask-ai').click();
}
getAskAiTabPanel() {
return this.getContainer().getByTestId('code-node-tab-ai');
return this.container.getByTestId('code-node-tab-ai');
}
getAskAiCtaButton() {
return this.getContainer().getByTestId('ask-ai-cta');
return this.container.getByTestId('ask-ai-cta');
}
getAskAiPromptInput() {
return this.getContainer().getByTestId('ask-ai-prompt-input');
return this.container.getByTestId('ask-ai-prompt-input');
}
getAskAiPromptCounter() {
return this.getContainer().getByTestId('ask-ai-prompt-counter');
return this.container.getByTestId('ask-ai-prompt-counter');
}
getAskAiCtaTooltipNoInputData() {
@ -323,11 +332,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getCodeTabPanel() {
return this.getContainer().getByTestId('code-node-tab-code');
return this.container.getByTestId('code-node-tab-code');
}
getCodeTab() {
return this.getContainer().locator('#tab-code');
return this.container.locator('#tab-code');
}
getCodeEditor() {
@ -381,7 +390,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getAssignmentCollectionContainer(paramName: string) {
return this.getContainer().getByTestId(`assignment-collection-${paramName}`);
return this.container.getByTestId(`assignment-collection-${paramName}`);
}
async selectInputNode(nodeName: string) {
@ -390,15 +399,20 @@ export class NodeDetailsViewPage extends BasePage {
await this.page.getByRole('option', { name: nodeName }).click();
}
getAssignments(paramName: string) {
return this.getAssignmentCollectionContainer(paramName).getByTestId('assignment');
}
getAssignmentName(paramName: string, index = 0) {
return this.getAssignmentCollectionContainer(paramName)
.getByTestId('assignment')
.nth(index)
.getByTestId('assignment-name');
return this.getAssignments(paramName).nth(index).getByTestId('assignment-name');
}
getAssignmentNameTextbox(paramName: string, index = 0) {
return this.getAssignmentName(paramName, index).getByRole('textbox');
}
getResourceMapperFieldsContainer() {
return this.getContainer().getByTestId('mapping-fields-container');
return this.container.getByTestId('mapping-fields-container');
}
getResourceMapperParameterInputs() {
@ -406,15 +420,15 @@ export class NodeDetailsViewPage extends BasePage {
}
getResourceMapperSelectColumn() {
return this.getContainer().getByTestId('matching-column-select');
return this.container.getByTestId('matching-column-select');
}
getResourceMapperColumnsOptionsButton() {
return this.getContainer().getByTestId('columns-parameter-input-options-container');
return this.container.getByTestId('columns-parameter-input-options-container');
}
getResourceMapperRemoveFieldButton(fieldName: string) {
return this.getContainer().getByTestId(`remove-field-button-${fieldName}`);
return this.container.getByTestId(`remove-field-button-${fieldName}`);
}
getResourceMapperRemoveAllFieldsOption() {
@ -506,7 +520,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getCopyInputButton() {
return this.getContainer().getByTestId('copy-input');
return this.container.getByTestId('copy-input');
}
getOutputPagination() {
@ -535,7 +549,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getRunDataInfoCallout() {
return this.getContainer().getByTestId('run-data-callout');
return this.container.getByTestId('run-data-callout');
}
async checkParameterCheckboxInputByName(name: string): Promise<void> {
@ -545,9 +559,9 @@ export class NodeDetailsViewPage extends BasePage {
// Credentials modal helpers
async clickCreateNewCredential(eq: number = 0): Promise<void> {
const setupManually = this.getContainer().getByTestId('setup-manually-link').nth(eq);
const setupCredential = this.getContainer().getByTestId('setup-credential-button').nth(eq);
const credentialSelect = this.getContainer().getByTestId('node-credentials-select').nth(eq);
const setupManually = this.container.getByTestId('setup-manually-link').nth(eq);
const setupCredential = this.container.getByTestId('setup-credential-button').nth(eq);
const credentialSelect = this.container.getByTestId('node-credentials-select').nth(eq);
// Wait for one of the three credential UI states to appear
await Promise.race([
@ -584,11 +598,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getNodeRunErrorMessage() {
return this.getContainer().getByTestId('node-error-message');
return this.container.getByTestId('node-error-message');
}
getNodeRunErrorDescription() {
return this.getContainer().getByTestId('node-error-description');
return this.container.getByTestId('node-error-description');
}
async isOutputRunLinkingEnabled() {
@ -625,15 +639,15 @@ export class NodeDetailsViewPage extends BasePage {
}
getExecuteNodeButton() {
return this.getContainer().getByTestId('node-execute-button');
return this.container.getByTestId('node-execute-button');
}
getTriggerPanelExecuteButton() {
return this.getContainer().getByTestId('trigger-execute-button');
return this.container.getByTestId('trigger-execute-button');
}
async openCodeEditorFullscreen() {
await this.getContainer().getByTestId('code-editor-fullscreen-button').click();
await this.container.getByTestId('code-editor-fullscreen-button').click();
}
getCodeEditorFullscreen() {
@ -649,23 +663,23 @@ export class NodeDetailsViewPage extends BasePage {
}
getNodeRunSuccessIndicator() {
return this.getContainer().getByTestId('node-run-status-success');
return this.container.getByTestId('node-run-status-success');
}
getNodeRunErrorIndicator() {
return this.getContainer().getByTestId('node-run-status-danger');
return this.container.getByTestId('node-run-status-danger');
}
getNodeRunTooltipIndicator() {
return this.getContainer().getByTestId('node-run-info');
return this.container.getByTestId('node-run-info');
}
getStaleNodeIndicator() {
return this.getContainer().getByTestId('node-run-info-stale');
return this.container.getByTestId('node-run-info-stale');
}
getExecuteStepButton() {
return this.getContainer().getByTestId('node-execute-button');
return this.container.getByTestId('node-execute-button');
}
async clickExecuteStep() {
@ -673,11 +687,11 @@ export class NodeDetailsViewPage extends BasePage {
}
async openSettings() {
await this.getContainer().getByTestId('tab-settings').click();
await this.container.getByTestId('tab-settings').click();
}
getNodeVersion() {
return this.getContainer().getByTestId('node-version');
return this.container.getByTestId('node-version');
}
async searchOutputData(searchTerm: string) {
@ -703,11 +717,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getFloatingNodeByPosition(position: 'inputMain' | 'outputMain' | 'inputSub' | 'outputSub') {
return this.getContainer().locator(`[data-node-placement="${position}"]`);
return this.container.locator(`[data-node-placement="${position}"]`);
}
getNodeNameContainer() {
return this.getContainer().getByTestId('node-title-container');
return this.container.getByTestId('node-title-container');
}
async clickFloatingNodeByPosition(
@ -739,11 +753,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getAddSubNodeButton(connectionType: string, index: number = 0) {
return this.getContainer().getByTestId(`add-subnode-${connectionType}-${index}`);
return this.container.getByTestId(`add-subnode-${connectionType}-${index}`);
}
getNodesWithIssues() {
return this.getContainer().locator('[class*="hasIssues"]');
return this.container.locator('[class*="hasIssues"]');
}
async connectAISubNode(connectionType: string, nodeName: string, index: number = 0) {
@ -753,11 +767,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getFloatingNode() {
return this.getContainer().getByTestId('floating-node');
return this.container.getByTestId('floating-node');
}
async addItemToFixedCollection(collectionName: string) {
const collection = this.getContainer().getByTestId(`fixed-collection-${collectionName}`);
const collection = this.container.getByTestId(`fixed-collection-${collectionName}`);
const explicitAddControl = collection
.locator(
[
@ -797,23 +811,31 @@ export class NodeDetailsViewPage extends BasePage {
}
getParameterItemWithText(text: string) {
return this.getContainer().getByTestId('parameter-item').getByText(text);
return this.container.getByTestId('parameter-item').getByText(text);
}
getParameterInputWithIssues(parameterPath: string) {
return this.getContainer().locator(
return this.container.locator(
`[data-test-id="parameter-input-field"][title*="${parameterPath}"][title*="has issues"]`,
);
}
getResourceLocator(paramName: string) {
return this.getContainer().getByTestId(`resource-locator-${paramName}`);
return this.container.getByTestId(`resource-locator-${paramName}`);
}
getResourceLocatorInput(paramName: string) {
return this.getResourceLocator(paramName).getByTestId('rlc-input-container');
}
getResourceLocatorInputField(paramName: string) {
return this.getResourceLocatorInput(paramName).locator('input');
}
getResourceLocatorLink(paramName: string) {
return this.getResourceLocatorInput(paramName).locator('a');
}
getResourceLocatorModeSelector(paramName: string) {
return this.getResourceLocator(paramName).getByTestId('rlc-mode-selector');
}
@ -835,7 +857,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getParameterInputIssues() {
return this.getContainer().getByTestId('parameter-issues');
return this.container.getByTestId('parameter-issues');
}
getResourceLocatorItems() {
@ -847,7 +869,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getExpressionModeToggle(index: number = 1) {
return this.getContainer().getByTestId('radio-button-expression').nth(index);
return this.container.getByTestId('radio-button-expression').nth(index);
}
async setRLCValue(paramName: string, value: string, index = 0): Promise<void> {
@ -862,7 +884,7 @@ export class NodeDetailsViewPage extends BasePage {
}
getInputSelect() {
return this.getContainer().getByTestId('ndv-input-select').locator('input');
return this.container.getByTestId('ndv-input-select').locator('input');
}
getOutputRunSelectorInput() {
@ -870,15 +892,15 @@ export class NodeDetailsViewPage extends BasePage {
}
getAiOutputModeToggle() {
return this.getContainer().getByTestId('ai-output-mode-select');
return this.container.getByTestId('ai-output-mode-select');
}
getCredentialLabel(credentialType: string) {
return this.getContainer().getByText(credentialType);
return this.container.getByText(credentialType);
}
getFilterComponent(paramName: string) {
return this.getContainer().getByTestId(`filter-${paramName}`);
return this.container.getByTestId(`filter-${paramName}`);
}
getFilterConditions(paramName: string) {
@ -914,11 +936,11 @@ export class NodeDetailsViewPage extends BasePage {
}
getWebhookTestEvent() {
return this.getContainer().getByText('Listening for test event');
return this.container.getByText('Listening for test event');
}
getAddOptionDropdown() {
return this.getContainer().getByRole('combobox', { name: 'Add option' });
return this.container.getByRole('combobox', { name: 'Add option' });
}
async setInvalidExpression({

View file

@ -7,20 +7,24 @@ export class SidebarPage {
this.page = page;
}
get container() {
return this.page.locator('#side-menu');
}
async clickHomeButton() {
await this.page.getByTestId('project-home-menu-item').click();
await this.container.getByTestId('project-home-menu-item').click();
}
async universalAdd() {
await this.page.getByTestId('universal-add').click();
await this.container.getByTestId('universal-add').click();
}
async clickHomeMenuItem() {
await this.page.getByTestId('project-home-menu-item').click();
await this.container.getByTestId('project-home-menu-item').click();
}
async clickPersonalMenuItem() {
await this.page.getByTestId('project-personal-menu-item').click();
await this.container.getByTestId('project-personal-menu-item').click();
}
async clickWorkflowsLink(): Promise<void> {
@ -48,7 +52,7 @@ export class SidebarPage {
}
getProjectMenuItems(): Locator {
return this.page.getByTestId('project-menu-item');
return this.container.getByTestId('project-menu-item');
}
async clickProjectMenuItem(projectName: string) {
@ -57,7 +61,7 @@ export class SidebarPage {
}
getSettings(): Locator {
return this.page.getByTestId('main-sidebar-settings');
return this.container.getByTestId('main-sidebar-settings');
}
getLogoutMenuItem(): Locator {
@ -69,7 +73,7 @@ export class SidebarPage {
}
getHelp(): Locator {
return this.page.getByTestId('main-sidebar-help');
return this.container.getByTestId('main-sidebar-help');
}
async clickHelpMenuItem(): Promise<void> {
@ -90,7 +94,7 @@ export class SidebarPage {
}
getAdminPanel(): Locator {
return this.page.getByTestId('main-sidebar-cloud-admin');
return this.container.getByTestId('main-sidebar-cloud-admin');
}
getTrialBanner(): Locator {
@ -98,7 +102,7 @@ export class SidebarPage {
}
getTemplatesLink(): Locator {
return this.page.getByTestId('main-sidebar-templates').locator('a');
return this.container.getByTestId('main-sidebar-templates').locator('a');
}
getVersionUpdateItem(): Locator {
@ -106,15 +110,15 @@ export class SidebarPage {
}
getSourceControlPushButton(): Locator {
return this.page.getByTestId('main-sidebar-source-control-push');
return this.container.getByTestId('main-sidebar-source-control-push');
}
getSourceControlPullButton(): Locator {
return this.page.getByTestId('main-sidebar-source-control-pull');
return this.container.getByTestId('main-sidebar-source-control-pull');
}
getSourceControlConnectedIndicator(): Locator {
return this.page.getByTestId('main-sidebar-source-control-connected');
return this.container.getByTestId('main-sidebar-source-control-connected');
}
async openSettings(): Promise<void> {
@ -136,11 +140,11 @@ export class SidebarPage {
// First ensure the sidebar is visible before checking if it is expanded
await expect(this.getSettings()).toBeVisible();
const logo = this.page.getByTestId('n8n-logo');
const logo = this.container.getByTestId('n8n-logo');
const isExpanded = await logo.isVisible();
if (!isExpanded) {
const collapseButton = this.page.locator('#toggle-sidebar-button');
const collapseButton = this.container.locator('#toggle-sidebar-button');
await expect(collapseButton).toBeVisible();
await collapseButton.click();
}

View file

@ -3,10 +3,14 @@ import type { Locator } from '@playwright/test';
import { BasePage } from './BasePage';
export class WorkflowSettingsModal extends BasePage {
getModal(): Locator {
get container() {
return this.page.getByTestId('workflow-settings-dialog');
}
getModal(): Locator {
return this.container;
}
getWorkflowMenu(): Locator {
return this.page.getByTestId('workflow-menu');
}
@ -16,35 +20,35 @@ export class WorkflowSettingsModal extends BasePage {
}
getErrorWorkflowField(): Locator {
return this.page.getByTestId('workflow-settings-error-workflow');
return this.container.getByTestId('workflow-settings-error-workflow');
}
getTimezoneField(): Locator {
return this.page.getByTestId('workflow-settings-timezone');
return this.container.getByTestId('workflow-settings-timezone');
}
getSaveFailedExecutionsField(): Locator {
return this.page.getByTestId('workflow-settings-save-failed-executions');
return this.container.getByTestId('workflow-settings-save-failed-executions');
}
getSaveSuccessExecutionsField(): Locator {
return this.page.getByTestId('workflow-settings-save-success-executions');
return this.container.getByTestId('workflow-settings-save-success-executions');
}
getSaveManualExecutionsField(): Locator {
return this.page.getByTestId('workflow-settings-save-manual-executions');
return this.container.getByTestId('workflow-settings-save-manual-executions');
}
getSaveExecutionProgressField(): Locator {
return this.page.getByTestId('workflow-settings-save-execution-progress');
return this.container.getByTestId('workflow-settings-save-execution-progress');
}
getTimeoutSwitch(): Locator {
return this.page.getByTestId('workflow-settings-timeout-workflow');
return this.container.getByTestId('workflow-settings-timeout-workflow');
}
getTimeoutInput(): Locator {
return this.page.getByTestId('workflow-settings-timeout-form').locator('input').first();
return this.container.getByTestId('workflow-settings-timeout-form').locator('input').first();
}
getDuplicateMenuItem(): Locator {
@ -88,7 +92,7 @@ export class WorkflowSettingsModal extends BasePage {
}
getSaveButton(): Locator {
return this.page.getByRole('button', { name: 'Save' });
return this.container.getByRole('button', { name: 'Save' });
}
getDuplicateModal(): Locator {

View file

@ -89,9 +89,8 @@ test.describe(
password: 'testtesttest',
});
await n8n.ndv.getParameterInput('sessionIdType').click();
await n8n.page.getByRole('option', { name: 'Define below' }).click();
await n8n.ndv.getParameterInput('sessionKey').locator('input').fill('asdasd');
await n8n.ndv.selectOptionInParameterDropdown('sessionIdType', 'Define below');
await n8n.ndv.fillParameterInputByName('sessionKey', 'asdasd');
await n8n.ndv.clickBackToCanvasButton();
// Add and configure OpenAI Language Model
@ -166,9 +165,8 @@ test.describe(
// Open the AI Agent node
await n8n.canvas.openNode(AGENT_NODE_NAME);
await n8n.ndv.getParameterInput('promptType').click();
await n8n.page.getByRole('option', { name: 'Define below' }).click();
await n8n.ndv.getParameterInput('text').locator('textarea').fill('Some text');
await n8n.ndv.selectOptionInParameterDropdown('promptType', 'Define below');
await n8n.ndv.getParameterTextarea('text').fill('Some text');
await n8n.ndv.execute();
await waitForWorkflowSuccess(n8n);

View file

@ -60,7 +60,7 @@ test.describe(
await n8n.ndv.editFields.setSingleFieldValue('testField', 'string', 'Hello World');
const nameInput = n8n.ndv.getAssignmentName('assignments', 0).getByRole('textbox');
const nameInput = n8n.ndv.getAssignmentNameTextbox('assignments', 0);
await expect(nameInput).toHaveValue('testField');
});
@ -73,9 +73,7 @@ test.describe(
{ name: 'booleanField', type: 'boolean', value: true },
]);
await expect(
n8n.ndv.getAssignmentCollectionContainer('assignments').getByTestId('assignment'),
).toHaveCount(3);
await expect(n8n.ndv.getAssignments('assignments')).toHaveCount(3);
});
test('should configure Edit Fields node with all field types', async ({ n8n }) => {
@ -88,9 +86,7 @@ test.describe(
{ name: 'myArray', type: 'array', value: '["item1", "item2"]' },
]);
await expect(
n8n.ndv.getAssignmentCollectionContainer('assignments').getByTestId('assignment'),
).toHaveCount(4);
await expect(n8n.ndv.getAssignments('assignments')).toHaveCount(4);
});
},
);

View file

@ -1,5 +1,4 @@
import { test, expect, chatHubTestConfig } from './fixtures';
import { CredentialModal } from '../../../pages/components/CredentialModal';
test.use(chatHubTestConfig);
@ -32,8 +31,6 @@ test.describe(
n8n,
anthropicApiKey,
}) => {
const credModal = new CredentialModal(n8n.page.getByTestId('editCredential-modal'));
await n8n.navigate.toChatHub();
await n8n.chatHubChat.dismissWelcomeScreen();
@ -48,9 +45,9 @@ test.describe(
.getVisiblePopoverMenuItem('Configure credentials', { exact: true })
.click();
await credModal.fillField('apiKey', anthropicApiKey);
await credModal.save();
await credModal.close();
await n8n.canvas.credentialModal.fillField('apiKey', anthropicApiKey);
await n8n.canvas.credentialModal.save();
await n8n.canvas.credentialModal.close();
await expect(n8n.chatHubChat.getModelSelectorButton()).toContainText(/claude/i); // auto-select a model

View file

@ -19,7 +19,7 @@ test.describe(
await expect(n8n.canvas.nodeCreator.getActiveSubcategory()).toContainText(editImageNode);
await n8n.canvas.nodeCreator.selectItem('Crop Image');
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.page.keyboard.press('Escape');
await expect(n8n.canvas.getCanvasNodes()).toHaveCount(2);
@ -35,7 +35,7 @@ test.describe(
await n8n.canvas.nodeCreator.searchFor('rename');
await n8n.canvas.nodeCreator.selectItem('Rename');
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.page.keyboard.press('Escape');
await expect(n8n.canvas.getCanvasNodes()).toHaveCount(2);

View file

@ -83,7 +83,7 @@ test.describe(
await n8n.ndv.clickCreateNewCredential();
await expect(n8n.page.getByTestId('editCredential-modal')).toContainText('Notion API');
await expect(n8n.canvas.credentialModal.getModal()).toContainText('Notion API');
});
test('should render custom node with custom credential', async ({ n8n }) => {
@ -97,9 +97,7 @@ test.describe(
await n8n.ndv.clickCreateNewCredential();
await expect(n8n.page.getByTestId('editCredential-modal')).toContainText(
'Custom E2E Credential',
);
await expect(n8n.canvas.credentialModal.getModal()).toContainText('Custom E2E Credential');
});
},
);

View file

@ -67,8 +67,7 @@ test.describe(
const webhookPath = await n8n.ndv.setupHelper.getWebhookPath();
// Add the Response Code optional parameter
await n8n.ndv.getAddOptionDropdown().click();
await n8n.page.getByRole('option', { name: 'Response Code' }).click();
await n8n.ndv.addParameterOptionByName('Response Code');
// Select 201 from the dropdown
await n8n.ndv.selectOptionInParameterDropdown('responseCode', '201');
await n8n.ndv.execute();

View file

@ -15,7 +15,7 @@ test.describe(
for (const node of ['hackernews_top', 'hackernews_sub']) {
await n8n.canvas.openNode(node);
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.ndv.inputPanel.get()).toBeVisible();
// Switch to JSON mode within the mapping view

View file

@ -23,12 +23,10 @@ test.describe(
await n8n.canvas.toggleFocusPanelButton().click();
await n8n.canvas.canvasPane().click();
await n8n.canvas.nodeByName('Code').dblclick();
await n8n.ndv.getParameterByLabel('JavaScript').getByRole('textbox').fill('alert(1)');
await n8n.ndv.getParameterTextboxByLabel('JavaScript').fill('alert(1)');
await n8n.ndv.close();
await n8n.canvas.nodeByName('Code').dblclick();
await expect(n8n.ndv.getParameterByLabel('JavaScript').getByRole('textbox')).toHaveText(
'alert(1)',
);
await expect(n8n.ndv.getParameterTextboxByLabel('JavaScript')).toHaveText('alert(1)');
});
},
);

View file

@ -25,15 +25,13 @@ test.describe(
n8n.ndv.getPlaceholderText('// Loop over input items and add a new field'),
).toBeVisible();
await n8n.ndv.getParameterInput('mode').click();
await n8n.page.getByRole('option', { name: 'Run Once for Each Item' }).click();
await n8n.ndv.selectOptionInParameterDropdown('mode', 'Run Once for Each Item');
await expect(
n8n.ndv.getPlaceholderText("// Add a new field called 'myNewField'"),
).toBeVisible();
await n8n.ndv.getParameterInput('mode').click();
await n8n.page.getByRole('option', { name: 'Run Once for All Items' }).click();
await n8n.ndv.selectOptionInParameterDropdown('mode', 'Run Once for All Items');
await expect(
n8n.ndv.getPlaceholderText('// Loop over input items and add a new field'),
@ -47,8 +45,7 @@ test.describe(
n8n.notifications.getNotificationByTitle('Node executed successfully').first(),
).toBeVisible();
await n8n.ndv.getParameterInput('mode').click();
await n8n.page.getByRole('option', { name: 'Run Once for Each Item' }).click();
await n8n.ndv.selectOptionInParameterDropdown('mode', 'Run Once for Each Item');
await n8n.ndv.execute();

View file

@ -197,7 +197,7 @@ test.describe(
await expect(n8n.ndv.outputPanel.getTbodyCell(0, 0)).toContainText('Trigger A');
await n8n.ndv.clickBackToCanvasButton();
await expect(n8n.ndv.getContainer()).toBeHidden();
await expect(n8n.ndv.container).toBeHidden();
await n8n.canvas.nodeByName('Trigger B').hover();
await expect(n8n.canvas.getExecuteWorkflowButton('Trigger A')).toHaveCSS('opacity', '0');

View file

@ -16,8 +16,7 @@ test.describe(
await n8n.ndv.getAssignmentCollectionAdd('assignments').click();
// Switch assignment value to Expression mode
const assignmentValue = n8n.ndv.getAssignmentValue('assignments');
await assignmentValue.locator('text=Expression').click();
await n8n.ndv.clickAssignmentExpressionToggle('assignments');
}
test('$json + native string methods', async ({ n8n }) => {

View file

@ -21,9 +21,9 @@ test.describe(
await n8n.canvas.addNode('Manual Trigger');
const canvasNodes = n8n.canvas.getCanvasNodes();
await canvasNodes.first().dblclick();
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.ndv.clickBackToCanvasButton();
await expect(n8n.ndv.getContainer()).toBeHidden();
await expect(n8n.ndv.container).toBeHidden();
});
test('should show input panel when node is not connected', async ({ n8n }) => {
@ -32,7 +32,7 @@ test.describe(
await n8n.canvas.addNode('Edit Fields (Set)', { closeNDV: true });
const canvasNodes = n8n.canvas.getCanvasNodes();
await canvasNodes.last().dblclick();
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.ndv.inputPanel.get()).toContainText('No input connected');
});
@ -49,12 +49,12 @@ test.describe(
await expect(n8n.ndv.inputPanel.get()).toContainText('start');
await n8n.ndv.clickBackToCanvasButton();
await expect(n8n.ndv.getContainer()).toBeHidden();
await expect(n8n.ndv.container).toBeHidden();
});
test('should show correct validation state for resource locator params', async ({ n8n }) => {
await n8n.canvas.addNode('Typeform Trigger', { closeNDV: false });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.ndv.clickBackToCanvasButton();
@ -65,7 +65,7 @@ test.describe(
test('should show validation errors only after blur or re-opening of NDV', async ({ n8n }) => {
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.addNode('Airtable', { closeNDV: false, action: 'Search records' });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.canvas.getNodeIssuesByName('Airtable')).toBeHidden();
@ -118,7 +118,7 @@ test.describe(
await n8n.ndv.getParameterInputField('path').clear();
const webhookUrlsContainer = n8n.ndv.getContainer().getByText('Webhook URLs').locator('..');
const webhookUrlsContainer = n8n.ndv.container.getByText('Webhook URLs').locator('..');
const urlText = await webhookUrlsContainer.textContent();
const uuidRegex = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
expect(urlText).toMatch(uuidRegex);
@ -175,7 +175,7 @@ test.describe(
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.addNode('Code', { action: 'Code in JavaScript', closeNDV: false });
const codeEditor = n8n.ndv.getParameterInput('jsCode').locator('.cm-content');
const codeEditor = n8n.ndv.getCodeEditor();
await codeEditor.click();
await n8n.page.keyboard.press('ControlOrMeta+a');
await n8n.page.keyboard.press('Delete');
@ -206,9 +206,7 @@ test.describe(
await n8n.ndv.closeCodeEditorDialog();
await expect(n8n.ndv.getParameterInput('jsCode').locator('.cm-content')).toContainText(
'foo()',
);
await expect(n8n.ndv.getCodeEditor()).toContainText('foo()');
});
test.describe('Complex Edge Cases', () => {

View file

@ -13,7 +13,7 @@ test.describe(
test('should traverse floating nodes with mouse', async ({ n8n }) => {
await n8n.start.fromImportedWorkflow('Floating_Nodes.json');
await n8n.canvas.getCanvasNodes().first().dblclick();
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.ndv.getFloatingNodeByPosition('inputMain')).toBeHidden();
await expect(n8n.ndv.getFloatingNodeByPosition('outputMain')).toBeVisible();
@ -26,7 +26,7 @@ test.describe(
await expect(n8n.canvas.getSelectedNodes()).toHaveCount(1);
await n8n.canvas.getSelectedNodes().first().dblclick();
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
}
await n8n.ndv.clickFloatingNodeByPosition('outputMain');
@ -51,7 +51,7 @@ test.describe(
await n8n.start.fromImportedWorkflow('Floating_Nodes.json');
await n8n.canvas.getCanvasNodes().first().dblclick();
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.ndv.getFloatingNodeByPosition('inputMain')).toBeHidden();
await expect(n8n.ndv.getFloatingNodeByPosition('outputMain')).toBeVisible();
@ -64,7 +64,7 @@ test.describe(
await expect(n8n.canvas.getSelectedNodes()).toHaveCount(1);
await n8n.canvas.getSelectedNodes().first().dblclick();
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
}
await n8n.ndv.navigateToNextFloatingNodeWithKeyboard();
@ -87,7 +87,7 @@ test.describe(
test('should connect floating sub-nodes', async ({ n8n }) => {
await n8n.canvas.addNode('AI Agent', { closeNDV: false });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.ndv.connectAISubNode('ai_languageModel', 'Anthropic Chat Model');
await n8n.ndv.connectAISubNode('ai_memory', 'Redis Chat Memory');
@ -100,7 +100,7 @@ test.describe(
await n8n.start.fromImportedWorkflow('Floating_Nodes.json');
await n8n.canvas.openNode('Merge');
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
expect(await n8n.ndv.getFloatingNodeCount('inputMain')).toBe(2);
await n8n.ndv.verifyFloatingNodeName('inputMain', 'Edit Fields1', 0);
@ -109,7 +109,7 @@ test.describe(
await n8n.ndv.close();
await n8n.canvas.openNode('Merge1');
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
expect(await n8n.ndv.getFloatingNodeCount('inputMain')).toBe(2);
await n8n.ndv.verifyFloatingNodeName('inputMain', 'Edit Fields0', 0);

View file

@ -53,7 +53,7 @@ test.describe(
});
await n8n.canvas.addNode('E2E Test', { action: 'Remote Options' });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.ndv.fillFirstAvailableTextParameterMultipleTimes(['test1', 'test2', 'test3']);
@ -69,7 +69,7 @@ test.describe(
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.addNode('Notion', { action: 'Update a database page', closeNDV: false });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.ndv.addItemToFixedCollection('propertiesUi');
await expect(
@ -84,7 +84,7 @@ test.describe(
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.addNode('Notion', { action: 'Update a database page', closeNDV: false });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.credentialsComposer.createFromNdv({
apiKey: 'sk_test_123',
@ -100,7 +100,7 @@ test.describe(
test('Should clear mismatched collection parameters', async ({ n8n }) => {
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.addNode('Notion', { action: 'Create a database page', closeNDV: false });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.ndv.addItemToFixedCollection('propertiesUi');
await n8n.ndv.changeNodeOperation('Update');
@ -116,18 +116,18 @@ test.describe(
closeNDV: false,
action: 'Append row in sheet',
});
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.ndv.setRLCValue('documentId', TEST_DOC_ID);
await n8n.ndv.changeNodeOperation('Append or Update Row');
const input = n8n.ndv.getResourceLocatorInput('documentId').locator('input');
const input = n8n.ndv.getResourceLocatorInputField('documentId');
await expect(input).toHaveValue(TEST_DOC_ID);
});
test('Should not clear resource/operation after credential change', async ({ n8n }) => {
await n8n.canvas.addNode('Manual Trigger');
await n8n.canvas.addNode('Discord', { closeNDV: false, action: 'Delete a message' });
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await n8n.credentialsComposer.createFromNdv({
botToken: 'sk_test_123',
});
@ -181,7 +181,7 @@ test.describe(
await n8n.canvas.openNode('Set');
await n8n.ndv.getAssignmentValue('assignments').getByText('Expression').click();
await n8n.ndv.getAssignmentExpressionToggle('assignments').click();
const expressionInput = n8n.ndv.getInlineExpressionEditorInput();
await expressionInput.click();

View file

@ -87,7 +87,7 @@ test.describe(
await n8n.canvas.addNode(NODES.EDIT_FIELDS);
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.ndv.getEditPinnedDataButton()).toBeVisible();
await expect(n8n.ndv.outputPanel.getPinDataButton()).toBeHidden();
@ -119,7 +119,7 @@ test.describe(
await n8n.canvas.addNode(NODES.EDIT_FIELDS);
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.ndv.getEditPinnedDataButton()).toBeVisible();
await expect(n8n.ndv.outputPanel.getPinDataButton()).toBeHidden();
@ -139,7 +139,7 @@ test.describe(
await n8n.canvas.addNode(NODES.EDIT_FIELDS);
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
await expect(n8n.ndv.getEditPinnedDataButton()).toBeVisible();
await expect(n8n.ndv.outputPanel.getPinDataButton()).toBeHidden();

View file

@ -116,7 +116,7 @@ test.describe(
await n8n.ndv.setRLCValue('sheetName', '123', 1);
await n8n.ndv.setRLCValue('documentId', '321');
await expect(n8n.ndv.getResourceLocatorInput('sheetName').locator('input')).toHaveValue('');
await expect(n8n.ndv.getResourceLocatorInputField('sheetName')).toHaveValue('');
});
// unlike RMC and remote options, RLC does not support loadOptionDependsOn
@ -125,7 +125,7 @@ test.describe(
await n8n.ndv.getResourceLocatorInput('rlc').click();
await expect(n8n.page.getByTestId('rlc-item').first()).toBeVisible();
await expect(n8n.ndv.getResourceLocatorItems().first()).toBeVisible();
const visiblePopper = n8n.ndv.getVisiblePopper();
await expect(visiblePopper).toHaveCount(1);
await expect(visiblePopper.getByTestId('rlc-item')).toHaveCount(5);
@ -139,7 +139,7 @@ test.describe(
await n8n.ndv.getResourceLocatorInput('rlc').click();
await expect(n8n.page.getByTestId('rlc-item').first()).toBeVisible();
await expect(n8n.ndv.getResourceLocatorItems().first()).toBeVisible();
const visiblePopperAfter = n8n.ndv.getVisiblePopper();
await expect(visiblePopperAfter).toHaveCount(1);
await expect(visiblePopperAfter.getByTestId('rlc-item')).toHaveCount(5);

View file

@ -65,11 +65,11 @@ test.describe(
await n8n.page.keyboard.press('Escape');
await n8n.canvas.waitForSaveWorkflowCompleted();
await expect(n8n.ndv.getContainer()).toBeHidden();
await expect(n8n.ndv.container).toBeHidden();
await n8n.page.goto(ndvUrl);
await expect(n8n.ndv.getContainer()).toBeVisible();
await expect(n8n.ndv.container).toBeVisible();
});
test('should open show warning and drop nodeId from URL if it contained an unknown nodeId', async ({
@ -83,7 +83,7 @@ test.describe(
await n8n.page.keyboard.press('Escape');
await n8n.canvas.waitForSaveWorkflowCompleted();
await expect(n8n.ndv.getContainer()).toBeHidden();
await expect(n8n.ndv.container).toBeHidden();
await n8n.page.goto(ndvUrl + 'thisMessesUpTheNodeId');

View file

@ -60,13 +60,13 @@ test.describe(
await expect(items.filter({ hasText: 'Search DB' })).toHaveCount(0);
await n8n.ndvComposer.selectFirstFilteredWorkflow();
const inputField = n8n.ndv.getResourceLocatorInput('workflowId').locator('input');
const inputField = n8n.ndv.getResourceLocatorInputField('workflowId');
await expect(inputField).toHaveValue(/Get_Weather/);
});
test('should render sub-workflow links correctly', async ({ n8n }) => {
await n8n.ndvComposer.selectWorkflowFromList('workflowId', 'Search_DB');
const link = n8n.ndv.getResourceLocatorInput('workflowId').locator('a');
const link = n8n.ndv.getResourceLocatorLink('workflowId');
await expect(link).toBeVisible();
await n8n.ndv.getExpressionModeToggle().click();
@ -75,7 +75,7 @@ test.describe(
test('should switch to ID mode on expression', async ({ n8n }) => {
await n8n.ndvComposer.selectWorkflowFromList('workflowId', 'Search_DB');
const modeSelector = n8n.ndv.getResourceLocatorModeSelector('workflowId').locator('input');
const modeSelector = n8n.ndv.getResourceLocatorModeSelectorInput('workflowId');
await expect(modeSelector).toHaveValue('From list');
await n8n.ndvComposer.switchToExpressionMode('workflowId');