@joinezco/markdown-editor 0.0.3 → 0.0.5
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/.turbo/turbo-build.log +1 -1
- package/.vitest-attachments/191c5ac00ef68f41dab054113c3cfe7c5fa0f29c.png +0 -0
- package/.vitest-attachments/2d964ac96925db03e3f5b6f229ad2728d612b3fb.png +0 -0
- package/.vitest-attachments/4acd142a2d0a0c0540fc4d74925054d52b537980.png +0 -0
- package/.vitest-attachments/5cc628ad0cab3b550b2e25b88de53ab9ec8d4f11.png +0 -0
- package/.vitest-attachments/8f6e01234099b8ca51ff0aa029923ff59ba00b0f.png +0 -0
- package/.vitest-attachments/a9caa7012ce500be895d1cc484dd577dc3162ada.png +0 -0
- package/.vitest-attachments/c110ea1993512d3fc47f8b3768b5adaa5221c21f.png +0 -0
- package/.vitest-attachments/c1a5f1644502d507eba379d7a6e188e64475b059.png +0 -0
- package/dist/editor/extensions/codeblock.js +70 -29
- package/dist/editor/index.js +23 -0
- package/dist/editor/styles.js +8 -0
- package/package.json +21 -21
- package/public/fonts/UbuntuMonoNerdFont-Regular.ttf +0 -0
- package/public/snapshot.bin +0 -0
- package/src/lib/editor/extensions/bullet-to-task.test.ts +5 -14
- package/src/lib/editor/extensions/codeblock.ts +77 -32
- package/src/lib/editor/index.ts +23 -0
- package/src/lib/editor/styles.ts +8 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Formatting-should-handle-code-blocks-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Selection-and-Cursor-Management-should-handle-cursor-positioning-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Code-Block-Extension-should-handle-code-blocks-without-language-specification-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Code-Block-Extension-should-handle-different-programming-languages-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Code-Block-Extension-should-render-code-blocks-with-syntax-highlighting-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Extension-Interactions-should-handle-multiple-extensions-working-together-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-File-System-Integration-should-handle-file-references-in-code-blocks-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Table-Extension-should-render-tables-correctly-1.png +0 -0
- package/src/test/editor.test.ts +12 -8
- package/src/test/extensions.test.ts +33 -44
- package/src/test/multiview-sync.test.ts +137 -0
- package/vitest.config.ts +56 -9
- package/TEST_README.md +0 -359
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Basic-Editor-Functionality-should-be-focusable-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Basic-Editor-Functionality-should-have-initial-content-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Basic-Editor-Functionality-should-render-in-the-DOM-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Browser-specific-Features-should-handle-copy-and-paste-operations-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Browser-specific-Features-should-handle-undo-and-redo-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Editor-State-and-Updates-should-maintain-state-across-content-changes-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Editor-State-and-Updates-should-trigger-update-callbacks-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Error-Handling-should-handle-invalid-markdown-gracefully-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Error-Handling-should-handle-very-long-content-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Keyboard-Shortcuts-should-handle-Ctrl-B-for-bold-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Keyboard-Shortcuts-should-handle-Ctrl-I-for-italic-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Content-Management-should-get-markdown-content-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Content-Management-should-handle-empty-content-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Content-Management-should-set-markdown-content-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Formatting-should-handle-bold-text-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Formatting-should-handle-headings-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Formatting-should-handle-inline-code-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Formatting-should-handle-italic-text-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Formatting-should-handle-lists-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Markdown-Formatting-should-handle-task-lists-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Selection-and-Cursor-Management-should-set-and-get-selection-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Text-Input-and-Editing-should-handle-line-breaks-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Text-Input-and-Editing-should-handle-typing-at-different-positions-1.png +0 -0
- package/src/test/__screenshots__/editor.test.ts/MarkdownEditor-Text-Input-and-Editing-should-insert-text-at-cursor-position-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Code-Block-Extension-should-handle-inline-code-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Extension-Interactions-should-maintain-editor-state-across-complex-operations-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-File-System-Integration-should-maintain-file-system-state-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Link-Extension-should-auto-detect-URLs-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Link-Extension-should-handle-email-links-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Link-Extension-should-render-links-correctly-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Markdown-Storage-should-provide-markdown-storage-interface-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Markdown-Storage-should-sync-markdown-content-with-storage-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Slash-Commands-Extension-should-handle-heading-commands-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Slash-Commands-Extension-should-trigger-slash-commands-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Table-Extension-should-handle-table-navigation-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Task-List-Extension-should-handle-nested-task-lists-1.png +0 -0
- package/src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Task-List-Extension-should-toggle-task-completion-1.png +0 -0
- /package/{src/test/__screenshots__/editor.test.ts/MarkdownEditor-Basic-Editor-Functionality-should-create-an-editor-instance-1.png → .vitest-attachments/1ffc226577cf810f92353973baca01fa249e8090.png} +0 -0
- /package/{src/test/__screenshots__/extensions.test.ts/MarkdownEditor-Extensions-Task-List-Extension-should-render-task-lists-correctly-1.png → .vitest-attachments/caef333e04ddcbe3101c10bd6058ff3b8da894d1.png} +0 -0
|
@@ -96,25 +96,18 @@ describe('MarkdownEditor Extensions', () => {
|
|
|
96
96
|
const table = editor.view.dom.querySelector('table')
|
|
97
97
|
expect(table).toBeTruthy()
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
expect(thead).toBeTruthy()
|
|
102
|
-
expect(tbody).toBeTruthy()
|
|
103
|
-
|
|
104
|
-
const headers = thead?.querySelectorAll('th')
|
|
99
|
+
// Tiptap renders header cells as <th> directly in <tr>, without <thead>/<tbody> wrappers
|
|
100
|
+
const headers = table?.querySelectorAll('th')
|
|
105
101
|
expect(headers?.length).toBe(3)
|
|
106
102
|
expect(headers?.[0].textContent?.trim()).toBe('Header 1')
|
|
107
103
|
expect(headers?.[1].textContent?.trim()).toBe('Header 2')
|
|
108
104
|
expect(headers?.[2].textContent?.trim()).toBe('Header 3')
|
|
109
105
|
|
|
110
|
-
const
|
|
111
|
-
expect(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
expect(
|
|
115
|
-
expect(firstRowCells?.[0].textContent?.trim()).toBe('Cell 1')
|
|
116
|
-
expect(firstRowCells?.[1].textContent?.trim()).toBe('Cell 2')
|
|
117
|
-
expect(firstRowCells?.[2].textContent?.trim()).toBe('Cell 3')
|
|
106
|
+
const dataCells = table?.querySelectorAll('td')
|
|
107
|
+
expect(dataCells?.length).toBe(6)
|
|
108
|
+
expect(dataCells?.[0].textContent?.trim()).toBe('Cell 1')
|
|
109
|
+
expect(dataCells?.[1].textContent?.trim()).toBe('Cell 2')
|
|
110
|
+
expect(dataCells?.[2].textContent?.trim()).toBe('Cell 3')
|
|
118
111
|
})
|
|
119
112
|
|
|
120
113
|
it('should handle table navigation', () => {
|
|
@@ -181,38 +174,33 @@ describe('MarkdownEditor Extensions', () => {
|
|
|
181
174
|
const codeBlock = '```javascript\nfunction hello() {\n console.log("Hello, World!");\n}\n```'
|
|
182
175
|
editor.commands.setContent(codeBlock)
|
|
183
176
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
expect(
|
|
189
|
-
expect(
|
|
190
|
-
expect(codeContent).toContain('Hello, World!')
|
|
177
|
+
// Code blocks render via CodeMirror node view, not <pre>
|
|
178
|
+
const json = editor.getJSON()
|
|
179
|
+
const codeNode = json.content?.find((n: any) => n.type === 'ezcodeBlock' || n.type === 'codeBlock')
|
|
180
|
+
expect(codeNode).toBeTruthy()
|
|
181
|
+
expect(codeNode?.attrs?.language).toBe('javascript')
|
|
182
|
+
expect(codeNode?.content?.[0]?.text).toContain('function hello')
|
|
191
183
|
})
|
|
192
184
|
|
|
193
185
|
it('should handle different programming languages', () => {
|
|
194
186
|
const pythonCode = '```python\ndef hello():\n print("Hello, World!")\n```'
|
|
195
187
|
editor.commands.setContent(pythonCode)
|
|
196
188
|
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
expect(
|
|
202
|
-
expect(codeContent).toContain('print')
|
|
203
|
-
expect(codeContent).toContain('Hello, World!')
|
|
189
|
+
const json = editor.getJSON()
|
|
190
|
+
const codeNode = json.content?.find((n: any) => n.type === 'ezcodeBlock' || n.type === 'codeBlock')
|
|
191
|
+
expect(codeNode).toBeTruthy()
|
|
192
|
+
expect(codeNode?.attrs?.language).toBe('python')
|
|
193
|
+
expect(codeNode?.content?.[0]?.text).toContain('def hello')
|
|
204
194
|
})
|
|
205
195
|
|
|
206
196
|
it('should handle code blocks without language specification', () => {
|
|
207
197
|
const plainCode = '```\nplain text code\nno syntax highlighting\n```'
|
|
208
198
|
editor.commands.setContent(plainCode)
|
|
209
199
|
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
expect(codeContent).toContain('plain text code')
|
|
215
|
-
expect(codeContent).toContain('no syntax highlighting')
|
|
200
|
+
const json = editor.getJSON()
|
|
201
|
+
const codeNode = json.content?.find((n: any) => n.type === 'ezcodeBlock' || n.type === 'codeBlock')
|
|
202
|
+
expect(codeNode).toBeTruthy()
|
|
203
|
+
expect(codeNode?.content?.[0]?.text).toContain('plain text code')
|
|
216
204
|
})
|
|
217
205
|
|
|
218
206
|
it('should handle inline code', () => {
|
|
@@ -242,12 +230,12 @@ describe('MarkdownEditor Extensions', () => {
|
|
|
242
230
|
const fileReference = '```src/example.js\nconsole.log("File content");\n```'
|
|
243
231
|
editor.commands.setContent(fileReference)
|
|
244
232
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
expect(
|
|
250
|
-
expect(
|
|
233
|
+
// Verify via JSON — CodeMirror node view doesn't render <pre>
|
|
234
|
+
const json = editor.getJSON()
|
|
235
|
+
const codeNode = json.content?.find((n: any) => n.type === 'ezcodeBlock' || n.type === 'codeBlock')
|
|
236
|
+
expect(codeNode).toBeTruthy()
|
|
237
|
+
expect(codeNode?.content?.[0]?.text).toContain('console.log')
|
|
238
|
+
expect(codeNode?.content?.[0]?.text).toContain('File content')
|
|
251
239
|
})
|
|
252
240
|
|
|
253
241
|
it('should maintain file system state', () => {
|
|
@@ -313,10 +301,11 @@ Visit [our website](https://example.com) for more info.`
|
|
|
313
301
|
expect(editor.view.dom.querySelector('[data-checked="false"]')).toBeTruthy()
|
|
314
302
|
expect(editor.view.dom.querySelector('[data-checked="true"]')).toBeTruthy()
|
|
315
303
|
|
|
316
|
-
// Code blocks
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
expect(
|
|
304
|
+
// Code blocks (verified via JSON since CodeMirror node view replaces <pre>)
|
|
305
|
+
const json = editor.getJSON()
|
|
306
|
+
const codeNode = json.content?.find((n: any) => n.type === 'ezcodeBlock' || n.type === 'codeBlock')
|
|
307
|
+
expect(codeNode).toBeTruthy()
|
|
308
|
+
expect(codeNode?.content?.[0]?.text).toContain('function example')
|
|
320
309
|
|
|
321
310
|
// Tables
|
|
322
311
|
const table = editor.view.dom.querySelector('table')
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { fileChangeBus } from '@joinezco/codeblock'
|
|
3
|
+
import { EditorView } from '@codemirror/view'
|
|
4
|
+
import { EditorState } from '@codemirror/state'
|
|
5
|
+
|
|
6
|
+
describe('FileChangeBus', () => {
|
|
7
|
+
let viewA: EditorView
|
|
8
|
+
let viewB: EditorView
|
|
9
|
+
let containerA: HTMLElement
|
|
10
|
+
let containerB: HTMLElement
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
containerA = document.createElement('div')
|
|
14
|
+
containerB = document.createElement('div')
|
|
15
|
+
document.body.appendChild(containerA)
|
|
16
|
+
document.body.appendChild(containerB)
|
|
17
|
+
|
|
18
|
+
viewA = new EditorView({
|
|
19
|
+
state: EditorState.create({ doc: 'initial' }),
|
|
20
|
+
parent: containerA,
|
|
21
|
+
})
|
|
22
|
+
viewB = new EditorView({
|
|
23
|
+
state: EditorState.create({ doc: 'initial' }),
|
|
24
|
+
parent: containerB,
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
viewA.destroy()
|
|
30
|
+
viewB.destroy()
|
|
31
|
+
containerA.remove()
|
|
32
|
+
containerB.remove()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should notify other subscribers but not the source', () => {
|
|
36
|
+
const received: { view: string; content: string }[] = []
|
|
37
|
+
|
|
38
|
+
fileChangeBus.subscribe('test.txt', viewA, (content) => {
|
|
39
|
+
received.push({ view: 'A', content })
|
|
40
|
+
})
|
|
41
|
+
fileChangeBus.subscribe('test.txt', viewB, (content) => {
|
|
42
|
+
received.push({ view: 'B', content })
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Notify from view A — only B should receive
|
|
46
|
+
fileChangeBus.notify('test.txt', 'hello from A', viewA)
|
|
47
|
+
|
|
48
|
+
expect(received).toEqual([{ view: 'B', content: 'hello from A' }])
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('should not notify after unsubscribe', () => {
|
|
52
|
+
const received: string[] = []
|
|
53
|
+
|
|
54
|
+
const unsub = fileChangeBus.subscribe('test.txt', viewA, (content) => {
|
|
55
|
+
received.push(content)
|
|
56
|
+
})
|
|
57
|
+
fileChangeBus.subscribe('test.txt', viewB, () => {})
|
|
58
|
+
|
|
59
|
+
unsub()
|
|
60
|
+
fileChangeBus.notify('test.txt', 'hello', viewB)
|
|
61
|
+
|
|
62
|
+
expect(received).toEqual([])
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should handle multiple files independently', () => {
|
|
66
|
+
const received: string[] = []
|
|
67
|
+
|
|
68
|
+
fileChangeBus.subscribe('a.txt', viewA, (content) => {
|
|
69
|
+
received.push('a:' + content)
|
|
70
|
+
})
|
|
71
|
+
fileChangeBus.subscribe('b.txt', viewA, (content) => {
|
|
72
|
+
received.push('b:' + content)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
fileChangeBus.notify('a.txt', 'one', viewB)
|
|
76
|
+
fileChangeBus.notify('b.txt', 'two', viewB)
|
|
77
|
+
|
|
78
|
+
expect(received).toEqual(['a:one', 'b:two'])
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('should sync document content between views via the bus', () => {
|
|
82
|
+
// Simulate two views on the same file using the bus to sync
|
|
83
|
+
|
|
84
|
+
const unsubA = fileChangeBus.subscribe('shared.txt', viewA, (content) => {
|
|
85
|
+
if (viewA.state.doc.toString() !== content) {
|
|
86
|
+
viewA.dispatch({ changes: { from: 0, to: viewA.state.doc.length, insert: content } })
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
const unsubB = fileChangeBus.subscribe('shared.txt', viewB, (content) => {
|
|
90
|
+
if (viewB.state.doc.toString() !== content) {
|
|
91
|
+
viewB.dispatch({ changes: { from: 0, to: viewB.state.doc.length, insert: content } })
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Edit view A and "save" (notify the bus)
|
|
96
|
+
viewA.dispatch({ changes: { from: 0, to: viewA.state.doc.length, insert: 'updated content' } })
|
|
97
|
+
fileChangeBus.notify('shared.txt', 'updated content', viewA)
|
|
98
|
+
|
|
99
|
+
// View B should have received the update
|
|
100
|
+
expect(viewB.state.doc.toString()).toBe('updated content')
|
|
101
|
+
// View A should NOT have been re-dispatched (it was the source)
|
|
102
|
+
expect(viewA.state.doc.toString()).toBe('updated content')
|
|
103
|
+
|
|
104
|
+
unsubA()
|
|
105
|
+
unsubB()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('should not create infinite loops when both views subscribe', () => {
|
|
109
|
+
let dispatchCountA = 0
|
|
110
|
+
let dispatchCountB = 0
|
|
111
|
+
|
|
112
|
+
fileChangeBus.subscribe('shared.txt', viewA, (content) => {
|
|
113
|
+
if (viewA.state.doc.toString() !== content) {
|
|
114
|
+
dispatchCountA++
|
|
115
|
+
viewA.dispatch({ changes: { from: 0, to: viewA.state.doc.length, insert: content } })
|
|
116
|
+
// In the real codeblockView, this dispatch would NOT trigger save because
|
|
117
|
+
// receivingExternalUpdate is true. So we do NOT re-notify.
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
fileChangeBus.subscribe('shared.txt', viewB, (content) => {
|
|
121
|
+
if (viewB.state.doc.toString() !== content) {
|
|
122
|
+
dispatchCountB++
|
|
123
|
+
viewB.dispatch({ changes: { from: 0, to: viewB.state.doc.length, insert: content } })
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// Simulate save from A
|
|
128
|
+
viewA.dispatch({ changes: { from: 0, to: viewA.state.doc.length, insert: 'final' } })
|
|
129
|
+
fileChangeBus.notify('shared.txt', 'final', viewA)
|
|
130
|
+
|
|
131
|
+
// Only B should have dispatched once
|
|
132
|
+
expect(dispatchCountA).toBe(0)
|
|
133
|
+
expect(dispatchCountB).toBe(1)
|
|
134
|
+
expect(viewA.state.doc.toString()).toBe('final')
|
|
135
|
+
expect(viewB.state.doc.toString()).toBe('final')
|
|
136
|
+
})
|
|
137
|
+
})
|
package/vitest.config.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineConfig } from 'vitest/config'
|
|
2
|
+
import { playwright } from '@vitest/browser-playwright'
|
|
2
3
|
import path from 'path'
|
|
3
4
|
|
|
4
5
|
export default defineConfig({
|
|
@@ -6,15 +7,17 @@ export default defineConfig({
|
|
|
6
7
|
// Enable browser testing
|
|
7
8
|
browser: {
|
|
8
9
|
enabled: true,
|
|
9
|
-
|
|
10
|
-
provider: 'playwright',
|
|
11
|
-
// Headless mode for CI, can be disabled for debugging
|
|
10
|
+
provider: playwright(),
|
|
12
11
|
headless: true,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
instances: [
|
|
13
|
+
{
|
|
14
|
+
browser: 'chromium',
|
|
15
|
+
viewport: {
|
|
16
|
+
width: 1280,
|
|
17
|
+
height: 720,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
],
|
|
18
21
|
},
|
|
19
22
|
// Test environment setup
|
|
20
23
|
environment: 'happy-dom',
|
|
@@ -51,9 +54,53 @@ export default defineConfig({
|
|
|
51
54
|
'@/lib': path.resolve(__dirname, './src/lib'),
|
|
52
55
|
},
|
|
53
56
|
},
|
|
54
|
-
//
|
|
57
|
+
// @joinezco/codeblock is a workspace link — exclude it from optimization so
|
|
58
|
+
// Vite serves its source directly. Its transitive deps must be listed with
|
|
59
|
+
// the "package > dep" syntax so Vite can resolve them through the excluded package.
|
|
55
60
|
optimizeDeps: {
|
|
56
61
|
exclude: ['@joinezco/codeblock'],
|
|
62
|
+
include: [
|
|
63
|
+
'@joinezco/codeblock > @codemirror/autocomplete',
|
|
64
|
+
'@joinezco/codeblock > @codemirror/commands',
|
|
65
|
+
'@joinezco/codeblock > @codemirror/lang-cpp',
|
|
66
|
+
'@joinezco/codeblock > @codemirror/lang-css',
|
|
67
|
+
'@joinezco/codeblock > @codemirror/lang-html',
|
|
68
|
+
'@joinezco/codeblock > @codemirror/lang-java',
|
|
69
|
+
'@joinezco/codeblock > @codemirror/lang-javascript',
|
|
70
|
+
'@joinezco/codeblock > @codemirror/lang-less',
|
|
71
|
+
'@joinezco/codeblock > @codemirror/lang-markdown',
|
|
72
|
+
'@joinezco/codeblock > @codemirror/lang-php',
|
|
73
|
+
'@joinezco/codeblock > @codemirror/lang-python',
|
|
74
|
+
'@joinezco/codeblock > @codemirror/lang-rust',
|
|
75
|
+
'@joinezco/codeblock > @codemirror/lang-sass',
|
|
76
|
+
'@joinezco/codeblock > @codemirror/lang-sql',
|
|
77
|
+
'@joinezco/codeblock > @codemirror/lang-xml',
|
|
78
|
+
'@joinezco/codeblock > @codemirror/lang-yaml',
|
|
79
|
+
'@joinezco/codeblock > @codemirror/language',
|
|
80
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/clike',
|
|
81
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/cmake',
|
|
82
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/dockerfile',
|
|
83
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/go',
|
|
84
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/haskell',
|
|
85
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/lua',
|
|
86
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/perl',
|
|
87
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/properties',
|
|
88
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/ruby',
|
|
89
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/shell',
|
|
90
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/swift',
|
|
91
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/toml',
|
|
92
|
+
'@joinezco/codeblock > @codemirror/legacy-modes/mode/vb',
|
|
93
|
+
'@joinezco/codeblock > @codemirror/lint',
|
|
94
|
+
'@joinezco/codeblock > @codemirror/search',
|
|
95
|
+
'@joinezco/codeblock > @lezer/highlight',
|
|
96
|
+
'@joinezco/codeblock > @m234/nerd-fonts/fs',
|
|
97
|
+
'@joinezco/codeblock > @volar/language-service',
|
|
98
|
+
'@joinezco/codeblock > comlink',
|
|
99
|
+
'@joinezco/codeblock > lodash',
|
|
100
|
+
'@joinezco/codeblock > minisearch',
|
|
101
|
+
'@joinezco/codeblock > path-browserify',
|
|
102
|
+
'marked',
|
|
103
|
+
],
|
|
57
104
|
},
|
|
58
105
|
// Server configuration for tests
|
|
59
106
|
server: {
|