-
-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy pathaccess-tokens.integration.test.tsx
More file actions
138 lines (121 loc) · 3.61 KB
/
Copy pathaccess-tokens.integration.test.tsx
File metadata and controls
138 lines (121 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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)
})
})