@prosekit/core 0.8.2 → 0.8.4

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 (168) hide show
  1. package/dist/editor-CfkZ4TNU.d.ts +748 -0
  2. package/dist/editor-CfkZ4TNU.d.ts.map +1 -0
  3. package/dist/{editor-DbMrpnmL.js → editor-CizSwUN8.js} +102 -192
  4. package/dist/editor-CizSwUN8.js.map +1 -0
  5. package/dist/prosekit-core-test.d.ts +20 -19
  6. package/dist/prosekit-core-test.d.ts.map +1 -0
  7. package/dist/prosekit-core-test.js +4 -5
  8. package/dist/prosekit-core-test.js.map +1 -0
  9. package/dist/prosekit-core.d.ts +782 -757
  10. package/dist/prosekit-core.d.ts.map +1 -0
  11. package/dist/prosekit-core.js +30 -45
  12. package/dist/prosekit-core.js.map +1 -0
  13. package/package.json +14 -11
  14. package/src/commands/add-mark.ts +53 -0
  15. package/src/commands/expand-mark.ts +96 -0
  16. package/src/commands/insert-default-block.spec.ts +102 -0
  17. package/src/commands/insert-default-block.ts +49 -0
  18. package/src/commands/insert-node.ts +71 -0
  19. package/src/commands/insert-text.ts +24 -0
  20. package/src/commands/remove-mark.ts +54 -0
  21. package/src/commands/remove-node.ts +43 -0
  22. package/src/commands/select-all.ts +16 -0
  23. package/src/commands/set-block-type.ts +64 -0
  24. package/src/commands/set-node-attrs.ts +68 -0
  25. package/src/commands/toggle-mark.ts +65 -0
  26. package/src/commands/toggle-node.ts +47 -0
  27. package/src/commands/toggle-wrap.spec.ts +35 -0
  28. package/src/commands/toggle-wrap.ts +42 -0
  29. package/src/commands/unset-block-type.spec.ts +49 -0
  30. package/src/commands/unset-block-type.ts +84 -0
  31. package/src/commands/unset-mark.spec.ts +35 -0
  32. package/src/commands/unset-mark.ts +38 -0
  33. package/src/commands/wrap.ts +50 -0
  34. package/src/editor/action.spec.ts +143 -0
  35. package/src/editor/action.ts +248 -0
  36. package/src/editor/editor.spec.ts +186 -0
  37. package/src/editor/editor.ts +563 -0
  38. package/src/editor/union.spec.ts +108 -0
  39. package/src/editor/union.ts +47 -0
  40. package/src/editor/with-priority.ts +25 -0
  41. package/src/error.ts +28 -0
  42. package/src/extensions/clipboard-serializer.ts +107 -0
  43. package/src/extensions/command.ts +121 -0
  44. package/src/extensions/default-state.spec.ts +60 -0
  45. package/src/extensions/default-state.ts +76 -0
  46. package/src/extensions/doc.ts +31 -0
  47. package/src/extensions/events/doc-change.ts +34 -0
  48. package/src/extensions/events/dom-event.spec.ts +70 -0
  49. package/src/extensions/events/dom-event.ts +117 -0
  50. package/src/extensions/events/editor-event.ts +293 -0
  51. package/src/extensions/events/focus.spec.ts +50 -0
  52. package/src/extensions/events/focus.ts +28 -0
  53. package/src/extensions/events/plugin-view.ts +132 -0
  54. package/src/extensions/history.ts +81 -0
  55. package/src/extensions/keymap-base.ts +60 -0
  56. package/src/extensions/keymap.spec.ts +89 -0
  57. package/src/extensions/keymap.ts +96 -0
  58. package/src/extensions/mark-spec.spec.ts +177 -0
  59. package/src/extensions/mark-spec.ts +181 -0
  60. package/src/extensions/mark-view-effect.ts +85 -0
  61. package/src/extensions/mark-view.ts +43 -0
  62. package/src/extensions/node-spec.spec.ts +224 -0
  63. package/src/extensions/node-spec.ts +199 -0
  64. package/src/extensions/node-view-effect.ts +85 -0
  65. package/src/extensions/node-view.ts +43 -0
  66. package/src/extensions/paragraph.ts +61 -0
  67. package/src/extensions/plugin.ts +91 -0
  68. package/src/extensions/text.ts +34 -0
  69. package/src/facets/base-extension.ts +54 -0
  70. package/src/facets/command.ts +21 -0
  71. package/src/facets/facet-extension.spec.ts +173 -0
  72. package/src/facets/facet-extension.ts +53 -0
  73. package/src/facets/facet-node.spec.ts +265 -0
  74. package/src/facets/facet-node.ts +185 -0
  75. package/src/facets/facet-types.ts +9 -0
  76. package/src/facets/facet.spec.ts +76 -0
  77. package/src/facets/facet.ts +84 -0
  78. package/src/facets/root.ts +44 -0
  79. package/src/facets/schema-spec.ts +30 -0
  80. package/src/facets/schema.ts +26 -0
  81. package/src/facets/state.ts +57 -0
  82. package/src/facets/union-extension.ts +41 -0
  83. package/src/index.ts +302 -0
  84. package/src/test/index.ts +4 -0
  85. package/src/test/test-builder.ts +68 -0
  86. package/src/test/test-editor.spec.ts +104 -0
  87. package/src/test/test-editor.ts +113 -0
  88. package/src/testing/index.ts +283 -0
  89. package/src/testing/keyboard.ts +5 -0
  90. package/src/types/any-function.ts +4 -0
  91. package/src/types/assert-type-equal.ts +8 -0
  92. package/src/types/attrs.ts +32 -0
  93. package/src/types/base-node-view-options.ts +33 -0
  94. package/src/types/dom-node.ts +1 -0
  95. package/src/types/extension-command.ts +52 -0
  96. package/src/types/extension-mark.ts +15 -0
  97. package/src/types/extension-node.ts +15 -0
  98. package/src/types/extension.spec.ts +56 -0
  99. package/src/types/extension.ts +168 -0
  100. package/src/types/model.ts +54 -0
  101. package/src/types/object-entries.ts +13 -0
  102. package/src/types/pick-string-literal.spec.ts +10 -0
  103. package/src/types/pick-string-literal.ts +6 -0
  104. package/src/types/pick-sub-type.spec.ts +20 -0
  105. package/src/types/pick-sub-type.ts +6 -0
  106. package/src/types/priority.ts +12 -0
  107. package/src/types/setter.ts +4 -0
  108. package/src/types/simplify-deeper.spec.ts +40 -0
  109. package/src/types/simplify-deeper.ts +6 -0
  110. package/src/types/simplify-union.spec.ts +21 -0
  111. package/src/types/simplify-union.ts +11 -0
  112. package/src/utils/array-grouping.spec.ts +29 -0
  113. package/src/utils/array-grouping.ts +25 -0
  114. package/src/utils/array.ts +21 -0
  115. package/src/utils/assert.ts +13 -0
  116. package/src/utils/attrs-match.ts +20 -0
  117. package/src/utils/can-use-regex-lookbehind.ts +12 -0
  118. package/src/utils/clsx.spec.ts +14 -0
  119. package/src/utils/clsx.ts +12 -0
  120. package/src/utils/collect-children.ts +21 -0
  121. package/src/utils/collect-nodes.ts +37 -0
  122. package/src/utils/combine-event-handlers.spec.ts +27 -0
  123. package/src/utils/combine-event-handlers.ts +27 -0
  124. package/src/utils/contains-inline-node.ts +17 -0
  125. package/src/utils/deep-equals.spec.ts +26 -0
  126. package/src/utils/deep-equals.ts +29 -0
  127. package/src/utils/default-block-at.ts +15 -0
  128. package/src/utils/editor-content.spec.ts +47 -0
  129. package/src/utils/editor-content.ts +77 -0
  130. package/src/utils/env.ts +6 -0
  131. package/src/utils/find-parent-node-of-type.ts +29 -0
  132. package/src/utils/find-parent-node.spec.ts +68 -0
  133. package/src/utils/find-parent-node.ts +55 -0
  134. package/src/utils/get-custom-selection.ts +19 -0
  135. package/src/utils/get-dom-api.ts +56 -0
  136. package/src/utils/get-id.spec.ts +14 -0
  137. package/src/utils/get-id.ts +13 -0
  138. package/src/utils/get-mark-type.ts +20 -0
  139. package/src/utils/get-node-type.ts +20 -0
  140. package/src/utils/get-node-types.ts +19 -0
  141. package/src/utils/includes-mark.ts +18 -0
  142. package/src/utils/is-at-block-start.ts +26 -0
  143. package/src/utils/is-in-code-block.ts +18 -0
  144. package/src/utils/is-mark-absent.spec.ts +53 -0
  145. package/src/utils/is-mark-absent.ts +42 -0
  146. package/src/utils/is-mark-active.ts +27 -0
  147. package/src/utils/is-node-active.ts +25 -0
  148. package/src/utils/is-subset.spec.ts +12 -0
  149. package/src/utils/is-subset.ts +11 -0
  150. package/src/utils/maybe-run.spec.ts +39 -0
  151. package/src/utils/maybe-run.ts +11 -0
  152. package/src/utils/merge-objects.spec.ts +30 -0
  153. package/src/utils/merge-objects.ts +11 -0
  154. package/src/utils/merge-specs.ts +35 -0
  155. package/src/utils/object-equal.spec.ts +26 -0
  156. package/src/utils/object-equal.ts +28 -0
  157. package/src/utils/output-spec.test.ts +95 -0
  158. package/src/utils/output-spec.ts +130 -0
  159. package/src/utils/parse.spec.ts +46 -0
  160. package/src/utils/parse.ts +321 -0
  161. package/src/utils/remove-undefined-values.spec.ts +15 -0
  162. package/src/utils/remove-undefined-values.ts +9 -0
  163. package/src/utils/set-selection-around.ts +11 -0
  164. package/src/utils/type-assertion.ts +91 -0
  165. package/src/utils/unicode.spec.ts +10 -0
  166. package/src/utils/unicode.ts +4 -0
  167. package/src/utils/with-skip-code-block.ts +15 -0
  168. package/dist/editor-CjVyjJqw.d.ts +0 -739
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @internal
3
+ */
4
+ export function maybeRun<
5
+ Value,
6
+ Args extends unknown[],
7
+ >(value: Value | ((...args: Args) => Value), ...args: Args): Value {
8
+ return typeof value === 'function'
9
+ ? (value as (...args: Args) => Value)(...args)
10
+ : value
11
+ }
@@ -0,0 +1,30 @@
1
+ import {
2
+ expect,
3
+ test,
4
+ } from 'vitest'
5
+
6
+ import { mergeObjects } from './merge-objects'
7
+
8
+ // basic merge
9
+ test('merge simple objects', () => {
10
+ const a = { a: 1 }
11
+ const b = { b: 2 }
12
+ expect(
13
+ mergeObjects<{ a: number; b: number }>(a, b),
14
+ ).toEqual({ a: 1, b: 2 })
15
+ })
16
+
17
+ // undefined values should be removed and overwritten
18
+ test('skip undefined values and override', () => {
19
+ const a = { a: 1, b: undefined as number | undefined }
20
+ const b = { b: 2 }
21
+ expect(
22
+ mergeObjects<{ a: number; b: number | undefined }>(a, b),
23
+ ).toEqual({ a: 1, b: 2 })
24
+ })
25
+
26
+ // null or undefined arguments should be ignored
27
+ test('ignore null and undefined inputs', () => {
28
+ const a = { a: 1 }
29
+ expect(mergeObjects(null, undefined, a)).toEqual({ a: 1 })
30
+ })
@@ -0,0 +1,11 @@
1
+ import { removeUndefinedValues } from './remove-undefined-values'
2
+ import { isNotNullish } from './type-assertion'
3
+
4
+ export function mergeObjects<T extends object>(
5
+ ...objects: Array<Partial<T> | null | undefined>
6
+ ): Partial<T> {
7
+ const filteredObjects = objects
8
+ .filter(isNotNullish)
9
+ .map(removeUndefinedValues)
10
+ return Object.assign({}, ...filteredObjects) as Partial<T>
11
+ }
@@ -0,0 +1,35 @@
1
+ import type {
2
+ MarkSpec,
3
+ NodeSpec,
4
+ } from '@prosekit/pm/model'
5
+
6
+ import { mergeObjects } from './merge-objects'
7
+
8
+ function mergeSpecs(a: NodeSpec, b: NodeSpec): NodeSpec
9
+ function mergeSpecs(a: MarkSpec, b: MarkSpec): MarkSpec
10
+ function mergeSpecs(
11
+ a: NodeSpec | MarkSpec,
12
+ b: NodeSpec | MarkSpec,
13
+ ): NodeSpec | MarkSpec {
14
+ type T = typeof a
15
+
16
+ const attrs: T['attrs'] = {}
17
+ const attrNames = new Set([
18
+ ...Object.keys(a.attrs ?? {}),
19
+ ...Object.keys(b.attrs ?? {}),
20
+ ])
21
+ for (const name of attrNames) {
22
+ const attrSpecA = a.attrs?.[name]
23
+ const attrSpecB = b.attrs?.[name]
24
+ const attrSpecMerged = mergeObjects(attrSpecA, attrSpecB)
25
+ if (attrSpecMerged) {
26
+ attrs[name] = attrSpecMerged
27
+ }
28
+ }
29
+
30
+ const parseDOM: T['parseDOM'] = [...(a.parseDOM ?? []), ...(b.parseDOM ?? [])]
31
+
32
+ return mergeObjects<T>(a, b, { attrs, parseDOM })
33
+ }
34
+
35
+ export { mergeSpecs }
@@ -0,0 +1,26 @@
1
+ import {
2
+ expect,
3
+ test,
4
+ } from 'vitest'
5
+
6
+ import { objectEqual } from './object-equal'
7
+
8
+ test('objects with same keys and values are equal', () => {
9
+ expect(objectEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true)
10
+ })
11
+
12
+ test('different keys result in inequality', () => {
13
+ expect(objectEqual({ a: 1, b: 2 }, { a: 1, c: 2 })).toBe(false)
14
+ })
15
+
16
+ test('nested objects are compared recursively', () => {
17
+ const obj1 = { a: { c: 3 }, b: 2 }
18
+ const obj2 = { a: { c: 3 }, b: 2 }
19
+ expect(objectEqual(obj1, obj2)).toBe(true)
20
+ })
21
+
22
+ test('nested objects with different values are not equal', () => {
23
+ const obj1 = { a: { c: 3 }, b: 2 }
24
+ const obj2 = { a: { c: 4 }, b: 2 }
25
+ expect(objectEqual(obj1, obj2)).toBe(false)
26
+ })
@@ -0,0 +1,28 @@
1
+ export function objectEqual<T>(a: T, b: T): boolean {
2
+ if (a === b) {
3
+ return true
4
+ }
5
+ if (typeof a !== 'object' || typeof b !== 'object') {
6
+ return false
7
+ }
8
+ if (a === null || b === null) {
9
+ return false
10
+ }
11
+ if (Array.isArray(a) || Array.isArray(b)) {
12
+ return false
13
+ }
14
+ const aKeys = Object.keys(a) as (keyof T)[]
15
+ const bKeys = Object.keys(b) as (keyof T)[]
16
+ if (aKeys.length !== bKeys.length) {
17
+ return false
18
+ }
19
+ for (const key of aKeys) {
20
+ if (!bKeys.includes(key)) {
21
+ return false
22
+ }
23
+ if (!objectEqual(a[key], b[key])) {
24
+ return false
25
+ }
26
+ }
27
+ return true
28
+ }
@@ -0,0 +1,95 @@
1
+ import type { DOMOutputSpec } from '@prosekit/pm/model'
2
+ import {
3
+ describe,
4
+ expect,
5
+ it,
6
+ } from 'vitest'
7
+
8
+ import { insertOutputSpecAttrs } from './output-spec'
9
+
10
+ describe('insertOutputSpecAttrs', () => {
11
+ it('should insert attrs into an array without attributes', () => {
12
+ const spec: DOMOutputSpec = ['input']
13
+ const result = insertOutputSpecAttrs(spec, [
14
+ ['data-foo', 'foo'],
15
+ ['checked', ''],
16
+ ['style', 'background-color: red'],
17
+ ['style', 'color: blue'],
18
+ ])
19
+ expect(result).toMatchInlineSnapshot(`
20
+ [
21
+ "input",
22
+ {
23
+ "checked": "",
24
+ "data-foo": "foo",
25
+ "style": "color: blue; background-color: red",
26
+ },
27
+ ]
28
+ `)
29
+ })
30
+
31
+ it('should insert attrs into an array with attributes', () => {
32
+ const spec: DOMOutputSpec = ['input', { type: 'checkbox' }]
33
+ const result = insertOutputSpecAttrs(spec, [
34
+ ['data-foo', 'foo'],
35
+ ['checked', ''],
36
+ ['style', 'background-color: red'],
37
+ ['style', 'color: blue'],
38
+ ])
39
+ expect(result).toMatchInlineSnapshot(`
40
+ [
41
+ "input",
42
+ {
43
+ "checked": "",
44
+ "data-foo": "foo",
45
+ "style": "color: blue; background-color: red",
46
+ "type": "checkbox",
47
+ },
48
+ ]
49
+ `)
50
+ })
51
+
52
+ it('should insert attrs into an element', () => {
53
+ const element = document.createElement('input')
54
+ element.type = 'checkbox'
55
+
56
+ const spec: DOMOutputSpec = element
57
+ const result = insertOutputSpecAttrs(spec, [
58
+ ['data-foo', 'foo'],
59
+ ['checked', ''],
60
+ ['style', 'background-color: red'],
61
+ ['style', 'color: blue'],
62
+ ])
63
+ expect(result).toMatchInlineSnapshot(`
64
+ <input
65
+ checked=""
66
+ data-foo="foo"
67
+ style="color: blue; background-color: red"
68
+ type="checkbox"
69
+ />
70
+ `)
71
+ })
72
+
73
+ it('should insert attrs into an object ', () => {
74
+ const element = document.createElement('input')
75
+ element.type = 'checkbox'
76
+
77
+ const spec: DOMOutputSpec = { dom: element }
78
+ const result = insertOutputSpecAttrs(spec, [
79
+ ['data-foo', 'foo'],
80
+ ['checked', ''],
81
+ ['style', 'background-color: red'],
82
+ ['style', 'color: blue'],
83
+ ])
84
+ expect(result).toMatchInlineSnapshot(`
85
+ {
86
+ "dom": <input
87
+ checked=""
88
+ data-foo="foo"
89
+ style="color: blue; background-color: red"
90
+ type="checkbox"
91
+ />,
92
+ }
93
+ `)
94
+ })
95
+ })
@@ -0,0 +1,130 @@
1
+ import { isElementLike } from '@ocavue/utils'
2
+ import type {
3
+ DOMOutputSpec,
4
+ Mark,
5
+ ProseMirrorNode,
6
+ TagParseRule,
7
+ } from '@prosekit/pm/model'
8
+
9
+ import { isNotNullish } from './type-assertion'
10
+
11
+ interface AttrOptions {
12
+ attr: string
13
+ toDOM?: (value: unknown) => [key: string, value: string] | null | undefined
14
+ parseDOM?: (node: HTMLElement) => unknown
15
+ }
16
+
17
+ export function wrapOutputSpecAttrs<
18
+ T extends ProseMirrorNode | Mark,
19
+ Args extends readonly unknown[],
20
+ >(
21
+ toDOM: (node: T, ...args: Args) => DOMOutputSpec,
22
+ options: AttrOptions[],
23
+ ): (node: T, ...args: Args) => DOMOutputSpec {
24
+ return (node, ...args) => {
25
+ const dom = toDOM(node, ...args)
26
+ const pairs = options
27
+ .map((option) => option.toDOM?.(node.attrs[option.attr]))
28
+ .filter(isNotNullish)
29
+ return insertOutputSpecAttrs(dom, pairs)
30
+ }
31
+ }
32
+
33
+ export function wrapTagParseRuleAttrs(
34
+ rule: TagParseRule,
35
+ options: AttrOptions[],
36
+ ): TagParseRule {
37
+ const existingGetAttrs = rule.getAttrs
38
+ const existingAttrs = rule.attrs
39
+
40
+ return {
41
+ ...rule,
42
+ getAttrs: (dom) => {
43
+ const baseAttrs = existingGetAttrs?.(dom) ?? existingAttrs ?? {}
44
+
45
+ if (baseAttrs === false || !dom || !isElementLike(dom)) {
46
+ return baseAttrs ?? null
47
+ }
48
+
49
+ const insertedAttrs: Record<string, unknown> = {}
50
+
51
+ for (const option of options) {
52
+ if (option.parseDOM) {
53
+ insertedAttrs[option.attr] = option.parseDOM(dom)
54
+ }
55
+ }
56
+
57
+ return { ...baseAttrs, ...insertedAttrs }
58
+ },
59
+ }
60
+ }
61
+
62
+ export function insertOutputSpecAttrs(
63
+ dom: DOMOutputSpec,
64
+ attrs: Array<[key: string, value: string]>,
65
+ ): DOMOutputSpec {
66
+ if (!dom) {
67
+ return dom
68
+ }
69
+
70
+ if (Array.isArray(dom)) {
71
+ const rest = dom.slice(1) as Array<unknown>
72
+ let oldAttrs: Record<string, unknown>
73
+
74
+ if (rest.length > 0 && (rest[0] == null || typeof rest[0] === 'object')) {
75
+ oldAttrs = rest.shift() as Record<string, unknown>
76
+ } else {
77
+ oldAttrs = {}
78
+ }
79
+
80
+ const newAttrs = setObjectAttributes(oldAttrs, attrs)
81
+ return [dom[0], newAttrs, ...rest]
82
+ }
83
+
84
+ if (isElementLike(dom)) {
85
+ return setElementAttributes(dom, attrs)
86
+ }
87
+
88
+ if (typeof dom === 'object' && 'dom' in dom && isElementLike(dom.dom)) {
89
+ return { ...dom, dom: setElementAttributes(dom.dom, attrs) }
90
+ }
91
+
92
+ return dom
93
+ }
94
+
95
+ function setObjectAttributes(
96
+ obj: Record<string, unknown>,
97
+ attrs: Array<[key: string, value: string]>,
98
+ ): Record<string, unknown> {
99
+ obj = { ...obj }
100
+ for (const [key, value] of attrs) {
101
+ const oldValue = obj[key]
102
+ const newValue = key === 'style'
103
+ ? joinStyles(value, typeof oldValue === 'string' ? oldValue : '')
104
+ : value
105
+ obj[key] = newValue
106
+ }
107
+ return obj
108
+ }
109
+
110
+ function setElementAttributes(
111
+ element: Element,
112
+ attrs: Array<[key: string, value: string]>,
113
+ ): Element {
114
+ element = element.cloneNode(true) as Element
115
+ for (const [key, value] of attrs) {
116
+ const oldValue = element.getAttribute(key)
117
+ const newValue = key === 'style'
118
+ ? joinStyles(value, typeof oldValue === 'string' ? oldValue : '')
119
+ : value
120
+ element.setAttribute(key, newValue)
121
+ }
122
+ return element
123
+ }
124
+
125
+ function joinStyles(...styles: string[]) {
126
+ return styles
127
+ .map((style) => style.trim().replace(/;$/, ''))
128
+ .filter(Boolean)
129
+ .join('; ')
130
+ }
@@ -0,0 +1,46 @@
1
+ import {
2
+ describe,
3
+ expect,
4
+ test,
5
+ } from 'vitest'
6
+
7
+ import { createEditor } from '../editor/editor'
8
+ import { defineTestExtension } from '../testing'
9
+
10
+ import {
11
+ elementFromHTML,
12
+ htmlFromNode,
13
+ nodeFromElement,
14
+ nodeFromHTML,
15
+ } from './parse'
16
+
17
+ describe('parse', () => {
18
+ const extension = defineTestExtension()
19
+ const editor = createEditor({ extension })
20
+ const schema = editor.schema
21
+ const n = editor.nodes
22
+
23
+ const element = document.createElement('div')
24
+ element.innerHTML = '<p>hello</p>'
25
+
26
+ const node = n.doc(n.paragraph(schema.text('hello')))
27
+
28
+ const html = '<p>hello</p>'
29
+
30
+ test('nodeFromElement', () => {
31
+ expect(node.eq(nodeFromElement(element, { schema }))).toBe(true)
32
+ })
33
+
34
+ test('nodeFromHTML', () => {
35
+ expect(nodeFromHTML(html, { schema }).eq(node)).toBe(true)
36
+ })
37
+
38
+ test('elementFromHTML', () => {
39
+ expect(elementFromHTML(html).innerHTML).toBe(html)
40
+ })
41
+
42
+ test('htmlFromNode', () => {
43
+ expect(htmlFromNode(node)).toBe('<div><p>hello</p></div>')
44
+ expect(htmlFromNode(node.child(0))).toBe('<p>hello</p>')
45
+ })
46
+ })