Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions packages/browser/src/client/tester/expect-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ function element<T extends HTMLElement | SVGElement | null | Locator>(elementOrL
return elementOrLocator.elements() as unknown as HTMLElement
}

if (name === 'toMatchScreenshot' && !chai.util.flag(this, '_poll.assert_once')) {
// `toMatchScreenshot` should only run once after the element resolves
chai.util.flag(this, '_poll.assert_once', true)
}

// element selector uses prettyDOM under the hood, which is an expensive call
// that should not be called on each failed locator attempt to avoid memory leak:
// https://github.com/vitest-dev/vitest/issues/7139
Expand Down
37 changes: 25 additions & 12 deletions packages/vitest/src/integrations/chai/poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,36 @@ export function createExpectPoll(expect: ExpectStatic): ExpectStatic['poll'] {
let timeoutId: any
let lastError: any
const { setTimeout, clearTimeout } = getSafeTimers()
const rejectWithCause = (error: any) => {
if (error.cause == null) {
error.cause = new Error('Matcher did not succeed in time.')
}
reject(
copyStackTrace(
error,
STACK_TRACE_ERROR,
),
)
}
const check = async () => {
try {
chai.util.flag(assertion, '_name', key)
const obj = await fn()
chai.util.flag(assertion, 'object', obj)
resolve(await assertionFunction.call(assertion, ...args))
try {
resolve(await assertionFunction.call(assertion, ...args))
}
catch (err) {
if (chai.util.flag(assertion, '_poll.assert_once')) {
clearTimeout(intervalId)
clearTimeout(timeoutId)

rejectWithCause(err)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely convinced by this solution, it adds yet-another exit point to a function that already has many...

else {
throw err
}
}
clearTimeout(intervalId)
clearTimeout(timeoutId)
}
Expand All @@ -88,17 +112,6 @@ export function createExpectPoll(expect: ExpectStatic): ExpectStatic['poll'] {
timeoutId = setTimeout(() => {
clearTimeout(intervalId)
chai.util.flag(assertion, '_isLastPollAttempt', true)
const rejectWithCause = (error: any) => {
if (error.cause == null) {
error.cause = new Error('Matcher did not succeed in time.')
}
reject(
copyStackTrace(
error,
STACK_TRACE_ERROR,
),
)
}
check()
.then(() => rejectWithCause(lastError))
.catch(e => rejectWithCause(e))
Expand Down
Loading