Test Supabase RLS Policies
--
Quickly test Row Level Security policies locally without manual database queries.
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.SUPABASE_URL!;const supabaseAnonKey = process.env.SUPABASE_ANON_KEY!;
// Test with anonymous user (public access)const anonClient = createClient(supabaseUrl, supabaseAnonKey);
// Test with authenticated userconst authClient = createClient(supabaseUrl, supabaseAnonKey);
async function testRLS() { console.log('🔐 Testing RLS Policies...\n');
// Test 1: Anonymous read console.log('1️⃣ Testing anonymous read access...'); const { data: anonData, error: anonError } = await anonClient .from('posts') .select('*');
if (anonError) { console.error('❌ Anonymous read failed:', anonError.message); } else { console.log(`✅ Anonymous can read ${anonData.length} posts`); }
// Test 2: Sign in and test auth read console.log('\n2️⃣ Testing authenticated read access...'); const { data: authData } = await authClient.auth.signInWithPassword({ password: 'password123', });
if (authData.user) { const { data: userPosts, error: userError } = await authClient .from('posts') .select('*');
if (userError) { console.error('❌ Auth read failed:', userError.message); } else { console.log(`✅ Authenticated can read ${userPosts.length} posts`); } }
// Test 3: Write access console.log('\n3️⃣ Testing write access...'); const { error: writeError } = await authClient .from('posts') .insert({ title: 'Test Post', content: 'Test content' });
if (writeError) { console.error('❌ Write failed:', writeError.message); } else { console.log('✅ Write succeeded'); }
// Test 4: Update own vs others console.log('\n4️⃣ Testing update policies...'); const { error: updateError } = await authClient .from('posts') .update({ title: 'Updated' }) .eq('author_id', authData.user?.id);
if (updateError) { console.error('❌ Update own post failed:', updateError.message); } else { console.log('✅ Can update own posts'); }
// Clean up await authClient.auth.signOut(); console.log('\n✅ RLS tests complete!');}
testRLS().catch(console.error);Run with:
npx tsx test-rls.tsOutput:
🔐 Testing RLS Policies...
1️⃣ Testing anonymous read access...✅ Anonymous can read 5 posts
2️⃣ Testing authenticated read access...✅ Authenticated can read 12 posts
3️⃣ Testing write access...✅ Write succeeded
4️⃣ Testing update policies...✅ Can update own posts
✅ RLS tests complete!Bonus: Automated test suite
interface PolicyTest { name: string; test: () => Promise<boolean>;}
const tests: PolicyTest[] = [ { name: 'Anonymous can read published posts', test: async () => { const { data, error } = await anonClient .from('posts') .select('*') .eq('published', true); return !error && data.length > 0; }, }, { name: 'Anonymous cannot read drafts', test: async () => { const { data, error } = await anonClient .from('posts') .select('*') .eq('published', false); return !error && data.length === 0; }, }, // Add more tests...];
for (const test of tests) { const passed = await test.test(); console.log(passed ? '✅' : '❌', test.name);}When to use:
- Before deploying RLS changes
- Debugging permission issues
- CI/CD testing
- Local development validation