Skip to content

Commit f234ef1

Browse files
authored
ToHaveStyle improvement (#1950)
* update-1 * updating docs * update
1 parent 5b5c1dd commit f234ef1

File tree

4 files changed

+176
-6
lines changed

4 files changed

+176
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ coverage
66

77
.vscode
88
.idea
9+
.DS_Store
910

1011
*.log
1112
*.log.*

docs/API.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,21 @@ const elem = await $('#elem')
501501
await expect(elem).toHaveId('elem')
502502
```
503503

504+
### toHaveStyle
505+
506+
Checks if an element has specific `CSS` properties. By default, values must match exactly. Only the `CSS` properties you specify are validated; other properties on the element are ignored.
507+
508+
##### Usage
509+
510+
```js
511+
const elem = await $('#elem')
512+
await expect(elem).toHaveStyle({
513+
'font-family': 'Faktum',
514+
'font-weight': '500',
515+
'font-size': '12px',
516+
})
517+
```
518+
504519
### toHaveText
505520

506521
Checks if element has a specific text. Can also be called with an array as parameter in the case where the element can have different texts.
@@ -580,7 +595,7 @@ await expect(list).toHaveChildren() // the list has at least one item
580595
await expect(list).toHaveChildren({ gte: 1 })
581596

582597
await expect(list).toHaveChildren(3) // the list has 3 items
583-
// same as
598+
// same as
584599
await expect(list).toHaveChildren({ eq: 3 })
585600
```
586601

src/utils.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,15 +309,23 @@ export const compareObject = (actual: object | number, expected: string | number
309309
export const compareStyle = async (
310310
actualEl: WebdriverIO.Element,
311311
style: { [key: string]: string },
312-
{ ignoreCase = true, trim = false }
312+
{
313+
ignoreCase = false,
314+
trim = true,
315+
containing = false,
316+
atStart = false,
317+
atEnd = false,
318+
atIndex,
319+
replace,
320+
}: ExpectWebdriverIO.StringOptions
313321
) => {
314322
let result = true
315323
const actual: Record<string, string | undefined> = {}
316324

317325
for (const key in style) {
318326
const css: ParsedCSSValue = await actualEl.getCSSProperty(key)
319327

320-
let actualVal: string = css.value as string
328+
let actualVal: string = String(css.value || '')
321329
let expectedVal: string = style[key]
322330

323331
if (trim) {
@@ -329,8 +337,26 @@ export const compareStyle = async (
329337
expectedVal = expectedVal.toLowerCase()
330338
}
331339

332-
result = result && actualVal === expectedVal
333-
actual[key] = css.value
340+
if (containing) {
341+
result = actualVal.includes(expectedVal)
342+
actual[key] = actualVal
343+
} else if (atStart) {
344+
result = actualVal.startsWith(expectedVal)
345+
actual[key] = actualVal
346+
} else if (atEnd) {
347+
result = actualVal.endsWith(expectedVal)
348+
actual[key] = actualVal
349+
} else if (atIndex) {
350+
result = actualVal.substring(atIndex, actualVal.length).startsWith(expectedVal)
351+
actual[key] = actualVal
352+
} else if (replace){
353+
const replacedActual = replaceActual(replace, actualVal)
354+
result = replacedActual === expectedVal
355+
actual[key] = replacedActual
356+
} else {
357+
result = result && actualVal === expectedVal
358+
actual[key] = css.value
359+
}
334360
}
335361

336362
return {

test/matchers/element/toHaveStyle.test.ts

Lines changed: 129 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,132 @@ describe('toHaveStyle', () => {
224224
expect(result.pass).toBe(true)
225225
expect(el._attempts).toBe(1)
226226
})
227-
})
227+
228+
test('sucess if style matches with containing', async () => {
229+
const el: any = await $('sel')
230+
el._attempts = 0
231+
let counter = 0
232+
233+
el.getCSSProperty = vi.fn().mockImplementation((property: string) => {
234+
counter++
235+
if (counter === Object.keys(mockStyle).length) {
236+
counter = 0
237+
el._attempts++
238+
}
239+
return { value: mockStyle[property] }
240+
})
241+
242+
const result = await toHaveStyle.call(
243+
{},
244+
el,
245+
{
246+
'font-family': 'Faktum',
247+
'font-size': '26',
248+
color: '000',
249+
},
250+
{ containing: true }
251+
)
252+
expect(result.pass).toBe(true)
253+
expect(el._attempts).toBe(1)
254+
})
255+
256+
test('sucess if style matches with atStart', async () => {
257+
const el: any = await $('sel')
258+
el._attempts = 0
259+
let counter = 0
260+
261+
const actualStyle: { [key: string]: string } = {
262+
'font-family': 'Faktum Lorem ipsum dolor sit amet',
263+
'text-rendering': 'optimizeLegibility',
264+
'overflow-wrap': 'break-word',
265+
}
266+
267+
el.getCSSProperty = vi.fn().mockImplementation((property: string) => {
268+
counter++
269+
if (counter === Object.keys(actualStyle).length) {
270+
counter = 0
271+
el._attempts++
272+
}
273+
return { value: actualStyle[property] }
274+
})
275+
276+
const result = await toHaveStyle.call(
277+
{},
278+
el,
279+
{
280+
'font-family': 'Faktum',
281+
'text-rendering': 'optimize',
282+
'overflow-wrap': 'break',
283+
},
284+
{ atStart: true }
285+
)
286+
expect(result.pass).toBe(true)
287+
expect(el._attempts).toBe(1)
288+
})
289+
290+
test('sucess if style matches with atEnd', async () => {
291+
const el: any = await $('sel')
292+
el._attempts = 0
293+
let counter = 0
294+
295+
const actualStyle: { [key: string]: string } = {
296+
'font-family': 'Faktum Lorem ipsum dolor sit amet',
297+
'text-rendering': 'optimizeLegibility',
298+
'overflow-wrap': 'break-word',
299+
}
300+
301+
el.getCSSProperty = vi.fn().mockImplementation((property: string) => {
302+
counter++
303+
if (counter === Object.keys(actualStyle).length) {
304+
counter = 0
305+
el._attempts++
306+
}
307+
return { value: actualStyle[property] }
308+
})
309+
310+
const result = await toHaveStyle.call(
311+
{},
312+
el,
313+
{
314+
'font-family': 'sit amet',
315+
'text-rendering': 'Legibility',
316+
'overflow-wrap': '-word',
317+
},
318+
{ atEnd: true }
319+
)
320+
expect(result.pass).toBe(true)
321+
expect(el._attempts).toBe(1)
322+
})
323+
324+
test('sucess if style matches with atIndex', async () => {
325+
const el: any = await $('sel')
326+
el._attempts = 0
327+
let counter = 0
328+
329+
const actualStyle: { [key: string]: string } = {
330+
'font-family': 'Faktum Lorem ipsum dolor sit amet',
331+
'text-rendering': 'optimizeLegibility',
332+
'overflow-wrap': 'break-word',
333+
}
334+
335+
el.getCSSProperty = vi.fn().mockImplementation((property: string) => {
336+
counter++
337+
if (counter === Object.keys(actualStyle).length) {
338+
counter = 0
339+
el._attempts++
340+
}
341+
return { value: actualStyle[property] }
342+
})
343+
344+
const result = await toHaveStyle.call({}, el,
345+
{
346+
'font-family': 'tum Lorem ipsum dolor sit amet',
347+
'text-rendering': 'imizeLegibility',
348+
'overflow-wrap': 'ak-word',
349+
},
350+
{ atIndex: 3 })
351+
expect(result.pass).toBe(true)
352+
expect(el._attempts).toBe(1)
353+
})
354+
355+
})

0 commit comments

Comments
 (0)