kempo-ui 0.3.9 → 0.3.11
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/dist/components/HtmlEditor.js +15 -15
- package/docs/src/components/HtmlEditor.js +15 -15
- package/package.json +3 -3
- package/src/components/HtmlEditor.js +24 -29
- package/tests/components/htmlEditorControls/Align.browser-test.js +203 -0
- package/tests/components/htmlEditorControls/Bold.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/BulletList.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/CharacterCount.browser-test.js +106 -0
- package/tests/components/htmlEditorControls/ClearFormatting.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/CodeBlock.browser-test.js +143 -0
- package/tests/components/htmlEditorControls/ControlGroup.browser-test.js +116 -0
- package/tests/components/htmlEditorControls/ControlSpacer.browser-test.js +69 -0
- package/tests/components/htmlEditorControls/CreateLink.browser-test.js +129 -0
- package/tests/components/htmlEditorControls/DropdownControl.browser-test.js +138 -0
- package/tests/components/htmlEditorControls/FormatBlock.browser-test.js +163 -0
- package/tests/components/htmlEditorControls/InlineCode.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/InsertTable.browser-test.js +129 -0
- package/tests/components/htmlEditorControls/Italic.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/Mode.browser-test.js +138 -0
- package/tests/components/htmlEditorControls/NumberList.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/Strikethrough.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/TextBackgroundColor.browser-test.js +136 -0
- package/tests/components/htmlEditorControls/TextColor.browser-test.js +136 -0
- package/tests/components/htmlEditorControls/Underline.browser-test.js +127 -0
- package/tests/components/htmlEditorControls/WordCount.browser-test.js +106 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import AlignLeft from '../../../src/components/htmlEditorControls/AlignLeft.js';
|
|
3
|
+
import AlignCenter from '../../../src/components/htmlEditorControls/AlignCenter.js';
|
|
4
|
+
import AlignRight from '../../../src/components/htmlEditorControls/AlignRight.js';
|
|
5
|
+
import AlignJustify from '../../../src/components/htmlEditorControls/AlignJustify.js';
|
|
6
|
+
|
|
7
|
+
const createEditorWithControls = async () => {
|
|
8
|
+
const container = document.createElement('div');
|
|
9
|
+
container.innerHTML = `
|
|
10
|
+
<k-html-editor>
|
|
11
|
+
<k-hec-align-left slot="toolbar-top-left"></k-hec-align-left>
|
|
12
|
+
<k-hec-align-center slot="toolbar-top-left"></k-hec-align-center>
|
|
13
|
+
<k-hec-align-right slot="toolbar-top-left"></k-hec-align-right>
|
|
14
|
+
<k-hec-align-justify slot="toolbar-top-left"></k-hec-align-justify>
|
|
15
|
+
</k-html-editor>
|
|
16
|
+
`;
|
|
17
|
+
document.body.appendChild(container);
|
|
18
|
+
const editor = container.querySelector('k-html-editor');
|
|
19
|
+
await new Promise(r => editor.addEventListener('ready', r, { once: true }));
|
|
20
|
+
return {
|
|
21
|
+
container,
|
|
22
|
+
editor,
|
|
23
|
+
left: container.querySelector('k-hec-align-left'),
|
|
24
|
+
center: container.querySelector('k-hec-align-center'),
|
|
25
|
+
right: container.querySelector('k-hec-align-right'),
|
|
26
|
+
justify: container.querySelector('k-hec-align-justify')
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const cleanup = container => {
|
|
31
|
+
if(container?.parentNode) container.parentNode.removeChild(container);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
/*
|
|
36
|
+
AlignLeft
|
|
37
|
+
*/
|
|
38
|
+
'AlignLeft: should create element': async ({pass, fail}) => {
|
|
39
|
+
const { container, left } = await createEditorWithControls();
|
|
40
|
+
if(!(left instanceof AlignLeft)){
|
|
41
|
+
cleanup(container);
|
|
42
|
+
return fail('Element should be instance of AlignLeft');
|
|
43
|
+
}
|
|
44
|
+
cleanup(container);
|
|
45
|
+
pass('AlignLeft element created correctly');
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
'AlignLeft: should render format_align_left icon': async ({pass, fail}) => {
|
|
49
|
+
const { container, left } = await createEditorWithControls();
|
|
50
|
+
await left.updateComplete;
|
|
51
|
+
const icon = left.shadowRoot.querySelector('k-icon');
|
|
52
|
+
if(icon?.getAttribute('name') !== 'format_align_left'){
|
|
53
|
+
cleanup(container);
|
|
54
|
+
return fail(`Expected icon "format_align_left", got "${icon?.getAttribute('name')}"`);
|
|
55
|
+
}
|
|
56
|
+
cleanup(container);
|
|
57
|
+
pass('AlignLeft renders correct icon');
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
'AlignLeft: click should call editor.alignLeft()': async ({pass, fail}) => {
|
|
61
|
+
const { container, editor, left } = await createEditorWithControls();
|
|
62
|
+
await left.updateComplete;
|
|
63
|
+
let called = false;
|
|
64
|
+
editor.alignLeft = () => { called = true; };
|
|
65
|
+
left.shadowRoot.querySelector('button').click();
|
|
66
|
+
if(!called){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail('Click should call editor.alignLeft()');
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('Click calls editor.alignLeft()');
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
'AlignLeft: should hide in code mode': async ({pass, fail}) => {
|
|
75
|
+
const { container, editor, left } = await createEditorWithControls();
|
|
76
|
+
editor.setMode('code');
|
|
77
|
+
await new Promise(r => editor.addEventListener('mode-changed', r, { once: true }));
|
|
78
|
+
await left.updateComplete;
|
|
79
|
+
if(!left.hidden){
|
|
80
|
+
cleanup(container);
|
|
81
|
+
return fail('AlignLeft should be hidden in code mode');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('AlignLeft is hidden in code mode');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
AlignCenter
|
|
89
|
+
*/
|
|
90
|
+
'AlignCenter: should create element': async ({pass, fail}) => {
|
|
91
|
+
const { container, center } = await createEditorWithControls();
|
|
92
|
+
if(!(center instanceof AlignCenter)){
|
|
93
|
+
cleanup(container);
|
|
94
|
+
return fail('Element should be instance of AlignCenter');
|
|
95
|
+
}
|
|
96
|
+
cleanup(container);
|
|
97
|
+
pass('AlignCenter element created correctly');
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
'AlignCenter: should render format_align_center icon': async ({pass, fail}) => {
|
|
101
|
+
const { container, center } = await createEditorWithControls();
|
|
102
|
+
await center.updateComplete;
|
|
103
|
+
const icon = center.shadowRoot.querySelector('k-icon');
|
|
104
|
+
if(icon?.getAttribute('name') !== 'format_align_center'){
|
|
105
|
+
cleanup(container);
|
|
106
|
+
return fail(`Expected icon "format_align_center", got "${icon?.getAttribute('name')}"`);
|
|
107
|
+
}
|
|
108
|
+
cleanup(container);
|
|
109
|
+
pass('AlignCenter renders correct icon');
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
'AlignCenter: click should call editor.alignCenter()': async ({pass, fail}) => {
|
|
113
|
+
const { container, editor, center } = await createEditorWithControls();
|
|
114
|
+
await center.updateComplete;
|
|
115
|
+
let called = false;
|
|
116
|
+
editor.alignCenter = () => { called = true; };
|
|
117
|
+
center.shadowRoot.querySelector('button').click();
|
|
118
|
+
if(!called){
|
|
119
|
+
cleanup(container);
|
|
120
|
+
return fail('Click should call editor.alignCenter()');
|
|
121
|
+
}
|
|
122
|
+
cleanup(container);
|
|
123
|
+
pass('Click calls editor.alignCenter()');
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
/*
|
|
127
|
+
AlignRight
|
|
128
|
+
*/
|
|
129
|
+
'AlignRight: should create element': async ({pass, fail}) => {
|
|
130
|
+
const { container, right } = await createEditorWithControls();
|
|
131
|
+
if(!(right instanceof AlignRight)){
|
|
132
|
+
cleanup(container);
|
|
133
|
+
return fail('Element should be instance of AlignRight');
|
|
134
|
+
}
|
|
135
|
+
cleanup(container);
|
|
136
|
+
pass('AlignRight element created correctly');
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
'AlignRight: should render format_align_right icon': async ({pass, fail}) => {
|
|
140
|
+
const { container, right } = await createEditorWithControls();
|
|
141
|
+
await right.updateComplete;
|
|
142
|
+
const icon = right.shadowRoot.querySelector('k-icon');
|
|
143
|
+
if(icon?.getAttribute('name') !== 'format_align_right'){
|
|
144
|
+
cleanup(container);
|
|
145
|
+
return fail(`Expected icon "format_align_right", got "${icon?.getAttribute('name')}"`);
|
|
146
|
+
}
|
|
147
|
+
cleanup(container);
|
|
148
|
+
pass('AlignRight renders correct icon');
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
'AlignRight: click should call editor.alignRight()': async ({pass, fail}) => {
|
|
152
|
+
const { container, editor, right } = await createEditorWithControls();
|
|
153
|
+
await right.updateComplete;
|
|
154
|
+
let called = false;
|
|
155
|
+
editor.alignRight = () => { called = true; };
|
|
156
|
+
right.shadowRoot.querySelector('button').click();
|
|
157
|
+
if(!called){
|
|
158
|
+
cleanup(container);
|
|
159
|
+
return fail('Click should call editor.alignRight()');
|
|
160
|
+
}
|
|
161
|
+
cleanup(container);
|
|
162
|
+
pass('Click calls editor.alignRight()');
|
|
163
|
+
},
|
|
164
|
+
|
|
165
|
+
/*
|
|
166
|
+
AlignJustify
|
|
167
|
+
*/
|
|
168
|
+
'AlignJustify: should create element': async ({pass, fail}) => {
|
|
169
|
+
const { container, justify } = await createEditorWithControls();
|
|
170
|
+
if(!(justify instanceof AlignJustify)){
|
|
171
|
+
cleanup(container);
|
|
172
|
+
return fail('Element should be instance of AlignJustify');
|
|
173
|
+
}
|
|
174
|
+
cleanup(container);
|
|
175
|
+
pass('AlignJustify element created correctly');
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
'AlignJustify: should render format_align_justify icon': async ({pass, fail}) => {
|
|
179
|
+
const { container, justify } = await createEditorWithControls();
|
|
180
|
+
await justify.updateComplete;
|
|
181
|
+
const icon = justify.shadowRoot.querySelector('k-icon');
|
|
182
|
+
if(icon?.getAttribute('name') !== 'format_align_justify'){
|
|
183
|
+
cleanup(container);
|
|
184
|
+
return fail(`Expected icon "format_align_justify", got "${icon?.getAttribute('name')}"`);
|
|
185
|
+
}
|
|
186
|
+
cleanup(container);
|
|
187
|
+
pass('AlignJustify renders correct icon');
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
'AlignJustify: click should call editor.alignJustify()': async ({pass, fail}) => {
|
|
191
|
+
const { container, editor, justify } = await createEditorWithControls();
|
|
192
|
+
await justify.updateComplete;
|
|
193
|
+
let called = false;
|
|
194
|
+
editor.alignJustify = () => { called = true; };
|
|
195
|
+
justify.shadowRoot.querySelector('button').click();
|
|
196
|
+
if(!called){
|
|
197
|
+
cleanup(container);
|
|
198
|
+
return fail('Click should call editor.alignJustify()');
|
|
199
|
+
}
|
|
200
|
+
cleanup(container);
|
|
201
|
+
pass('Click calls editor.alignJustify()');
|
|
202
|
+
},
|
|
203
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import Bold from '../../../src/components/htmlEditorControls/Bold.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async () => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-bold slot="toolbar-top-left"></k-hec-bold>
|
|
9
|
+
</k-html-editor>
|
|
10
|
+
`;
|
|
11
|
+
document.body.appendChild(container);
|
|
12
|
+
const editor = container.querySelector('k-html-editor');
|
|
13
|
+
await new Promise(r => editor.addEventListener('ready', r, { once: true }));
|
|
14
|
+
const control = container.querySelector('k-hec-bold');
|
|
15
|
+
return { container, editor, control };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const cleanup = container => {
|
|
19
|
+
if(container?.parentNode) container.parentNode.removeChild(container);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
/*
|
|
24
|
+
Element Creation
|
|
25
|
+
*/
|
|
26
|
+
'should create k-hec-bold element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof Bold)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of Bold');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('Bold element created correctly');
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
'should have shadow root': async ({pass, fail}) => {
|
|
37
|
+
const { container, control } = await createEditorWithControl();
|
|
38
|
+
if(!control.shadowRoot){
|
|
39
|
+
cleanup(container);
|
|
40
|
+
return fail('Bold should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('Bold has shadow root');
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
'should render a button': async ({pass, fail}) => {
|
|
47
|
+
const { container, control } = await createEditorWithControl();
|
|
48
|
+
await control.updateComplete;
|
|
49
|
+
const button = control.shadowRoot.querySelector('button');
|
|
50
|
+
if(!button){
|
|
51
|
+
cleanup(container);
|
|
52
|
+
return fail('Bold should render a button');
|
|
53
|
+
}
|
|
54
|
+
cleanup(container);
|
|
55
|
+
pass('Bold renders a button');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
'should render format_bold icon': async ({pass, fail}) => {
|
|
59
|
+
const { container, control } = await createEditorWithControl();
|
|
60
|
+
await control.updateComplete;
|
|
61
|
+
const icon = control.shadowRoot.querySelector('k-icon');
|
|
62
|
+
if(!icon){
|
|
63
|
+
cleanup(container);
|
|
64
|
+
return fail('Bold should render a k-icon');
|
|
65
|
+
}
|
|
66
|
+
if(icon.getAttribute('name') !== 'format_bold'){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail(`Expected icon name "format_bold", got "${icon.getAttribute('name')}"`);
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('Bold renders format_bold icon');
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/*
|
|
75
|
+
Editor Integration
|
|
76
|
+
*/
|
|
77
|
+
'should find parent editor': async ({pass, fail}) => {
|
|
78
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
79
|
+
if(control.editor !== editor){
|
|
80
|
+
cleanup(container);
|
|
81
|
+
return fail('Bold should find its parent k-html-editor');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('Bold finds parent editor');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
'click should call editor.bold()': async ({pass, fail}) => {
|
|
88
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
89
|
+
await control.updateComplete;
|
|
90
|
+
let called = false;
|
|
91
|
+
editor.bold = () => { called = true; };
|
|
92
|
+
control.shadowRoot.querySelector('button').click();
|
|
93
|
+
if(!called){
|
|
94
|
+
cleanup(container);
|
|
95
|
+
return fail('Click should call editor.bold()');
|
|
96
|
+
}
|
|
97
|
+
cleanup(container);
|
|
98
|
+
pass('Click calls editor.bold()');
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/*
|
|
102
|
+
Code Mode Visibility
|
|
103
|
+
*/
|
|
104
|
+
'should hide in code mode': async ({pass, fail}) => {
|
|
105
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
106
|
+
editor.setMode('code');
|
|
107
|
+
await new Promise(r => editor.addEventListener('mode-changed', r, { once: true }));
|
|
108
|
+
await control.updateComplete;
|
|
109
|
+
if(!control.hidden){
|
|
110
|
+
cleanup(container);
|
|
111
|
+
return fail('Bold should be hidden in code mode');
|
|
112
|
+
}
|
|
113
|
+
cleanup(container);
|
|
114
|
+
pass('Bold is hidden in code mode');
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
'should be visible in visual mode': async ({pass, fail}) => {
|
|
118
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
119
|
+
await control.updateComplete;
|
|
120
|
+
if(control.hidden){
|
|
121
|
+
cleanup(container);
|
|
122
|
+
return fail('Bold should be visible in visual mode');
|
|
123
|
+
}
|
|
124
|
+
cleanup(container);
|
|
125
|
+
pass('Bold is visible in visual mode');
|
|
126
|
+
},
|
|
127
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import BulletList from '../../../src/components/htmlEditorControls/BulletList.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async () => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-bullet-list slot="toolbar-top-left"></k-hec-bullet-list>
|
|
9
|
+
</k-html-editor>
|
|
10
|
+
`;
|
|
11
|
+
document.body.appendChild(container);
|
|
12
|
+
const editor = container.querySelector('k-html-editor');
|
|
13
|
+
await new Promise(r => editor.addEventListener('ready', r, { once: true }));
|
|
14
|
+
const control = container.querySelector('k-hec-bullet-list');
|
|
15
|
+
return { container, editor, control };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const cleanup = container => {
|
|
19
|
+
if(container?.parentNode) container.parentNode.removeChild(container);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
/*
|
|
24
|
+
Element Creation
|
|
25
|
+
*/
|
|
26
|
+
'should create k-hec-bullet-list element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof BulletList)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of BulletList');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('BulletList element created correctly');
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
'should have shadow root': async ({pass, fail}) => {
|
|
37
|
+
const { container, control } = await createEditorWithControl();
|
|
38
|
+
if(!control.shadowRoot){
|
|
39
|
+
cleanup(container);
|
|
40
|
+
return fail('BulletList should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('BulletList has shadow root');
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
'should render a button': async ({pass, fail}) => {
|
|
47
|
+
const { container, control } = await createEditorWithControl();
|
|
48
|
+
await control.updateComplete;
|
|
49
|
+
const button = control.shadowRoot.querySelector('button');
|
|
50
|
+
if(!button){
|
|
51
|
+
cleanup(container);
|
|
52
|
+
return fail('BulletList should render a button');
|
|
53
|
+
}
|
|
54
|
+
cleanup(container);
|
|
55
|
+
pass('BulletList renders a button');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
'should render format_list_bulleted icon': async ({pass, fail}) => {
|
|
59
|
+
const { container, control } = await createEditorWithControl();
|
|
60
|
+
await control.updateComplete;
|
|
61
|
+
const icon = control.shadowRoot.querySelector('k-icon');
|
|
62
|
+
if(!icon){
|
|
63
|
+
cleanup(container);
|
|
64
|
+
return fail('BulletList should render a k-icon');
|
|
65
|
+
}
|
|
66
|
+
if(icon.getAttribute('name') !== 'format_list_bulleted'){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail(`Expected icon name "format_list_bulleted", got "${icon.getAttribute('name')}"`);
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('BulletList renders format_list_bulleted icon');
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/*
|
|
75
|
+
Editor Integration
|
|
76
|
+
*/
|
|
77
|
+
'should find parent editor': async ({pass, fail}) => {
|
|
78
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
79
|
+
if(control.editor !== editor){
|
|
80
|
+
cleanup(container);
|
|
81
|
+
return fail('BulletList should find its parent k-html-editor');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('BulletList finds parent editor');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
'click should call editor.unorderedList()': async ({pass, fail}) => {
|
|
88
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
89
|
+
await control.updateComplete;
|
|
90
|
+
let called = false;
|
|
91
|
+
editor.unorderedList = () => { called = true; };
|
|
92
|
+
control.shadowRoot.querySelector('button').click();
|
|
93
|
+
if(!called){
|
|
94
|
+
cleanup(container);
|
|
95
|
+
return fail('Click should call editor.unorderedList()');
|
|
96
|
+
}
|
|
97
|
+
cleanup(container);
|
|
98
|
+
pass('Click calls editor.unorderedList()');
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/*
|
|
102
|
+
Code Mode Visibility
|
|
103
|
+
*/
|
|
104
|
+
'should hide in code mode': async ({pass, fail}) => {
|
|
105
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
106
|
+
editor.setMode('code');
|
|
107
|
+
await new Promise(r => editor.addEventListener('mode-changed', r, { once: true }));
|
|
108
|
+
await control.updateComplete;
|
|
109
|
+
if(!control.hidden){
|
|
110
|
+
cleanup(container);
|
|
111
|
+
return fail('BulletList should be hidden in code mode');
|
|
112
|
+
}
|
|
113
|
+
cleanup(container);
|
|
114
|
+
pass('BulletList is hidden in code mode');
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
'should be visible in visual mode': async ({pass, fail}) => {
|
|
118
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
119
|
+
await control.updateComplete;
|
|
120
|
+
if(control.hidden){
|
|
121
|
+
cleanup(container);
|
|
122
|
+
return fail('BulletList should be visible in visual mode');
|
|
123
|
+
}
|
|
124
|
+
cleanup(container);
|
|
125
|
+
pass('BulletList is visible in visual mode');
|
|
126
|
+
},
|
|
127
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import CharacterCount from '../../../src/components/htmlEditorControls/CharacterCount.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async () => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-character-count slot="toolbar-bottom-left"></k-hec-character-count>
|
|
9
|
+
</k-html-editor>
|
|
10
|
+
`;
|
|
11
|
+
document.body.appendChild(container);
|
|
12
|
+
const editor = container.querySelector('k-html-editor');
|
|
13
|
+
await new Promise(r => editor.addEventListener('ready', r, { once: true }));
|
|
14
|
+
const control = container.querySelector('k-hec-character-count');
|
|
15
|
+
return { container, editor, control };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const cleanup = container => {
|
|
19
|
+
if(container?.parentNode) container.parentNode.removeChild(container);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
/*
|
|
24
|
+
Element Creation
|
|
25
|
+
*/
|
|
26
|
+
'should create k-hec-character-count element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof CharacterCount)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of CharacterCount');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('CharacterCount element created correctly');
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
'should have shadow root': async ({pass, fail}) => {
|
|
37
|
+
const { container, control } = await createEditorWithControl();
|
|
38
|
+
if(!control.shadowRoot){
|
|
39
|
+
cleanup(container);
|
|
40
|
+
return fail('CharacterCount should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('CharacterCount has shadow root');
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
Editor Integration
|
|
48
|
+
*/
|
|
49
|
+
'should find parent editor': async ({pass, fail}) => {
|
|
50
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
51
|
+
if(control.editor !== editor){
|
|
52
|
+
cleanup(container);
|
|
53
|
+
return fail('CharacterCount should find its parent k-html-editor');
|
|
54
|
+
}
|
|
55
|
+
cleanup(container);
|
|
56
|
+
pass('CharacterCount finds parent editor');
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
'should initialize count to 0': async ({pass, fail}) => {
|
|
60
|
+
const { container, control } = await createEditorWithControl();
|
|
61
|
+
if(control.count !== 0){
|
|
62
|
+
cleanup(container);
|
|
63
|
+
return fail(`Expected initial count 0, got ${control.count}`);
|
|
64
|
+
}
|
|
65
|
+
cleanup(container);
|
|
66
|
+
pass('CharacterCount initializes count to 0');
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
'should update count when editor content changes': async ({pass, fail}) => {
|
|
70
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
71
|
+
editor.setValue('<p>hello</p>');
|
|
72
|
+
await new Promise(r => setTimeout(r, 200));
|
|
73
|
+
await control.updateComplete;
|
|
74
|
+
if(control.count !== 5){
|
|
75
|
+
cleanup(container);
|
|
76
|
+
return fail(`Expected count 5, got ${control.count}`);
|
|
77
|
+
}
|
|
78
|
+
cleanup(container);
|
|
79
|
+
pass('CharacterCount updates on content change');
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
'should count empty content as 0 characters': async ({pass, fail}) => {
|
|
83
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
84
|
+
editor.setValue('');
|
|
85
|
+
await new Promise(r => setTimeout(r, 200));
|
|
86
|
+
await control.updateComplete;
|
|
87
|
+
if(control.count !== 0){
|
|
88
|
+
cleanup(container);
|
|
89
|
+
return fail(`Expected count 0 for empty content, got ${control.count}`);
|
|
90
|
+
}
|
|
91
|
+
cleanup(container);
|
|
92
|
+
pass('CharacterCount counts empty content as 0');
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
'should render character count span': async ({pass, fail}) => {
|
|
96
|
+
const { container, control } = await createEditorWithControl();
|
|
97
|
+
await control.updateComplete;
|
|
98
|
+
const span = control.shadowRoot.querySelector('.character-count');
|
|
99
|
+
if(!span){
|
|
100
|
+
cleanup(container);
|
|
101
|
+
return fail('CharacterCount should render a .character-count span');
|
|
102
|
+
}
|
|
103
|
+
cleanup(container);
|
|
104
|
+
pass('CharacterCount renders character count span');
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import ClearFormatting from '../../../src/components/htmlEditorControls/ClearFormatting.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async () => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-clear-formatting slot="toolbar-top-left"></k-hec-clear-formatting>
|
|
9
|
+
</k-html-editor>
|
|
10
|
+
`;
|
|
11
|
+
document.body.appendChild(container);
|
|
12
|
+
const editor = container.querySelector('k-html-editor');
|
|
13
|
+
await new Promise(r => editor.addEventListener('ready', r, { once: true }));
|
|
14
|
+
const control = container.querySelector('k-hec-clear-formatting');
|
|
15
|
+
return { container, editor, control };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const cleanup = container => {
|
|
19
|
+
if(container?.parentNode) container.parentNode.removeChild(container);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default {
|
|
23
|
+
/*
|
|
24
|
+
Element Creation
|
|
25
|
+
*/
|
|
26
|
+
'should create k-hec-clear-formatting element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof ClearFormatting)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of ClearFormatting');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('ClearFormatting element created correctly');
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
'should have shadow root': async ({pass, fail}) => {
|
|
37
|
+
const { container, control } = await createEditorWithControl();
|
|
38
|
+
if(!control.shadowRoot){
|
|
39
|
+
cleanup(container);
|
|
40
|
+
return fail('ClearFormatting should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('ClearFormatting has shadow root');
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
'should render a button': async ({pass, fail}) => {
|
|
47
|
+
const { container, control } = await createEditorWithControl();
|
|
48
|
+
await control.updateComplete;
|
|
49
|
+
const button = control.shadowRoot.querySelector('button');
|
|
50
|
+
if(!button){
|
|
51
|
+
cleanup(container);
|
|
52
|
+
return fail('ClearFormatting should render a button');
|
|
53
|
+
}
|
|
54
|
+
cleanup(container);
|
|
55
|
+
pass('ClearFormatting renders a button');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
'should render format_clear icon': async ({pass, fail}) => {
|
|
59
|
+
const { container, control } = await createEditorWithControl();
|
|
60
|
+
await control.updateComplete;
|
|
61
|
+
const icon = control.shadowRoot.querySelector('k-icon');
|
|
62
|
+
if(!icon){
|
|
63
|
+
cleanup(container);
|
|
64
|
+
return fail('ClearFormatting should render a k-icon');
|
|
65
|
+
}
|
|
66
|
+
if(icon.getAttribute('name') !== 'format_clear'){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail(`Expected icon name "format_clear", got "${icon.getAttribute('name')}"`);
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('ClearFormatting renders format_clear icon');
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/*
|
|
75
|
+
Editor Integration
|
|
76
|
+
*/
|
|
77
|
+
'should find parent editor': async ({pass, fail}) => {
|
|
78
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
79
|
+
if(control.editor !== editor){
|
|
80
|
+
cleanup(container);
|
|
81
|
+
return fail('ClearFormatting should find its parent k-html-editor');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('ClearFormatting finds parent editor');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
'click should call editor.removeFormat()': async ({pass, fail}) => {
|
|
88
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
89
|
+
await control.updateComplete;
|
|
90
|
+
let called = false;
|
|
91
|
+
editor.removeFormat = () => { called = true; };
|
|
92
|
+
control.shadowRoot.querySelector('button').click();
|
|
93
|
+
if(!called){
|
|
94
|
+
cleanup(container);
|
|
95
|
+
return fail('Click should call editor.removeFormat()');
|
|
96
|
+
}
|
|
97
|
+
cleanup(container);
|
|
98
|
+
pass('Click calls editor.removeFormat()');
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/*
|
|
102
|
+
Code Mode Visibility
|
|
103
|
+
*/
|
|
104
|
+
'should hide in code mode': async ({pass, fail}) => {
|
|
105
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
106
|
+
editor.setMode('code');
|
|
107
|
+
await new Promise(r => editor.addEventListener('mode-changed', r, { once: true }));
|
|
108
|
+
await control.updateComplete;
|
|
109
|
+
if(!control.hidden){
|
|
110
|
+
cleanup(container);
|
|
111
|
+
return fail('ClearFormatting should be hidden in code mode');
|
|
112
|
+
}
|
|
113
|
+
cleanup(container);
|
|
114
|
+
pass('ClearFormatting is hidden in code mode');
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
'should be visible in visual mode': async ({pass, fail}) => {
|
|
118
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
119
|
+
await control.updateComplete;
|
|
120
|
+
if(control.hidden){
|
|
121
|
+
cleanup(container);
|
|
122
|
+
return fail('ClearFormatting should be visible in visual mode');
|
|
123
|
+
}
|
|
124
|
+
cleanup(container);
|
|
125
|
+
pass('ClearFormatting is visible in visual mode');
|
|
126
|
+
},
|
|
127
|
+
};
|