Skip to content

Commit 8bef5d2

Browse files
authoredOct 7, 2024··
fix(browser): not.toBeInTheDocument works with locators API (#6634)
1 parent 9ece395 commit 8bef5d2

File tree

7 files changed

+24
-9
lines changed

7 files changed

+24
-9
lines changed
 

Diff for: ‎packages/browser/matchers.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ declare module 'vitest' {
1616
type PromisifyDomAssertion<T> = Promisify<Assertion<T>>
1717

1818
interface ExpectStatic {
19-
element: <T extends Element | Locator>(element: T, options?: ExpectPollOptions) => PromisifyDomAssertion<Awaited<Element>>
19+
element: <T extends Element | Locator>(element: T, options?: ExpectPollOptions) => PromisifyDomAssertion<Awaited<Element | null>>
2020
}
2121
}
2222

Diff for: ‎packages/browser/src/client/tester/expect-element.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as matchers from '@testing-library/jest-dom/matchers'
22
import type { Locator } from '@vitest/browser/context'
33
import type { ExpectPollOptions } from 'vitest'
4-
import { expect } from 'vitest'
4+
import { chai, expect } from 'vitest'
55

66
export async function setupExpectDom() {
77
expect.extend(matchers)
@@ -10,10 +10,16 @@ export async function setupExpectDom() {
1010
throw new Error(`Invalid element or locator: ${elementOrLocator}. Expected an instance of Element or Locator, received ${typeof elementOrLocator}`)
1111
}
1212

13-
return expect.poll<Element>(() => {
14-
if (elementOrLocator instanceof Element) {
13+
return expect.poll<Element | null>(function element(this: object) {
14+
if (elementOrLocator instanceof Element || elementOrLocator == null) {
1515
return elementOrLocator
1616
}
17+
const isNot = chai.util.flag(this, 'negate')
18+
const name = chai.util.flag(this, '_name')
19+
// special case for `toBeInTheDocument` matcher
20+
if (isNot && name === 'toBeInTheDocument') {
21+
return elementOrLocator.query()
22+
}
1723
return elementOrLocator.element()
1824
}, options)
1925
}

Diff for: ‎packages/expect/src/jest-expect.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
stringify,
2323
} from './jest-matcher-utils'
2424
import { JEST_MATCHERS_OBJECT } from './constants'
25-
import { recordAsyncExpect, wrapSoft } from './utils'
25+
import { recordAsyncExpect, wrapAssertion } from './utils'
2626

2727
// polyfill globals because expect can be used in node environment
2828
declare class Node {
@@ -43,7 +43,7 @@ export const JestChaiExpect: ChaiPlugin = (chai, utils) => {
4343
fn: (this: Chai.AssertionStatic & Assertion, ...args: any[]) => any,
4444
) {
4545
const addMethod = (n: keyof Assertion) => {
46-
const softWrapper = wrapSoft(utils, fn)
46+
const softWrapper = wrapAssertion(utils, n, fn)
4747
utils.addMethod(chai.Assertion.prototype, n, softWrapper)
4848
utils.addMethod(
4949
(globalThis as any)[JEST_MATCHERS_OBJECT].matchers,

Diff for: ‎packages/expect/src/jest-extend.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from './jest-matcher-utils'
1919

2020
import { equals, iterableEquality, subsetEquality } from './jest-utils'
21-
import { wrapSoft } from './utils'
21+
import { wrapAssertion } from './utils'
2222

2323
function getMatcherState(
2424
assertion: Chai.AssertionStatic & Chai.Assertion,
@@ -96,7 +96,7 @@ function JestExtendPlugin(
9696
}
9797
}
9898

99-
const softWrapper = wrapSoft(utils, expectWrapper)
99+
const softWrapper = wrapAssertion(utils, expectAssertionName, expectWrapper)
100100
utils.addMethod(
101101
(globalThis as any)[JEST_MATCHERS_OBJECT].matchers,
102102
expectAssertionName,

Diff for: ‎packages/expect/src/utils.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ export function recordAsyncExpect(
2626
return promise
2727
}
2828

29-
export function wrapSoft(
29+
export function wrapAssertion(
3030
utils: Chai.ChaiUtils,
31+
name: string,
3132
fn: (this: Chai.AssertionStatic & Assertion, ...args: any[]) => void,
3233
) {
3334
return function (this: Chai.AssertionStatic & Assertion, ...args: any[]) {
35+
utils.flag(this, '_name', name)
36+
3437
if (!utils.flag(this, 'soft')) {
3538
return fn.apply(this, args)
3639
}

Diff for: ‎packages/vitest/src/integrations/chai/poll.ts

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export function createExpectPoll(expect: ExpectStatic): ExpectStatic['poll'] {
3838
const assertion = expect(null, message).withContext({
3939
poll: true,
4040
}) as Assertion
41+
fn = fn.bind(assertion)
4142
const proxy: any = new Proxy(assertion, {
4243
get(target, key, receiver) {
4344
const assertionFunction = Reflect.get(target, key, receiver)
@@ -75,6 +76,7 @@ export function createExpectPoll(expect: ExpectStatic): ExpectStatic['poll'] {
7576
}, timeout)
7677
const check = async () => {
7778
try {
79+
chai.util.flag(assertion, '_name', key)
7880
const obj = await fn()
7981
chai.util.flag(assertion, 'object', obj)
8082
resolve(await assertionFunction.call(assertion, ...args))

Diff for: ‎test/browser/test/dom.test.ts

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ describe('dom related activity', () => {
1515
expect(window.innerHeight).toBe(600)
1616
})
1717

18+
test('element doesn\'t exist', async () => {
19+
await expect.element(page.getByText('empty')).not.toBeInTheDocument()
20+
})
21+
1822
test('renders div', async () => {
1923
const wrapper = createWrapper()
2024
const div = createNode()

0 commit comments

Comments
 (0)
Please sign in to comment.