diff --git a/src/matchers/element/toHaveHeight.ts b/src/matchers/element/toHaveHeight.ts index 60d1c02a6..0905d2183 100644 --- a/src/matchers/element/toHaveHeight.ts +++ b/src/matchers/element/toHaveHeight.ts @@ -1,24 +1,25 @@ import { DEFAULT_OPTIONS } from '../../constants.js' import type { WdioElementMaybePromise } from '../../types.js' import { + compareNumbers, enhanceError, executeCommand, + numberError, waitUntil, - wrapExpectedWithArray } from '../../utils.js' -async function condition(el: WebdriverIO.Element, height: number) { +async function condition(el: WebdriverIO.Element, height: number, options: ExpectWebdriverIO.NumberOptions) { const actualHeight = await el.getSize('height') return { - value: actualHeight, - result: actualHeight === height, + result: compareNumbers(actualHeight, options), + value: actualHeight } } export async function toHaveHeight( received: WdioElementMaybePromise, - expectedValue: number, + expectedValue: number | ExpectWebdriverIO.NumberOptions, options: ExpectWebdriverIO.CommandOptions = DEFAULT_OPTIONS ) { const isNot = this.isNot @@ -30,12 +31,22 @@ export async function toHaveHeight( options, }) + // type check + let numberOptions: ExpectWebdriverIO.NumberOptions + if (typeof expectedValue === 'number') { + numberOptions = { eq: expectedValue } as ExpectWebdriverIO.NumberOptions + } else if (!expectedValue || (typeof expectedValue.eq !== 'number' && typeof expectedValue.gte !== 'number' && typeof expectedValue.lte !== 'number')) { + throw new Error('Invalid params passed to toHaveHeight.') + } else { + numberOptions = expectedValue + } + let el = await received?.getElement() let actualHeight const pass = await waitUntil( async () => { - const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]) + const result = await executeCommand.call(this, el, condition, numberOptions, [expectedValue, numberOptions]) el = result.el as WebdriverIO.Element actualHeight = result.values @@ -43,12 +54,13 @@ export async function toHaveHeight( return result.success }, isNot, - options + { ...numberOptions, ...options } ) + const error = numberError(numberOptions) const message = enhanceError( el, - wrapExpectedWithArray(el, actualHeight, expectedValue), + error, actualHeight, this, verb, diff --git a/src/matchers/element/toHaveWidth.ts b/src/matchers/element/toHaveWidth.ts index 011bb0682..6f706ffcb 100644 --- a/src/matchers/element/toHaveWidth.ts +++ b/src/matchers/element/toHaveWidth.ts @@ -1,24 +1,25 @@ import { DEFAULT_OPTIONS } from '../../constants.js' import type { WdioElementMaybePromise } from '../../types.js' import { + compareNumbers, enhanceError, executeCommand, + numberError, waitUntil, - wrapExpectedWithArray } from '../../utils.js' -async function condition(el: WebdriverIO.Element, width: number) { +async function condition(el: WebdriverIO.Element, width: number, options: ExpectWebdriverIO.NumberOptions) { const actualWidth = await el.getSize('width') return { - value: actualWidth, - result: actualWidth === width, + result: compareNumbers(actualWidth, options), + value: actualWidth } } export async function toHaveWidth( received: WdioElementMaybePromise, - expectedValue: number, + expectedValue: number | ExpectWebdriverIO.NumberOptions, options: ExpectWebdriverIO.CommandOptions = DEFAULT_OPTIONS ) { const isNot = this.isNot @@ -30,12 +31,22 @@ export async function toHaveWidth( options, }) + // type check + let numberOptions: ExpectWebdriverIO.NumberOptions + if (typeof expectedValue === 'number') { + numberOptions = { eq: expectedValue } as ExpectWebdriverIO.NumberOptions + } else if (!expectedValue || (typeof expectedValue.eq !== 'number' && typeof expectedValue.gte !== 'number' && typeof expectedValue.lte !== 'number')) { + throw new Error('Invalid params passed to toHaveHeight.') + } else { + numberOptions = expectedValue + } + let el = await received?.getElement() let actualWidth const pass = await waitUntil( async () => { - const result = await executeCommand.call(this, el, condition, options, [expectedValue, options]) + const result = await executeCommand.call(this, el, condition, numberOptions, [expectedValue, numberOptions]) el = result.el as WebdriverIO.Element actualWidth = result.values @@ -43,12 +54,13 @@ export async function toHaveWidth( return result.success }, isNot, - options + { ...numberOptions, ...options } ) + const error = numberError(numberOptions) const message = enhanceError( el, - wrapExpectedWithArray(el, actualWidth, expectedValue), + error, actualWidth, this, verb, diff --git a/test/matchers/element/toHaveHeight.test.ts b/test/matchers/element/toHaveHeight.test.ts index 8c504aecc..fae9b55a0 100755 --- a/test/matchers/element/toHaveHeight.test.ts +++ b/test/matchers/element/toHaveHeight.test.ts @@ -67,6 +67,7 @@ describe('toHaveHeight', () => { } const result = await toHaveHeight.call({}, el, 32, {}) + expect(result.message()).toEqual('Expect $(`sel`) to have height\n\nExpected: 32\nReceived: serializes to the same string') expect(result.pass).toBe(true) expect(el._attempts).toBe(1) }) @@ -86,6 +87,7 @@ describe('toHaveHeight', () => { } const result = await toHaveHeight.call({}, el, 10, { wait: 0 }) + expect(result.message()).toEqual('Expect $(`sel`) to have height\n\nExpected: 10\nReceived: 32') expect(result.pass).toBe(false) expect(el._attempts).toBe(1) }) @@ -109,6 +111,26 @@ describe('toHaveHeight', () => { expect(el._attempts).toBe(1) }) + test('gte and lte', async () => { + const el: any = await $('sel') + el._attempts = 0 + el._size = function (property?: 'width' | 'height') { + this._attempts++ + if (property === 'width') { + return 50 + } + if (property === 'height') { + return 32 + } + return { width: 50, height: 32 } + } + + const result = await toHaveHeight.call({}, el, { gte: 31, lte: 33 }, { wait: 0 }) + expect(result.message()).toEqual('Expect $(`sel`) to have height\n\nExpected: ">= 31 && <= 33"\nReceived: 32') + expect(result.pass).toBe(true) + expect(el._attempts).toBe(1) + }) + test('not - failure', async () => { const el: any = await $('sel') el._size = function (property?: 'width' | 'height') { diff --git a/test/matchers/element/toHaveWidth.test.ts b/test/matchers/element/toHaveWidth.test.ts index c6ea86724..14bae40e2 100755 --- a/test/matchers/element/toHaveWidth.test.ts +++ b/test/matchers/element/toHaveWidth.test.ts @@ -67,6 +67,7 @@ describe('toHaveWidth', () => { } const result = await toHaveWidth.call({}, el, 50, {}) + expect(result.message()).toEqual('Expect $(`sel`) to have width\n\nExpected: 50\nReceived: serializes to the same string') expect(result.pass).toBe(true) expect(el._attempts).toBe(1) }) @@ -86,6 +87,7 @@ describe('toHaveWidth', () => { } const result = await toHaveWidth.call({}, el, 10, { wait: 0 }) + expect(result.message()).toEqual('Expect $(`sel`) to have width\n\nExpected: 10\nReceived: 50') expect(result.pass).toBe(false) expect(el._attempts).toBe(1) }) @@ -109,6 +111,26 @@ describe('toHaveWidth', () => { expect(el._attempts).toBe(1) }) + test('gte and lte', async () => { + const el: any = await $('sel') + el._attempts = 0 + el._size = function (property?: 'width' | 'height') { + this._attempts++ + if (property === 'width') { + return 50 + } + if (property === 'height') { + return 32 + } + return { width: 50, height: 32 } + } + + const result = await toHaveWidth.call({}, el, { gte: 49, lte: 51 }, { wait: 0 }) + expect(result.message()).toEqual('Expect $(`sel`) to have width\n\nExpected: ">= 49 && <= 51"\nReceived: 50') + expect(result.pass).toBe(true) + expect(el._attempts).toBe(1) + }) + test('not - failure', async () => { const el: any = await $('sel') el._size = function (property?: 'width' | 'height') {