@neo4j-cypher/react-codemirror 2.0.0-next.7 → 2.0.0-next.9
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 +26 -0
- package/dist/CypherEditor.d.ts +60 -2
- package/dist/CypherEditor.js +115 -20
- package/dist/CypherEditor.js.map +1 -1
- package/dist/e2e_tests/autoCompletion.spec.js +112 -17
- package/dist/e2e_tests/autoCompletion.spec.js.map +1 -1
- 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 +63 -0
- package/dist/e2e_tests/debounce.spec.js.map +1 -0
- package/dist/e2e_tests/e2eUtils.js +9 -1
- package/dist/e2e_tests/e2eUtils.js.map +1 -1
- package/dist/e2e_tests/extraKeybindings.spec.js +0 -1
- package/dist/e2e_tests/extraKeybindings.spec.js.map +1 -1
- package/dist/e2e_tests/historyNavigation.spec.js +107 -16
- package/dist/e2e_tests/historyNavigation.spec.js.map +1 -1
- package/dist/e2e_tests/sanityChecks.spec.js +0 -10
- package/dist/e2e_tests/sanityChecks.spec.js.map +1 -1
- package/dist/e2e_tests/signatureHelp.spec.js +43 -15
- package/dist/e2e_tests/signatureHelp.spec.js.map +1 -1
- 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.js +0 -1
- package/dist/e2e_tests/syntaxHighlighting.spec.js.map +1 -1
- package/dist/e2e_tests/syntaxValidation.spec.js +3 -3
- package/dist/e2e_tests/syntaxValidation.spec.js.map +1 -1
- package/dist/historyNavigation.js +1 -1
- package/dist/historyNavigation.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lang-cypher/autocomplete.d.ts +4 -1
- package/dist/lang-cypher/autocomplete.js +79 -17
- package/dist/lang-cypher/autocomplete.js.map +1 -1
- package/dist/lang-cypher/contants.test.js +2 -2
- package/dist/lang-cypher/contants.test.js.map +1 -1
- package/dist/lang-cypher/createCypherTheme.js +34 -2
- package/dist/lang-cypher/createCypherTheme.js.map +1 -1
- package/dist/lang-cypher/langCypher.d.ts +5 -0
- package/dist/lang-cypher/langCypher.js +11 -5
- package/dist/lang-cypher/langCypher.js.map +1 -1
- package/dist/lang-cypher/signatureHelp.js +39 -22
- package/dist/lang-cypher/signatureHelp.js.map +1 -1
- 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/neo4jSetup.js +35 -1
- package/dist/neo4jSetup.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/CypherEditor.tsx +233 -31
- package/src/e2e_tests/autoCompletion.spec.tsx +189 -18
- package/src/e2e_tests/configuration.spec.tsx +111 -0
- package/src/e2e_tests/debounce.spec.tsx +100 -0
- package/src/e2e_tests/e2eUtils.ts +11 -1
- package/src/e2e_tests/extraKeybindings.spec.tsx +0 -2
- package/src/e2e_tests/historyNavigation.spec.tsx +136 -17
- package/src/e2e_tests/sanityChecks.spec.tsx +0 -16
- package/src/e2e_tests/signatureHelp.spec.tsx +86 -18
- package/src/e2e_tests/snippets.spec.tsx +92 -0
- package/src/e2e_tests/syntaxHighlighting.spec.tsx +0 -2
- package/src/e2e_tests/syntaxValidation.spec.tsx +3 -3
- package/src/historyNavigation.ts +1 -1
- package/src/index.ts +4 -1
- package/src/lang-cypher/autocomplete.ts +95 -19
- package/src/lang-cypher/contants.test.ts +5 -2
- package/src/lang-cypher/createCypherTheme.ts +34 -2
- package/src/lang-cypher/langCypher.ts +17 -5
- package/src/lang-cypher/signatureHelp.ts +61 -30
- package/src/lang-cypher/utils.ts +9 -0
- package/src/neo4jSetup.tsx +51 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/experimental-ct-react';
|
|
2
|
+
import { CypherEditor } from '../CypherEditor';
|
|
3
|
+
|
|
4
|
+
test('prompt shows up', async ({ mount, page }) => {
|
|
5
|
+
const component = await mount(<CypherEditor prompt="neo4j>" />);
|
|
6
|
+
|
|
7
|
+
await expect(component).toContainText('neo4j>');
|
|
8
|
+
|
|
9
|
+
await component.update(<CypherEditor prompt="test>" />);
|
|
10
|
+
await expect(component).toContainText('test>');
|
|
11
|
+
|
|
12
|
+
const textField = page.getByRole('textbox');
|
|
13
|
+
await textField.press('a');
|
|
14
|
+
|
|
15
|
+
await expect(textField).toHaveText('a');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('line numbers can be turned on/off', async ({ mount }) => {
|
|
19
|
+
const component = await mount(<CypherEditor lineNumbers />);
|
|
20
|
+
|
|
21
|
+
await expect(component).toContainText('1');
|
|
22
|
+
|
|
23
|
+
await component.update(<CypherEditor lineNumbers={false} />);
|
|
24
|
+
await expect(component).not.toContainText('1');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('can configure readonly', async ({ mount, page }) => {
|
|
28
|
+
const component = await mount(<CypherEditor readonly />);
|
|
29
|
+
|
|
30
|
+
const textField = page.getByRole('textbox');
|
|
31
|
+
await textField.press('a');
|
|
32
|
+
await expect(textField).not.toHaveText('a');
|
|
33
|
+
|
|
34
|
+
await component.update(<CypherEditor readonly={false} />);
|
|
35
|
+
await textField.press('b');
|
|
36
|
+
await expect(textField).toHaveText('b');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('can set placeholder ', async ({ mount, page }) => {
|
|
40
|
+
const component = await mount(<CypherEditor placeholder="bulbasaur" />);
|
|
41
|
+
|
|
42
|
+
const textField = page.getByRole('textbox');
|
|
43
|
+
await expect(textField).toHaveText('bulbasaur');
|
|
44
|
+
|
|
45
|
+
await component.update(<CypherEditor placeholder="venusaur" />);
|
|
46
|
+
await expect(textField).not.toHaveText('bulbasaur');
|
|
47
|
+
await expect(textField).toHaveText('venusaur');
|
|
48
|
+
|
|
49
|
+
await textField.fill('abc');
|
|
50
|
+
await expect(textField).not.toHaveText('venusaur');
|
|
51
|
+
await expect(textField).toHaveText('abc');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('can set/unset onFocus/onBlur', async ({ mount, page }) => {
|
|
55
|
+
const component = await mount(<CypherEditor />);
|
|
56
|
+
|
|
57
|
+
let focusFireCount = 0;
|
|
58
|
+
let blurFireCount = 0;
|
|
59
|
+
|
|
60
|
+
const focus = () => {
|
|
61
|
+
focusFireCount += 1;
|
|
62
|
+
};
|
|
63
|
+
const blur = () => {
|
|
64
|
+
blurFireCount += 1;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await component.update(<CypherEditor domEventHandlers={{ blur, focus }} />);
|
|
68
|
+
|
|
69
|
+
const textField = page.getByRole('textbox');
|
|
70
|
+
await textField.click();
|
|
71
|
+
await expect(textField).toBeFocused();
|
|
72
|
+
|
|
73
|
+
// this is to give the events time to fire
|
|
74
|
+
await expect(() => {
|
|
75
|
+
expect(focusFireCount).toBe(1);
|
|
76
|
+
expect(blurFireCount).toBe(0);
|
|
77
|
+
}).toPass();
|
|
78
|
+
|
|
79
|
+
await textField.blur();
|
|
80
|
+
|
|
81
|
+
await expect(() => {
|
|
82
|
+
expect(focusFireCount).toBe(1);
|
|
83
|
+
expect(blurFireCount).toBe(1);
|
|
84
|
+
}).toPass();
|
|
85
|
+
|
|
86
|
+
await component.update(<CypherEditor />);
|
|
87
|
+
await textField.click();
|
|
88
|
+
await expect(textField).toBeFocused();
|
|
89
|
+
await textField.blur();
|
|
90
|
+
|
|
91
|
+
await expect(() => {
|
|
92
|
+
expect(focusFireCount).toBe(1);
|
|
93
|
+
expect(blurFireCount).toBe(1);
|
|
94
|
+
}).toPass();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('aria-label is not set by default', async ({ mount, page }) => {
|
|
98
|
+
await mount(<CypherEditor />);
|
|
99
|
+
|
|
100
|
+
const textField = page.getByRole('textbox');
|
|
101
|
+
expect(await textField.getAttribute('aria-label')).toBeNull();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('can set aria-label', async ({ mount, page }) => {
|
|
105
|
+
const ariaLabel = 'Cypher Editor';
|
|
106
|
+
|
|
107
|
+
await mount(<CypherEditor ariaLabel={ariaLabel} />);
|
|
108
|
+
|
|
109
|
+
const textField = page.getByRole('textbox');
|
|
110
|
+
expect(await textField.getAttribute('aria-label')).toEqual(ariaLabel);
|
|
111
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/experimental-ct-react';
|
|
2
|
+
import { CypherEditor } from '../CypherEditor';
|
|
3
|
+
import { CypherEditorPage } from './e2eUtils';
|
|
4
|
+
|
|
5
|
+
const DEBOUNCE_TIMER = 200;
|
|
6
|
+
|
|
7
|
+
test('external updates should override debounced updates', async ({
|
|
8
|
+
mount,
|
|
9
|
+
page,
|
|
10
|
+
}) => {
|
|
11
|
+
const editorPage = new CypherEditorPage(page);
|
|
12
|
+
let value = '';
|
|
13
|
+
|
|
14
|
+
const onChange = (val: string) => {
|
|
15
|
+
value = val;
|
|
16
|
+
void component.update(<CypherEditor value={val} onChange={onChange} />);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const component = await mount(
|
|
20
|
+
<CypherEditor value={value} onChange={onChange} />,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
await editorPage.getEditor().pressSequentially('RETURN 1');
|
|
24
|
+
onChange('foo');
|
|
25
|
+
await page.waitForTimeout(DEBOUNCE_TIMER);
|
|
26
|
+
await expect(component).toContainText('foo');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('onExecute updates should override debounce updates', async ({
|
|
30
|
+
mount,
|
|
31
|
+
page,
|
|
32
|
+
}) => {
|
|
33
|
+
const editorPage = new CypherEditorPage(page);
|
|
34
|
+
let value = '';
|
|
35
|
+
|
|
36
|
+
const onExecute = () => {
|
|
37
|
+
value = '';
|
|
38
|
+
void component.update(
|
|
39
|
+
<CypherEditor value={value} onChange={onChange} onExecute={onExecute} />,
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const onChange = (val: string) => {
|
|
44
|
+
value = val;
|
|
45
|
+
void component.update(
|
|
46
|
+
<CypherEditor value={val} onChange={onChange} onExecute={onExecute} />,
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const component = await mount(
|
|
51
|
+
<CypherEditor value={value} onChange={onChange} onExecute={onExecute} />,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
await editorPage.getEditor().pressSequentially('RETURN 1');
|
|
55
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
56
|
+
await page.waitForTimeout(DEBOUNCE_TIMER);
|
|
57
|
+
await expect(component).not.toContainText('RETURN 1');
|
|
58
|
+
|
|
59
|
+
await editorPage.getEditor().pressSequentially('RETURN 1');
|
|
60
|
+
await editorPage.getEditor().pressSequentially('');
|
|
61
|
+
await editorPage.getEditor().pressSequentially('RETURN 1');
|
|
62
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
63
|
+
await page.waitForTimeout(DEBOUNCE_TIMER);
|
|
64
|
+
await expect(component).not.toContainText('RETURN 1');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test('onExecute should fire after debounced updates', async ({
|
|
68
|
+
mount,
|
|
69
|
+
page,
|
|
70
|
+
}) => {
|
|
71
|
+
const editorPage = new CypherEditorPage(page);
|
|
72
|
+
let value = '';
|
|
73
|
+
let executedCommand = '';
|
|
74
|
+
|
|
75
|
+
const onExecute = (cmd: string) => {
|
|
76
|
+
executedCommand = cmd;
|
|
77
|
+
void component.update(
|
|
78
|
+
<CypherEditor value={value} onChange={onChange} onExecute={onExecute} />,
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const onChange = (val: string) => {
|
|
83
|
+
value = val;
|
|
84
|
+
void component.update(
|
|
85
|
+
<CypherEditor value={val} onChange={onChange} onExecute={onExecute} />,
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const component = await mount(
|
|
90
|
+
<CypherEditor value={value} onChange={onChange} onExecute={onExecute} />,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
await editorPage.getEditor().fill('RETURN 1');
|
|
94
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
95
|
+
await editorPage.getEditor().fill('RETURN 2');
|
|
96
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
97
|
+
await page.waitForTimeout(DEBOUNCE_TIMER);
|
|
98
|
+
await expect(component).toContainText('RETURN 2');
|
|
99
|
+
expect(executedCommand).toBe('RETURN 2');
|
|
100
|
+
});
|
|
@@ -65,11 +65,21 @@ export class CypherEditorPage {
|
|
|
65
65
|
expectedMsg: string,
|
|
66
66
|
) {
|
|
67
67
|
await expect(this.page.locator('.cm-lintRange-' + type).last()).toBeVisible(
|
|
68
|
-
{ timeout:
|
|
68
|
+
{ timeout: 3000 },
|
|
69
69
|
);
|
|
70
70
|
|
|
71
71
|
await this.page.getByText(queryChunk, { exact: true }).hover();
|
|
72
72
|
await expect(this.page.locator('.cm-tooltip-hover').last()).toBeVisible();
|
|
73
73
|
await expect(this.page.getByText(expectedMsg)).toBeVisible();
|
|
74
|
+
/* Return the mouse to the beginning of the query and
|
|
75
|
+
This is because if for example we have an overlay with a
|
|
76
|
+
first interaction that covers the element we want to perform
|
|
77
|
+
the second interaction on, we won't be able to see that second element
|
|
78
|
+
*/
|
|
79
|
+
await this.page.mouse.move(0, 0);
|
|
80
|
+
// Make the sure the tooltip closed
|
|
81
|
+
await expect(
|
|
82
|
+
this.page.locator('.cm-tooltip-hover').last(),
|
|
83
|
+
).not.toBeVisible();
|
|
74
84
|
}
|
|
75
85
|
}
|
|
@@ -2,8 +2,6 @@ import { expect, test } from '@playwright/experimental-ct-react';
|
|
|
2
2
|
import { CypherEditor } from '../CypherEditor';
|
|
3
3
|
import { CypherEditorPage } from './e2eUtils';
|
|
4
4
|
|
|
5
|
-
test.use({ viewport: { width: 500, height: 500 } });
|
|
6
|
-
|
|
7
5
|
test('can add extra keybinding statically', async ({ mount, page }) => {
|
|
8
6
|
const editorPage = new CypherEditorPage(page);
|
|
9
7
|
let hasRun = false;
|
|
@@ -2,8 +2,6 @@ import { expect, test } from '@playwright/experimental-ct-react';
|
|
|
2
2
|
import { CypherEditor } from '../CypherEditor';
|
|
3
3
|
import { CypherEditorPage } from './e2eUtils';
|
|
4
4
|
|
|
5
|
-
test.use({ viewport: { width: 500, height: 500 } });
|
|
6
|
-
|
|
7
5
|
test('respects preloaded history', async ({ page, mount }) => {
|
|
8
6
|
const editorPage = new CypherEditorPage(page);
|
|
9
7
|
|
|
@@ -27,13 +25,75 @@ test('respects preloaded history', async ({ page, mount }) => {
|
|
|
27
25
|
await editorPage.getEditor().press('ArrowUp');
|
|
28
26
|
await expect(page.getByText('second')).toBeVisible();
|
|
29
27
|
|
|
28
|
+
// First arrow down is to get to end of line
|
|
29
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
30
30
|
await editorPage.getEditor().press('ArrowDown');
|
|
31
31
|
await expect(page.getByText('first')).toBeVisible();
|
|
32
32
|
await editorPage.getEditor().press('ArrowDown');
|
|
33
33
|
await expect(page.getByText(initialValue)).toBeVisible();
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
test('can
|
|
36
|
+
test('can add new lines without onExecute', async ({ page, mount }) => {
|
|
37
|
+
const editorPage = new CypherEditorPage(page);
|
|
38
|
+
|
|
39
|
+
const editorComponent = await mount(<CypherEditor />);
|
|
40
|
+
|
|
41
|
+
// Ctrl-Enter does nothing when onExecute is false
|
|
42
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
43
|
+
await expect(editorComponent).toHaveText('1\n', {
|
|
44
|
+
useInnerText: true,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Enter adds new lines
|
|
48
|
+
await editorPage.getEditor().fill('Brock');
|
|
49
|
+
await editorPage.getEditor().press('Enter');
|
|
50
|
+
await editorPage.getEditor().press('Enter');
|
|
51
|
+
await expect(editorComponent).toHaveText('1\n2\n3\nBrock', {
|
|
52
|
+
useInnerText: true,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Shift-Enter adds new lines
|
|
56
|
+
await editorPage.getEditor().press('Shift+Enter');
|
|
57
|
+
await editorPage.getEditor().press('Shift+Enter');
|
|
58
|
+
await expect(editorComponent).toHaveText('1\n2\n3\n4\n5\nBrock', {
|
|
59
|
+
useInnerText: true,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('can add new lines with newLineOnEnter and without onExecute', async ({
|
|
64
|
+
page,
|
|
65
|
+
mount,
|
|
66
|
+
}) => {
|
|
67
|
+
const editorPage = new CypherEditorPage(page);
|
|
68
|
+
|
|
69
|
+
const editorComponent = await mount(<CypherEditor newLineOnEnter />);
|
|
70
|
+
|
|
71
|
+
// Ctrl-Enter does nothing when onExecute is false
|
|
72
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
73
|
+
await expect(editorComponent).toHaveText('1\n', {
|
|
74
|
+
useInnerText: true,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Enter adds new lines
|
|
78
|
+
await editorPage.getEditor().fill('Brock');
|
|
79
|
+
await editorPage.getEditor().press('Enter');
|
|
80
|
+
await editorPage.getEditor().press('Enter');
|
|
81
|
+
await expect(editorComponent).toHaveText('1\n2\n3\nBrock', {
|
|
82
|
+
useInnerText: true,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Shift-Enter adds new lines
|
|
86
|
+
await editorPage.getEditor().press('Shift+Enter');
|
|
87
|
+
await editorPage.getEditor().press('Shift+Enter');
|
|
88
|
+
await expect(editorComponent).toHaveText('1\n2\n3\n4\n5\nBrock', {
|
|
89
|
+
useInnerText: true,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('can execute queries and see them in history with newLineOnEnter', async ({
|
|
94
|
+
page,
|
|
95
|
+
mount,
|
|
96
|
+
}) => {
|
|
37
97
|
const editorPage = new CypherEditorPage(page);
|
|
38
98
|
|
|
39
99
|
const initialValue = `MATCH (n)
|
|
@@ -49,6 +109,7 @@ RETURN n;`;
|
|
|
49
109
|
value={initialValue}
|
|
50
110
|
history={history}
|
|
51
111
|
onExecute={onExecute}
|
|
112
|
+
newLineOnEnter
|
|
52
113
|
/>,
|
|
53
114
|
);
|
|
54
115
|
|
|
@@ -63,12 +124,12 @@ RETURN n;`;
|
|
|
63
124
|
await editorPage.getEditor().press('Meta+Enter');
|
|
64
125
|
expect(history.length).toBe(1);
|
|
65
126
|
|
|
66
|
-
// Ensure
|
|
127
|
+
// Ensure cmd+enter is required in multiline
|
|
67
128
|
await editorPage.getEditor().fill('multiline');
|
|
68
129
|
await editorPage.getEditor().press('Enter');
|
|
69
130
|
await editorPage.getEditor().press('Enter');
|
|
70
131
|
await editorPage.getEditor().press('Enter');
|
|
71
|
-
await editorPage.getEditor().press('Enter');
|
|
132
|
+
await editorPage.getEditor().press('Shift+Enter');
|
|
72
133
|
await page.keyboard.type('entry');
|
|
73
134
|
expect(history.length).toBe(1);
|
|
74
135
|
|
|
@@ -102,10 +163,15 @@ RETURN n;`;
|
|
|
102
163
|
await expect(page.getByText('multiline')).toBeVisible();
|
|
103
164
|
|
|
104
165
|
// arrow movements don't matter until bottom is hit
|
|
166
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
167
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
105
168
|
await editorPage.getEditor().press('ArrowUp');
|
|
106
169
|
await editorPage.getEditor().press('ArrowUp');
|
|
107
170
|
await editorPage.getEditor().press('ArrowDown');
|
|
108
171
|
await editorPage.getEditor().press('ArrowDown');
|
|
172
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
173
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
174
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
109
175
|
|
|
110
176
|
// editor still multiline
|
|
111
177
|
await expect(page.getByText('multiline')).toBeVisible();
|
|
@@ -115,6 +181,59 @@ RETURN n;`;
|
|
|
115
181
|
await expect(page.getByText('draft')).toBeVisible();
|
|
116
182
|
});
|
|
117
183
|
|
|
184
|
+
test('can execute queries without newLineOnEnter', async ({ page, mount }) => {
|
|
185
|
+
const editorPage = new CypherEditorPage(page);
|
|
186
|
+
|
|
187
|
+
const initialValue = 'Brock';
|
|
188
|
+
|
|
189
|
+
const history: string[] = [];
|
|
190
|
+
const onExecute = (cmd: string) => {
|
|
191
|
+
history.unshift(cmd);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const editorComponent = await mount(
|
|
195
|
+
<CypherEditor value={initialValue} onExecute={onExecute} />,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
// Cmd/Control still executes initial query
|
|
199
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
200
|
+
await editorPage.getEditor().press('Meta+Enter');
|
|
201
|
+
expect(history.length).toBe(1);
|
|
202
|
+
|
|
203
|
+
// Ensure query execution doesn't fire if the query is only whitespace
|
|
204
|
+
await editorPage.getEditor().fill(' ');
|
|
205
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
206
|
+
await editorPage.getEditor().press('Meta+Enter');
|
|
207
|
+
await editorPage.getEditor().press('Enter');
|
|
208
|
+
expect(history.length).toBe(1);
|
|
209
|
+
|
|
210
|
+
// Ensure enter executes query when in single line
|
|
211
|
+
await editorPage.getEditor().fill('Misty');
|
|
212
|
+
await editorPage.getEditor().press('Enter');
|
|
213
|
+
expect(history.length).toBe(2);
|
|
214
|
+
expect(history).toEqual(['Misty', 'Brock']);
|
|
215
|
+
|
|
216
|
+
// Ensure cmd+enter is required in multiline
|
|
217
|
+
await editorPage.getEditor().fill('multiline');
|
|
218
|
+
await editorPage.getEditor().press('Shift+Enter');
|
|
219
|
+
await editorPage.getEditor().press('Enter');
|
|
220
|
+
await editorPage.getEditor().press('A');
|
|
221
|
+
|
|
222
|
+
// line numbers and the text
|
|
223
|
+
await expect(editorComponent).toHaveText('1\n2\n3\nmultiline\nA', {
|
|
224
|
+
useInnerText: true,
|
|
225
|
+
});
|
|
226
|
+
await editorPage.getEditor().press('Enter');
|
|
227
|
+
await editorPage.getEditor().press('Enter');
|
|
228
|
+
await editorPage.getEditor().press('Enter');
|
|
229
|
+
await editorPage.getEditor().press('Enter');
|
|
230
|
+
expect(history.length).toBe(2);
|
|
231
|
+
|
|
232
|
+
await editorPage.getEditor().press('Control+Enter');
|
|
233
|
+
await editorPage.getEditor().press('Meta+Enter');
|
|
234
|
+
expect(history.length).toBe(3);
|
|
235
|
+
});
|
|
236
|
+
|
|
118
237
|
test('can navigate with cmd+up as well', async ({ page, mount }) => {
|
|
119
238
|
const editorPage = new CypherEditorPage(page);
|
|
120
239
|
const isMac = process.platform === 'darwin';
|
|
@@ -127,11 +246,11 @@ test('can navigate with cmd+up as well', async ({ page, mount }) => {
|
|
|
127
246
|
<CypherEditor
|
|
128
247
|
value={initialValue}
|
|
129
248
|
history={[
|
|
249
|
+
'first',
|
|
130
250
|
`one
|
|
131
251
|
multiline
|
|
132
252
|
entry
|
|
133
253
|
.`,
|
|
134
|
-
'second',
|
|
135
254
|
]}
|
|
136
255
|
onExecute={() => {
|
|
137
256
|
/* needed to turn on history movements */
|
|
@@ -139,24 +258,24 @@ entry
|
|
|
139
258
|
/>,
|
|
140
259
|
);
|
|
141
260
|
|
|
261
|
+
await editorPage.getEditor().press(metaUp);
|
|
262
|
+
await expect(page.getByText('first')).toBeVisible();
|
|
263
|
+
|
|
264
|
+
// move in history
|
|
142
265
|
await editorPage.getEditor().press(metaUp);
|
|
143
266
|
await expect(page.getByText('multiline')).toBeVisible();
|
|
144
267
|
|
|
145
|
-
// Single meta
|
|
268
|
+
// Single meta down moves all the way to top of editor on mac
|
|
146
269
|
if (isMac) {
|
|
147
|
-
await editorPage.getEditor().press(
|
|
270
|
+
await editorPage.getEditor().press(metaDown);
|
|
148
271
|
} else {
|
|
149
|
-
await editorPage.getEditor().press('
|
|
150
|
-
await editorPage.getEditor().press('
|
|
151
|
-
await editorPage.getEditor().press('
|
|
152
|
-
await editorPage.getEditor().press('
|
|
272
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
273
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
274
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
275
|
+
await editorPage.getEditor().press('ArrowDown');
|
|
153
276
|
}
|
|
154
|
-
// move in history
|
|
155
|
-
await editorPage.getEditor().press(metaUp);
|
|
156
|
-
await expect(page.getByText('second')).toBeVisible();
|
|
157
|
-
|
|
158
277
|
await editorPage.getEditor().press(metaDown);
|
|
159
|
-
await expect(page.getByText('
|
|
278
|
+
await expect(page.getByText('first')).toBeVisible();
|
|
160
279
|
});
|
|
161
280
|
|
|
162
281
|
test('test onExecute', async ({ page, mount }) => {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { expect, test } from '@playwright/experimental-ct-react';
|
|
2
2
|
import { CypherEditor } from '../CypherEditor';
|
|
3
3
|
|
|
4
|
-
test.use({ viewport: { width: 500, height: 500 } });
|
|
5
|
-
|
|
6
4
|
test('can mount the editor with text', async ({ mount }) => {
|
|
7
5
|
const component = await mount(<CypherEditor value="MATCH (n) RETURN n;" />);
|
|
8
6
|
|
|
@@ -76,17 +74,3 @@ test('can complete CALL/CREATE', async ({ page, mount }) => {
|
|
|
76
74
|
|
|
77
75
|
await expect(textField).toHaveText('CALL');
|
|
78
76
|
});
|
|
79
|
-
|
|
80
|
-
test('prompt shows up', async ({ mount, page }) => {
|
|
81
|
-
const component = await mount(<CypherEditor prompt="neo4j>" />);
|
|
82
|
-
|
|
83
|
-
await expect(component).toContainText('neo4j>');
|
|
84
|
-
|
|
85
|
-
await component.update(<CypherEditor prompt="test>" />);
|
|
86
|
-
await expect(component).toContainText('test>');
|
|
87
|
-
|
|
88
|
-
const textField = page.getByRole('textbox');
|
|
89
|
-
await textField.press('a');
|
|
90
|
-
|
|
91
|
-
await expect(textField).toHaveText('a');
|
|
92
|
-
});
|