Skip to content

Commit 55d420f

Browse files
committed
Review jasmine asymmetric compatibility
1 parent 2a52080 commit 55d420f

6 files changed

Lines changed: 59 additions & 105 deletions

File tree

docs/API.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,18 +1010,10 @@ await expect(browser).toHaveTitle(expect.not.stringContaining('some title'))
10101010

10111011
### Jasmine
10121012

1013-
Even under `@wdio/jasmine-framework`, Jasmine asymmetric matchers do not work with WebdriverIO matchers.
1013+
Under `@wdio/jasmine-framework`, Jasmine asymmetric matchers now works with WebdriverIO matchers and the global import
10141014

10151015
```ts
1016-
// DOES NOT work
1016+
// Jasmine stringContaining works just lik expect one's
10171017
await expect(browser).toHaveTitle(jasmine.stringContaining('some title'))
1018-
1019-
// Use expect
10201018
await expect(browser).toHaveTitle(expect.stringContaining('some title'))
10211019
```
1022-
1023-
However, when using Jasmine original matchers, both works.
1024-
```ts
1025-
await expect(url).toEqual(jasmine.stringMatching(/^https:\/\//))
1026-
await expect(url).toEqual(expect.stringMatching(/^https:\/\//))
1027-
```

package-lock.json

Lines changed: 0 additions & 68 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,7 @@
9999
"shelljs": "^0.10.0",
100100
"typescript": "^5.9.3",
101101
"vitest": "^4.0.16",
102-
"webdriverio": "^9.21.0",
103-
"jasmine": "^5.1.2",
104-
"jasmine-core": "^5.1.2"
102+
"webdriverio": "^9.21.0"
105103
},
106104
"peerDependencies": {
107105
"@wdio/globals": "^9.0.0",

src/matchers/browser/toHaveUrl.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ export async function toHaveUrl(
1919
const pass = await waitUntil(async () => {
2020
actual = await browser.getUrl()
2121

22-
console.log('toHaveUrl', { actual, expectedValue })
2322
return compareText(actual, expectedValue, options).result
2423
}, isNot, options)
2524

src/utils.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,38 +19,32 @@ export function isJasmineAsymmetricMatcher<T>(expected: unknown): expected is Ja
1919
return isAsymmetricMatcher(expected) && 'expected' in expected
2020
}
2121

22-
export function isAsymmetricMatcher(expected: unknown): expected is WdioAsymmetricMatcher<unknown> | JasmineAsymmetricMatcher<unknown> {
22+
export function isAsymmetricMatcher<T>(expected: unknown): expected is WdioAsymmetricMatcher<T> | JasmineAsymmetricMatcher<T> {
2323
return (
2424
typeof expected === 'object' &&
2525
!!expected &&
2626
'asymmetricMatch' in expected &&
27-
Boolean(expected.asymmetricMatch)
27+
!!expected.asymmetricMatch
2828
)
2929
}
3030

31-
export function isStringContainingMatcher(expected: unknown): expected is WdioAsymmetricMatcher<unknown> | JasmineAsymmetricMatcher<unknown> {
31+
export function isStringContainingMatcherLike(expected: unknown): expected is WdioAsymmetricMatcher<string> | JasmineAsymmetricMatcher<string> {
3232
return !!expected && expected.constructor.name === 'StringContaining'
3333
}
3434

35-
export function isStrictStringContainingMatcher(expected: unknown): expected is WdioAsymmetricMatcher<unknown> | JasmineAsymmetricMatcher<unknown> {
36-
if (isStringContainingMatcher(expected)) {
37-
if (isWdioAsymmetricMatcher(expected)) {
38-
return expected.toString().includes('StringContaining')
39-
}
40-
return true
41-
}
42-
return false
35+
export function isStrictlyStringContainingMatcher(expected: unknown): expected is WdioAsymmetricMatcher<string> | JasmineAsymmetricMatcher<string> {
36+
return isStringContainingMatcherLike(expected) && (!isWdioAsymmetricMatcher(expected) || expected.toString().includes('StringContaining'))
4337
}
4438

45-
export function getValueFromAsymmetricMatcher<T>(
39+
export function getAsymmetricMatcherValue<T>(
4640
expected: WdioAsymmetricMatcher<T> | JasmineAsymmetricMatcher<T>
4741
): T {
4842
if ('expected' in expected) {
4943
return expected.expected
5044
} else if ('sample' in expected) {
5145
return expected.sample
5246
}
53-
throw new Error('Could not extract value from asymmetric matcher: ' + expected)
47+
throw new Error(`Could not extract value from asymmetric matcher: ${String(expected)}`)
5448
}
5549

5650
/**
@@ -191,9 +185,9 @@ export const compareText = (
191185
actual = actual.toLowerCase()
192186
if (typeof expected === 'string') {
193187
expected = expected.toLowerCase()
194-
} else if (isStringContainingMatcher(expected)) {
195-
const sample = getValueFromAsymmetricMatcher<string>(expected).toString().toLocaleLowerCase()
196-
expected = (isStrictStringContainingMatcher(expected)
188+
} else if (isStringContainingMatcherLike(expected)) {
189+
const sample = getAsymmetricMatcherValue<string>(expected).toString().toLocaleLowerCase()
190+
expected = (isStrictlyStringContainingMatcher(expected)
197191
? expect.stringContaining(sample)
198192
: expect.not.stringContaining(sample)) as WdioAsymmetricMatcher<string>
199193
}
@@ -279,7 +273,7 @@ export const compareTextWithArray = (
279273
if (typeof item === 'string') {
280274
return item.toLowerCase()
281275
}
282-
if (isStringContainingMatcher(item)) {
276+
if (isStringContainingMatcherLike(item)) {
283277
return (item.toString() === 'StringContaining'
284278
? expect.stringContaining(item.sample?.toString().toLowerCase())
285279
: expect.not.stringContaining(item.sample?.toString().toLowerCase())) as WdioAsymmetricMatcher<string>

test/utils.test.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, test, expect, vi } from 'vitest'
2-
import { compareNumbers, compareObject, compareText, compareTextWithArray, isAsymmetricMatcher, isStringContainingMatcher, waitUntil } from '../src/utils'
2+
import { compareNumbers, compareObject, compareText, compareTextWithArray, getAsymmetricMatcherValue, isAsymmetricMatcher, isStrictlyStringContainingMatcher, isStringContainingMatcherLike, waitUntil } from '../src/utils'
33

44
describe('utils', () => {
55

@@ -386,7 +386,7 @@ describe('utils', () => {
386386
// @ts-expect-error
387387
expect(() => new StringContaining(123)).toThrow('Expected is not a string')
388388
})
389-
test('toString and getExpectedType', () => {
389+
test('jasmineToString and getExpectedType', () => {
390390
const matcher = new StringContaining('foo')
391391
expect(matcher.jasmineToString()).toBe('<jasmine.stringContaining>')
392392
expect(matcher.getExpectedType()).toBe('string')
@@ -396,19 +396,58 @@ describe('utils', () => {
396396
test.for([
397397
expect.stringContaining('foo'),
398398
new StringContaining('foo')
399-
])('isAsymmetricMatcher should work with %s matcher', async (asymmetricMatcher) => {
399+
])('should work with %s matcher', async (asymmetricMatcher) => {
400400
const isAsymmetric = isAsymmetricMatcher(asymmetricMatcher)
401401

402402
expect(isAsymmetric).toBe(true)
403403
})
404+
})
404405

406+
describe(isStringContainingMatcherLike, () => {
405407
test.for([
406408
expect.stringContaining('foo'),
409+
expect.not.stringContaining('foo'),
407410
new StringContaining('foo')
408-
])('isStringContainingMatcher should work with %s matcher', async (asymmetricMatcher) => {
409-
const isAsymmetric = isStringContainingMatcher(asymmetricMatcher)
411+
])('should work with %s matcher', async (asymmetricMatcher) => {
412+
const isStringContaining = isStringContainingMatcherLike(asymmetricMatcher)
410413

411-
expect(isAsymmetric).toBe(true)
414+
expect(isStringContaining).toBe(true)
415+
})
416+
})
417+
418+
describe(isStrictlyStringContainingMatcher, () => {
419+
test.for([
420+
// expect.stringContaining('foo'),
421+
new StringContaining('foo')
422+
])('should work with %s matcher', async (asymmetricMatcher) => {
423+
const isStrictlyStringContaining = isStrictlyStringContainingMatcher(asymmetricMatcher)
424+
425+
expect(isStrictlyStringContaining).toBe(true)
426+
})
427+
428+
test('should work with %s matcher', async () => {
429+
const asymmetricMatcher = expect.not.stringContaining('foo')
430+
431+
const isStrictlyStringContaining = isStrictlyStringContainingMatcher(asymmetricMatcher)
432+
433+
expect(isStrictlyStringContaining).toBe(false)
434+
})
435+
})
436+
437+
describe(getAsymmetricMatcherValue, () => {
438+
test.for([
439+
expect.stringContaining('foo'),
440+
expect.not.stringContaining('foo'),
441+
new StringContaining('foo'),
442+
])('should return expected value of matcher', (asymmetricMatcher) => {
443+
444+
const value = getAsymmetricMatcherValue(asymmetricMatcher)
445+
446+
expect(value).toBe('foo')
447+
})
448+
449+
test('should throw when unknown matcher', () => {
450+
expect(() => getAsymmetricMatcherValue({} as any)).toThrow('Could not extract value from asymmetric matcher: [object Object]')
412451
})
413452
})
414453
})

0 commit comments

Comments
 (0)