kempo-css 1.1.1 → 1.1.2
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/docs/docs.inc.html +39 -0
- package/docs/kempo.css +36 -2
- package/docs/theme-editor.html +5 -2
- package/package.json +3 -1
- package/scripts/build.js +4 -4
- package/src/kempo.css +36 -2
- package/tests/base_reset.browser-test.js +201 -0
- package/tests/buttons.browser-test.js +223 -0
- package/tests/colors.browser-test.js +221 -0
- package/tests/components.browser-test.js +144 -0
- package/tests/css_variables.browser-test.js +170 -0
- package/tests/display_flex.browser-test.js +159 -0
- package/tests/forms.browser-test.js +224 -0
- package/tests/rows_columns.browser-test.js +171 -0
- package/tests/spacing.browser-test.js +310 -0
- package/tests/tables.browser-test.js +192 -0
- package/tests/typography.browser-test.js +255 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const getStyle = (el, prop) => getComputedStyle(el)[prop];
|
|
2
|
+
|
|
3
|
+
export const beforeAll = async () => {
|
|
4
|
+
const link = document.createElement('link');
|
|
5
|
+
link.rel = 'stylesheet';
|
|
6
|
+
link.href = '/src/kempo.css';
|
|
7
|
+
document.head.appendChild(link);
|
|
8
|
+
await new Promise(resolve => link.onload = resolve);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
'should apply flex display to .row': ({pass, fail}) => {
|
|
13
|
+
const el = document.createElement('div');
|
|
14
|
+
el.className = 'row';
|
|
15
|
+
document.body.appendChild(el);
|
|
16
|
+
const display = getStyle(el, 'display');
|
|
17
|
+
const flexWrap = getStyle(el, 'flexWrap');
|
|
18
|
+
el.remove();
|
|
19
|
+
if(display === 'flex' && flexWrap === 'wrap'){
|
|
20
|
+
pass('.row applies flex with wrap');
|
|
21
|
+
} else {
|
|
22
|
+
fail(`Expected flex/wrap, got display: ${display}, wrap: ${flexWrap}`);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
'should apply flex to .col': ({pass, fail}) => {
|
|
27
|
+
const el = document.createElement('div');
|
|
28
|
+
el.className = 'col';
|
|
29
|
+
document.body.appendChild(el);
|
|
30
|
+
const flexGrow = getStyle(el, 'flexGrow');
|
|
31
|
+
el.remove();
|
|
32
|
+
if(flexGrow === '1'){
|
|
33
|
+
pass('.col has flex-grow: 1');
|
|
34
|
+
} else {
|
|
35
|
+
fail(`Expected flex-grow: 1, got ${flexGrow}`);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
'should apply span-6 as 50% width': ({pass, fail}) => {
|
|
40
|
+
const row = document.createElement('div');
|
|
41
|
+
row.className = 'row';
|
|
42
|
+
row.style.width = '1000px';
|
|
43
|
+
const col = document.createElement('div');
|
|
44
|
+
col.className = 'span-6';
|
|
45
|
+
row.appendChild(col);
|
|
46
|
+
document.body.appendChild(row);
|
|
47
|
+
const flexBasis = getStyle(col, 'flexBasis');
|
|
48
|
+
row.remove();
|
|
49
|
+
if(flexBasis === '50%'){
|
|
50
|
+
pass('.span-6 sets flex-basis to 50%');
|
|
51
|
+
} else {
|
|
52
|
+
fail(`Expected 50%, got ${flexBasis}`);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
'should apply span-12 as 100% width': ({pass, fail}) => {
|
|
57
|
+
const col = document.createElement('div');
|
|
58
|
+
col.className = 'span-12';
|
|
59
|
+
document.body.appendChild(col);
|
|
60
|
+
const flexBasis = getStyle(col, 'flexBasis');
|
|
61
|
+
col.remove();
|
|
62
|
+
if(flexBasis === '100%'){
|
|
63
|
+
pass('.span-12 sets flex-basis to 100%');
|
|
64
|
+
} else {
|
|
65
|
+
fail(`Expected 100%, got ${flexBasis}`);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
'should apply span-4 as ~33.333% width': ({pass, fail}) => {
|
|
70
|
+
const col = document.createElement('div');
|
|
71
|
+
col.className = 'span-4';
|
|
72
|
+
document.body.appendChild(col);
|
|
73
|
+
const flexBasis = getStyle(col, 'flexBasis');
|
|
74
|
+
col.remove();
|
|
75
|
+
if(flexBasis.includes('33.333')){
|
|
76
|
+
pass(`.span-4 sets flex-basis to ${flexBasis}`);
|
|
77
|
+
} else {
|
|
78
|
+
fail(`Expected ~33.333%, got ${flexBasis}`);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
'should apply span-3 as 25% width': ({pass, fail}) => {
|
|
83
|
+
const col = document.createElement('div');
|
|
84
|
+
col.className = 'span-3';
|
|
85
|
+
document.body.appendChild(col);
|
|
86
|
+
const flexBasis = getStyle(col, 'flexBasis');
|
|
87
|
+
col.remove();
|
|
88
|
+
if(flexBasis === '25%'){
|
|
89
|
+
pass('.span-3 sets flex-basis to 25%');
|
|
90
|
+
} else {
|
|
91
|
+
fail(`Expected 25%, got ${flexBasis}`);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
'should apply grid columns with .cols-2': ({pass, fail}) => {
|
|
96
|
+
const el = document.createElement('div');
|
|
97
|
+
el.className = 'd-g cols-2';
|
|
98
|
+
document.body.appendChild(el);
|
|
99
|
+
const cols = getStyle(el, 'gridTemplateColumns');
|
|
100
|
+
el.remove();
|
|
101
|
+
if(cols.split(' ').length === 2){
|
|
102
|
+
pass(`.cols-2 creates 2 columns: ${cols}`);
|
|
103
|
+
} else {
|
|
104
|
+
fail(`Expected 2 columns, got ${cols}`);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
'should apply grid columns with .cols-3': ({pass, fail}) => {
|
|
109
|
+
const el = document.createElement('div');
|
|
110
|
+
el.className = 'd-g cols-3';
|
|
111
|
+
document.body.appendChild(el);
|
|
112
|
+
const cols = getStyle(el, 'gridTemplateColumns');
|
|
113
|
+
el.remove();
|
|
114
|
+
if(cols.split(' ').length === 3){
|
|
115
|
+
pass(`.cols-3 creates 3 columns: ${cols}`);
|
|
116
|
+
} else {
|
|
117
|
+
fail(`Expected 3 columns, got ${cols}`);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
'should apply grid columns with .cols-4': ({pass, fail}) => {
|
|
122
|
+
const el = document.createElement('div');
|
|
123
|
+
el.className = 'd-g cols-4';
|
|
124
|
+
document.body.appendChild(el);
|
|
125
|
+
const cols = getStyle(el, 'gridTemplateColumns');
|
|
126
|
+
el.remove();
|
|
127
|
+
if(cols.split(' ').length === 4){
|
|
128
|
+
pass(`.cols-4 creates 4 columns: ${cols}`);
|
|
129
|
+
} else {
|
|
130
|
+
fail(`Expected 4 columns, got ${cols}`);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
'should have all span classes 1-12': ({pass, fail}) => {
|
|
135
|
+
const missing = [];
|
|
136
|
+
for(let i = 1; i <= 12; i++){
|
|
137
|
+
const col = document.createElement('div');
|
|
138
|
+
col.className = `span-${i}`;
|
|
139
|
+
document.body.appendChild(col);
|
|
140
|
+
const flexBasis = getStyle(col, 'flexBasis');
|
|
141
|
+
col.remove();
|
|
142
|
+
if(!flexBasis || flexBasis === '0%' || flexBasis === 'auto'){
|
|
143
|
+
missing.push(i);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if(missing.length === 0){
|
|
147
|
+
pass('All span-1 through span-12 classes exist');
|
|
148
|
+
} else {
|
|
149
|
+
fail(`Missing spans: ${missing.join(', ')}`);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
'should have cols classes 2-10': ({pass, fail}) => {
|
|
154
|
+
const working = [];
|
|
155
|
+
for(let i = 2; i <= 10; i++){
|
|
156
|
+
const el = document.createElement('div');
|
|
157
|
+
el.className = `d-g cols-${i}`;
|
|
158
|
+
document.body.appendChild(el);
|
|
159
|
+
const cols = getStyle(el, 'gridTemplateColumns');
|
|
160
|
+
el.remove();
|
|
161
|
+
if(cols.split(' ').length === i){
|
|
162
|
+
working.push(i);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if(working.length === 9){
|
|
166
|
+
pass('All cols-2 through cols-10 classes work');
|
|
167
|
+
} else {
|
|
168
|
+
fail(`Working: ${working.join(', ')}, expected 2-10`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
const getStyle = (el, prop) => getComputedStyle(el)[prop];
|
|
2
|
+
|
|
3
|
+
export const beforeAll = async () => {
|
|
4
|
+
const link = document.createElement('link');
|
|
5
|
+
link.rel = 'stylesheet';
|
|
6
|
+
link.href = '/src/kempo.css';
|
|
7
|
+
document.head.appendChild(link);
|
|
8
|
+
await new Promise(resolve => link.onload = resolve);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
'should apply full padding with .p': ({pass, fail}) => {
|
|
13
|
+
const el = document.createElement('div');
|
|
14
|
+
el.className = 'p';
|
|
15
|
+
document.body.appendChild(el);
|
|
16
|
+
const pt = parseFloat(getStyle(el, 'paddingTop'));
|
|
17
|
+
const pr = parseFloat(getStyle(el, 'paddingRight'));
|
|
18
|
+
const pb = parseFloat(getStyle(el, 'paddingBottom'));
|
|
19
|
+
const pl = parseFloat(getStyle(el, 'paddingLeft'));
|
|
20
|
+
el.remove();
|
|
21
|
+
if(pt > 0 && pr > 0 && pb > 0 && pl > 0 && pt === pr && pr === pb && pb === pl){
|
|
22
|
+
pass(`.p applies equal padding on all sides: ${pt}px`);
|
|
23
|
+
} else {
|
|
24
|
+
fail(`Expected equal padding, got t:${pt} r:${pr} b:${pb} l:${pl}`);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
'should apply directional padding classes': ({pass, fail}) => {
|
|
29
|
+
const tests = [
|
|
30
|
+
{className: 'pt', prop: 'paddingTop'},
|
|
31
|
+
{className: 'pr', prop: 'paddingRight'},
|
|
32
|
+
{className: 'pb', prop: 'paddingBottom'},
|
|
33
|
+
{className: 'pl', prop: 'paddingLeft'}
|
|
34
|
+
];
|
|
35
|
+
const failed = [];
|
|
36
|
+
tests.forEach(({className, prop}) => {
|
|
37
|
+
const el = document.createElement('div');
|
|
38
|
+
el.className = className;
|
|
39
|
+
document.body.appendChild(el);
|
|
40
|
+
const value = parseFloat(getStyle(el, prop));
|
|
41
|
+
el.remove();
|
|
42
|
+
if(value <= 0){
|
|
43
|
+
failed.push(`${className}: ${value}`);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
if(failed.length === 0){
|
|
47
|
+
pass('Directional padding classes work');
|
|
48
|
+
} else {
|
|
49
|
+
fail(`Failed: ${failed.join(', ')}`);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
'should apply axis padding with .px and .py': ({pass, fail}) => {
|
|
54
|
+
const elX = document.createElement('div');
|
|
55
|
+
elX.className = 'px';
|
|
56
|
+
const elY = document.createElement('div');
|
|
57
|
+
elY.className = 'py';
|
|
58
|
+
document.body.appendChild(elX);
|
|
59
|
+
document.body.appendChild(elY);
|
|
60
|
+
const pxL = parseFloat(getStyle(elX, 'paddingLeft'));
|
|
61
|
+
const pxR = parseFloat(getStyle(elX, 'paddingRight'));
|
|
62
|
+
const pyT = parseFloat(getStyle(elY, 'paddingTop'));
|
|
63
|
+
const pyB = parseFloat(getStyle(elY, 'paddingBottom'));
|
|
64
|
+
elX.remove();
|
|
65
|
+
elY.remove();
|
|
66
|
+
if(pxL > 0 && pxR > 0 && pyT > 0 && pyB > 0){
|
|
67
|
+
pass('.px and .py apply axis padding');
|
|
68
|
+
} else {
|
|
69
|
+
fail(`px: L${pxL}/R${pxR}, py: T${pyT}/B${pyB}`);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
'should apply half padding with .ph': ({pass, fail}) => {
|
|
74
|
+
const full = document.createElement('div');
|
|
75
|
+
full.className = 'p';
|
|
76
|
+
const half = document.createElement('div');
|
|
77
|
+
half.className = 'ph';
|
|
78
|
+
document.body.appendChild(full);
|
|
79
|
+
document.body.appendChild(half);
|
|
80
|
+
const fullVal = parseFloat(getStyle(full, 'paddingTop'));
|
|
81
|
+
const halfVal = parseFloat(getStyle(half, 'paddingTop'));
|
|
82
|
+
full.remove();
|
|
83
|
+
half.remove();
|
|
84
|
+
if(halfVal < fullVal && halfVal > 0){
|
|
85
|
+
pass(`.ph is smaller than .p (${halfVal}px < ${fullVal}px)`);
|
|
86
|
+
} else {
|
|
87
|
+
fail(`Expected half: ${halfVal} < full: ${fullVal}`);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
'should apply quarter padding with .pq': ({pass, fail}) => {
|
|
92
|
+
const full = document.createElement('div');
|
|
93
|
+
full.className = 'p';
|
|
94
|
+
const quarter = document.createElement('div');
|
|
95
|
+
quarter.className = 'pq';
|
|
96
|
+
document.body.appendChild(full);
|
|
97
|
+
document.body.appendChild(quarter);
|
|
98
|
+
const fullVal = parseFloat(getStyle(full, 'paddingTop'));
|
|
99
|
+
const quarterVal = parseFloat(getStyle(quarter, 'paddingTop'));
|
|
100
|
+
full.remove();
|
|
101
|
+
quarter.remove();
|
|
102
|
+
if(quarterVal < fullVal && quarterVal > 0){
|
|
103
|
+
pass(`.pq is smaller than .p (${quarterVal}px < ${fullVal}px)`);
|
|
104
|
+
} else {
|
|
105
|
+
fail(`Expected quarter: ${quarterVal} < full: ${fullVal}`);
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
'should reset padding with .p0': ({pass, fail}) => {
|
|
110
|
+
const el = document.createElement('div');
|
|
111
|
+
el.className = 'p0';
|
|
112
|
+
el.style.padding = '50px';
|
|
113
|
+
document.body.appendChild(el);
|
|
114
|
+
const pt = parseFloat(getStyle(el, 'paddingTop'));
|
|
115
|
+
el.remove();
|
|
116
|
+
if(pt < 1){
|
|
117
|
+
pass('.p0 resets padding to ~0');
|
|
118
|
+
} else {
|
|
119
|
+
fail(`Expected ~0, got ${pt}px`);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
'should apply full margin with .m': ({pass, fail}) => {
|
|
124
|
+
const el = document.createElement('div');
|
|
125
|
+
el.className = 'm';
|
|
126
|
+
document.body.appendChild(el);
|
|
127
|
+
const mt = parseFloat(getStyle(el, 'marginTop'));
|
|
128
|
+
const mr = parseFloat(getStyle(el, 'marginRight'));
|
|
129
|
+
const mb = parseFloat(getStyle(el, 'marginBottom'));
|
|
130
|
+
const ml = parseFloat(getStyle(el, 'marginLeft'));
|
|
131
|
+
el.remove();
|
|
132
|
+
if(mt > 0 && mr > 0 && mb > 0 && ml > 0){
|
|
133
|
+
pass(`.m applies margin on all sides: ${mt}px`);
|
|
134
|
+
} else {
|
|
135
|
+
fail(`Expected positive margins, got t:${mt} r:${mr} b:${mb} l:${ml}`);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
'should apply directional margin classes': ({pass, fail}) => {
|
|
140
|
+
const tests = [
|
|
141
|
+
{className: 'mt', prop: 'marginTop'},
|
|
142
|
+
{className: 'mr', prop: 'marginRight'},
|
|
143
|
+
{className: 'mb', prop: 'marginBottom'},
|
|
144
|
+
{className: 'ml', prop: 'marginLeft'}
|
|
145
|
+
];
|
|
146
|
+
const failed = [];
|
|
147
|
+
tests.forEach(({className, prop}) => {
|
|
148
|
+
const el = document.createElement('div');
|
|
149
|
+
el.className = className;
|
|
150
|
+
document.body.appendChild(el);
|
|
151
|
+
const value = parseFloat(getStyle(el, prop));
|
|
152
|
+
el.remove();
|
|
153
|
+
if(value <= 0){
|
|
154
|
+
failed.push(`${className}: ${value}`);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
if(failed.length === 0){
|
|
158
|
+
pass('Directional margin classes work');
|
|
159
|
+
} else {
|
|
160
|
+
fail(`Failed: ${failed.join(', ')}`);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
'should reset margin with .m0': ({pass, fail}) => {
|
|
165
|
+
const el = document.createElement('div');
|
|
166
|
+
el.className = 'm0';
|
|
167
|
+
el.style.margin = '50px';
|
|
168
|
+
document.body.appendChild(el);
|
|
169
|
+
const mt = parseFloat(getStyle(el, 'marginTop'));
|
|
170
|
+
el.remove();
|
|
171
|
+
if(mt === 0){
|
|
172
|
+
pass('.m0 resets margin to 0');
|
|
173
|
+
} else {
|
|
174
|
+
fail(`Expected 0, got ${mt}px`);
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
'should apply negative margin with .-m': ({pass, fail}) => {
|
|
179
|
+
const el = document.createElement('div');
|
|
180
|
+
el.className = '-m';
|
|
181
|
+
document.body.appendChild(el);
|
|
182
|
+
const mt = parseFloat(getStyle(el, 'marginTop'));
|
|
183
|
+
el.remove();
|
|
184
|
+
if(mt < 0){
|
|
185
|
+
pass(`.-m applies negative margin: ${mt}px`);
|
|
186
|
+
} else {
|
|
187
|
+
fail(`Expected negative margin, got ${mt}px`);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
'should apply border with .b': ({pass, fail}) => {
|
|
192
|
+
const el = document.createElement('div');
|
|
193
|
+
el.className = 'b';
|
|
194
|
+
document.body.appendChild(el);
|
|
195
|
+
const bt = parseFloat(getStyle(el, 'borderTopWidth'));
|
|
196
|
+
const br = parseFloat(getStyle(el, 'borderRightWidth'));
|
|
197
|
+
const bb = parseFloat(getStyle(el, 'borderBottomWidth'));
|
|
198
|
+
const bl = parseFloat(getStyle(el, 'borderLeftWidth'));
|
|
199
|
+
el.remove();
|
|
200
|
+
if(bt > 0 && br > 0 && bb > 0 && bl > 0){
|
|
201
|
+
pass('.b applies border on all sides');
|
|
202
|
+
} else {
|
|
203
|
+
fail(`Expected borders, got t:${bt} r:${br} b:${bb} l:${bl}`);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
'should apply directional borders': ({pass, fail}) => {
|
|
208
|
+
const tests = [
|
|
209
|
+
{className: 'bt', prop: 'borderTopWidth'},
|
|
210
|
+
{className: 'br', prop: 'borderRightWidth'},
|
|
211
|
+
{className: 'bb', prop: 'borderBottomWidth'},
|
|
212
|
+
{className: 'bl', prop: 'borderLeftWidth'}
|
|
213
|
+
];
|
|
214
|
+
const failed = [];
|
|
215
|
+
tests.forEach(({className, prop}) => {
|
|
216
|
+
const el = document.createElement('div');
|
|
217
|
+
el.className = className;
|
|
218
|
+
document.body.appendChild(el);
|
|
219
|
+
const value = parseFloat(getStyle(el, prop));
|
|
220
|
+
el.remove();
|
|
221
|
+
if(value <= 0){
|
|
222
|
+
failed.push(`${className}: ${value}`);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
if(failed.length === 0){
|
|
226
|
+
pass('Directional border classes work');
|
|
227
|
+
} else {
|
|
228
|
+
fail(`Failed: ${failed.join(', ')}`);
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
'should remove border with .b0': ({pass, fail}) => {
|
|
233
|
+
const el = document.createElement('div');
|
|
234
|
+
el.className = 'b0';
|
|
235
|
+
el.style.border = '5px solid red';
|
|
236
|
+
document.body.appendChild(el);
|
|
237
|
+
const bt = getStyle(el, 'borderTopStyle');
|
|
238
|
+
el.remove();
|
|
239
|
+
if(bt === 'none'){
|
|
240
|
+
pass('.b0 removes borders');
|
|
241
|
+
} else {
|
|
242
|
+
fail(`Expected none, got ${bt}`);
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
'should apply border radius with .r': ({pass, fail}) => {
|
|
247
|
+
const el = document.createElement('div');
|
|
248
|
+
el.className = 'r';
|
|
249
|
+
document.body.appendChild(el);
|
|
250
|
+
const radius = parseFloat(getStyle(el, 'borderTopLeftRadius'));
|
|
251
|
+
el.remove();
|
|
252
|
+
if(radius > 0){
|
|
253
|
+
pass(`.r applies border radius: ${radius}px`);
|
|
254
|
+
} else {
|
|
255
|
+
fail(`Expected radius, got ${radius}`);
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
'should apply corner-specific radius': ({pass, fail}) => {
|
|
260
|
+
const tests = [
|
|
261
|
+
{className: 'rtl', prop: 'borderTopLeftRadius'},
|
|
262
|
+
{className: 'rtr', prop: 'borderTopRightRadius'},
|
|
263
|
+
{className: 'rbr', prop: 'borderBottomRightRadius'},
|
|
264
|
+
{className: 'rbl', prop: 'borderBottomLeftRadius'}
|
|
265
|
+
];
|
|
266
|
+
const failed = [];
|
|
267
|
+
tests.forEach(({className, prop}) => {
|
|
268
|
+
const el = document.createElement('div');
|
|
269
|
+
el.className = className;
|
|
270
|
+
document.body.appendChild(el);
|
|
271
|
+
const value = parseFloat(getStyle(el, prop));
|
|
272
|
+
el.remove();
|
|
273
|
+
if(value <= 0){
|
|
274
|
+
failed.push(`${className}: ${value}`);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
if(failed.length === 0){
|
|
278
|
+
pass('Corner radius classes work');
|
|
279
|
+
} else {
|
|
280
|
+
fail(`Failed: ${failed.join(', ')}`);
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
'should remove radius with .r0': ({pass, fail}) => {
|
|
285
|
+
const el = document.createElement('div');
|
|
286
|
+
el.className = 'r0';
|
|
287
|
+
el.style.borderRadius = '20px';
|
|
288
|
+
document.body.appendChild(el);
|
|
289
|
+
const radius = parseFloat(getStyle(el, 'borderTopLeftRadius'));
|
|
290
|
+
el.remove();
|
|
291
|
+
if(radius === 0){
|
|
292
|
+
pass('.r0 removes border radius');
|
|
293
|
+
} else {
|
|
294
|
+
fail(`Expected 0, got ${radius}`);
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
'should apply pill shape with .round': ({pass, fail}) => {
|
|
299
|
+
const el = document.createElement('div');
|
|
300
|
+
el.className = 'round';
|
|
301
|
+
document.body.appendChild(el);
|
|
302
|
+
const radius = parseFloat(getStyle(el, 'borderTopLeftRadius'));
|
|
303
|
+
el.remove();
|
|
304
|
+
if(radius > 1000){
|
|
305
|
+
pass(`.round applies large radius: ${radius}px`);
|
|
306
|
+
} else {
|
|
307
|
+
fail(`Expected very large radius, got ${radius}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
const getStyle = (el, prop) => getComputedStyle(el)[prop];
|
|
2
|
+
|
|
3
|
+
export const beforeAll = async () => {
|
|
4
|
+
const link = document.createElement('link');
|
|
5
|
+
link.rel = 'stylesheet';
|
|
6
|
+
link.href = '/src/kempo.css';
|
|
7
|
+
document.head.appendChild(link);
|
|
8
|
+
await new Promise(resolve => link.onload = resolve);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
'should make table full width': ({pass, fail}) => {
|
|
13
|
+
const table = document.createElement('table');
|
|
14
|
+
document.body.appendChild(table);
|
|
15
|
+
const width = getStyle(table, 'width');
|
|
16
|
+
table.remove();
|
|
17
|
+
if(width.endsWith('%') || parseFloat(width) > 500){
|
|
18
|
+
pass(`Table has full width: ${width}`);
|
|
19
|
+
} else {
|
|
20
|
+
fail(`Expected full width, got ${width}`);
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
'should collapse table borders': ({pass, fail}) => {
|
|
25
|
+
const table = document.createElement('table');
|
|
26
|
+
document.body.appendChild(table);
|
|
27
|
+
const borderSpacing = getStyle(table, 'borderSpacing');
|
|
28
|
+
table.remove();
|
|
29
|
+
if(borderSpacing === '0px' || borderSpacing === '0px 0px'){
|
|
30
|
+
pass('Table has collapsed borders (border-spacing: 0)');
|
|
31
|
+
} else {
|
|
32
|
+
fail(`Expected 0 border-spacing, got ${borderSpacing}`);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
'should style th with bold font': ({pass, fail}) => {
|
|
37
|
+
const table = document.createElement('table');
|
|
38
|
+
const tr = document.createElement('tr');
|
|
39
|
+
const th = document.createElement('th');
|
|
40
|
+
th.textContent = 'Header';
|
|
41
|
+
tr.appendChild(th);
|
|
42
|
+
table.appendChild(tr);
|
|
43
|
+
document.body.appendChild(table);
|
|
44
|
+
const fontWeight = getStyle(th, 'fontWeight');
|
|
45
|
+
table.remove();
|
|
46
|
+
if(parseInt(fontWeight) >= 700){
|
|
47
|
+
pass(`th has bold font weight: ${fontWeight}`);
|
|
48
|
+
} else {
|
|
49
|
+
fail(`Expected bold, got ${fontWeight}`);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
'should style th with background': ({pass, fail}) => {
|
|
54
|
+
const table = document.createElement('table');
|
|
55
|
+
const tr = document.createElement('tr');
|
|
56
|
+
const th = document.createElement('th');
|
|
57
|
+
tr.appendChild(th);
|
|
58
|
+
table.appendChild(tr);
|
|
59
|
+
document.body.appendChild(table);
|
|
60
|
+
const bg = getStyle(th, 'backgroundColor');
|
|
61
|
+
table.remove();
|
|
62
|
+
if(bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent'){
|
|
63
|
+
pass(`th has background: ${bg}`);
|
|
64
|
+
} else {
|
|
65
|
+
fail('th should have background color');
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
'should apply left text-align to th': ({pass, fail}) => {
|
|
70
|
+
const table = document.createElement('table');
|
|
71
|
+
const tr = document.createElement('tr');
|
|
72
|
+
const th = document.createElement('th');
|
|
73
|
+
tr.appendChild(th);
|
|
74
|
+
table.appendChild(tr);
|
|
75
|
+
document.body.appendChild(table);
|
|
76
|
+
const textAlign = getStyle(th, 'textAlign');
|
|
77
|
+
table.remove();
|
|
78
|
+
if(textAlign === 'left' || textAlign === 'start'){
|
|
79
|
+
pass(`th has left alignment: ${textAlign}`);
|
|
80
|
+
} else {
|
|
81
|
+
fail(`Expected left alignment, got ${textAlign}`);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
'should apply padding to th and td': ({pass, fail}) => {
|
|
86
|
+
const table = document.createElement('table');
|
|
87
|
+
const tr = document.createElement('tr');
|
|
88
|
+
const th = document.createElement('th');
|
|
89
|
+
const td = document.createElement('td');
|
|
90
|
+
tr.appendChild(th);
|
|
91
|
+
tr.appendChild(td);
|
|
92
|
+
table.appendChild(tr);
|
|
93
|
+
document.body.appendChild(table);
|
|
94
|
+
const thPadding = parseFloat(getStyle(th, 'padding'));
|
|
95
|
+
const tdPadding = parseFloat(getStyle(td, 'padding'));
|
|
96
|
+
table.remove();
|
|
97
|
+
if(thPadding > 0 && tdPadding > 0){
|
|
98
|
+
pass(`th and td have padding: th=${thPadding}px, td=${tdPadding}px`);
|
|
99
|
+
} else {
|
|
100
|
+
fail(`Expected padding, got th: ${thPadding}, td: ${tdPadding}`);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
'should apply borders to th and td': ({pass, fail}) => {
|
|
105
|
+
const table = document.createElement('table');
|
|
106
|
+
const tr = document.createElement('tr');
|
|
107
|
+
const th = document.createElement('th');
|
|
108
|
+
const td = document.createElement('td');
|
|
109
|
+
tr.appendChild(th);
|
|
110
|
+
tr.appendChild(td);
|
|
111
|
+
table.appendChild(tr);
|
|
112
|
+
document.body.appendChild(table);
|
|
113
|
+
const thBorder = parseFloat(getStyle(th, 'borderBottomWidth'));
|
|
114
|
+
const tdBorder = parseFloat(getStyle(td, 'borderBottomWidth'));
|
|
115
|
+
table.remove();
|
|
116
|
+
if(thBorder > 0 && tdBorder > 0){
|
|
117
|
+
pass('th and td have borders');
|
|
118
|
+
} else {
|
|
119
|
+
fail(`Expected borders, got th: ${thBorder}, td: ${tdBorder}`);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
'should apply border radius to first th': ({pass, fail}) => {
|
|
124
|
+
const table = document.createElement('table');
|
|
125
|
+
const tr = document.createElement('tr');
|
|
126
|
+
const th = document.createElement('th');
|
|
127
|
+
tr.appendChild(th);
|
|
128
|
+
table.appendChild(tr);
|
|
129
|
+
document.body.appendChild(table);
|
|
130
|
+
const radius = parseFloat(getStyle(th, 'borderTopLeftRadius'));
|
|
131
|
+
table.remove();
|
|
132
|
+
if(radius > 0){
|
|
133
|
+
pass(`First th has border-top-left-radius: ${radius}px`);
|
|
134
|
+
} else {
|
|
135
|
+
fail('First th should have border radius');
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
'should apply border radius to last th': ({pass, fail}) => {
|
|
140
|
+
const table = document.createElement('table');
|
|
141
|
+
const tr = document.createElement('tr');
|
|
142
|
+
const th1 = document.createElement('th');
|
|
143
|
+
const th2 = document.createElement('th');
|
|
144
|
+
tr.appendChild(th1);
|
|
145
|
+
tr.appendChild(th2);
|
|
146
|
+
table.appendChild(tr);
|
|
147
|
+
document.body.appendChild(table);
|
|
148
|
+
const radius = parseFloat(getStyle(th2, 'borderTopRightRadius'));
|
|
149
|
+
table.remove();
|
|
150
|
+
if(radius > 0){
|
|
151
|
+
pass(`Last th has border-top-right-radius: ${radius}px`);
|
|
152
|
+
} else {
|
|
153
|
+
fail('Last th should have border radius');
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
'should apply border radius to last row cells': ({pass, fail}) => {
|
|
158
|
+
const table = document.createElement('table');
|
|
159
|
+
const tr1 = document.createElement('tr');
|
|
160
|
+
const th = document.createElement('th');
|
|
161
|
+
tr1.appendChild(th);
|
|
162
|
+
const tr2 = document.createElement('tr');
|
|
163
|
+
const td1 = document.createElement('td');
|
|
164
|
+
const td2 = document.createElement('td');
|
|
165
|
+
tr2.appendChild(td1);
|
|
166
|
+
tr2.appendChild(td2);
|
|
167
|
+
table.appendChild(tr1);
|
|
168
|
+
table.appendChild(tr2);
|
|
169
|
+
document.body.appendChild(table);
|
|
170
|
+
const td1Radius = parseFloat(getStyle(td1, 'borderBottomLeftRadius'));
|
|
171
|
+
const td2Radius = parseFloat(getStyle(td2, 'borderBottomRightRadius'));
|
|
172
|
+
table.remove();
|
|
173
|
+
if(td1Radius > 0 && td2Radius > 0){
|
|
174
|
+
pass('Last row has corner border radius');
|
|
175
|
+
} else {
|
|
176
|
+
fail(`Expected radius, got td1: ${td1Radius}, td2: ${td2Radius}`);
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
'should style .table-wrapper with overflow-x auto': ({pass, fail}) => {
|
|
181
|
+
const wrapper = document.createElement('div');
|
|
182
|
+
wrapper.className = 'table-wrapper';
|
|
183
|
+
document.body.appendChild(wrapper);
|
|
184
|
+
const overflow = getStyle(wrapper, 'overflowX');
|
|
185
|
+
wrapper.remove();
|
|
186
|
+
if(overflow === 'auto'){
|
|
187
|
+
pass('.table-wrapper has overflow-x: auto');
|
|
188
|
+
} else {
|
|
189
|
+
fail(`Expected auto, got ${overflow}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|