Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dbd628e
Add upgrade plan for Next.js 16 and shadcn/ui updates
claude Jan 6, 2026
200862d
Add Vitest testing setup with Button component tests
claude Jan 6, 2026
3ef44fd
Replace unit tests with form integration test
claude Jan 6, 2026
1f14380
Add test coverage reporting with v8 provider
claude Jan 6, 2026
38d0a62
Add GitHub Actions workflow for website tests
claude Jan 6, 2026
83567b9
Use Coveralls instead of Codecov for coverage
claude Jan 6, 2026
a0b2bdd
Add theme integration test for improved coverage
claude Jan 6, 2026
291460e
Add UI components integration test
claude Jan 6, 2026
3599081
Add layout integration test
claude Jan 6, 2026
b24302e
Add access tokens integration test
claude Jan 6, 2026
096944a
Add search integration test
claude Jan 6, 2026
41aa094
Add auth integration test
claude Jan 6, 2026
65e2862
Address PR review comments
claude Jan 9, 2026
1d280ec
Upgrade to Next.js 16 and React Query v5
claude Jan 9, 2026
abf56a4
Fix CI: Prettier formatting and React 19 compatibility
claude Jan 11, 2026
7ed398d
Fix: Format next-env.d.ts with single quotes
claude Jan 11, 2026
56c094d
Merge pull request #1 from kiwicopple/claude/update-shadcn-nextjs-Bl0AW
kiwicopple Jan 11, 2026
f990904
update lockfile
alaister Jan 13, 2026
9a7f91a
Upgrade final-form to v5 for react-final-form compatibility
alaister Jan 13, 2026
bb40571
Update pnpm lockfile for final-form v5
alaister Jan 13, 2026
4aa80e0
Remove package-lock.json (project uses pnpm)
alaister Jan 13, 2026
93cc0a4
fix: failing website tests in GH action
imor Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/website-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Website Tests

on:
push:
branches: [master]
paths:
- "website/**"
- ".github/workflows/website-tests.yaml"
pull_request:
branches: [master]
paths:
- "website/**"
- ".github/workflows/website-tests.yaml"

jobs:
test:
name: Test & Coverage
runs-on: ubuntu-latest
defaults:
run:
working-directory: website

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: latest

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
cache: "pnpm"
cache-dependency-path: website/pnpm-lock.yaml

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run tests with coverage
run: pnpm run test:coverage

- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
file: website/coverage/lcov.info
flag-name: frontend
201 changes: 201 additions & 0 deletions PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# Upgrade Plan: Next.js 16 & shadcn/ui Updates

## Overview

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.

---

## Current State

| Component | Current | Target |
|-----------|---------|--------|
| Next.js | 15.4.10 | 16.1.x |
| React | 19.1.0 | 19.x (compatible) |
| shadcn/ui | Installed components | Latest patterns |
| Turbopack | Not default | Default (Next.js 16) |

---

## Phase 1: Next.js 16 Upgrade

### 1.1 Update Core Dependencies

```bash
cd website
npm install next@latest react@latest react-dom@latest
```

### 1.2 Address Breaking Changes

Based on Next.js 16 upgrade guide:

- [ ] **Turbopack is now default** - Remove any `--turbo` flags, now automatic
- [ ] **Middleware renamed to proxy** - Check if any middleware needs updates
- [ ] **React Compiler** - Consider enabling for automatic memoization
- [ ] **Cache Components** - Evaluate `"use cache"` directive for applicable pages

### 1.3 Configuration Updates

Update `next.config.js` if needed:
- Review experimental flags that may now be stable
- Enable React Compiler if desired

### 1.4 Test the Upgrade

```bash
npm run dev
npm run build
npm run lint
```

---

## Phase 2: shadcn/ui Configuration Updates

### 2.1 Update components.json

Current configuration has `"rsc": false`. For App Router, consider enabling RSC:

```json
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "styles/globals.css",
"baseColor": "slate",
"cssVariables": true
},
"aliases": {
"components": "~/components",
"utils": "~/lib/utils"
}
}
```

### 2.2 Update Radix UI Dependencies

Current versions to update:

| Package | Current | Action |
|---------|---------|--------|
| @radix-ui/react-avatar | ^1.1.10 | Check for updates |
| @radix-ui/react-dialog | ^1.1.14 | Check for updates |
| @radix-ui/react-dropdown-menu | ^2.1.15 | Check for updates |
| @radix-ui/react-label | ^2.1.7 | Check for updates |
| @radix-ui/react-separator | ^1.1.7 | Check for updates |
| @radix-ui/react-slot | ^1.2.3 | Check for updates |
| @radix-ui/react-tabs | ^1.1.12 | Check for updates |
| @radix-ui/react-toast | ^1.2.14 | Check for updates |

```bash
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
```

### 2.3 Update Utility Dependencies

```bash
npm update class-variance-authority clsx tailwind-merge lucide-react
```

---

## Phase 3: Component Pattern Updates

### 3.1 Review Existing Components

Components in `website/components/ui/`:
- [ ] avatar.tsx
- [ ] badge.tsx
- [ ] button.tsx
- [ ] card.tsx
- [ ] dropdown-menu.tsx
- [ ] input.tsx
- [ ] label.tsx
- [ ] separator.tsx
- [ ] tabs.tsx
- [ ] toast.tsx

