A test that passes when you expected it to fail is a signal, not a gift. The tempting reaction is to accept the green check and move on, but that result may mean you have written a test that cannot fail — a test that will stay green even after someone breaks the code it claims to cover.
The problem with green tests that can't go red
Take a function called isPasswordAllowed, which rejects passwords missing key characteristics. A set of tests exercises it against several invalid passwords and asserts the function returns false.
// __tests__/utils.js
import { isPasswordAllowed } from '#app/utils'
test('allows passwords that are good', () => {
expect(isPasswordAllowed('Ab3.efgh')).toBe(true)
})
test('disallows passwords less than 7 characters', () => {
expect(isPasswordAllowed('Ab3.ef')).toBe(false)
})
test('disallows passwords that do not contain a non-alphanumeric character', () => {
expect(isPasswordAllowed('Ab3')).toBe(false)
})
test('disallows passwords that do not contain a digit', () => {
expect(isPasswordAllowed('Ab.')).toBe(false)
})
test('disallows passwords that do not contain an uppercase letter', () => {
expect(isPasswordAllowed('b3.')).toBe(false)
})
test('disallows passwords that do not contain a lowercase letter', () => {
expect(isPasswordAllowed('A3.')).toBe(false)
})
They pass, but look at the implementation they're testing:
// utils.js
function isPasswordAllowed(password) {
return (
password.length > 6 &&
// non-alphanumeric
/\W/.test(password) &&
// digit
/\d/.test(password) &&
// uppercase letter
/[A-Z]/.test(password) &&
// lowercase letter
/[a-z]/.test(password)
)
}
export { isPasswordAllowed }
The function returns false for every one of those inputs because they are too short — not because they lack the required characters. The assertions never actually reach the character rules. Comment out those rules and the suite stays green:
// utils.js
function isPasswordAllowed(password) {
return (
password.length > 6 &&
// non-alphanumeric
/\W/.test(password) &&
// digit
// /\d/.test(password) &&
// uppercase letter
/[A-Z]/.test(password) &&
// lowercase letter
/[a-z]/.test(password)
)
}
export { isPasswordAllowed }
The cost of a false sense of security
This is why, after a test starts passing, you should break the functionality it targets and confirm the test fails. A test that survives the break offers no confidence, and worse, it breeds complacency: you're less likely to write a meaningful test later because the suite already looks healthy.
Coverage tooling can sometimes expose gaps like this, but not reliably here. The character-checking lines are actually executed by the first test that asserts true for a valid password, so they appear covered. Only a close look at the line hit count would reveal the problem, and that count is easy to overlook.
Two adjacent mistakes, both easy to commit, produce the same outcome:
expect(thing) // expectation with no assertion
expect(thing).toMatchSnapshot() // snapshot: empty...
Some of these can be caught mechanically. The eslint-plugin-jest rules valid-expect and prefer-inline-snapshots target exactly these patterns. More broadly, when a better assertion exists than a snapshot, use it.
What a failing-capable test looks like
Rewriting the isPasswordAllowed tests so each one isolates a specific rule gives you the behavior you want:
// __tests__/utils.js
import { isPasswordAllowed } from '#app/utils'
test('allows passwords that are good', () => {
expect(isPasswordAllowed('Ab3.efgh')).toBe(true)
})
test('disallows passwords less than 7 characters', () => {
expect(isPasswordAllowed('Ab3.ef')).toBe(false)
})
test('disallows passwords that do not contain a non-alphanumeric character', () => {
expect(isPasswordAllowed('Ab3efgh')).toBe(false)
})
test('disallows passwords that do not contain a digit', () => {
expect(isPasswordAllowed('Ab.efgh')).toBe(false)
})
test('disallows passwords that do not contain an uppercase letter', () => {
expect(isPasswordAllowed('b3.efgh')).toBe(false)
})
test('disallows passwords that do not contain a lowercase letter', () => {
expect(isPasswordAllowed('A3.EFGH')).toBe(false)
})
Now, commenting out the code each test targets will turn that test red. The suite delivers real value instead of blocking releases with noise or masking breakage behind a passing run.



