Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 27 additions & 28 deletions src/util/formatMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@ import { equals } from '../jasmineUtils.js'
import type { WdioElements } from '../types.js'
import { isElementArray } from './elementsUtil.js'

const EXPECTED_LABEL = 'Expected'
const RECEIVED_LABEL = 'Received'
const NOT_SUFFIX = ' [not]'
const NOT_EXPECTED_LABEL = EXPECTED_LABEL + NOT_SUFFIX

export const getSelector = (el: WebdriverIO.Element | WebdriverIO.ElementArray) => {
let result = typeof el.selector === 'string' ? el.selector : '<fn>'
if (Array.isArray(el) && (el as WebdriverIO.ElementArray).props.length > 0) {
Expand Down Expand Up @@ -39,22 +34,20 @@ export const getSelectors = (el: WebdriverIO.Element | WdioElements) => {
return selectors.reverse().join('.')
}

export const not = (isNot: boolean): string => {
return `${isNot ? 'not ' : ''}`
}
const not = (isNot: boolean): string => `${isNot ? 'not ' : ''}`

export const enhanceError = (
subject: string | WebdriverIO.Element | WdioElements,
expected: unknown,
actual: unknown,
context: { isNot: boolean },
context: { isNot: boolean, useNotInLabel?: boolean },
verb: string,
expectation: string,
arg2 = '', {
expectedValueArgument2 = '', {
message = '',
containing = false
}): string => {
const { isNot = false } = context
} = {}): string => {
const { isNot = false, useNotInLabel = true } = context

subject = typeof subject === 'string' ? subject : getSelectors(subject)

Expand All @@ -67,37 +60,43 @@ export const enhanceError = (
verb += ' '
}

let diffString = isNot && equals(actual, expected)
? `${EXPECTED_LABEL}: ${printExpected(expected)}\n${RECEIVED_LABEL}: ${printReceived(actual)}`
: printDiffOrStringify(expected, actual, EXPECTED_LABEL, RECEIVED_LABEL, true)

if (isNot) {
diffString = diffString
.replace(EXPECTED_LABEL, NOT_EXPECTED_LABEL)
.replace(RECEIVED_LABEL, RECEIVED_LABEL + ' '.repeat(NOT_SUFFIX.length))
const label = {
expected: isNot && useNotInLabel ? 'Expected [not]' : 'Expected',
received: isNot && useNotInLabel ? 'Received ' : 'Received'
}

// Using `printDiffOrStringify()` with equals values output `Received: serializes to the same string`, so we need to tweak.
const diffString = equals(actual, expected) ?`\
${label.expected}: ${printExpected(expected)}
${label.received}: ${printReceived(actual)}`
: printDiffOrStringify(expected, actual, label.expected, label.received, true)

if (message) {
message += '\n'
}

if (arg2) {
arg2 = ` ${arg2}`
if (expectedValueArgument2) {
expectedValueArgument2 = ` ${expectedValueArgument2}`
}

const msg = `${message}Expect ${subject} ${not(isNot)}to ${verb}${expectation}${arg2}${contain}\n\n${diffString}`
const msg = `\
${message}Expect ${subject} ${not(isNot)}to ${verb}${expectation}${expectedValueArgument2}${contain}

${diffString}`

return msg
}

export const enhanceErrorBe = (
subject: string | WebdriverIO.Element | WebdriverIO.ElementArray,
pass: boolean,
context: { isNot: boolean },
verb: string,
expectation: string,
context: { isNot: boolean, verb: string, expectation: string },
options: ExpectWebdriverIO.CommandOptions
) => {
return enhanceError(subject, not(context.isNot) + expectation, not(!pass) + expectation, context, verb, expectation, '', options)
const { isNot, verb, expectation } = context
const expected = `${not(isNot)}${expectation}`
const actual = `${not(!isNot)}${expectation}`

return enhanceError(subject, expected, actual, { ...context, useNotInLabel: false }, verb, expectation, '', options)
}

export const numberError = (options: ExpectWebdriverIO.NumberOptions = {}): string | number => {
Expand Down
5 changes: 2 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ async function executeCommandBe(
command: (el: WebdriverIO.Element) => Promise<boolean>,
options: ExpectWebdriverIO.CommandOptions
): ExpectWebdriverIO.AsyncAssertionResult {
const { expectation, verb = 'be' } = this

let el = await received?.getElement()
const pass = await waitUntil(
async () => {
Expand All @@ -89,7 +87,8 @@ async function executeCommandBe(
options
)

const message = enhanceErrorBe(el, pass, this, verb, expectation, options)
const { verb = 'be' } = this
const message = enhanceErrorBe(el, { ...this, verb }, options)

return {
pass,
Expand Down
12 changes: 1 addition & 11 deletions test/__fixtures__/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
export function matcherNameToString(matcherName: string) {
return matcherName.replace(/([A-Z])/g, ' $1').toLowerCase()
}

export function matcherLastWordName(matcherName: string) {
export function matcherNameLastWords(matcherName: string) {
return matcherName.replace(/^toHave/, '').replace(/^toBe/, '')
.replace(/([A-Z])/g, ' $1').trim().toLowerCase()
}
Expand All @@ -22,9 +18,3 @@ export function getReceived(msg: string) {
function getReceivedOrExpected(msg: string, type: string) {
return msg.split('\n').find((line, idx) => idx > 1 && line.startsWith(type))
}

export function removeColors(msg: string) {
// eslint-disable-next-line no-control-regex
const s = msg.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '')
return s
}
28 changes: 14 additions & 14 deletions test/matchers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,43 +111,43 @@ describe('Custom Wdio Matchers Integration Tests', async () => {
await expect(() => expectLib(el).not.toBeDisplayed({ wait: 1 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be displayed

Expected [not]: "not displayed"
Received : "displayed"`
Expected: "not displayed"
Received: "displayed"`
)

await expect(() => expectLib(el).not.toBeExisting({ wait: 1 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be existing

Expected [not]: "not existing"
Received : "existing"`
Expected: "not existing"
Received: "existing"`
)

await expect(() => expectLib(el).not.toBeEnabled({ wait: 1 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be enabled

Expected [not]: "not enabled"
Received : "enabled"`
Expected: "not enabled"
Received: "enabled"`
)

await expect(() => expectLib(el).not.toBeClickable({ wait: 1 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be clickable

Expected [not]: "not clickable"
Received : "clickable"`
Expected: "not clickable"
Received: "clickable"`
)

await expect(() => expectLib(el).not.toBeFocused({ wait: 1 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be focused

Expected [not]: "not focused"
Received : "focused"`
Expected: "not focused"
Received: "focused"`
)

await expect(() => expectLib(el).not.toBeSelected({ wait: 1 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be selected

Expected [not]: "not selected"
Received : "selected"`
Expected: "not selected"
Received: "selected"`
)
})

Expand Down Expand Up @@ -423,8 +423,8 @@ Received: 100`)
await expect(() => expectLib(el).not.toBeDisplayed({ wait: 300, interval: 100 })).rejects.toThrow(`\
Expect $(\`selector\`) not to be displayed

Expected [not]: "not displayed"
Received : "displayed"`)
Expected: "not displayed"
Received: "displayed"`)

expect(el.isDisplayed).toHaveBeenCalledTimes(6)
})
Expand Down
15 changes: 8 additions & 7 deletions test/matchers/beMatchers.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { vi, test, describe, expect } from 'vitest'
import { $ } from '@wdio/globals'
import { matcherLastWordName } from '../__fixtures__/utils.js'
import { matcherNameLastWords } from '../__fixtures__/utils.js'
import * as Matchers from '../../src/matchers.js'

vi.mock('@wdio/globals')
Expand Down Expand Up @@ -78,6 +78,7 @@ describe('be* matchers', () => {
el[elementFnName] = vi.fn().mockResolvedValue(true)

const result = await matcherFn.call({}, el, { wait: 0 }) as ExpectWebdriverIO.AssertionResult

expect(result.pass).toBe(true)
expect(el[elementFnName]).toHaveBeenCalledTimes(1)
})
Expand All @@ -89,10 +90,10 @@ describe('be* matchers', () => {

expect(result.pass).toBe(true) // failure, boolean is inverted later because of `.not`
expect(result.message()).toEqual(`\
Expect $(\`sel\`) not to be ${matcherLastWordName(matcherName)}
Expect $(\`sel\`) not to be ${matcherNameLastWords(matcherName)}

Expected [not]: "not ${matcherLastWordName(matcherName)}"
Received : "${matcherLastWordName(matcherName)}"`
Expected: "not ${matcherNameLastWords(matcherName)}"
Received: "${matcherNameLastWords(matcherName)}"`
)
})

Expand Down Expand Up @@ -129,10 +130,10 @@ Received : "${matcherLastWordName(matcherName)}"`
const result = await matcherFn.call({}, el, { wait: 1 }) as ExpectWebdriverIO.AssertionResult
expect(result.pass).toBe(false)
expect(result.message()).toBe(`\
Expect $(\`sel\`) to be ${matcherLastWordName(matcherName)}
Expect $(\`sel\`) to be ${matcherNameLastWords(matcherName)}

Expected: "${matcherLastWordName(matcherName)}"
Received: "not ${matcherLastWordName(matcherName)}"`
Expected: "${matcherNameLastWords(matcherName)}"
Received: "not ${matcherNameLastWords(matcherName)}"`
)
})
})
Expand Down
14 changes: 10 additions & 4 deletions test/matchers/browserMatchers.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { vi, test, describe, expect } from 'vitest'
import { browser } from '@wdio/globals'

import { getExpectMessage, matcherNameToString, matcherLastWordName } from '../__fixtures__/utils.js'
import { matcherNameLastWords } from '../__fixtures__/utils.js'
import * as Matchers from '../../src/matchers.js'

vi.mock('@wdio/globals')
Expand Down Expand Up @@ -67,7 +67,7 @@ describe('browser matchers', () => {

expect(result.pass).toBe(true) // failure, boolean is inverted later because of `.not`
expect(result.message()).toEqual(`\
Expect window not to have ${matcherLastWordName(matcherName)}
Expect window not to have ${matcherNameLastWords(matcherName)}

Expected [not]: " Valid Text "
Received : " Valid Text "`
Expand All @@ -89,7 +89,7 @@ Received : " Valid Text "`

expect(result.pass).toBe(true) // failure, boolean is inverted later because of `.not`
expect(result.message()).toEqual(`\
Expect window not to have ${matcherLastWordName(matcherName)}
Expect window not to have ${matcherNameLastWords(matcherName)}

Expected [not]: " Valid Text "
Received : " Valid Text "`
Expand All @@ -106,7 +106,13 @@ Received : " Valid Text "`

test('message', async () => {
const result = await matcherFn.call({}, browser) as ExpectWebdriverIO.AssertionResult
expect(getExpectMessage(result.message())).toContain(matcherNameToString(matcherName))

expect(result.pass).toBe(false)
expect(result.message()).toEqual(`\
Expect window to have ${matcherNameLastWords(matcherName)}

Expected: undefined
Received: " Wrong Text "`)
})
})
})
Expand Down
8 changes: 4 additions & 4 deletions test/matchers/element/toBeDisabled.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ describe('toBeDisabled', () => {
expect(result.message()).toEqual(`\
Expect $(\`sel\`) not to be disabled

Expected [not]: "not disabled"
Received : "disabled"`
Expected: "not disabled"
Received: "disabled"`
)
})

Expand All @@ -102,8 +102,8 @@ Received : "disabled"`
expect(result.message()).toEqual(`\
Expect $(\`sel\`) not to be disabled

Expected [not]: "not disabled"
Received : "disabled"`
Expected: "not disabled"
Received: "disabled"`
)
})

Expand Down
4 changes: 2 additions & 2 deletions test/matchers/element/toBeDisplayed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ describe('toBeDisplayed', () => {
expect(result.message()).toEqual(`\
Expect $(\`sel\`) not to be displayed
Expected [not]: "not displayed"
Received : "displayed"`
Expected: "not displayed"
Received: "displayed"`
)
})

Expand Down
21 changes: 14 additions & 7 deletions test/matchers/element/toHaveComputedLabel.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { vi, test, describe, expect, beforeEach } from 'vitest'
import { $ } from '@wdio/globals'

import { getExpectMessage, getReceived, getExpected } from '../../__fixtures__/utils.js'
import { getExpectMessage } from '../../__fixtures__/utils.js'
import { toHaveComputedLabel } from '../../../src/matchers/element/toHaveComputedLabel.js'

vi.mock('@wdio/globals')
Expand Down Expand Up @@ -271,18 +271,25 @@ Received : "WebdriverIO"`

test('failure if no match', async () => {
const result = await toHaveComputedLabel.call({}, el, /Webdriver/i)

expect(result.pass).toBe(false)
expect(getExpectMessage(result.message())).toContain('to have computed label')
expect(getExpected(result.message())).toContain('/Webdriver/i')
expect(getReceived(result.message())).toContain('This is example computed label')
expect(result.message()).toEqual(`\
Expect $(\`sel\`) to have computed label

Expected: /Webdriver/i
Received: "This is example computed label"`)
})

test('failure if array does not match with computed label', async () => {
const result = await toHaveComputedLabel.call({}, el, ['div', /Webdriver/i])

expect(result.pass).toBe(false)
expect(getExpectMessage(result.message())).toContain('to have computed label')
expect(getExpected(result.message())).toContain('/Webdriver/i')
expect(getExpected(result.message())).toContain('div')
expect(result.message()).toEqual(`\
Expect $(\`sel\`) to have computed label

Expected: ["div", /Webdriver/i]
Received: "This is example computed label"`
)
})
})
})
9 changes: 5 additions & 4 deletions test/matchers/element/toHaveHeight.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { vi, test, describe, expect } from 'vitest'
import { $ } from '@wdio/globals'

import { getExpectMessage } from '../../__fixtures__/utils.js'
import { toHaveHeight } from '../../../src/matchers/element/toHaveHeight.js'

vi.mock('@wdio/globals')
Expand Down Expand Up @@ -48,7 +46,6 @@ 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.getSize).toHaveBeenCalledTimes(1)
})
Expand Down Expand Up @@ -130,6 +127,10 @@ Received : 32`

const result = await toHaveHeight.call({}, el, 50)

expect(getExpectMessage(result.message())).toContain('to have height')
expect(result.message()).toEqual(`\
Expect $(\`sel\`) to have height

Expected: 50
Received: null`)
})
})
Loading