### 3.2 Consider Adding New Components

shadcn/ui has added new components. Evaluate if any would benefit the project:
- Sonner (modern toast alternative)
- Drawer
- Resizable
- Carousel
- Chart

---

## Phase 4: Testing & Validation

### 4.1 Development Testing

```bash
npm run dev
```

- [ ] Verify all pages load correctly
- [ ] Test component functionality
- [ ] Check dark mode theming
- [ ] Verify form submissions

### 4.2 Build Testing

```bash
npm run build
npm run start
```

- [ ] Ensure production build succeeds
- [ ] No TypeScript errors
- [ ] No ESLint errors

### 4.3 Visual Regression

- [ ] Compare UI before/after upgrade
- [ ] Verify styling consistency

---

## Rollback Plan

If issues arise:

1. Revert `package.json` changes
2. Delete `node_modules` and `package-lock.json`
3. Run `npm install`
4. Verify application works on previous versions

---

## Files to Modify

| File | Changes |
|------|---------|
| `website/package.json` | Update Next.js, React, Radix UI versions |
| `website/components.json` | Enable RSC support |
| `website/next.config.js` | Review for deprecated options |
| `website/components/ui/*` | Update component patterns if needed |

---

## Timeline Considerations

- Phase 1 (Next.js upgrade): Core dependency update
- Phase 2 (shadcn config): Configuration alignment
- Phase 3 (Components): Pattern updates as needed
- Phase 4 (Testing): Validation before merge

---

## References

- [Next.js 16 Release Notes](https://nextjs.org/blog/next-16)
- [Next.js 16.1 Release Notes](https://nextjs.org/blog/next-16-1)
- [Next.js 16 Upgrade Guide](https://nextjs.org/docs/app/guides/upgrading/version-16)
- [shadcn/ui Documentation](https://ui.shadcn.com)
- [shadcn/ui Changelog](https://github.com/shadcn-ui/ui/releases)
138 changes: 138 additions & 0 deletions website/__tests__/access-tokens.integration.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

// Mock react-hot-toast - must be before component import
vi.mock('react-hot-toast', () => ({
toast: {
success: vi.fn(),
error: vi.fn(),
},
}))

// Mock the delete mutation
vi.mock('~/data/access-tokens/delete-access-token', () => ({
useDeleteAccessTokenMutation: ({
onSuccess,
}: {
onSuccess?: () => void
}) => ({
mutate: vi.fn((vars: { tokenId: string }) => {
onSuccess?.()
}),
isLoading: false,
}),
}))

import { toast } from 'react-hot-toast'
import AccessTokenCard from '~/components/access-tokens/AccessTokenCard'

// Setup dayjs with relativeTime
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
dayjs.extend(relativeTime)

function createQueryClient() {
return new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
})
}

function renderWithQueryClient(ui: React.ReactElement) {
const queryClient = createQueryClient()
return render(
<QueryClientProvider client={queryClient}>{ui}</QueryClientProvider>
)
}

describe('Access Tokens Integration', () => {
beforeEach(() => {
vi.clearAllMocks()
})

it('renders access token card with all information', () => {
const createdAt = new Date(
Date.now() - 7 * 24 * 60 * 60 * 1000
).toISOString() // 7 days ago

renderWithQueryClient(
<AccessTokenCard
tokenId="token-123"
tokenName="My API Token"
maskedToken="sk_****_abcd"
createdAt={createdAt}
/>
)

expect(screen.getByText('My API Token')).toBeInTheDocument()
expect(screen.getByText('Token: sk_****_abcd')).toBeInTheDocument()
expect(screen.getByText(/Created 7 days ago/)).toBeInTheDocument()
expect(screen.getByRole('button', { name: /revoke/i })).toBeInTheDocument()
})

it('calls delete mutation and shows toast on revoke', async () => {
const user = userEvent.setup()

renderWithQueryClient(
<AccessTokenCard
tokenId="token-456"
tokenName="Test Token"
maskedToken="sk_****_efgh"
createdAt={new Date().toISOString()}
/>
)

const revokeButton = screen.getByRole('button', { name: /revoke/i })
await user.click(revokeButton)

await waitFor(() => {
expect(toast.success).toHaveBeenCalledWith('Successfully revoked token!')
})
})

it('renders multiple tokens in a list', () => {
const tokens = [
{
id: '1',
name: 'Production API',
masked: 'sk_****_prod',
created: '2024-01-01',
},
{
id: '2',
name: 'Development API',
masked: 'sk_****_dev',
created: '2024-06-01',
},
{
id: '3',
name: 'CI/CD Token',
masked: 'sk_****_cicd',
created: '2024-12-01',
},
]

renderWithQueryClient(
<div className="space-y-4">
{tokens.map((token) => (
<AccessTokenCard
key={token.id}
tokenId={token.id}
tokenName={token.name}
maskedToken={token.masked}
createdAt={token.created}
/>
))}
</div>
)

expect(screen.getByText('Production API')).toBeInTheDocument()
expect(screen.getByText('Development API')).toBeInTheDocument()
expect(screen.getByText('CI/CD Token')).toBeInTheDocument()
expect(screen.getAllByRole('button', { name: /revoke/i })).toHaveLength(3)
})
})
Loading