Skip to content

Commit 3166dd6

Browse files
authored
Merge pull request #345 from supabase/kiwicopple/master
2 parents a3a93e8 + 93cc0a4 commit 3166dd6

37 files changed

+3534
-9929
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Website Tests
2+
3+
on:
4+
push:
5+
branches: [master]
6+
paths:
7+
- "website/**"
8+
- ".github/workflows/website-tests.yaml"
9+
pull_request:
10+
branches: [master]
11+
paths:
12+
- "website/**"
13+
- ".github/workflows/website-tests.yaml"
14+
15+
jobs:
16+
test:
17+
name: Test & Coverage
18+
runs-on: ubuntu-latest
19+
defaults:
20+
run:
21+
working-directory: website
22+
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
27+
- name: Setup pnpm
28+
uses: pnpm/action-setup@v4
29+
with:
30+
version: latest
31+
32+
- name: Setup Node.js
33+
uses: actions/setup-node@v4
34+
with:
35+
node-version: "24"
36+
cache: "pnpm"
37+
cache-dependency-path: website/pnpm-lock.yaml
38+
39+
- name: Install dependencies
40+
run: pnpm install --frozen-lockfile
41+
42+
- name: Run tests with coverage
43+
run: pnpm run test:coverage
44+
45+
- name: Upload coverage to Coveralls
46+
uses: coverallsapp/github-action@v2
47+
with:
48+
file: website/coverage/lcov.info
49+
flag-name: frontend

