Skip to content
46 changes: 34 additions & 12 deletions tests/password-policy.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { PostgrestError } from '@supabase/supabase-js'
import { randomUUID } from 'node:crypto'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'

Expand Down Expand Up @@ -278,7 +277,7 @@ describe('[POST] /private/validate_password_compliance', () => {
if (disableError)
throw disableError

let restoreError: PostgrestError | null = null
let testError: Error | null = null
try {
const response = await fetch(`${BASE_URL}/private/validate_password_compliance`, {
Comment on lines 281 to 282
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

PostgrestError is no longer referenced in this test after removing restoreError, so the type import at the top of the file is now unused and may fail lint/TS checks. Remove the unused import (or reintroduce a typed variable if still needed).

Copilot uses AI. Check for mistakes.
headers,
Expand All @@ -294,15 +293,26 @@ describe('[POST] /private/validate_password_compliance', () => {
const responseData = await response.json() as { error: string }
expect(responseData.error).toBe('no_policy')
}
catch (error) {
testError = error as Error
}
finally {
const { error } = await getSupabaseClient()
const { error: restoreError } = await getSupabaseClient()
.from('orgs')
.update({ password_policy_config: policyConfig })
.eq('id', ORG_ID)
restoreError = error ?? null

// If restore failed, throw it (but preserve test failure if there was one)
if (restoreError) {
if (testError)
throw new Error(`Test failed AND restore failed: ${testError.message} | Restore error: ${restoreError.message}`)
throw restoreError
}

// Re-throw original test error if any
if (testError)
throw testError
}
if (restoreError)
throw restoreError
})

it('reject request with invalid credentials', async () => {
Expand Down Expand Up @@ -409,7 +419,7 @@ describe('[POST] /private/validate_password_compliance', () => {
method: 'POST',
body: 'invalid json',
})
expect(response.status).toBeGreaterThanOrEqual(400)
expect(response.status).toBe(400)
})
})

Expand Down Expand Up @@ -548,16 +558,28 @@ describe('password Policy Enforcement Integration', () => {
describe('user_password_compliance table', () => {
it('can insert compliance record via service role', async () => {
// Get the policy hash
const { data: org } = await getSupabaseClient()
const { data: org, error: orgError } = await getSupabaseClient()
.from('orgs')
.select('password_policy_config')
.eq('id', ORG_ID)
.single()

const policyHash = org?.password_policy_config
// eslint-disable-next-line node/prefer-global/buffer
? Buffer.from(JSON.stringify(org.password_policy_config)).toString('base64').substring(0, 32)
: 'test_hash'
expect(orgError).toBeNull()
expect(org?.password_policy_config).not.toBeNull()
const policyConfig = org?.password_policy_config
if (policyConfig == null)
throw new Error('Expected password_policy_config to be set for test org')

// Use the same RPC that production uses to compute the password policy hash
const { data: rpcResult, error: rpcError } = await getSupabaseClient().rpc('get_password_policy_hash', {
policy_config: policyConfig,
})

expect(rpcError).toBeNull()
expect(rpcResult).not.toBeNull()
expect(typeof rpcResult).toBe('string')

const policyHash = rpcResult as string

const { error } = await getSupabaseClient()
.from('user_password_compliance')
Expand Down