Visitar URL original
test: a rejection assertion holds whether the call throws in place or… · stacksjs/stacks@78bca93 · GitHub
Skip to content

Commit 78bca93

Browse files
committed
test: a rejection assertion holds whether the call throws in place or rejects
`await assert.rejects(db.insertInto(...).execute())` evaluates the call before the assertion sees it, so it only works while the call returns a promise. A query that answers where it is written throws there instead, and the assertion never runs. Each such assertion now hands over the call unstarted, in an async function: `assert.rejects(async () => ...)`, `expect((async () => ...)())`. That is a rejection either way, so these pass before and after the query builder answers in place. `assert.rejects(() => ...)` with a plain arrow had the same flaw (a synchronous throw from it is reported as a failure of the assertion), so those are async arrows too.
1 parent f23ecf0 commit 78bca93

69 files changed

Lines changed: 142 additions & 141 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎storage/framework/core/api/tests/fixtures/generated-client-contracts.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,9 @@ try {
270270
assert.equal((await client.emptyText()).data, '')
271271
assert.equal((await client.head()).data, null)
272272
assert.equal((await client.remove()).data, null)
273-
await assert.rejects(() => client.alternate({body:{}}, {contentType:'application/xml'}), /media type/)
274-
await assert.rejects(() => client.override({id:'.'}), /Dot-only/)
275-
await assert.rejects(() => client.override({}), /Missing required/)
273+
await assert.rejects(async () => client.alternate({body:{}}, {contentType:'application/xml'}), /media type/)
274+
await assert.rejects(async () => client.override({id:'.'}), /Dot-only/)
275+
await assert.rejects(async () => client.override({}), /Missing required/)
276276
})
277277

278278
}

‎storage/framework/core/api/tests/operation.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ test('every transport invocation authorizes before it can run the operation', as
77
authorize: (context: { allowed: boolean }) => { if (!context.allowed) throw new Error('Forbidden') },
88
handle: () => ++writes,
99
})
10-
await expect(operation.execute({ allowed: false })).rejects.toThrow('Forbidden')
10+
await expect((async () => operation.execute({ allowed: false }))()).rejects.toThrow('Forbidden')
1111
expect(writes).toBe(0)
1212
expect(await operation.execute({ allowed: true })).toBe(1)
13-
await expect(operation.execute({ allowed: false })).rejects.toThrow('Forbidden')
13+
await expect((async () => operation.execute({ allowed: false }))()).rejects.toThrow('Forbidden')
1414
expect(writes).toBe(1)
1515
})
1616

@@ -19,5 +19,5 @@ test('captures operation policy at registration', async () => {
1919
const options = { authorize() { throw new Error('Forbidden') }, handle() { return 1 } }
2020
const operation = defineApiOperation(options)
2121
options.authorize = () => {}
22-
await expect(operation.execute(undefined)).rejects.toThrow('Forbidden')
22+
await expect((async () => operation.execute(undefined))()).rejects.toThrow('Forbidden')
2323
})

‎storage/framework/core/auth/tests/fixtures/auth-middleware-entrypoints.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ try {
5454
]) {
5555
const req = enhanceRequest(new Request('https://example.test/protected', { headers }) as EnhancedRequest)
5656
await runWithRequest(req, async () => {
57-
await assert.rejects(() => middleware.handle(req), (error: { status?: number }) => error.status === 401)
57+
await assert.rejects(async () => middleware.handle(req), (error: { status?: number }) => error.status === 401)
5858
assert.equal(req._authenticatedUser, undefined)
5959
})
6060
}

‎storage/framework/core/auth/tests/fixtures/auth-setup-schema.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ async function verifySetup(): Promise<void> {
184184
assert.equal(user.password_changed_at, null)
185185
const reset = { email: 'fixture@example.invalid', token: 'synthetic-reset', expires_at: '2030-01-01 00:00:00' }
186186
await db.insertInto('password_resets').values(reset).execute()
187-
await assert.rejects(db.insertInto('password_resets').values({ ...reset, token: 'synthetic-duplicate-reset' }).execute(), /unique|duplicate/i)
187+
await assert.rejects(async () => db.insertInto('password_resets').values({ ...reset, token: 'synthetic-duplicate-reset' }).execute(), /unique|duplicate/i)
188188
const verification = { user_id: 42, token: 'synthetic-verification', expires_at: '2030-01-01 00:00:00' }
189189
await db.insertInto('email_verifications').values(verification).execute()
190-
await assert.rejects(db.insertInto('email_verifications').values({ ...verification, token: 'synthetic-duplicate-verification' }).execute(), /unique|duplicate/i)
190+
await assert.rejects(async () => db.insertInto('email_verifications').values({ ...verification, token: 'synthetic-duplicate-verification' }).execute(), /unique|duplicate/i)
191191
}
192192
try { await verifySetup(); console.log('auth setup schema OK') }
193193
finally { resetDatabaseConnection() }