PLAN.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Upgrade Plan: Next.js 16 & shadcn/ui Updates
2+
3+
## Overview
4+
5+
This plan outlines the steps to upgrade the dbdev website from Next.js 15.4.10 to Next.js 16.x and update shadcn/ui components to follow the latest patterns.
6+
7+
---
8+
9+
## Current State
10+
11+
| Component | Current | Target |
12+
|-----------|---------|--------|
13+
| Next.js | 15.4.10 | 16.1.x |
14+
| React | 19.1.0 | 19.x (compatible) |
15+
| shadcn/ui | Installed components | Latest patterns |
16+
| Turbopack | Not default | Default (Next.js 16) |
17+
18+
---
19+
20+
## Phase 1: Next.js 16 Upgrade
21+
22+
### 1.1 Update Core Dependencies
23+
24+
```bash
25+
cd website
26+
npm install next@latest react@latest react-dom@latest
27+
```
28+
29+
### 1.2 Address Breaking Changes
30+
31+
Based on Next.js 16 upgrade guide:
32+
33+
- [ ] **Turbopack is now default** - Remove any `--turbo` flags, now automatic
34+
- [ ] **Middleware renamed to proxy** - Check if any middleware needs updates
35+
- [ ] **React Compiler** - Consider enabling for automatic memoization
36+
- [ ] **Cache Components** - Evaluate `"use cache"` directive for applicable pages
37+
38+
### 1.3 Configuration Updates
39+
40+
Update `next.config.js` if needed:
41+
- Review experimental flags that may now be stable
42+
- Enable React Compiler if desired
43+
44+
### 1.4 Test the Upgrade
45+
46+
```bash
47+
npm run dev
48+
npm run build
49+
npm run lint
50+
```
51+
52+
---
53+
54+
## Phase 2: shadcn/ui Configuration Updates
55+
56+
### 2.1 Update components.json
57+
58+
Current configuration has `"rsc": false`. For App Router, consider enabling RSC:
59+
60+
```json
61+
{
62+
"$schema": "https://ui.shadcn.com/schema.json",
63+
"style": "default",
64+
"rsc": true,
65+
"tsx": true,
66+
"tailwind": {
67+
"config": "tailwind.config.js",
68+
"css": "styles/globals.css",
69+
"baseColor": "slate",
70+
"cssVariables": true
71+
},
72+
"aliases": {
73+
"components": "~/components",
74+
"utils": "~/lib/utils"
75+
}
76+
}
77+
```
78+
79+
### 2.2 Update Radix UI Dependencies
80+
81+
Current versions to update:
82+
83+
| Package | Current | Action |
84+
|---------|---------|--------|
85+
| @radix-ui/react-avatar | ^1.1.10 | Check for updates |
86+
| @radix-ui/react-dialog | ^1.1.14 | Check for updates |
87+
| @radix-ui/react-dropdown-menu | ^2.1.15 | Check for updates |
88+
| @radix-ui/react-label | ^2.1.7 | Check for updates |
89+
| @radix-ui/react-separator | ^1.1.7 | Check for updates |
90+
| @radix-ui/react-slot | ^1.2.3 | Check for updates |
91+
| @radix-ui/react-tabs | ^1.1.12 | Check for updates |
92+
| @radix-ui/react-toast | ^1.2.14 | Check for updates |
93+
94+
```bash
95+
npm update @radix-ui/react-avatar @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-label @radix-ui/react-separator @radix-ui/react-slot @radix-ui/react-tabs @radix-ui/react-toast
96+
```
97+
98+
### 2.3 Update Utility Dependencies
99+
100+
```bash
101+
npm update class-variance-authority clsx tailwind-merge lucide-react
102+
```
103+
104+
---
105+
106+
## Phase 3: Component Pattern Updates
107+
108+
### 3.1 Review Existing Components
109+
110+
Components in `website/components/ui/`:
111+
- [ ] avatar.tsx
112+
- [ ] badge.tsx
113+
- [ ] button.tsx
114+
- [ ] card.tsx
115+
- [ ] dropdown-menu.tsx
116+
- [ ] input.tsx
117+
- [ ] label.tsx
118+
- [ ] separator.tsx
119+
- [ ] tabs.tsx
120+
- [ ] toast.tsx
121+
122+
### 3.2 Consider Adding New Components
123+
124+
shadcn/ui has added new components. Evaluate if any would benefit the project:
125+
- Sonner (modern toast alternative)
126+
- Drawer
127+
- Resizable
128+
- Carousel
129+
- Chart
130+
131+
---
132+
133+
## Phase 4: Testing & Validation
134+
135+
### 4.1 Development Testing
136+
137+
```bash
138+
npm run dev
139+
```
140+
141+
- [ ] Verify all pages load correctly
142+
- [ ] Test component functionality
143+
- [ ] Check dark mode theming
144+
- [ ] Verify form submissions
145+
146+
### 4.2 Build Testing
147+
148+
```bash
149+
npm run build
150+
npm run start
151+
```
152+
153+
- [ ] Ensure production build succeeds
154+
- [ ] No TypeScript errors
155+
- [ ] No ESLint errors
156+
157+
### 4.3 Visual Regression
158+
159+
- [ ] Compare UI before/after upgrade
160+
- [ ] Verify styling consistency
161+
162+
---
163+
164+
## Rollback Plan
165+
166+
If issues arise:
167+
168+
1. Revert `package.json` changes
169+
2. Delete `node_modules` and `package-lock.json`
170+
3. Run `npm install`
171+
4. Verify application works on previous versions
172+
173+
---
174+
175+
## Files to Modify
176+
177+
| File | Changes |
178+
|------|---------|
179+
| `website/package.json` | Update Next.js, React, Radix UI versions |
180+
| `website/components.json` | Enable RSC support |
181+
| `website/next.config.js` | Review for deprecated options |
182+
| `website/components/ui/*` | Update component patterns if needed |
183+
184+
---
185+
186+
## Timeline Considerations
187+
188+
- Phase 1 (Next.js upgrade): Core dependency update
189+
- Phase 2 (shadcn config): Configuration alignment
190+
- Phase 3 (Components): Pattern updates as needed
191+
- Phase 4 (Testing): Validation before merge
192+
193+
---
194+
195+
## References
196+
197+
- [Next.js 16 Release Notes](https://nextjs.org/blog/next-16)
198+
- [Next.js 16.1 Release Notes](https://nextjs.org/blog/next-16-1)
199+
- [Next.js 16 Upgrade Guide](https://nextjs.org/docs/app/guides/upgrading/version-16)
200+
- [shadcn/ui Documentation](https://ui.shadcn.com)
201+
- [shadcn/ui Changelog](https://github.com/shadcn-ui/ui/releases)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { render, screen, waitFor } from '@testing-library/react'
2+
import userEvent from '@testing-library/user-event'
3+
import { describe, it, expect, vi, beforeEach } from 'vitest'
4+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
5+
6+
// Mock react-hot-toast - must be before component import
7+
vi.mock('react-hot-toast', () => ({
8+
toast: {
9+
success: vi.fn(),
10+
error: vi.fn(),
11+
},
12+
}))
13+
14+
// Mock the delete mutation
15+
vi.mock('~/data/access-tokens/delete-access-token', () => ({
16+
useDeleteAccessTokenMutation: ({
17+
onSuccess,
18+
}: {
19+
onSuccess?: () => void
20+
}) => ({
21+
mutate: vi.fn((vars: { tokenId: string }) => {
22+
onSuccess?.()
23+
}),
24+
isLoading: false,
25+
}),
26+
}))
27+
28+
import { toast } from 'react-hot-toast'
29+
import AccessTokenCard from '~/components/access-tokens/AccessTokenCard'
30+
31+
// Setup dayjs with relativeTime
32+
import dayjs from 'dayjs'
33+
import relativeTime from 'dayjs/plugin/relativeTime'
34+
dayjs.extend(relativeTime)
35+
36+
function createQueryClient() {
37+
return new QueryClient({
38+
defaultOptions: {
39+
queries: { retry: false },
40+
mutations: { retry: false },
41+
},
42+
})
43+
}
44+
45+
function renderWithQueryClient(ui: React.ReactElement) {
46+
const queryClient = createQueryClient()
47+
return render(
48+
<QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>
49+
)
50+
}
51+
52+
describe('Access Tokens Integration', () => {
53+
beforeEach(() => {
54+
vi.clearAllMocks()
55+
})
56+
57+
it('renders access token card with all information', () => {
58+
const createdAt = new Date(
59+
Date.now() - 7 * 24 * 60 * 60 * 1000
60+
).toISOString() // 7 days ago
61+
62+
renderWithQueryClient(
63+
<AccessTokenCard
64+
tokenId="token-123"
65+
tokenName="My API Token"
66+
maskedToken="sk_****_abcd"
67+
createdAt={createdAt}
68+
/>
69+
)
70+
71+
expect(screen.getByText('My API Token')).toBeInTheDocument()
72+
expect(screen.getByText('Token: sk_****_abcd')).toBeInTheDocument()
73+
expect(screen.getByText(/Created 7 days ago/)).toBeInTheDocument()
74+
expect(screen.getByRole('button', { name: /revoke/i })).toBeInTheDocument()
75+
})
76+
77+
it('calls delete mutation and shows toast on revoke', async () => {
78+
const user = userEvent.setup()
79+
80+
renderWithQueryClient(
81+
<AccessTokenCard
82+
tokenId="token-456"
83+
tokenName="Test Token"
84+
maskedToken="sk_****_efgh"
85+
createdAt={new Date().toISOString()}
86+
/>
87+
)
88+
89+
const revokeButton = screen.getByRole('button', { name: /revoke/i })
90+
await user.click(revokeButton)
91+
92+
await waitFor(() => {
93+
expect(toast.success).toHaveBeenCalledWith('Successfully revoked token!')
94+
})
95+
})
96+
97+
it('renders multiple tokens in a list', () => {
98+
const tokens = [
99+
{
100+
id: '1',
101+
name: 'Production API',
102+
masked: 'sk_****_prod',
103+
created: '2024-01-01',
104+
},
105+
{
106+
id: '2',
107+
name: 'Development API',
108+
masked: 'sk_****_dev',
109+
created: '2024-06-01',
110+
},
111+
{
112+
id: '3',
113+
name: 'CI/CD Token',
114+
masked: 'sk_****_cicd',
115+
created: '2024-12-01',
116+
},
117+
]
118+
119+
renderWithQueryClient(
120+
<div className="space-y-4">
121+
{tokens.map((token) => (
122+
<AccessTokenCard
123+
key={token.id}
124+
tokenId={token.id}
125+
tokenName={token.name}
126+
maskedToken={token.masked}
127+
createdAt={token.created}
128+
/>
129+
))}
130+
</div>
131+
)
132+
133+
expect(screen.getByText('Production API')).toBeInTheDocument()
134+
expect(screen.getByText('Development API')).toBeInTheDocument()
135+
expect(screen.getByText('CI/CD Token')).toBeInTheDocument()
136+
expect(screen.getAllByRole('button', { name: /revoke/i })).toHaveLength(3)
137+
})
138+
})

0 commit comments

Comments
 (0)