@neo4j-cypher/react-codemirror 0.0.0-canary-20250423075344
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +279 -0
- package/LICENSE.md +201 -0
- package/README.md +35 -0
- package/dist/CypherEditor.d.ts +192 -0
- package/dist/CypherEditor.js +326 -0
- package/dist/CypherEditor.js.map +1 -0
- package/dist/CypherEditor.test.d.ts +1 -0
- package/dist/CypherEditor.test.js +151 -0
- package/dist/CypherEditor.test.js.map +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -0
- package/dist/e2e_tests/autoCompletion.spec.d.ts +1 -0
- package/dist/e2e_tests/autoCompletion.spec.js +318 -0
- package/dist/e2e_tests/autoCompletion.spec.js.map +1 -0
- package/dist/e2e_tests/configuration.spec.d.ts +1 -0
- package/dist/e2e_tests/configuration.spec.js +83 -0
- package/dist/e2e_tests/configuration.spec.js.map +1 -0
- package/dist/e2e_tests/debounce.spec.d.ts +1 -0
- package/dist/e2e_tests/debounce.spec.js +66 -0
- package/dist/e2e_tests/debounce.spec.js.map +1 -0
- package/dist/e2e_tests/e2eUtils.d.ts +13 -0
- package/dist/e2e_tests/e2eUtils.js +71 -0
- package/dist/e2e_tests/e2eUtils.js.map +1 -0
- package/dist/e2e_tests/extraKeybindings.spec.d.ts +1 -0
- package/dist/e2e_tests/extraKeybindings.spec.js +43 -0
- package/dist/e2e_tests/extraKeybindings.spec.js.map +1 -0
- package/dist/e2e_tests/historyNavigation.spec.d.ts +1 -0
- package/dist/e2e_tests/historyNavigation.spec.js +227 -0
- package/dist/e2e_tests/historyNavigation.spec.js.map +1 -0
- package/dist/e2e_tests/performanceTest.spec.d.ts +6 -0
- package/dist/e2e_tests/performanceTest.spec.js +97 -0
- package/dist/e2e_tests/performanceTest.spec.js.map +1 -0
- package/dist/e2e_tests/sanityChecks.spec.d.ts +1 -0
- package/dist/e2e_tests/sanityChecks.spec.js +53 -0
- package/dist/e2e_tests/sanityChecks.spec.js.map +1 -0
- package/dist/e2e_tests/signatureHelp.spec.d.ts +1 -0
- package/dist/e2e_tests/signatureHelp.spec.js +228 -0
- package/dist/e2e_tests/signatureHelp.spec.js.map +1 -0
- package/dist/e2e_tests/snippets.spec.d.ts +1 -0
- package/dist/e2e_tests/snippets.spec.js +62 -0
- package/dist/e2e_tests/snippets.spec.js.map +1 -0
- package/dist/e2e_tests/syntaxHighlighting.spec.d.ts +1 -0
- package/dist/e2e_tests/syntaxHighlighting.spec.js +90 -0
- package/dist/e2e_tests/syntaxHighlighting.spec.js.map +1 -0
- package/dist/e2e_tests/syntaxValidation.spec.d.ts +1 -0
- package/dist/e2e_tests/syntaxValidation.spec.js +116 -0
- package/dist/e2e_tests/syntaxValidation.spec.js.map +1 -0
- package/dist/historyNavigation.d.ts +7 -0
- package/dist/historyNavigation.js +163 -0
- package/dist/historyNavigation.js.map +1 -0
- package/dist/icons.d.ts +2 -0
- package/dist/icons.js +62 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/lang-cypher/autocomplete.d.ts +6 -0
- package/dist/lang-cypher/autocomplete.js +115 -0
- package/dist/lang-cypher/autocomplete.js.map +1 -0
- package/dist/lang-cypher/constants.d.ts +42 -0
- package/dist/lang-cypher/constants.js +69 -0
- package/dist/lang-cypher/constants.js.map +1 -0
- package/dist/lang-cypher/contants.test.d.ts +1 -0
- package/dist/lang-cypher/contants.test.js +103 -0
- package/dist/lang-cypher/contants.test.js.map +1 -0
- package/dist/lang-cypher/createCypherTheme.d.ts +26 -0
- package/dist/lang-cypher/createCypherTheme.js +182 -0
- package/dist/lang-cypher/createCypherTheme.js.map +1 -0
- package/dist/lang-cypher/langCypher.d.ts +14 -0
- package/dist/lang-cypher/langCypher.js +23 -0
- package/dist/lang-cypher/langCypher.js.map +1 -0
- package/dist/lang-cypher/lintWorker.d.ts +12 -0
- package/dist/lang-cypher/lintWorker.js +14 -0
- package/dist/lang-cypher/lintWorker.js.map +1 -0
- package/dist/lang-cypher/parser-adapter.d.ts +19 -0
- package/dist/lang-cypher/parser-adapter.js +113 -0
- package/dist/lang-cypher/parser-adapter.js.map +1 -0
- package/dist/lang-cypher/signatureHelp.d.ts +4 -0
- package/dist/lang-cypher/signatureHelp.js +109 -0
- package/dist/lang-cypher/signatureHelp.js.map +1 -0
- package/dist/lang-cypher/syntaxValidation.d.ts +4 -0
- package/dist/lang-cypher/syntaxValidation.js +52 -0
- package/dist/lang-cypher/syntaxValidation.js.map +1 -0
- package/dist/lang-cypher/themeIcons.d.ts +7 -0
- package/dist/lang-cypher/themeIcons.js +22 -0
- package/dist/lang-cypher/themeIcons.js.map +1 -0
- package/dist/lang-cypher/utils.d.ts +2 -0
- package/dist/lang-cypher/utils.js +10 -0
- package/dist/lang-cypher/utils.js.map +1 -0
- package/dist/ndlTokensCopy.d.ts +570 -0
- package/dist/ndlTokensCopy.js +571 -0
- package/dist/ndlTokensCopy.js.map +1 -0
- package/dist/ndlTokensCopy.test.d.ts +1 -0
- package/dist/ndlTokensCopy.test.js +12 -0
- package/dist/ndlTokensCopy.test.js.map +1 -0
- package/dist/neo4jSetup.d.ts +6 -0
- package/dist/neo4jSetup.js +120 -0
- package/dist/neo4jSetup.js.map +1 -0
- package/dist/themes.d.ts +11 -0
- package/dist/themes.js +93 -0
- package/dist/themes.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +82 -0
- package/src/CypherEditor.test.tsx +200 -0
- package/src/CypherEditor.tsx +607 -0
- package/src/constants.ts +1 -0
- package/src/e2e_tests/autoCompletion.spec.tsx +546 -0
- package/src/e2e_tests/configuration.spec.tsx +111 -0
- package/src/e2e_tests/debounce.spec.tsx +106 -0
- package/src/e2e_tests/e2eUtils.ts +97 -0
- package/src/e2e_tests/extraKeybindings.spec.tsx +55 -0
- package/src/e2e_tests/historyNavigation.spec.tsx +315 -0
- package/src/e2e_tests/performanceTest.spec.tsx +163 -0
- package/src/e2e_tests/sanityChecks.spec.tsx +72 -0
- package/src/e2e_tests/signatureHelp.spec.tsx +445 -0
- package/src/e2e_tests/snippets.spec.tsx +92 -0
- package/src/e2e_tests/syntaxHighlighting.spec.tsx +200 -0
- package/src/e2e_tests/syntaxValidation.spec.tsx +243 -0
- package/src/historyNavigation.ts +191 -0
- package/src/icons.ts +90 -0
- package/src/index.ts +4 -0
- package/src/lang-cypher/autocomplete.ts +147 -0
- package/src/lang-cypher/constants.ts +88 -0
- package/src/lang-cypher/contants.test.ts +108 -0
- package/src/lang-cypher/createCypherTheme.ts +249 -0
- package/src/lang-cypher/langCypher.ts +43 -0
- package/src/lang-cypher/lintWorker.ts +31 -0
- package/src/lang-cypher/parser-adapter.ts +145 -0
- package/src/lang-cypher/signatureHelp.ts +151 -0
- package/src/lang-cypher/syntaxValidation.ts +66 -0
- package/src/lang-cypher/themeIcons.ts +27 -0
- package/src/lang-cypher/utils.ts +9 -0
- package/src/ndlTokensCopy.test.ts +12 -0
- package/src/ndlTokensCopy.ts +570 -0
- package/src/neo4jSetup.tsx +190 -0
- package/src/themes.ts +105 -0
- package/src/viteEnv.d.ts +1 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { testData } from '@neo4j-cypher/language-support';
|
|
2
|
+
import { expect, test } from '@playwright/experimental-ct-react';
|
|
3
|
+
import { CypherEditor } from '../CypherEditor';
|
|
4
|
+
import { CypherEditorPage } from './e2eUtils';
|
|
5
|
+
|
|
6
|
+
test.use({ viewport: { width: 1000, height: 500 } });
|
|
7
|
+
declare global {
|
|
8
|
+
interface Window {
|
|
9
|
+
longtasks: number[];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
test('benchmarking & performance test session', async ({
|
|
14
|
+
browserName,
|
|
15
|
+
mount,
|
|
16
|
+
page,
|
|
17
|
+
}) => {
|
|
18
|
+
test.skip(browserName !== 'chromium');
|
|
19
|
+
const client = await page.context().newCDPSession(page);
|
|
20
|
+
if (process.env.BENCHMARKING === 'true') {
|
|
21
|
+
test.setTimeout(1000000);
|
|
22
|
+
await client.send('Performance.enable');
|
|
23
|
+
await client.send('Emulation.setCPUThrottlingRate', { rate: 4 });
|
|
24
|
+
await client.send('Overlay.setShowFPSCounter', { show: true });
|
|
25
|
+
|
|
26
|
+
await page.evaluate(() => {
|
|
27
|
+
window.longtasks = [];
|
|
28
|
+
const observer = new PerformanceObserver((list) => {
|
|
29
|
+
window.longtasks.push(...list.getEntries().map((e) => e.duration));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
observer.observe({ entryTypes: ['longtask'] });
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
test.setTimeout(30 * 1000);
|
|
36
|
+
}
|
|
37
|
+
const editorPage = new CypherEditorPage(page);
|
|
38
|
+
const component = await mount(
|
|
39
|
+
<CypherEditor
|
|
40
|
+
prompt="neo4j>"
|
|
41
|
+
theme="dark"
|
|
42
|
+
lint
|
|
43
|
+
schema={testData.mockSchema}
|
|
44
|
+
/>,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// pressSequentially is less efficient -> we want to test the performance of the editor
|
|
48
|
+
await editorPage.getEditor().pressSequentially(`
|
|
49
|
+
MATCH (n:Person) RETURN m;`);
|
|
50
|
+
|
|
51
|
+
await editorPage.checkErrorMessage('m', 'Variable `m` not defined');
|
|
52
|
+
|
|
53
|
+
// set and unset large query a few times
|
|
54
|
+
await component.update(
|
|
55
|
+
<CypherEditor value={testData.largeQuery} schema={testData.mockSchema} />,
|
|
56
|
+
);
|
|
57
|
+
await component.update(
|
|
58
|
+
<CypherEditor value="" schema={testData.mockSchema} />,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
await component.update(
|
|
62
|
+
<CypherEditor value={testData.largeQuery} schema={testData.mockSchema} />,
|
|
63
|
+
);
|
|
64
|
+
await component.update(<CypherEditor value="" />);
|
|
65
|
+
|
|
66
|
+
await component.update(
|
|
67
|
+
<CypherEditor value={testData.largeQuery} schema={testData.mockSchema} />,
|
|
68
|
+
);
|
|
69
|
+
await component.update(
|
|
70
|
+
<CypherEditor value="" schema={testData.mockSchema} />,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
await component.update(
|
|
74
|
+
<CypherEditor value={testData.largeQuery} schema={testData.mockSchema} />,
|
|
75
|
+
);
|
|
76
|
+
await component.update(
|
|
77
|
+
<CypherEditor value="" schema={testData.mockSchema} />,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
await component.update(
|
|
81
|
+
<CypherEditor value={testData.largeQuery} schema={testData.mockSchema} />,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
await editorPage.getEditor().pressSequentially(`
|
|
85
|
+
MATCH (n:P`);
|
|
86
|
+
|
|
87
|
+
await expect(
|
|
88
|
+
page.locator('.cm-tooltip-autocomplete').getByText('Person'),
|
|
89
|
+
).toBeVisible();
|
|
90
|
+
|
|
91
|
+
await page.locator('.cm-tooltip-autocomplete').getByText('Person').click();
|
|
92
|
+
|
|
93
|
+
await expect(page.locator('.cm-tooltip-autocomplete')).not.toBeVisible();
|
|
94
|
+
|
|
95
|
+
await expect(component).toContainText('MATCH (n:Person');
|
|
96
|
+
|
|
97
|
+
await editorPage.getEditor().pressSequentially(') RETRN my');
|
|
98
|
+
|
|
99
|
+
await expect(component).toContainText('MATCH (n:Person) RETRN m');
|
|
100
|
+
|
|
101
|
+
await editorPage.checkErrorMessage(
|
|
102
|
+
'RETRN',
|
|
103
|
+
`Invalid input 'RETRN': expected a graph pattern, 'FOREACH', ',', 'ORDER BY', 'CALL', 'CREATE', 'LOAD CSV', 'DELETE', 'DETACH', 'FINISH', 'INSERT', 'LIMIT', 'MATCH', 'MERGE', 'NODETACH', 'OFFSET', 'OPTIONAL', 'REMOVE', 'RETURN', 'SET', 'SKIP', 'UNION', 'UNWIND', 'USE', 'USING', 'WHERE', 'WITH' or <EOF>`,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
await editorPage
|
|
107
|
+
.getEditor()
|
|
108
|
+
.pressSequentially('veryveryveryverylongvariable');
|
|
109
|
+
|
|
110
|
+
if (process.env.BENCHMARKING === 'true') {
|
|
111
|
+
const longtasks = await page.evaluate(() => window.longtasks);
|
|
112
|
+
const sortedLongTasks = longtasks.sort((a, b) => a - b);
|
|
113
|
+
const medianLongTask =
|
|
114
|
+
sortedLongTasks[Math.floor(sortedLongTasks.length / 2)];
|
|
115
|
+
const averageLongTask =
|
|
116
|
+
sortedLongTasks.reduce((a, b) => a + b, 0) / sortedLongTasks.length;
|
|
117
|
+
const over500 = sortedLongTasks.filter((t) => t > 500).length;
|
|
118
|
+
const nintyninethPercentile =
|
|
119
|
+
sortedLongTasks[Math.floor(sortedLongTasks.length * 0.99)];
|
|
120
|
+
const longTaskCount = longtasks.length;
|
|
121
|
+
const totalLongTaskTime = longtasks.reduce((a, b) => a + b, 0);
|
|
122
|
+
|
|
123
|
+
const USER_ID = 1226722;
|
|
124
|
+
const API_KEY = process.env.GRAFANA_API_KEY;
|
|
125
|
+
if (!API_KEY) {
|
|
126
|
+
throw new Error('Missing grafana api key');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const metrics = {
|
|
130
|
+
medianLongTask,
|
|
131
|
+
averageLongTask,
|
|
132
|
+
over500,
|
|
133
|
+
nintyninethPercentile,
|
|
134
|
+
longTaskCount,
|
|
135
|
+
totalLongTaskTime,
|
|
136
|
+
};
|
|
137
|
+
const body = Object.entries(metrics)
|
|
138
|
+
.map(
|
|
139
|
+
([key, value]) =>
|
|
140
|
+
`benchmark,bar_label=${key},source=playwright metric=${value}`,
|
|
141
|
+
)
|
|
142
|
+
.join('\n');
|
|
143
|
+
|
|
144
|
+
await fetch(
|
|
145
|
+
'https://influx-prod-39-prod-eu-north-0.grafana.net/api/v1/push/influx/write',
|
|
146
|
+
{
|
|
147
|
+
method: 'post',
|
|
148
|
+
body,
|
|
149
|
+
headers: {
|
|
150
|
+
Authorization: `Bearer ${USER_ID}:${API_KEY}`,
|
|
151
|
+
'Content-Type': 'text/plain',
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
).then((res) => {
|
|
155
|
+
if (res.ok) {
|
|
156
|
+
// eslint-disable-next-line no-console
|
|
157
|
+
console.log('Metrics pushed to grafana successfully');
|
|
158
|
+
} else {
|
|
159
|
+
throw new Error(`Failed to push metrics to grafana: ${res.statusText}`);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/experimental-ct-react';
|
|
2
|
+
import { CypherEditor } from '../CypherEditor';
|
|
3
|
+
|
|
4
|
+
test('can mount the editor with text', async ({ mount }) => {
|
|
5
|
+
const component = await mount(<CypherEditor value="MATCH (n) RETURN n;" />);
|
|
6
|
+
|
|
7
|
+
await expect(component).toContainText('MATCH (n) RETURN n;');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test('the editors text can be externally controlled ', async ({ mount }) => {
|
|
11
|
+
const intitialValue = 'MATCH (n) RETURN n;';
|
|
12
|
+
|
|
13
|
+
const component = await mount(<CypherEditor value={intitialValue} />);
|
|
14
|
+
|
|
15
|
+
await expect(component).toContainText(intitialValue);
|
|
16
|
+
|
|
17
|
+
const newValue = 'RETURN 123';
|
|
18
|
+
await component.update(<CypherEditor value={newValue} />);
|
|
19
|
+
|
|
20
|
+
await expect(component).toContainText(newValue);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('the editor can report changes to the text ', async ({ mount, page }) => {
|
|
24
|
+
const intitialValue = 'MATCH (n) ';
|
|
25
|
+
|
|
26
|
+
let editorValueCopy = intitialValue;
|
|
27
|
+
const onChange = (val: string) => {
|
|
28
|
+
editorValueCopy = val;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
await mount(<CypherEditor value={intitialValue} onChange={onChange} />);
|
|
32
|
+
|
|
33
|
+
const textField = page.getByRole('textbox');
|
|
34
|
+
|
|
35
|
+
await textField.fill('');
|
|
36
|
+
await textField.fill('RETURN 12');
|
|
37
|
+
await expect(textField).toHaveText('RETURN 12');
|
|
38
|
+
|
|
39
|
+
// editor update is debounced, retry wait for debounced
|
|
40
|
+
await expect(() => {
|
|
41
|
+
expect(editorValueCopy).toBe('RETURN 12');
|
|
42
|
+
}).toPass({ intervals: [300, 300, 1000] });
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('can complete RETURN', async ({ page, mount }) => {
|
|
46
|
+
await mount(<CypherEditor />);
|
|
47
|
+
const textField = page.getByRole('textbox');
|
|
48
|
+
|
|
49
|
+
await textField.fill('RETU');
|
|
50
|
+
|
|
51
|
+
await page.getByText('RETURN').click();
|
|
52
|
+
await expect(textField).toHaveText('RETURN');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('can complete CALL/CREATE', async ({ page, mount }) => {
|
|
56
|
+
await mount(<CypherEditor />);
|
|
57
|
+
const textField = page.getByRole('textbox');
|
|
58
|
+
|
|
59
|
+
await textField.fill('C');
|
|
60
|
+
await expect(page.getByText('CALL')).toBeVisible();
|
|
61
|
+
await expect(page.getByText('CREATE')).toBeVisible();
|
|
62
|
+
|
|
63
|
+
await textField.fill('CA');
|
|
64
|
+
await expect(page.getByText('CALL')).toBeVisible();
|
|
65
|
+
await expect(page.getByText('CREATE')).not.toBeVisible();
|
|
66
|
+
|
|
67
|
+
// wait for the autocomplete interactivity
|
|
68
|
+
await page.waitForTimeout(500);
|
|
69
|
+
await textField.press('Enter');
|
|
70
|
+
|
|
71
|
+
await expect(textField).toHaveText('CALL');
|
|
72
|
+
});
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
|
+
import { testData } from '@neo4j-cypher/language-support';
|
|
3
|
+
import { expect, test } from '@playwright/experimental-ct-react';
|
|
4
|
+
import { Locator } from 'playwright/test';
|
|
5
|
+
import { CypherEditor } from '../CypherEditor';
|
|
6
|
+
|
|
7
|
+
test.use({ viewport: { width: 1000, height: 500 } });
|
|
8
|
+
|
|
9
|
+
type TooltipExpectations = {
|
|
10
|
+
includes?: string[];
|
|
11
|
+
excludes?: string[];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const importCsvProc =
|
|
15
|
+
testData.mockSchema.procedures['CYPHER 5']['apoc.import.csv'];
|
|
16
|
+
|
|
17
|
+
function testTooltip(tooltip: Locator, expectations: TooltipExpectations) {
|
|
18
|
+
const includes = expectations.includes ?? [];
|
|
19
|
+
const excludes = expectations.excludes ?? [];
|
|
20
|
+
|
|
21
|
+
const included = Promise.all(
|
|
22
|
+
includes.map((text) => {
|
|
23
|
+
return expect(tooltip).toContainText(text, {
|
|
24
|
+
timeout: 10000,
|
|
25
|
+
});
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const excluded = Promise.all(
|
|
30
|
+
excludes.map((text) => {
|
|
31
|
+
return expect(tooltip).not.toContainText(text, {
|
|
32
|
+
timeout: 10000,
|
|
33
|
+
});
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return Promise.all([included, excluded]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test('Signature help works for functions', async ({ page, mount }) => {
|
|
41
|
+
const query = 'RETURN abs(';
|
|
42
|
+
|
|
43
|
+
await mount(
|
|
44
|
+
<CypherEditor
|
|
45
|
+
value={query}
|
|
46
|
+
schema={testData.mockSchema}
|
|
47
|
+
autofocus={true}
|
|
48
|
+
/>,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
await expect(page.locator('.cm-signature-help-panel')).toBeVisible({
|
|
52
|
+
timeout: 10000,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('Signature help works for procedures', async ({ page, mount }) => {
|
|
57
|
+
const query = 'CALL apoc.import.csv(';
|
|
58
|
+
|
|
59
|
+
await mount(
|
|
60
|
+
<CypherEditor
|
|
61
|
+
value={query}
|
|
62
|
+
schema={testData.mockSchema}
|
|
63
|
+
autofocus={true}
|
|
64
|
+
/>,
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
await expect(page.locator('.cm-signature-help-panel')).toBeVisible({
|
|
68
|
+
timeout: 10000,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('Signature help shows the description for the first argument', async ({
|
|
73
|
+
page,
|
|
74
|
+
mount,
|
|
75
|
+
}) => {
|
|
76
|
+
const query = 'CALL apoc.import.csv(';
|
|
77
|
+
|
|
78
|
+
await mount(
|
|
79
|
+
<CypherEditor
|
|
80
|
+
value={query}
|
|
81
|
+
schema={testData.mockSchema}
|
|
82
|
+
autofocus={true}
|
|
83
|
+
/>,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
87
|
+
|
|
88
|
+
await testTooltip(tooltip, {
|
|
89
|
+
includes: [
|
|
90
|
+
testData.mockSchema.procedures['CYPHER 5']['apoc.import.csv']
|
|
91
|
+
.argumentDescription[0].description,
|
|
92
|
+
testData.mockSchema.procedures['CYPHER 5']['apoc.import.csv'].description,
|
|
93
|
+
],
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('Signature help shows the description for the first argument when the cursor is at that position', async ({
|
|
98
|
+
page,
|
|
99
|
+
mount,
|
|
100
|
+
}) => {
|
|
101
|
+
const query = 'CALL apoc.import.csv()';
|
|
102
|
+
|
|
103
|
+
await mount(
|
|
104
|
+
<CypherEditor value={query} schema={testData.mockSchema} offset={21} />,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
108
|
+
|
|
109
|
+
await testTooltip(tooltip, {
|
|
110
|
+
includes: [
|
|
111
|
+
importCsvProc.argumentDescription[0].description,
|
|
112
|
+
importCsvProc.description,
|
|
113
|
+
],
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('Signature help shows the description for the second argument', async ({
|
|
118
|
+
page,
|
|
119
|
+
mount,
|
|
120
|
+
}) => {
|
|
121
|
+
const query = 'CALL apoc.import.csv(nodes,';
|
|
122
|
+
|
|
123
|
+
await mount(
|
|
124
|
+
<CypherEditor
|
|
125
|
+
value={query}
|
|
126
|
+
schema={testData.mockSchema}
|
|
127
|
+
autofocus={true}
|
|
128
|
+
/>,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
132
|
+
|
|
133
|
+
await testTooltip(tooltip, {
|
|
134
|
+
includes: [
|
|
135
|
+
importCsvProc.argumentDescription[1].description,
|
|
136
|
+
importCsvProc.description,
|
|
137
|
+
],
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('Signature help shows the description for the second argument when the cursor is at that position', async ({
|
|
142
|
+
page,
|
|
143
|
+
mount,
|
|
144
|
+
}) => {
|
|
145
|
+
const query = 'CALL apoc.import.csv(nodes,)';
|
|
146
|
+
|
|
147
|
+
await mount(
|
|
148
|
+
<CypherEditor value={query} schema={testData.mockSchema} offset={27} />,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
152
|
+
|
|
153
|
+
await testTooltip(tooltip, {
|
|
154
|
+
includes: [
|
|
155
|
+
importCsvProc.argumentDescription[1].description,
|
|
156
|
+
importCsvProc.description,
|
|
157
|
+
],
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('Signature help shows the description for the second argument when the cursor is at that position, even after whitespaces', async ({
|
|
162
|
+
page,
|
|
163
|
+
mount,
|
|
164
|
+
}) => {
|
|
165
|
+
const query = 'CALL apoc.import.csv(nodes, )';
|
|
166
|
+
|
|
167
|
+
await mount(
|
|
168
|
+
<CypherEditor value={query} schema={testData.mockSchema} offset={28} />,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
172
|
+
|
|
173
|
+
await testTooltip(tooltip, {
|
|
174
|
+
includes: [
|
|
175
|
+
'rels :: LIST<MAP>',
|
|
176
|
+
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
|
|
177
|
+
],
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('Signature help shows description for arguments with a space following a separator', async ({
|
|
182
|
+
page,
|
|
183
|
+
mount,
|
|
184
|
+
}) => {
|
|
185
|
+
const query = 'CALL apoc.import.csv(nodes, ';
|
|
186
|
+
|
|
187
|
+
await mount(
|
|
188
|
+
<CypherEditor
|
|
189
|
+
value={query}
|
|
190
|
+
schema={testData.mockSchema}
|
|
191
|
+
autofocus={true}
|
|
192
|
+
/>,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
196
|
+
|
|
197
|
+
await testTooltip(tooltip, {
|
|
198
|
+
includes: [
|
|
199
|
+
'rels :: LIST<MAP>',
|
|
200
|
+
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
|
|
201
|
+
],
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
test('Signature help shows the description for the third argument', async ({
|
|
206
|
+
page,
|
|
207
|
+
mount,
|
|
208
|
+
}) => {
|
|
209
|
+
const query = 'CALL apoc.import.csv(nodes, rels,';
|
|
210
|
+
|
|
211
|
+
await mount(
|
|
212
|
+
<CypherEditor
|
|
213
|
+
value={query}
|
|
214
|
+
schema={testData.mockSchema}
|
|
215
|
+
autofocus={true}
|
|
216
|
+
/>,
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
220
|
+
|
|
221
|
+
await testTooltip(tooltip, {
|
|
222
|
+
includes: [
|
|
223
|
+
'config :: MAP',
|
|
224
|
+
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
|
|
225
|
+
],
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('Signature help works on multiline queries', async ({ page, mount }) => {
|
|
230
|
+
const query = `CALL apoc.import.csv(
|
|
231
|
+
nodes,
|
|
232
|
+
rels,
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
await mount(
|
|
236
|
+
<CypherEditor
|
|
237
|
+
value={query}
|
|
238
|
+
schema={testData.mockSchema}
|
|
239
|
+
autofocus={true}
|
|
240
|
+
/>,
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
244
|
+
|
|
245
|
+
await testTooltip(tooltip, {
|
|
246
|
+
includes: [
|
|
247
|
+
'config :: MAP',
|
|
248
|
+
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
|
|
249
|
+
],
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test('Signature help only shows the description past the last argument', async ({
|
|
254
|
+
page,
|
|
255
|
+
mount,
|
|
256
|
+
}) => {
|
|
257
|
+
const query = 'CALL apoc.import.csv(nodes, rels, config,';
|
|
258
|
+
|
|
259
|
+
await mount(
|
|
260
|
+
<CypherEditor
|
|
261
|
+
value={query}
|
|
262
|
+
schema={testData.mockSchema}
|
|
263
|
+
autofocus={true}
|
|
264
|
+
/>,
|
|
265
|
+
);
|
|
266
|
+
1;
|
|
267
|
+
|
|
268
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
269
|
+
|
|
270
|
+
await testTooltip(tooltip, {
|
|
271
|
+
includes: [
|
|
272
|
+
'apoc.import.csv(nodes :: LIST<MAP>, rels :: LIST<MAP>, config :: MAP)',
|
|
273
|
+
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file.',
|
|
274
|
+
],
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test('Signature help does not show any help when method finished', async ({
|
|
279
|
+
page,
|
|
280
|
+
mount,
|
|
281
|
+
}) => {
|
|
282
|
+
const query = 'CALL apoc.import.csv(nodes, rels, config)';
|
|
283
|
+
|
|
284
|
+
await mount(
|
|
285
|
+
<CypherEditor
|
|
286
|
+
value={query}
|
|
287
|
+
schema={testData.mockSchema}
|
|
288
|
+
autofocus={true}
|
|
289
|
+
/>,
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
await expect(page.locator('.cm-signature-help-panel')).not.toBeVisible({
|
|
293
|
+
timeout: 10000,
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
test('Signature help does not blow up on empty query', async ({
|
|
298
|
+
page,
|
|
299
|
+
mount,
|
|
300
|
+
}) => {
|
|
301
|
+
const query = '';
|
|
302
|
+
|
|
303
|
+
await mount(
|
|
304
|
+
<CypherEditor
|
|
305
|
+
value={query}
|
|
306
|
+
schema={testData.mockSchema}
|
|
307
|
+
autofocus={true}
|
|
308
|
+
/>,
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
await expect(page.locator('.cm-signature-help-panel')).not.toBeVisible({
|
|
312
|
+
timeout: 10000,
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test('Signature help is shown below the text by default', async ({
|
|
317
|
+
page,
|
|
318
|
+
mount,
|
|
319
|
+
}) => {
|
|
320
|
+
// We need to introduce new lines to make sure there's
|
|
321
|
+
// enough space to show the tooltip above
|
|
322
|
+
const query = '\n\n\n\n\n\n\nRETURN abs(';
|
|
323
|
+
|
|
324
|
+
await mount(
|
|
325
|
+
<CypherEditor
|
|
326
|
+
value={query}
|
|
327
|
+
schema={testData.mockSchema}
|
|
328
|
+
autofocus={true}
|
|
329
|
+
/>,
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
await expect(
|
|
333
|
+
page.locator('.cm-signature-help-panel.cm-tooltip-below'),
|
|
334
|
+
).toBeVisible({
|
|
335
|
+
timeout: 10000,
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
test('Setting showSignatureTooltipBelow to true shows the signature help above the text', async ({
|
|
340
|
+
page,
|
|
341
|
+
mount,
|
|
342
|
+
}) => {
|
|
343
|
+
// We need to introduce new lines to make sure there's
|
|
344
|
+
// enough space to show the tooltip above
|
|
345
|
+
const query = '\n\n\n\n\n\n\nRETURN abs(';
|
|
346
|
+
|
|
347
|
+
await mount(
|
|
348
|
+
<CypherEditor
|
|
349
|
+
value={query}
|
|
350
|
+
schema={testData.mockSchema}
|
|
351
|
+
showSignatureTooltipBelow={true}
|
|
352
|
+
autofocus={true}
|
|
353
|
+
/>,
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
await expect(
|
|
357
|
+
page.locator('.cm-signature-help-panel.cm-tooltip-below'),
|
|
358
|
+
).toBeVisible({
|
|
359
|
+
timeout: 10000,
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
test('Setting showSignatureTooltipBelow to false shows the signature help above the text', async ({
|
|
364
|
+
page,
|
|
365
|
+
mount,
|
|
366
|
+
}) => {
|
|
367
|
+
// We need to introduce new lines to make sure there's
|
|
368
|
+
// enough space to show the tooltip above
|
|
369
|
+
const query = '\n\n\n\n\n\n\nRETURN abs(';
|
|
370
|
+
|
|
371
|
+
await mount(
|
|
372
|
+
<CypherEditor
|
|
373
|
+
value={query}
|
|
374
|
+
schema={testData.mockSchema}
|
|
375
|
+
showSignatureTooltipBelow={false}
|
|
376
|
+
autofocus={true}
|
|
377
|
+
/>,
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
await expect(
|
|
381
|
+
page.locator('.cm-signature-help-panel.cm-tooltip-above'),
|
|
382
|
+
).toBeVisible({
|
|
383
|
+
timeout: 10000,
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test('Signature help depends on the Cypher version', async ({
|
|
388
|
+
page,
|
|
389
|
+
mount,
|
|
390
|
+
}) => {
|
|
391
|
+
const cypher5ArgDescription = 'The Cypher 5 statement to run.';
|
|
392
|
+
const cypher25ArgDescription = 'The Cypher 25 statement to run.';
|
|
393
|
+
|
|
394
|
+
await mount(
|
|
395
|
+
<CypherEditor
|
|
396
|
+
schema={{
|
|
397
|
+
functions: {
|
|
398
|
+
'CYPHER 5': {
|
|
399
|
+
cypher5Function: {
|
|
400
|
+
...testData.emptyFunction,
|
|
401
|
+
argumentDescription: [
|
|
402
|
+
{
|
|
403
|
+
isDeprecated: false,
|
|
404
|
+
description: cypher5ArgDescription,
|
|
405
|
+
name: 'statement',
|
|
406
|
+
type: 'STRING',
|
|
407
|
+
},
|
|
408
|
+
],
|
|
409
|
+
name: 'cypher5Function',
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
'CYPHER 25': {
|
|
413
|
+
cypher25Function: {
|
|
414
|
+
...testData.emptyFunction,
|
|
415
|
+
argumentDescription: [
|
|
416
|
+
{
|
|
417
|
+
isDeprecated: false,
|
|
418
|
+
description: cypher25ArgDescription,
|
|
419
|
+
name: 'statement',
|
|
420
|
+
type: 'STRING',
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
name: 'cypher25Function',
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
}}
|
|
428
|
+
featureFlags={{ cypher25: true }}
|
|
429
|
+
/>,
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
const textField = page.getByRole('textbox');
|
|
433
|
+
await textField.fill('CYPHER 5 RETURN cypher5Function(');
|
|
434
|
+
const tooltip = page.locator('.cm-signature-help-panel');
|
|
435
|
+
|
|
436
|
+
await testTooltip(tooltip, {
|
|
437
|
+
includes: [cypher5ArgDescription],
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
await textField.fill('CYPHER 25 RETURN cypher25Function(');
|
|
441
|
+
|
|
442
|
+
await testTooltip(tooltip, {
|
|
443
|
+
includes: [cypher25ArgDescription],
|
|
444
|
+
});
|
|
445
|
+
});
|