Skip to content

Commit a72077f

Browse files
author
georgiy.rusanov
committed
added postgre rls tests
1 parent d78ce0e commit a72077f

File tree

2 files changed

+157
-6
lines changed

2 files changed

+157
-6
lines changed

supabase/migrations/20250422000000_create_todos_table.sql

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,52 @@ CREATE TABLE IF NOT EXISTS public.todos (
33
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
44
task TEXT NOT NULL,
55
is_complete BOOLEAN NOT NULL DEFAULT FALSE,
6-
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
6+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
7+
user_id UUID REFERENCES auth.users(id)
78
);
89

910
-- Set up Row Level Security (RLS)
1011
ALTER TABLE public.todos ENABLE ROW LEVEL SECURITY;
1112

12-
-- Create policies
13-
CREATE POLICY "Allow anonymous access to todos" ON public.todos
14-
FOR ALL
13+
-- Allow anonymous users to read all todos (public data)
14+
CREATE POLICY "Allow anonymous read access" ON public.todos
15+
FOR SELECT
16+
TO anon
17+
USING (true);
18+
19+
-- Allow anonymous users to insert todos (for backward compatibility with old tests)
20+
CREATE POLICY "Allow anonymous insert access" ON public.todos
21+
FOR INSERT
1522
TO anon
16-
USING (true)
1723
WITH CHECK (true);
24+
25+
-- Allow anonymous users to delete todos (for backward compatibility with old tests)
26+
CREATE POLICY "Allow anonymous delete access" ON public.todos
27+
FOR DELETE
28+
TO anon
29+
USING (true);
30+
31+
-- Allow authenticated users to read their own todos
32+
CREATE POLICY "Allow authenticated read own todos" ON public.todos
33+
FOR SELECT
34+
TO authenticated
35+
USING (auth.uid() = user_id);
36+
37+
-- Allow authenticated users to insert their own todos
38+
CREATE POLICY "Allow authenticated insert own todos" ON public.todos
39+
FOR INSERT
40+
TO authenticated
41+
WITH CHECK (auth.uid() = user_id);
42+
43+
-- Allow authenticated users to update their own todos
44+
CREATE POLICY "Allow authenticated update own todos" ON public.todos
45+
FOR UPDATE
46+
TO authenticated
47+
USING (auth.uid() = user_id)
48+
WITH CHECK (auth.uid() = user_id);
49+
50+
-- Allow authenticated users to delete their own todos
51+
CREATE POLICY "Allow authenticated delete own todos" ON public.todos
52+
FOR DELETE
53+
TO authenticated
54+
USING (auth.uid() = user_id);

test/integration.test.ts

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('Supabase Integration Tests', () => {
1818
})
1919

2020
describe('PostgREST', () => {
21-
test('should query data from public schema', async () => {
21+
test('should connect to PostgREST API', async () => {
2222
const { data, error } = await supabase.from('todos').select('*').limit(5)
2323

2424
// The default schema includes a 'todos' table, but it might be empty
@@ -57,6 +57,120 @@ describe('Supabase Integration Tests', () => {
5757
})
5858
})
5959

60+
describe('PostgreSQL RLS', () => {
61+
let user1Email: string
62+
let user2Email: string
63+
let user1Id: string
64+
let user2Id: string
65+
let user1TodoId: string
66+
let user2TodoId: string
67+
68+
beforeAll(async () => {
69+
// Create two test users
70+
user1Email = `user1-${Date.now()}@example.com`
71+
user2Email = `user2-${Date.now()}@example.com`
72+
const password = 'password123'
73+
74+
const { data: user1Data } = await supabase.auth.signUp({
75+
email: user1Email,
76+
password,
77+
})
78+
user1Id = user1Data.user!.id
79+
80+
const { data: user2Data } = await supabase.auth.signUp({
81+
email: user2Email,
82+
password,
83+
})
84+
user2Id = user2Data.user!.id
85+
86+
// Create todos for both users
87+
await supabase.auth.signInWithPassword({ email: user1Email, password })
88+
const { data: user1Todo } = await supabase
89+
.from('todos')
90+
.insert({ task: 'User 1 Todo', is_complete: false, user_id: user1Id })
91+
.select()
92+
.single()
93+
user1TodoId = user1Todo!.id
94+
95+
await supabase.auth.signInWithPassword({ email: user2Email, password })
96+
const { data: user2Todo } = await supabase
97+
.from('todos')
98+
.insert({ task: 'User 2 Todo', is_complete: false, user_id: user2Id })
99+
.select()
100+
.single()
101+
user2TodoId = user2Todo!.id
102+
})
103+
104+
afterAll(async () => {
105+
await supabase.auth.signOut()
106+
})
107+
108+
test('should allow anonymous access via RLS policies', async () => {
109+
await supabase.auth.signOut()
110+
111+
const { data, error } = await supabase.from('todos').select('*').limit(5)
112+
113+
expect(error).toBeNull()
114+
expect(Array.isArray(data)).toBe(true)
115+
})
116+
117+
test('should allow authenticated user to access their own data', async () => {
118+
await supabase.auth.signInWithPassword({ email: user1Email, password: 'password123' })
119+
120+
const { data, error } = await supabase
121+
.from('todos')
122+
.select('*')
123+
.eq('id', user1TodoId)
124+
.single()
125+
126+
expect(error).toBeNull()
127+
expect(data).toBeDefined()
128+
expect(data!.task).toBe('User 1 Todo')
129+
})
130+
131+
test('should prevent access to other users data', async () => {
132+
await supabase.auth.signInWithPassword({ email: user1Email, password: 'password123' })
133+
134+
const { data, error } = await supabase
135+
.from('todos')
136+
.select('*')
137+
.eq('id', user2TodoId)
138+
.single()
139+
140+
expect(error).not.toBeNull()
141+
expect(data).toBeNull()
142+
})
143+
144+
test('should allow authenticated user to create their own data', async () => {
145+
await supabase.auth.signInWithPassword({ email: user1Email, password: 'password123' })
146+
147+
const { data, error } = await supabase
148+
.from('todos')
149+
.insert({ task: 'New User 1 Todo', is_complete: false, user_id: user1Id })
150+
.select()
151+
.single()
152+
153+
expect(error).toBeNull()
154+
expect(data).toBeDefined()
155+
expect(data!.task).toBe('New User 1 Todo')
156+
})
157+
158+
test('should allow authenticated user to update their own data', async () => {
159+
await supabase.auth.signInWithPassword({ email: user1Email, password: 'password123' })
160+
161+
const { data, error } = await supabase
162+
.from('todos')
163+
.update({ task: 'Updated User 1 Todo' })
164+
.eq('id', user1TodoId)
165+
.select()
166+
.single()
167+
168+
expect(error).toBeNull()
169+
expect(data).toBeDefined()
170+
expect(data!.task).toBe('Updated User 1 Todo')
171+
})
172+
})
173+
60174
describe('Authentication', () => {
61175
afterAll(async () => {
62176
// Clean up by signing out the user

0 commit comments

Comments
 (0)