kempo-ui 0.3.9 → 0.3.10
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/package.json +3 -3
- 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,138 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import DropdownControl from '../../../src/components/htmlEditorControls/DropdownControl.js';
|
|
3
|
+
import '../../../src/components/htmlEditorControls/Bold.js';
|
|
4
|
+
|
|
5
|
+
const createEditorWithControl = async () => {
|
|
6
|
+
const container = document.createElement('div');
|
|
7
|
+
container.innerHTML = `
|
|
8
|
+
<k-html-editor>
|
|
9
|
+
<k-hec-dropdown slot="toolbar-top-left">
|
|
10
|
+
<k-icon name="more_vert" slot="icon"></k-icon>
|
|
11
|
+
<k-hec-bold></k-hec-bold>
|
|
12
|
+
</k-hec-dropdown>
|
|
13
|
+
</k-html-editor>
|
|
14
|
+
`;
|
|
15
|
+
document.body.appendChild(container);
|
|
16
|
+
const editor = container.querySelector('k-html-editor');
|
|
17
|
+
await new Promise(r => editor.addEventListener('ready', r, { once: true }));
|
|
18
|
+
const control = container.querySelector('k-hec-dropdown');
|
|
19
|
+
return { container, editor, control };
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const cleanup = container => {
|
|
23
|
+
if(container?.parentNode) container.parentNode.removeChild(container);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
/*
|
|
28
|
+
Element Creation
|
|
29
|
+
*/
|
|
30
|
+
'should create k-hec-dropdown element': async ({pass, fail}) => {
|
|
31
|
+
const { container, control } = await createEditorWithControl();
|
|
32
|
+
if(!(control instanceof DropdownControl)){
|
|
33
|
+
cleanup(container);
|
|
34
|
+
return fail('Element should be instance of DropdownControl');
|
|
35
|
+
}
|
|
36
|
+
cleanup(container);
|
|
37
|
+
pass('DropdownControl element created correctly');
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
'should have shadow root': async ({pass, fail}) => {
|
|
41
|
+
const { container, control } = await createEditorWithControl();
|
|
42
|
+
if(!control.shadowRoot){
|
|
43
|
+
cleanup(container);
|
|
44
|
+
return fail('DropdownControl should have shadow root');
|
|
45
|
+
}
|
|
46
|
+
cleanup(container);
|
|
47
|
+
pass('DropdownControl has shadow root');
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
'should render a k-dropdown': async ({pass, fail}) => {
|
|
51
|
+
const { container, control } = await createEditorWithControl();
|
|
52
|
+
await control.updateComplete;
|
|
53
|
+
const dropdown = control.shadowRoot.querySelector('k-dropdown');
|
|
54
|
+
if(!dropdown){
|
|
55
|
+
cleanup(container);
|
|
56
|
+
return fail('DropdownControl should render a k-dropdown');
|
|
57
|
+
}
|
|
58
|
+
cleanup(container);
|
|
59
|
+
pass('DropdownControl renders a k-dropdown');
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
'should render a trigger button': async ({pass, fail}) => {
|
|
63
|
+
const { container, control } = await createEditorWithControl();
|
|
64
|
+
await control.updateComplete;
|
|
65
|
+
const button = control.shadowRoot.querySelector('button[slot="trigger"]');
|
|
66
|
+
if(!button){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail('DropdownControl should render a trigger button');
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('DropdownControl renders a trigger button');
|
|
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('DropdownControl should find its parent k-html-editor');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('DropdownControl finds parent editor');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
Opened State
|
|
89
|
+
*/
|
|
90
|
+
'should default to closed': async ({pass, fail}) => {
|
|
91
|
+
const { container, control } = await createEditorWithControl();
|
|
92
|
+
if(control.opened){
|
|
93
|
+
cleanup(container);
|
|
94
|
+
return fail('DropdownControl should default to closed');
|
|
95
|
+
}
|
|
96
|
+
cleanup(container);
|
|
97
|
+
pass('DropdownControl defaults to closed');
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
'handleToggle should toggle opened state': async ({pass, fail}) => {
|
|
101
|
+
const { container, control } = await createEditorWithControl();
|
|
102
|
+
control.handleToggle();
|
|
103
|
+
if(!control.opened){
|
|
104
|
+
cleanup(container);
|
|
105
|
+
return fail('handleToggle should open the dropdown');
|
|
106
|
+
}
|
|
107
|
+
control.handleToggle();
|
|
108
|
+
if(control.opened){
|
|
109
|
+
cleanup(container);
|
|
110
|
+
return fail('handleToggle should close the dropdown');
|
|
111
|
+
}
|
|
112
|
+
cleanup(container);
|
|
113
|
+
pass('handleToggle toggles opened state');
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
'handleOpened should set opened to true': async ({pass, fail}) => {
|
|
117
|
+
const { container, control } = await createEditorWithControl();
|
|
118
|
+
control.handleOpened();
|
|
119
|
+
if(!control.opened){
|
|
120
|
+
cleanup(container);
|
|
121
|
+
return fail('handleOpened should set opened to true');
|
|
122
|
+
}
|
|
123
|
+
cleanup(container);
|
|
124
|
+
pass('handleOpened sets opened to true');
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
'handleClosed should set opened to false': async ({pass, fail}) => {
|
|
128
|
+
const { container, control } = await createEditorWithControl();
|
|
129
|
+
control.opened = true;
|
|
130
|
+
control.handleClosed();
|
|
131
|
+
if(control.opened){
|
|
132
|
+
cleanup(container);
|
|
133
|
+
return fail('handleClosed should set opened to false');
|
|
134
|
+
}
|
|
135
|
+
cleanup(container);
|
|
136
|
+
pass('handleClosed sets opened to false');
|
|
137
|
+
},
|
|
138
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import FormatBlock from '../../../src/components/htmlEditorControls/FormatBlock.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async (tag = 'h1') => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-format-block tag="${tag}" slot="toolbar-top-left"></k-hec-format-block>
|
|
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-format-block');
|
|
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-format-block element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof FormatBlock)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of FormatBlock');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('FormatBlock 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('FormatBlock should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('FormatBlock 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('FormatBlock should render a button');
|
|
53
|
+
}
|
|
54
|
+
cleanup(container);
|
|
55
|
+
pass('FormatBlock renders a button');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
Tag Property
|
|
60
|
+
*/
|
|
61
|
+
'should default tag to "p"': async ({pass, fail}) => {
|
|
62
|
+
const container = document.createElement('div');
|
|
63
|
+
container.innerHTML = `
|
|
64
|
+
<k-html-editor>
|
|
65
|
+
<k-hec-format-block slot="toolbar-top-left"></k-hec-format-block>
|
|
66
|
+
</k-html-editor>
|
|
67
|
+
`;
|
|
68
|
+
document.body.appendChild(container);
|
|
69
|
+
const editor = container.querySelector('k-html-editor');
|
|
70
|
+
await new Promise(r => editor.addEventListener('ready', r, { once: true }));
|
|
71
|
+
const control = container.querySelector('k-hec-format-block');
|
|
72
|
+
if(control.tag !== 'p'){
|
|
73
|
+
cleanup(container);
|
|
74
|
+
return fail(`Expected default tag "p", got "${control.tag}"`);
|
|
75
|
+
}
|
|
76
|
+
cleanup(container);
|
|
77
|
+
pass('Default tag is "p"');
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
'should accept tag attribute': async ({pass, fail}) => {
|
|
81
|
+
const { container, control } = await createEditorWithControl('h2');
|
|
82
|
+
if(control.tag !== 'h2'){
|
|
83
|
+
cleanup(container);
|
|
84
|
+
return fail(`Expected tag "h2", got "${control.tag}"`);
|
|
85
|
+
}
|
|
86
|
+
cleanup(container);
|
|
87
|
+
pass('Tag attribute is accepted');
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
Editor Integration
|
|
92
|
+
*/
|
|
93
|
+
'should find parent editor': async ({pass, fail}) => {
|
|
94
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
95
|
+
if(control.editor !== editor){
|
|
96
|
+
cleanup(container);
|
|
97
|
+
return fail('FormatBlock should find its parent k-html-editor');
|
|
98
|
+
}
|
|
99
|
+
cleanup(container);
|
|
100
|
+
pass('FormatBlock finds parent editor');
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
'click should call editor.formatBlock with tag value': async ({pass, fail}) => {
|
|
104
|
+
const { container, editor, control } = await createEditorWithControl('h3');
|
|
105
|
+
await control.updateComplete;
|
|
106
|
+
let calledWith = null;
|
|
107
|
+
editor.formatBlock = tag => { calledWith = tag; };
|
|
108
|
+
control.shadowRoot.querySelector('button').click();
|
|
109
|
+
if(calledWith !== 'h3'){
|
|
110
|
+
cleanup(container);
|
|
111
|
+
return fail(`Expected formatBlock("h3"), got formatBlock("${calledWith}")`);
|
|
112
|
+
}
|
|
113
|
+
cleanup(container);
|
|
114
|
+
pass('Click calls editor.formatBlock with tag value');
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
/*
|
|
118
|
+
Helper Methods
|
|
119
|
+
*/
|
|
120
|
+
'getDefaultLabel should return correct labels': async ({pass, fail}) => {
|
|
121
|
+
const { container, control } = await createEditorWithControl('h1');
|
|
122
|
+
const expected = {h1: 'Heading 1', h2: 'Heading 2', p: 'Paragraph'};
|
|
123
|
+
for(const [tag, label] of Object.entries(expected)){
|
|
124
|
+
control.tag = tag;
|
|
125
|
+
if(control.getDefaultLabel() !== label){
|
|
126
|
+
cleanup(container);
|
|
127
|
+
return fail(`Expected label "${label}" for tag "${tag}", got "${control.getDefaultLabel()}"`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
cleanup(container);
|
|
131
|
+
pass('getDefaultLabel returns correct labels');
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
'getDefaultIcon should return correct icons': async ({pass, fail}) => {
|
|
135
|
+
const { container, control } = await createEditorWithControl('h1');
|
|
136
|
+
const expected = {h1: 'format_h1', h2: 'format_h2', p: 'format_paragraph'};
|
|
137
|
+
for(const [tag, icon] of Object.entries(expected)){
|
|
138
|
+
control.tag = tag;
|
|
139
|
+
if(control.getDefaultIcon() !== icon){
|
|
140
|
+
cleanup(container);
|
|
141
|
+
return fail(`Expected icon "${icon}" for tag "${tag}", got "${control.getDefaultIcon()}"`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
cleanup(container);
|
|
145
|
+
pass('getDefaultIcon returns correct icons');
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
/*
|
|
149
|
+
Code Mode Visibility
|
|
150
|
+
*/
|
|
151
|
+
'should hide in code mode': async ({pass, fail}) => {
|
|
152
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
153
|
+
editor.setMode('code');
|
|
154
|
+
await new Promise(r => editor.addEventListener('mode-changed', r, { once: true }));
|
|
155
|
+
await control.updateComplete;
|
|
156
|
+
if(!control.hidden){
|
|
157
|
+
cleanup(container);
|
|
158
|
+
return fail('FormatBlock should be hidden in code mode');
|
|
159
|
+
}
|
|
160
|
+
cleanup(container);
|
|
161
|
+
pass('FormatBlock is hidden in code mode');
|
|
162
|
+
},
|
|
163
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import InlineCode from '../../../src/components/htmlEditorControls/InlineCode.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async () => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-inline-code slot="toolbar-top-left"></k-hec-inline-code>
|
|
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-inline-code');
|
|
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-inline-code element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof InlineCode)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of InlineCode');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('InlineCode 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('InlineCode should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('InlineCode 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('InlineCode should render a button');
|
|
53
|
+
}
|
|
54
|
+
cleanup(container);
|
|
55
|
+
pass('InlineCode renders a button');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
'should render code_blocks 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('InlineCode should render a k-icon');
|
|
65
|
+
}
|
|
66
|
+
if(icon.getAttribute('name') !== 'code_blocks'){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail(`Expected icon name "code_blocks", got "${icon.getAttribute('name')}"`);
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('InlineCode renders code_blocks 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('InlineCode should find its parent k-html-editor');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('InlineCode finds parent editor');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
'click should call editor.inlineCode()': async ({pass, fail}) => {
|
|
88
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
89
|
+
await control.updateComplete;
|
|
90
|
+
let called = false;
|
|
91
|
+
editor.inlineCode = () => { called = true; };
|
|
92
|
+
control.shadowRoot.querySelector('button').click();
|
|
93
|
+
if(!called){
|
|
94
|
+
cleanup(container);
|
|
95
|
+
return fail('Click should call editor.inlineCode()');
|
|
96
|
+
}
|
|
97
|
+
cleanup(container);
|
|
98
|
+
pass('Click calls editor.inlineCode()');
|
|
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('InlineCode should be hidden in code mode');
|
|
112
|
+
}
|
|
113
|
+
cleanup(container);
|
|
114
|
+
pass('InlineCode 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('InlineCode should be visible in visual mode');
|
|
123
|
+
}
|
|
124
|
+
cleanup(container);
|
|
125
|
+
pass('InlineCode is visible in visual mode');
|
|
126
|
+
},
|
|
127
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import InsertTable from '../../../src/components/htmlEditorControls/InsertTable.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async () => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-insert-table slot="toolbar-top-left"></k-hec-insert-table>
|
|
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-insert-table');
|
|
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-insert-table element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof InsertTable)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of InsertTable');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('InsertTable 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('InsertTable should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('InsertTable 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('InsertTable should render a button');
|
|
53
|
+
}
|
|
54
|
+
cleanup(container);
|
|
55
|
+
pass('InsertTable renders a button');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
'should render table 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('InsertTable should render a k-icon');
|
|
65
|
+
}
|
|
66
|
+
if(icon.getAttribute('name') !== 'table'){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail(`Expected icon name "table", got "${icon.getAttribute('name')}"`);
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('InsertTable renders table 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('InsertTable should find its parent k-html-editor');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('InsertTable finds parent editor');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
'click should open a dialog': async ({pass, fail}) => {
|
|
88
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
89
|
+
await control.updateComplete;
|
|
90
|
+
editor.getTableAtSelection = () => null;
|
|
91
|
+
control.shadowRoot.querySelector('button').click();
|
|
92
|
+
await new Promise(r => setTimeout(r, 100));
|
|
93
|
+
const dialog = document.querySelector('k-dialog');
|
|
94
|
+
if(!dialog){
|
|
95
|
+
cleanup(container);
|
|
96
|
+
return fail('Click should open a k-dialog');
|
|
97
|
+
}
|
|
98
|
+
dialog.remove();
|
|
99
|
+
cleanup(container);
|
|
100
|
+
pass('Click opens a dialog');
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/*
|
|
104
|
+
Code Mode Visibility
|
|
105
|
+
*/
|
|
106
|
+
'should hide in code mode': async ({pass, fail}) => {
|
|
107
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
108
|
+
editor.setMode('code');
|
|
109
|
+
await new Promise(r => editor.addEventListener('mode-changed', r, { once: true }));
|
|
110
|
+
await control.updateComplete;
|
|
111
|
+
if(!control.hidden){
|
|
112
|
+
cleanup(container);
|
|
113
|
+
return fail('InsertTable should be hidden in code mode');
|
|
114
|
+
}
|
|
115
|
+
cleanup(container);
|
|
116
|
+
pass('InsertTable is hidden in code mode');
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
'should be visible in visual mode': async ({pass, fail}) => {
|
|
120
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
121
|
+
await control.updateComplete;
|
|
122
|
+
if(control.hidden){
|
|
123
|
+
cleanup(container);
|
|
124
|
+
return fail('InsertTable should be visible in visual mode');
|
|
125
|
+
}
|
|
126
|
+
cleanup(container);
|
|
127
|
+
pass('InsertTable is visible in visual mode');
|
|
128
|
+
},
|
|
129
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import '../../../src/components/HtmlEditor.js';
|
|
2
|
+
import Italic from '../../../src/components/htmlEditorControls/Italic.js';
|
|
3
|
+
|
|
4
|
+
const createEditorWithControl = async () => {
|
|
5
|
+
const container = document.createElement('div');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<k-html-editor>
|
|
8
|
+
<k-hec-italic slot="toolbar-top-left"></k-hec-italic>
|
|
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-italic');
|
|
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-italic element': async ({pass, fail}) => {
|
|
27
|
+
const { container, control } = await createEditorWithControl();
|
|
28
|
+
if(!(control instanceof Italic)){
|
|
29
|
+
cleanup(container);
|
|
30
|
+
return fail('Element should be instance of Italic');
|
|
31
|
+
}
|
|
32
|
+
cleanup(container);
|
|
33
|
+
pass('Italic 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('Italic should have shadow root');
|
|
41
|
+
}
|
|
42
|
+
cleanup(container);
|
|
43
|
+
pass('Italic 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('Italic should render a button');
|
|
53
|
+
}
|
|
54
|
+
cleanup(container);
|
|
55
|
+
pass('Italic renders a button');
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
'should render format_italic 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('Italic should render a k-icon');
|
|
65
|
+
}
|
|
66
|
+
if(icon.getAttribute('name') !== 'format_italic'){
|
|
67
|
+
cleanup(container);
|
|
68
|
+
return fail(`Expected icon name "format_italic", got "${icon.getAttribute('name')}"`);
|
|
69
|
+
}
|
|
70
|
+
cleanup(container);
|
|
71
|
+
pass('Italic renders format_italic 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('Italic should find its parent k-html-editor');
|
|
82
|
+
}
|
|
83
|
+
cleanup(container);
|
|
84
|
+
pass('Italic finds parent editor');
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
'click should call editor.italic()': async ({pass, fail}) => {
|
|
88
|
+
const { container, editor, control } = await createEditorWithControl();
|
|
89
|
+
await control.updateComplete;
|
|
90
|
+
let called = false;
|
|
91
|
+
editor.italic = () => { called = true; };
|
|
92
|
+
control.shadowRoot.querySelector('button').click();
|
|
93
|
+
if(!called){
|
|
94
|
+
cleanup(container);
|
|
95
|
+
return fail('Click should call editor.italic()');
|
|
96
|
+
}
|
|
97
|
+
cleanup(container);
|
|
98
|
+
pass('Click calls editor.italic()');
|
|
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('Italic should be hidden in code mode');
|
|
112
|
+
}
|
|
113
|
+
cleanup(container);
|
|
114
|
+
pass('Italic 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('Italic should be visible in visual mode');
|
|
123
|
+
}
|
|
124
|
+
cleanup(container);
|
|
125
|
+
pass('Italic is visible in visual mode');
|
|
126
|
+
},
|
|
127
|
+
};
|