vitest
vitest copied to clipboard
fix: validation for arraykeys in suite for it.each cases
Description
Change validation within suite.ts to fix switching issue in scenarios using it.each.
Used an early return to prevent tests from falling into an incorrect flow.
fixes #8189
Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- [x] It's really useful if your PR references an issue where it is discussed ahead of time. If the feature is substantial or introduces breaking changes without a discussion, PR might be closed.
- [x] Ideally, include a test that fails without this PR but passes with it.
- [x] Please, don't make changes to
pnpm-lock.yamlunless you introduce a new test example.
Tests
- [x] Run the tests with
pnpm test:ci.
Documentation
- [x] If you introduce new functionality, document it. You can run documentation with
pnpm run docscommand.
Changesets
- [x] Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with
feat:,fix:,perf:,docs:, orchore:.
Deploy Preview for vitest-dev ready!
Built without sensitive environment variables
| Name | Link |
|---|---|
| Latest commit | 2337581af0d4efd1f19638866957d08acfab0a0c |
| Latest deploy log | https://app.netlify.com/projects/vitest-dev/deploys/686add37271d040008ce7cba |
| Deploy Preview | https://deploy-preview-8192--vitest-dev.netlify.app |
| Preview on mobile | Toggle QR Code...Use your smartphone camera to open QR code link. |
To edit notification comments on pull requests, go to your Netlify project configuration.
@hi-ogawa As I had tagged you in the issue debate, can you give me some support on how we will proceed with the adjustment?
Thanks for the effort, however this only changes the order of expansion from % -> $ to $ -> % and that's not a proper solution as I wrote in https://github.com/vitest-dev/vitest/issues/8189#issuecomment-3088609224. For example, this previously passed but now fails:
test.for([{ a: '%o' }])('$a', (_, ctx) => {
expect(ctx.task.name).toBe("'%o'")
// Expected: "'%o'"
// Received: "'{ a: '%o' }'"
});
Also please add an test case in a way it satisfies the 2nd checkbox in PR description. You only added only examples and they don't fail on current main.
[ ] Ideally, include a test that fails without this PR but passes with it.
There are similar test cases already in https://github.com/vitest-dev/vitest/blob/c1ac15c6b22903cf17b5b105dffd0b8aabf083c3/test/reporters/tests/default.test.ts#L202
Thanks for the effort, however this only changes the order of expansion from
% -> $to$ -> %and that's not a proper solution as I wrote in #8189 (comment). For example, this previously passed but now fails:test.for([{ a: '%o' }])('$a', (_, ctx) => { expect(ctx.task.name).toBe("'%o'") // Expected: "'%o'" // Received: "'{ a: '%o' }'" });Also please add an test case in a way it satisfies the 2nd checkbox in PR description. You only added only examples and they don't fail on current main.
[ ] Ideally, include a test that fails without this PR but passes with it.
There are similar test cases already in
https://github.com/vitest-dev/vitest/blob/c1ac15c6b22903cf17b5b105dffd0b8aabf083c3/test/reporters/tests/default.test.ts#L202
@hi-ogawa It really makes sense, maybe it's more complex than we imagined 😄 . I implemented an idea, can I send the code here for you to take a look at or do you prefer that I commit it?
Yes, this is tricky and I'm not sure the fix is that simple either. What I have in mind would roughly look like a following process:
"$a %o $b %s"
⇓ (replace $ with placeholder)
"__tmp1__ %o __tmp2__ %s"
⇓ (apply % formatting)
"__tmp1__ xxx __tmp2__ yyy"
---
"$a" "$b"
⇓ ⇓ (apply $ formatting individually)
"www" "zzz"
---
"__tmp1__ xxx __tmp2__ yyy"
⇓ (restore $ placeholder)
"www xxx zzz yyy"
my idea would be the following, looking at the code:
function formatTitle(template: string, items: any[], idx: number) {
// Step 1: Replace escaped percent signs
template = template.replace(/%%/g, '__vitest_escaped_%__')
// Step 2: Replace % expansions
if (template.includes('%#') || template.includes('%$')) {
template = template
.replace(/%#/g, `${idx}`)
.replace(/%\$/g, `${idx + 1}`)
}
// Step 3: Replace $ expansions
// We want to expand $vars in the template, but only outside of %f or other %... expansions
// We'll split the template into segments: those inside %f (or other %X) and those outside
// For simplicity, let's process $expansions everywhere, but only if not inside a %... sequence
// Find all %f, %s, etc. and replace them with placeholders
const percentRegex = /%[a-z]/gi
const percentMatches: RegExpMatchArray | null = template.match(percentRegex)
const percentCount = percentMatches ? percentMatches.length : 0
// Replace $expansions
const isObjectItem = isObject(items[0])
template = template.replace(
/\$([$\w.]+)/g,
(_, key: string) => {
const isArrayKey = /^\d+$/.test(key)
if (!isObjectItem && !isArrayKey) {
return `$${key}`
}
const arrayElement = isArrayKey ? objectAttr(items, key) : undefined
const value = isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement
return objDisplay(value, {
truncate: runner?.config?.chaiConfig?.truncateThreshold,
}) as unknown as string
},
)
// Step 4: Restore escaped percent signs
template = template.replace(/__vitest_escaped_%__/g, '%')
// Step 5: Handle %f special case for -0 and NaN
if (template.includes('%f')) {
const placeholders = template.match(/%f/g) || []
let temporaryTemplate = template
placeholders.forEach((_, i) => {
if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
let occurrence = 0
temporaryTemplate = temporaryTemplate.replace(/%f/g, (match) => {
occurrence++
return occurrence === i + 1 ? '-%f' : match
})
}
})
return format(temporaryTemplate, ...items.slice(0, percentCount))
}
return format(template, ...items.slice(0, percentCount))
}
@hi-ogawa
Please feel free to update the code and let's see the test case 🙂
Please feel free to update the code and let's see the test case 🙂
I uploaded the code I commented on.
Regarding the reporter tests, I inserted it into the file you mentioned, but I'm not sure if it's the best place. I can change it if I see fit
@hi-ogawa