‎storage/framework/core/auth/tests/fixtures/authorization-middleware-entrypoints.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ async function check(name: string, user: Record<string, unknown> | undefined, pa
4545
req.params = { document: '17' }
4646
await runWithRequest(req, async () => {
4747
if (status) {
48-
await assert.rejects(() => modules.get(name).handle(req), (error: { status?: number }) => error.status === status)
48+
await assert.rejects(async () => modules.get(name).handle(req), (error: { status?: number }) => error.status === status)
4949
}
5050
else {
5151
assert.equal(await modules.get(name).handle(req), undefined)

‎storage/framework/core/auth/tests/fixtures/credential-consumption.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ try {
149149
await resetTotp()
150150
await db.unsafe('ALTER TABLE users RENAME COLUMN two_factor_last_used_step TO hidden_totp_step').execute()
151151
try {
152-
await assert.rejects(() => verifyTwoFactorLoginCode(1, code), /two_factor_last_used_step/i, 'TOTP: missing replay schema must fail closed')
152+
await assert.rejects(async () => verifyTwoFactorLoginCode(1, code), /two_factor_last_used_step/i, 'TOTP: missing replay schema must fail closed')
153153
}
154154
catch (error) { failures.push(String(error)) }
155155
finally { await db.unsafe('ALTER TABLE users RENAME COLUMN hidden_totp_step TO two_factor_last_used_step').execute() }
@@ -182,7 +182,7 @@ try {
182182
await resetTotp()
183183
contender.exec("CREATE TRIGGER reject_totp_claim BEFORE UPDATE OF two_factor_last_used_step ON users BEGIN SELECT RAISE(ABORT, 'synthetic claim failure'); END")
184184
try {
185-
await assert.rejects(() => verifyTwoFactorLoginCode(1, code), /synthetic claim failure/, 'TOTP: a failed persistence write must never authorize')
185+
await assert.rejects(async () => verifyTwoFactorLoginCode(1, code), /synthetic claim failure/, 'TOTP: a failed persistence write must never authorize')
186186
}
187187
catch (error) { failures.push(String(error)) }
188188
finally { contender.exec('DROP TRIGGER reject_totp_claim') }
@@ -213,7 +213,7 @@ try {
213213
assert.equal(await updatePasskeyCounter(1, 'synthetic-key', 0), true, 'passkey: no-counter authenticators remain valid')
214214
assert.equal(await updatePasskeyCounter(1, 'synthetic-key', 0), true, 'passkey: unchanged MySQL timestamp must not reject no-counter authenticators')
215215
assert((await Promise.all(Array.from({ length: 8 }, () => updatePasskeyCounter(1, 'synthetic-key', 0)))).every(Boolean), 'passkey: counterless authenticators do not claim one-use counter values')
216-
await assert.rejects(db.transaction(async () => {
216+
await assert.rejects(async () => db.transaction(async () => {
217217
assert.equal(await updatePasskeyCounter(1, 'synthetic-key', 1), true)
218218
throw new Error('rollback passkey counter')
219219
}), /rollback passkey counter/)

‎storage/framework/core/auth/tests/fixtures/credential-sweep.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ try {
123123
await check('revokeAccountCredentials joins the caller\'s transaction and rolls back with it', async () => {
124124
await resetUser('pw')
125125
const pair = await oldPair('a')
126-
await assert.rejects(db.transaction(async (tx) => {
126+
await assert.rejects(async () => db.transaction(async (tx) => {
127127
await revokeAccountCredentials(42, { tx })
128128
throw new Error('caller rolls back')
129129
}), /caller rolls back/)
@@ -189,7 +189,7 @@ try {
189189
const credential = mintPasswordResetToken()
190190
await db.deleteFrom('password_resets').execute()
191191
await db.insertInto('password_resets').values({ email: 'Ada@Example.com', token: credential.digest, created_at: sqlDateTime() } as never).execute()
192-
await assert.rejects(() => consumePasswordResetToken(credential.token, async () => { throw new Error('valid before change') }), /valid before change/)
192+
await assert.rejects(async () => consumePasswordResetToken(credential.token, async () => { throw new Error('valid before change') }), /valid before change/)
193193
assert.equal((await changePassword(42, 'old-password', 'chosen-password', { notify: false })).success, true)
194194
assert.deepEqual(await consumePasswordResetToken(credential.token, async () => 'old recovery still accepted'), { consumed: false })
195195
})
@@ -198,7 +198,7 @@ try {
198198
await resetUser('old-password')
199199
const credential = mintPasswordResetToken()
200200
await db.insertInto('password_resets').values({ email: 'ada@example.com', token: credential.digest, created_at: sqlDateTime() } as never).execute()
201-
await assert.rejects(() => consumePasswordResetToken(credential.token, async claim => {
201+
await assert.rejects(async () => consumePasswordResetToken(credential.token, async claim => {
202202
await revokeAccountCredentials(claim.userId)
203203
throw new Error('outer recovery failed')
204204
}), /outer recovery failed/)

‎storage/framework/core/auth/tests/fixtures/email-verification-consumption.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ try {
8383
})
8484
await check('an outer rollback restores both user and token', async () => {
8585
await seed()
86-
await assert.rejects(db.transaction(async () => {
86+
await assert.rejects(async () => db.transaction(async () => {
8787
assert.equal((await verifyEmail(1, token)).success, true)
8888
throw new Error('synthetic outer rollback')
8989
}), /synthetic outer rollback/)
@@ -101,7 +101,7 @@ try {
101101
else
102102
await db.unsafe("CREATE TRIGGER reject_email_mark BEFORE UPDATE ON users BEGIN SELECT RAISE(ABORT, 'synthetic email mark failure'); END").execute()
103103
try {
104-
await assert.rejects(() => verifyEmail(1, token), /synthetic email mark failure/)
104+
await assert.rejects(async () => verifyEmail(1, token), /synthetic email mark failure/)
105105
assert.equal((await db.primary.selectFrom('email_verifications').selectAll().execute()).length, 1)
106106
}
107107
finally {
@@ -121,7 +121,7 @@ try {
121121
else
122122
await db.unsafe("CREATE TRIGGER reject_email_delete BEFORE DELETE ON email_verifications BEGIN SELECT RAISE(ABORT, 'synthetic email delete failure'); END").execute()
123123
try {
124-
await assert.rejects(() => verifyEmail(1, token), /synthetic email delete failure/)
124+
await assert.rejects(async () => verifyEmail(1, token), /synthetic email delete failure/)
125125
assert.equal((await db.primary.selectFrom('users').where('id', '=', 1).selectAll().executeTakeFirst())?.email_verified_at, null)
126126
}
127127
finally {
@@ -139,7 +139,7 @@ try {
139139
else
140140
await db.unsafe('CREATE TRIGGER ignore_email_mark BEFORE UPDATE ON users BEGIN SELECT RAISE(IGNORE); END').execute()
141141
try {
142-
await assert.rejects(() => verifyEmail(1, token), /could not update the user/)
142+
await assert.rejects(async () => verifyEmail(1, token), /could not update the user/)
143143
assert.equal((await db.primary.selectFrom('email_verifications').selectAll().execute()).length, 1)
144144
assert.equal((await db.primary.selectFrom('users').where('id', '=', 1).selectAll().executeTakeFirst())?.email_verified_at, null)
145145
}

‎storage/framework/core/auth/tests/fixtures/email-verification-resend-race.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ try {
164164
})
165165
await check('outer rollback does not send or consume the cooldown', async () => {
166166
await seed(true)
167-
await assert.rejects(db.transaction(async () => {
167+
await assert.rejects(async () => db.transaction(async () => {
168168
assert.equal((await resendVerificationEmail(user)).success, true)
169169
assert.equal(sent.length, 0)
170170
throw new Error('fixture resend rollback')

‎storage/framework/core/auth/tests/fixtures/email-verification-send-atomicity.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ try {
7878
})
7979
await check('outer rollback never delivers an invalid link', async () => {
8080
await seed()
81-
await assert.rejects(db.transaction(async () => {
81+
await assert.rejects(async () => db.transaction(async () => {
8282
await sendVerificationEmail(user)
8383
throw new Error('fixture rollback')
8484
}), /fixture rollback/)

0 commit comments

Comments
 (0)