@neo4j-cypher/react-codemirror 2.0.0-next.4 → 2.0.0-next.41

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.
Files changed (186) hide show
  1. package/CHANGELOG.md +370 -0
  2. package/README.md +3 -2
  3. package/dist/src/CypherEditor.d.ts +245 -0
  4. package/dist/src/CypherEditor.js +513 -0
  5. package/dist/src/CypherEditor.js.map +1 -0
  6. package/dist/src/CypherEditor.test.js +162 -0
  7. package/dist/src/CypherEditor.test.js.map +1 -0
  8. package/dist/src/constants.d.ts +1 -0
  9. package/dist/src/constants.js +2 -0
  10. package/dist/src/constants.js.map +1 -0
  11. package/dist/src/diffView.d.ts +13 -0
  12. package/dist/src/diffView.js +11 -0
  13. package/dist/src/diffView.js.map +1 -0
  14. package/dist/src/e2e_tests/autoCompletion.spec.js +334 -0
  15. package/dist/src/e2e_tests/autoCompletion.spec.js.map +1 -0
  16. package/dist/src/e2e_tests/configuration.spec.js +83 -0
  17. package/dist/src/e2e_tests/configuration.spec.js.map +1 -0
  18. package/dist/src/e2e_tests/debounce.spec.js +66 -0
  19. package/dist/src/e2e_tests/debounce.spec.js.map +1 -0
  20. package/dist/{types/e2e_tests/e2e-utils.d.ts → src/e2e_tests/e2eUtils.d.ts} +2 -0
  21. package/dist/src/e2e_tests/e2eUtils.js +79 -0
  22. package/dist/src/e2e_tests/e2eUtils.js.map +1 -0
  23. package/dist/src/e2e_tests/extraKeybindings.spec.js +43 -0
  24. package/dist/src/e2e_tests/extraKeybindings.spec.js.map +1 -0
  25. package/dist/src/e2e_tests/historyNavigation.spec.js +227 -0
  26. package/dist/src/e2e_tests/historyNavigation.spec.js.map +1 -0
  27. package/dist/src/e2e_tests/performanceTest.spec.d.ts +6 -0
  28. package/dist/src/e2e_tests/performanceTest.spec.js +97 -0
  29. package/dist/src/e2e_tests/performanceTest.spec.js.map +1 -0
  30. package/dist/src/e2e_tests/sanityChecks.spec.js +64 -0
  31. package/dist/src/e2e_tests/sanityChecks.spec.js.map +1 -0
  32. package/dist/src/e2e_tests/signatureHelp.spec.js +226 -0
  33. package/dist/src/e2e_tests/signatureHelp.spec.js.map +1 -0
  34. package/dist/src/e2e_tests/snippets.spec.js +14 -0
  35. package/dist/src/e2e_tests/snippets.spec.js.map +1 -0
  36. package/dist/src/e2e_tests/syntaxHighlighting.spec.d.ts +1 -0
  37. package/dist/src/e2e_tests/syntaxHighlighting.spec.js +90 -0
  38. package/dist/src/e2e_tests/syntaxHighlighting.spec.js.map +1 -0
  39. package/dist/src/e2e_tests/syntaxValidation.spec.d.ts +1 -0
  40. package/dist/src/e2e_tests/syntaxValidation.spec.js +129 -0
  41. package/dist/src/e2e_tests/syntaxValidation.spec.js.map +1 -0
  42. package/dist/src/editorActions.d.ts +17 -0
  43. package/dist/src/editorActions.js +259 -0
  44. package/dist/src/editorActions.js.map +1 -0
  45. package/dist/{types/history-navigation.d.ts → src/historyNavigation.d.ts} +1 -1
  46. package/dist/src/historyNavigation.js +163 -0
  47. package/dist/src/historyNavigation.js.map +1 -0
  48. package/dist/src/hostCallbacks.d.ts +9 -0
  49. package/dist/src/hostCallbacks.js +2 -0
  50. package/dist/src/hostCallbacks.js.map +1 -0
  51. package/dist/{types → src}/icons.d.ts +1 -1
  52. package/dist/src/icons.js +62 -0
  53. package/dist/src/icons.js.map +1 -0
  54. package/dist/src/index.d.ts +6 -0
  55. package/dist/src/index.js +5 -0
  56. package/dist/src/index.js.map +1 -0
  57. package/dist/src/inlinePanel.d.ts +27 -0
  58. package/dist/src/inlinePanel.js +86 -0
  59. package/dist/src/inlinePanel.js.map +1 -0
  60. package/dist/src/lang-cypher/autocomplete.d.ts +6 -0
  61. package/dist/src/lang-cypher/autocomplete.js +116 -0
  62. package/dist/src/lang-cypher/autocomplete.js.map +1 -0
  63. package/dist/{types → src}/lang-cypher/constants.d.ts +15 -2
  64. package/dist/src/lang-cypher/constants.js +74 -0
  65. package/dist/src/lang-cypher/constants.js.map +1 -0
  66. package/dist/src/lang-cypher/contants.test.d.ts +1 -0
  67. package/dist/src/lang-cypher/contants.test.js +103 -0
  68. package/dist/src/lang-cypher/contants.test.js.map +1 -0
  69. package/dist/{types/lang-cypher/create-cypher-theme.d.ts → src/lang-cypher/createCypherTheme.d.ts} +14 -3
  70. package/dist/src/lang-cypher/createCypherTheme.js +202 -0
  71. package/dist/src/lang-cypher/createCypherTheme.js.map +1 -0
  72. package/dist/src/lang-cypher/langCypher.d.ts +15 -0
  73. package/dist/src/lang-cypher/langCypher.js +23 -0
  74. package/dist/src/lang-cypher/langCypher.js.map +1 -0
  75. package/dist/src/lang-cypher/lintWorker.mjs +2039 -0
  76. package/dist/src/lang-cypher/parser-adapter.d.ts +21 -0
  77. package/dist/src/lang-cypher/parser-adapter.js +115 -0
  78. package/dist/src/lang-cypher/parser-adapter.js.map +1 -0
  79. package/dist/src/lang-cypher/prism-global.d.ts +1 -0
  80. package/dist/src/lang-cypher/prism-global.js +7 -0
  81. package/dist/src/lang-cypher/prism-global.js.map +1 -0
  82. package/dist/src/lang-cypher/signatureHelp.d.ts +4 -0
  83. package/dist/src/lang-cypher/signatureHelp.js +108 -0
  84. package/dist/src/lang-cypher/signatureHelp.js.map +1 -0
  85. package/dist/src/lang-cypher/syntaxValidation.d.ts +4 -0
  86. package/dist/src/lang-cypher/syntaxValidation.js +65 -0
  87. package/dist/src/lang-cypher/syntaxValidation.js.map +1 -0
  88. package/dist/src/lang-cypher/themeIcons.js +22 -0
  89. package/dist/src/lang-cypher/themeIcons.js.map +1 -0
  90. package/dist/src/lang-cypher/utils.d.ts +2 -0
  91. package/dist/src/lang-cypher/utils.js +10 -0
  92. package/dist/src/lang-cypher/utils.js.map +1 -0
  93. package/dist/src/ndlTokensCopy.d.ts +570 -0
  94. package/dist/src/ndlTokensCopy.js +571 -0
  95. package/dist/src/ndlTokensCopy.js.map +1 -0
  96. package/dist/src/ndlTokensCopy.test.d.ts +1 -0
  97. package/dist/src/ndlTokensCopy.test.js +12 -0
  98. package/dist/src/ndlTokensCopy.test.js.map +1 -0
  99. package/dist/src/neo4jSetup.d.ts +6 -0
  100. package/dist/src/neo4jSetup.js +120 -0
  101. package/dist/src/neo4jSetup.js.map +1 -0
  102. package/dist/src/richClipboardCopier.d.ts +4 -0
  103. package/dist/src/richClipboardCopier.js +78 -0
  104. package/dist/src/richClipboardCopier.js.map +1 -0
  105. package/dist/src/richClipboardCopier.test.d.ts +1 -0
  106. package/dist/src/richClipboardCopier.test.js +53 -0
  107. package/dist/src/richClipboardCopier.test.js.map +1 -0
  108. package/dist/src/themes.d.ts +5 -0
  109. package/dist/src/themes.js +107 -0
  110. package/dist/src/themes.js.map +1 -0
  111. package/dist/tsconfig.tsbuildinfo +1 -0
  112. package/package.json +64 -62
  113. package/src/CypherEditor.test.tsx +211 -0
  114. package/src/CypherEditor.tsx +586 -59
  115. package/src/constants.ts +1 -0
  116. package/src/diffView.ts +24 -0
  117. package/src/e2e_tests/autoCompletion.spec.tsx +576 -0
  118. package/src/e2e_tests/configuration.spec.tsx +111 -0
  119. package/src/e2e_tests/debounce.spec.tsx +102 -0
  120. package/src/e2e_tests/{e2e-utils.ts → e2eUtils.ts} +41 -3
  121. package/src/e2e_tests/{extra-keybindings.spec.tsx → extraKeybindings.spec.tsx} +1 -3
  122. package/src/e2e_tests/{history-navigation.spec.tsx → historyNavigation.spec.tsx} +138 -19
  123. package/src/e2e_tests/performanceTest.spec.tsx +163 -0
  124. package/src/e2e_tests/{sanity-checks.spec.tsx → sanityChecks.spec.tsx} +28 -20
  125. package/src/e2e_tests/signatureHelp.spec.tsx +442 -0
  126. package/src/e2e_tests/snippets.spec.tsx +19 -0
  127. package/src/e2e_tests/{syntax-highlighting.spec.tsx → syntaxHighlighting.spec.tsx} +26 -24
  128. package/src/e2e_tests/syntaxValidation.spec.tsx +252 -0
  129. package/src/editorActions.ts +334 -0
  130. package/src/{history-navigation.ts → historyNavigation.ts} +6 -4
  131. package/src/hostCallbacks.ts +9 -0
  132. package/src/icons.ts +3 -0
  133. package/src/index.ts +4 -2
  134. package/src/inlinePanel.ts +140 -0
  135. package/src/lang-cypher/autocomplete.ts +96 -19
  136. package/src/lang-cypher/constants.ts +35 -2
  137. package/src/lang-cypher/contants.test.ts +7 -3
  138. package/src/lang-cypher/{create-cypher-theme.ts → createCypherTheme.ts} +97 -33
  139. package/src/lang-cypher/langCypher.ts +44 -0
  140. package/src/lang-cypher/lintWorker.mjs +2039 -0
  141. package/src/lang-cypher/parser-adapter.ts +146 -0
  142. package/src/lang-cypher/prism-global.ts +7 -0
  143. package/src/lang-cypher/signatureHelp.ts +154 -0
  144. package/src/lang-cypher/syntaxValidation.ts +81 -0
  145. package/src/lang-cypher/utils.ts +9 -0
  146. package/src/{ndl-tokens-copy.test.ts → ndlTokensCopy.test.ts} +2 -1
  147. package/src/ndlTokensCopy.ts +570 -0
  148. package/src/{neo4j-setup.tsx → neo4jSetup.tsx} +79 -18
  149. package/src/richClipboardCopier.test.ts +67 -0
  150. package/src/richClipboardCopier.ts +99 -0
  151. package/src/themes.ts +63 -71
  152. package/src/viteEnv.d.ts +1 -0
  153. package/dist/cjs/index.cjs +0 -1441
  154. package/dist/cjs/index.cjs.map +0 -7
  155. package/dist/esm/index.mjs +0 -1464
  156. package/dist/esm/index.mjs.map +0 -7
  157. package/dist/types/CypherEditor.d.ts +0 -113
  158. package/dist/types/e2e_tests/mock-data.d.ts +0 -3779
  159. package/dist/types/index.d.ts +0 -4
  160. package/dist/types/lang-cypher/ParserAdapter.d.ts +0 -14
  161. package/dist/types/lang-cypher/autocomplete.d.ts +0 -3
  162. package/dist/types/lang-cypher/lang-cypher.d.ts +0 -7
  163. package/dist/types/lang-cypher/syntax-validation.d.ts +0 -3
  164. package/dist/types/ndl-tokens-copy.d.ts +0 -379
  165. package/dist/types/neo4j-setup.d.ts +0 -2
  166. package/dist/types/themes.d.ts +0 -11
  167. package/dist/types/tsconfig.tsbuildinfo +0 -1
  168. package/src/e2e_tests/auto-completion.spec.tsx +0 -232
  169. package/src/e2e_tests/mock-data.ts +0 -4310
  170. package/src/e2e_tests/performance-test.spec.tsx +0 -71
  171. package/src/e2e_tests/syntax-validation.spec.tsx +0 -156
  172. package/src/lang-cypher/ParserAdapter.ts +0 -92
  173. package/src/lang-cypher/lang-cypher.ts +0 -32
  174. package/src/lang-cypher/syntax-validation.ts +0 -24
  175. package/src/ndl-tokens-copy.ts +0 -379
  176. /package/dist/{types/e2e_tests/auto-completion.spec.d.ts → src/CypherEditor.test.d.ts} +0 -0
  177. /package/dist/{types/e2e_tests/extra-keybindings.spec.d.ts → src/e2e_tests/autoCompletion.spec.d.ts} +0 -0
  178. /package/dist/{types/e2e_tests/history-navigation.spec.d.ts → src/e2e_tests/configuration.spec.d.ts} +0 -0
  179. /package/dist/{types/e2e_tests/performance-test.spec.d.ts → src/e2e_tests/debounce.spec.d.ts} +0 -0
  180. /package/dist/{types/e2e_tests/sanity-checks.spec.d.ts → src/e2e_tests/extraKeybindings.spec.d.ts} +0 -0
  181. /package/dist/{types/e2e_tests/syntax-highlighting.spec.d.ts → src/e2e_tests/historyNavigation.spec.d.ts} +0 -0
  182. /package/dist/{types/e2e_tests/syntax-validation.spec.d.ts → src/e2e_tests/sanityChecks.spec.d.ts} +0 -0
  183. /package/dist/{types/lang-cypher/contants.test.d.ts → src/e2e_tests/signatureHelp.spec.d.ts} +0 -0
  184. /package/dist/{types/ndl-tokens-copy.test.d.ts → src/e2e_tests/snippets.spec.d.ts} +0 -0
  185. /package/dist/{types/lang-cypher/theme-icons.d.ts → src/lang-cypher/themeIcons.d.ts} +0 -0
  186. /package/src/lang-cypher/{theme-icons.ts → themeIcons.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,22 @@
1
1
  {
2
2
  "name": "@neo4j-cypher/react-codemirror",
3
+ "version": "2.0.0-next.41",
4
+ "keywords": [
5
+ "codemirror",
6
+ "codemirror 6",
7
+ "cypher",
8
+ "editor",
9
+ "neo4j",
10
+ "react"
11
+ ],
12
+ "bugs": {
13
+ "url": "https://github.com/neo4j/cypher-language-support/issues"
14
+ },
3
15
  "license": "Apache-2.0",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git://github.com/neo4j/cypher-language-support.git"
19
+ },
4
20
  "files": [
5
21
  "dist",
6
22
  "src",
@@ -9,76 +25,62 @@
9
25
  "LICENSE.md",
10
26
  "CHANGELOG.md"
11
27
  ],
12
- "keywords": [
13
- "neo4j",
14
- "cypher",
15
- "react",
16
- "editor",
17
- "codemirror",
18
- "codemirror 6"
28
+ "type": "module",
29
+ "sideEffects": [
30
+ "**/lang-cypher/prism-global.js"
19
31
  ],
20
- "version": "2.0.0-next.4",
21
- "main": "./dist/cjs/index.cjs",
22
- "module": "./dist/esm/index.mjs",
23
- "types": "./dist/types/index.d.ts",
24
- "exports": {
25
- ".": {
26
- "require": "./dist/cjs/index.cjs",
27
- "import": "./dist/esm/index.mjs",
28
- "default": "./dist/cjs/index.cjs"
29
- }
30
- },
31
- "sideEffects": false,
32
- "scripts": {
33
- "build": "concurrently 'npm:build-types' 'npm:build-esm' 'npm:build-commonjs'",
34
- "build-types": "tsc --emitDeclarationOnly --outDir dist/types",
35
- "build-esm": "esbuild ./src/index.ts --bundle --format=esm --sourcemap --packages=external --outfile=dist/esm/index.mjs",
36
- "build-commonjs": "esbuild ./src/index.ts --bundle --format=cjs --sourcemap --packages=external --outfile=dist/cjs/index.cjs",
37
- "clean": "rm -rf dist",
38
- "test": "jest",
39
- "test:e2e": "playwright test -c playwright-ct.config.ts",
40
- "test:e2e-ui": "playwright test -c playwright-ct.config.ts --ui"
41
- },
42
- "repository": {
43
- "type": "git",
44
- "url": "git://github.com/neo4j/cypher-language-support.git"
45
- },
46
- "bugs": {
47
- "url": "https://github.com/neo4j/cypher-language-support/issues"
48
- },
49
- "engineStrict": true,
50
- "engines": {
51
- "node": ">=18.18.2"
52
- },
32
+ "main": "./dist/src/index.js",
33
+ "types": "./dist/src/index.d.ts",
53
34
  "dependencies": {
54
- "@neo4j-cypher/language-support": "2.0.0-next.2",
55
- "@codemirror/autocomplete": "^6.5.1",
56
- "@codemirror/commands": "^6.2.2",
57
- "@codemirror/language": "^6.6.0",
58
- "@codemirror/lint": "^6.2.2",
59
- "@codemirror/search": "^6.5.0",
60
- "@codemirror/state": "^6.2.1",
61
- "@codemirror/view": "^6.13.2",
35
+ "@codemirror/autocomplete": "^6.18.6",
36
+ "@codemirror/commands": "^6.8.1",
37
+ "@codemirror/language": "^6.11.2",
38
+ "@codemirror/lint": "^6.8.5",
39
+ "@codemirror/merge": "^6.12.1",
40
+ "@codemirror/search": "^6.5.11",
41
+ "@codemirror/state": "^6.5.2",
42
+ "@codemirror/view": "^6.38.1",
62
43
  "@lezer/common": "^1.0.2",
63
44
  "@lezer/highlight": "^1.1.3",
64
- "ayu": "^8.0.1",
65
- "fastest-levenshtein": "^1.0.16",
66
- "vscode-languageserver-types": "^3.17.3"
45
+ "@types/prismjs": "^1.26.3",
46
+ "lodash.debounce": "^4.0.8",
47
+ "prismjs": "^1.29.0",
48
+ "style-mod": "^4.1.2",
49
+ "vscode-languageserver-types": "^3.17.3",
50
+ "workerpool": "^9.3.3",
51
+ "@neo4j-cypher/language-support": "2.0.0-next.38",
52
+ "@neo4j-cypher/lint-worker": "1.10.1-next.15"
67
53
  },
68
54
  "devDependencies": {
69
- "@neo4j-ndl/base": "^1.10.1",
70
- "@playwright/experimental-ct-react": "^1.39.0",
71
- "@playwright/test": "^1.36.2",
55
+ "@neo4j-ndl/base": "^3.2.10",
56
+ "@playwright/experimental-ct-react": "1.62.1",
57
+ "@playwright/test": "1.62.1",
58
+ "@types/lodash.debounce": "^4.0.9",
72
59
  "@types/react": "^18.0.28",
73
- "@vitejs/plugin-react": "^3.1.0",
74
- "concurrently": "^8.2.1",
75
- "esbuild": "^0.19.4",
76
- "lodash": "^4.17.21",
77
- "playwright": "^1.36.2",
60
+ "@types/react-dom": "^18.0.11",
61
+ "@vitejs/plugin-react": "^6.1.1",
62
+ "copyfiles": "^2.4.1",
63
+ "jsdom": "^24.1.1",
64
+ "playwright": "1.62.1",
78
65
  "react": "^18.2.0",
79
- "typescript": "^4.9.5"
66
+ "react-dom": "^18.2.0",
67
+ "vite": "^8.2.2"
80
68
  },
81
69
  "peerDependencies": {
82
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
70
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
71
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
72
+ },
73
+ "engines": {
74
+ "node": ">=24.11.1"
75
+ },
76
+ "scripts": {
77
+ "dev": "tsc --watch",
78
+ "build": "pnpm copy-lint-worker && tsc --declaration --outDir dist/",
79
+ "copy-lint-worker": "copyfiles -u 4 ../lint-worker/dist/esm/lintWorker.mjs dist/src/lang-cypher && copyfiles -u 4 ../lint-worker/dist/esm/lintWorker.mjs src/lang-cypher",
80
+ "clean": "rm -rf dist tsconfig*.tsbuildinfo",
81
+ "test": "vitest run",
82
+ "test:e2e": "playwright test -c playwright-ct.config.ts",
83
+ "test:e2e-ui": "playwright test -c playwright-ct.config.ts --ui",
84
+ "benchmark": "BENCHMARKING=true playwright test -c playwright-ct.config.ts -g \"benchmarking & performance test session\""
83
85
  }
84
- }
86
+ }
@@ -0,0 +1,211 @@
1
+ // @vitest-environment jsdom
2
+
3
+ import type { EditorView } from '@codemirror/view';
4
+ import { createRef } from 'react';
5
+ import { createRoot } from 'react-dom/client';
6
+ import { act } from 'react-dom/test-utils';
7
+ import { afterEach, beforeEach, expect, test, vi } from 'vitest';
8
+ import { DEBOUNCE_TIME } from './constants';
9
+ import { CypherEditor } from './CypherEditor';
10
+
11
+ const container = document.createElement('div');
12
+ let root: ReturnType<typeof createRoot>;
13
+
14
+ const ref = createRef<CypherEditor>();
15
+ let value = '';
16
+ const onChange = vi.fn<(v: string) => void>((v) => {
17
+ value = v;
18
+ rerender();
19
+ });
20
+
21
+ (global as any).IS_REACT_ACT_ENVIRONMENT = true;
22
+ const DEBOUNCE_TIME_WITH_MARGIN = DEBOUNCE_TIME + 100;
23
+
24
+ /** Avoids crash in test environment */
25
+ function mockEditorView(editorView: EditorView) {
26
+ editorView.coordsAtPos = vi
27
+ .fn<() => { left: number; top: number; right: number; bottom: number }>()
28
+ .mockReturnValue({
29
+ left: 0,
30
+ top: 0,
31
+ right: 0,
32
+ bottom: 0,
33
+ });
34
+ }
35
+
36
+ async function debounce() {
37
+ await new Promise((resolve) =>
38
+ setTimeout(resolve, DEBOUNCE_TIME_WITH_MARGIN),
39
+ );
40
+ }
41
+
42
+ function getEditorValue() {
43
+ return ref.current.editorView.current.state.doc.toString();
44
+ }
45
+
46
+ function rerender() {
47
+ act(() => {
48
+ root.render(<CypherEditor value={value} onChange={onChange} ref={ref} />);
49
+ });
50
+ }
51
+
52
+ beforeEach(() => {
53
+ root = createRoot(container);
54
+ act(() => {
55
+ root.render(<CypherEditor value={value} onChange={onChange} ref={ref} />);
56
+ });
57
+ mockEditorView(ref.current.editorView.current);
58
+ });
59
+
60
+ afterEach(() => {
61
+ act(() => {
62
+ root.unmount();
63
+ });
64
+ value = '';
65
+ vi.clearAllMocks();
66
+ });
67
+
68
+ test('editorValue updates props.value after debounce', async () => {
69
+ ref.current.setValueAndFocus('new value');
70
+ expect(onChange).not.toHaveBeenCalled();
71
+ expect(getEditorValue()).toBe('new value');
72
+ expect(value).toBe('');
73
+ await debounce();
74
+
75
+ expect(onChange).toHaveBeenCalledOnce();
76
+ expect(getEditorValue()).toBe('new value');
77
+ expect(value).toBe('new value');
78
+ });
79
+
80
+ test('editorValue updates should not be applied twice', async () => {
81
+ const dispatch = vi.spyOn(ref.current.editorView.current, 'dispatch');
82
+
83
+ ref.current.setValueAndFocus('new value');
84
+ await debounce();
85
+
86
+ expect(onChange).toHaveBeenCalledOnce();
87
+ expect(dispatch).toHaveBeenCalledOnce(); // it gets called once for the initial setValueAndFocus
88
+ });
89
+
90
+ test('props.value updates editorValue', () => {
91
+ value = 'external value';
92
+ rerender();
93
+
94
+ expect(getEditorValue()).toBe('external value');
95
+ expect(value).toBe('external value');
96
+ });
97
+
98
+ test('props.value set to undefined preserves editorValue', () => {
99
+ // 1. value is set initially
100
+ value = 'initial';
101
+ rerender();
102
+
103
+ // 2. value is set to undefined
104
+ value = undefined;
105
+ rerender();
106
+
107
+ expect(onChange).not.toHaveBeenCalled();
108
+ expect(value).toBeUndefined();
109
+ expect(getEditorValue()).toBe('initial');
110
+ });
111
+
112
+ // This test documents unexpected behaviour:
113
+ // value updates (from outside onExecute) are overwritten by pending updates.
114
+ test('new props.value should cancel onChange', async () => {
115
+ // 1. value is updated internally
116
+ ref.current.setValueAndFocus('update');
117
+
118
+ // 2. editor is rerendered with a new value while a value update is still pending
119
+ // the update to 'new external value' is overwritten by the pending update to 'update'
120
+ value = 'new external value';
121
+ rerender();
122
+
123
+ await debounce();
124
+
125
+ // NOTE: These assertions currently check for the WRONG behavior (they are inverted).
126
+ expect(onChange).toHaveBeenCalled();
127
+ expect(getEditorValue()).not.toBe('new external value');
128
+ expect(value).not.toBe('new external value');
129
+ });
130
+
131
+ // This test documents unexpected behaviour:
132
+ // value updates (from outside onExecute) are overwritten by pending updates
133
+ test('new props.value set to same value should cancel onChange', async () => {
134
+ // 1. value is set initially
135
+ value = 'same value';
136
+ rerender();
137
+
138
+ // 2. value is updated internally
139
+ ref.current.setValueAndFocus('update');
140
+
141
+ // 3. editor is rerendered with a new value while a value update is still pending
142
+ // the update to 'same value' is overwritten by the pending update to 'update'
143
+ value = 'same value';
144
+ rerender();
145
+
146
+ await debounce();
147
+
148
+ // NOTE: These assertions currently check for the WRONG behavior (they are inverted).
149
+ expect(onChange).toHaveBeenCalled();
150
+ expect(getEditorValue()).not.toBe('same value');
151
+ expect(value).not.toBe('same value');
152
+ });
153
+
154
+ test('rerender should not cancel onChange', async () => {
155
+ // 1. value is updated internally
156
+ ref.current.setValueAndFocus('changed');
157
+
158
+ // 2. editor is rerendered while a value update is still pending
159
+ rerender();
160
+
161
+ await debounce();
162
+
163
+ expect(onChange).toHaveBeenCalledOnce();
164
+ expect(getEditorValue()).toBe('changed');
165
+ expect(value).toBe('changed');
166
+ });
167
+
168
+ test('rerender with a previous update should not cancel onChange', async () => {
169
+ // 1. value is updated internally
170
+ ref.current.setValueAndFocus('changed');
171
+ await debounce();
172
+
173
+ // 2. value is updated internally again
174
+ ref.current.setValueAndFocus('new change');
175
+
176
+ // 3. editor is rerendered while a value update is still pending
177
+ rerender();
178
+
179
+ await debounce();
180
+
181
+ expect(onChange).toHaveBeenCalledTimes(2);
182
+ expect(getEditorValue()).toBe('new change');
183
+ expect(value).toBe('new change');
184
+ });
185
+
186
+ test('rerender with prior external update should not cancel onChange', async () => {
187
+ // 1. value is set initially
188
+ ref.current.setValueAndFocus('initial');
189
+ await debounce();
190
+
191
+ // 2. value is updated externally
192
+ value = 'external update';
193
+ rerender();
194
+
195
+ // 3. value is updated internally
196
+ ref.current.setValueAndFocus('internal update');
197
+
198
+ // 4. editor is rerendered while a value update is still pending
199
+ rerender();
200
+
201
+ await debounce();
202
+
203
+ expect(getEditorValue()).toBe('internal update');
204
+ expect(value).toBe('internal update');
205
+ });
206
+
207
+ test('setValueAndFocus should handle CRLF newline characters', () => {
208
+ expect(() =>
209
+ ref.current.setValueAndFocus('new value\r\nnew line'),
210
+ ).not.toThrow();
211
+ });