@tscircuit/fake-snippets 0.0.66 → 0.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/bun-tests/fake-snippets-api/fixtures/get-circuit-json.ts +5 -143
  2. package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +1 -4
  3. package/bun-tests/fake-snippets-api/fixtures/start-server.ts +7 -3
  4. package/bun-tests/fake-snippets-api/routes/order_quotes/create.test.ts +20 -56
  5. package/bun-tests/fake-snippets-api/routes/package_files/create_or_update.test.ts +2 -2
  6. package/bun-tests/fake-snippets-api/routes/package_releases/update.test.ts +1 -1
  7. package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +0 -11
  8. package/bun.lock +15 -17
  9. package/dist/bundle.js +32 -39
  10. package/fake-snippets-api/routes/api/order_quotes/create.ts +30 -37
  11. package/fake-snippets-api/routes/api/order_quotes/get.ts +5 -8
  12. package/package.json +4 -3
  13. package/src/App.tsx +0 -7
  14. package/src/ContextProviders.tsx +2 -0
  15. package/src/components/DownloadButtonAndMenu.tsx +1 -4
  16. package/src/components/Footer.tsx +5 -2
  17. package/src/components/HeaderLogin.tsx +37 -54
  18. package/src/components/ImageWithFallback.tsx +37 -0
  19. package/src/components/JLCPCBImportDialog.tsx +43 -24
  20. package/src/components/PackageCard.tsx +2 -2
  21. package/src/components/{SnippetLink.tsx → PackageLink.tsx} +8 -16
  22. package/src/components/PackageSearchResults.tsx +87 -0
  23. package/src/components/PackagesList.tsx +3 -3
  24. package/src/components/PageSearchComponent.tsx +9 -9
  25. package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +5 -28
  26. package/src/components/ViewPackagePage/components/main-content-header.tsx +8 -8
  27. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +24 -14
  28. package/src/components/ViewPackagePage/components/package-header.tsx +6 -1
  29. package/src/components/package-port/CodeEditor.tsx +13 -10
  30. package/src/components/package-port/CodeEditorHeader.tsx +1 -1
  31. package/src/components/package-port/EditorNav.tsx +2 -2
  32. package/src/hooks/use-global-store.ts +1 -0
  33. package/src/hooks/use-shiki-highlighter.ts +13 -6
  34. package/src/lib/download-fns/download-gltf.ts +3 -10
  35. package/src/lib/handleManualEditsImport.tsx +1 -1
  36. package/src/lib/types.ts +4 -2
  37. package/src/pages/dashboard.tsx +3 -4
  38. package/src/pages/editor.tsx +20 -14
  39. package/src/pages/latest.tsx +25 -26
  40. package/src/pages/search.tsx +120 -19
  41. package/src/pages/trending.tsx +14 -58
  42. package/src/pages/user-profile.tsx +13 -8
  43. package/bun-tests/fake-snippets-api/routes/snippets/add_star.test.ts +0 -84
  44. package/bun-tests/fake-snippets-api/routes/snippets/create.test.ts +0 -53
  45. package/bun-tests/fake-snippets-api/routes/snippets/delete.test.ts +0 -82
  46. package/bun-tests/fake-snippets-api/routes/snippets/download.test.ts +0 -90
  47. package/bun-tests/fake-snippets-api/routes/snippets/generate_from_jlcpcb.test.ts +0 -16
  48. package/bun-tests/fake-snippets-api/routes/snippets/get.test.ts +0 -163
  49. package/bun-tests/fake-snippets-api/routes/snippets/get_image.test.ts +0 -117
  50. package/bun-tests/fake-snippets-api/routes/snippets/images.test.ts +0 -114
  51. package/bun-tests/fake-snippets-api/routes/snippets/list.test.ts +0 -169
  52. package/bun-tests/fake-snippets-api/routes/snippets/list_newest.test.ts +0 -50
  53. package/bun-tests/fake-snippets-api/routes/snippets/list_trending.test.ts +0 -72
  54. package/bun-tests/fake-snippets-api/routes/snippets/remove_star.test.ts +0 -80
  55. package/bun-tests/fake-snippets-api/routes/snippets/search.test.ts +0 -75
  56. package/bun-tests/fake-snippets-api/routes/snippets/star-count.test.ts +0 -51
  57. package/bun-tests/fake-snippets-api/routes/snippets/update.test.ts +0 -175
  58. package/src/components/AiChatInterface.tsx +0 -229
  59. package/src/components/CodeAndPreview.tsx +0 -289
  60. package/src/components/CodeEditor.tsx +0 -539
  61. package/src/components/CodeEditorHeader.tsx +0 -135
  62. package/src/components/EditorNav.tsx +0 -502
  63. package/src/components/PreviewContent.tsx +0 -372
  64. package/src/components/SnippetCard.tsx +0 -159
  65. package/src/components/SnippetList.tsx +0 -71
  66. package/src/hooks/use-compiled-tsx.ts +0 -37
  67. package/src/hooks/use-run-tsx/construct-circuit.tsx +0 -62
  68. package/src/hooks/use-run-tsx/index.tsx +0 -256
  69. package/src/hooks/use-save-snippet.ts +0 -66
  70. package/src/hooks/use-typecheck.ts +0 -54
  71. package/src/lib/utils/getSyntaxError.ts +0 -13
  72. package/src/pages/ai.tsx +0 -92
  73. package/src/pages/view-snippet.tsx +0 -166
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from "react"
2
2
  import { useQuery } from "react-query"
3
3
  import { useAxios } from "@/hooks/use-axios"
4
- import { Snippet } from "fake-snippets-api/lib/db/schema"
4
+ import { Package } from "fake-snippets-api/lib/db/schema"
5
5
  import Header from "@/components/Header"
6
6
  import Footer from "@/components/Footer"
7
7
  import {
@@ -23,8 +23,8 @@ import {
23
23
  SelectTrigger,
24
24
  SelectValue,
25
25
  } from "@/components/ui/select"
26
- import { SnippetCard } from "@/components/SnippetCard"
27
26
  import { PackageCardSkeleton } from "@/components/PackageCardSkeleton"
27
+ import { PackageCard } from "@/components/PackageCard"
28
28
 
29
29
  const LatestPage: React.FC = () => {
30
30
  const axios = useAxios()
@@ -33,30 +33,30 @@ const LatestPage: React.FC = () => {
33
33
  const [category, setCategory] = useState("all")
34
34
 
35
35
  const {
36
- data: snippets,
36
+ data: packages,
37
37
  isLoading,
38
38
  error,
39
- } = useQuery<Snippet[]>(
40
- ["latestSnippets", category],
39
+ } = useQuery<Package[]>(
40
+ ["latestPackages", category],
41
41
  async () => {
42
42
  const params = category !== "all" ? { tag: category } : {}
43
- const response = await axios.get("/snippets/list_latest", { params })
44
- return response.data.snippets
43
+ const response = await axios.get("/packages/list_latest", { params })
44
+ return response.data.packages
45
45
  },
46
46
  {
47
47
  keepPreviousData: true,
48
48
  },
49
49
  )
50
50
 
51
- const filteredSnippets = snippets?.filter((snippet) => {
51
+ const filteredPackages = packages?.filter((pkg) => {
52
52
  if (!searchQuery) return true
53
53
 
54
54
  const query = searchQuery.toLowerCase().trim()
55
55
 
56
56
  const searchableFields = [
57
- snippet.unscoped_name.toLowerCase(),
58
- snippet.owner_name.toLowerCase(),
59
- (snippet.description || "").toLowerCase(),
57
+ pkg.unscoped_name.toLowerCase(),
58
+ pkg.owner_github_username?.toLowerCase() ?? "",
59
+ (pkg.description || "").toLowerCase(),
60
60
  ]
61
61
 
62
62
  return searchableFields.some((field) => {
@@ -73,7 +73,7 @@ const LatestPage: React.FC = () => {
73
73
  <div className="flex items-center gap-2 mb-3">
74
74
  <Calendar className="w-6 h-6 text-blue-500" />
75
75
  <h1 className="text-4xl font-bold text-gray-900">
76
- Latest Snippets
76
+ Latest Packages
77
77
  </h1>
78
78
  </div>
79
79
  <p className="text-lg text-gray-600 mb-4">
@@ -99,7 +99,7 @@ const LatestPage: React.FC = () => {
99
99
  <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
100
100
  <Input
101
101
  type="text"
102
- placeholder="Search latest snippets..."
102
+ placeholder="Search latest packages..."
103
103
  value={searchQuery}
104
104
  onChange={(e) => setSearchQuery(e.target.value)}
105
105
  className="pl-10"
@@ -154,40 +154,39 @@ const LatestPage: React.FC = () => {
154
154
  </div>
155
155
  <div>
156
156
  <h3 className="text-lg font-semibold mb-2">
157
- Error Loading Snippets
157
+ Error Loading Packages
158
158
  </h3>
159
159
  <p className="text-red-600">
160
- We couldn't load the latest snippets. Please try again later.
160
+ We couldn't load the latest packages. Please try again later.
161
161
  </p>
162
162
  </div>
163
163
  </div>
164
164
  </div>
165
- ) : filteredSnippets?.length === 0 ? (
165
+ ) : filteredPackages?.length === 0 ? (
166
166
  <div className="text-center py-12 px-4">
167
167
  <div className="bg-slate-50 inline-flex rounded-full p-4 mb-4">
168
168
  <Search className="w-8 h-8 text-slate-400" />
169
169
  </div>
170
170
  <h3 className="text-xl font-medium text-slate-900 mb-2">
171
- No Matching Snippets
171
+ No Matching Packages
172
172
  </h3>
173
173
  <p className="text-slate-500 max-w-md mx-auto mb-6">
174
174
  {searchQuery
175
- ? `No snippets match your search for "${searchQuery}".`
175
+ ? `No packages match your search for "${searchQuery}".`
176
176
  : category !== "all"
177
- ? `No ${category} snippets found in the latest list.`
178
- : "There are no new snippets at the moment."}
177
+ ? `No ${category} packages found in the latest list.`
178
+ : "There are no new packages at the moment."}
179
179
  </p>
180
180
  </div>
181
181
  ) : (
182
182
  <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
183
- {filteredSnippets
183
+ {filteredPackages
184
184
  ?.sort((a, b) => b.created_at.localeCompare(a.created_at))
185
- ?.map((snippet) => (
186
- <SnippetCard
187
- key={snippet.snippet_id}
188
- snippet={snippet}
185
+ ?.map((pkg) => (
186
+ <PackageCard
187
+ key={pkg.package_id}
188
+ pkg={pkg}
189
189
  baseUrl={apiBaseUrl}
190
- showOwner={true}
191
190
  />
192
191
  ))}
193
192
  </div>
@@ -1,13 +1,92 @@
1
+ import React, { useState, useEffect } from "react"
2
+ import { useQuery } from "react-query"
3
+ import { useAxios } from "@/hooks/use-axios"
4
+ import { useSearchParams } from "wouter"
1
5
  import Header from "@/components/Header"
2
6
  import Footer from "@/components/Footer"
3
- import PageSearchComponent from "@/components/PageSearchComponent"
4
- import { useState } from "react"
5
- import { Search, Tag, Filter } from "lucide-react"
6
- import { Badge } from "@/components/ui/badge"
7
- import { PrefetchPageLink } from "@/components/PrefetchPageLink"
7
+ import { Input } from "@/components/ui/input"
8
+ import { Search } from "lucide-react"
9
+ import PackageSearchResults from "@/components/PackageSearchResults"
10
+ import { useSnippetsBaseApiUrl } from "@/hooks/use-snippets-base-api-url"
11
+ import {
12
+ Select,
13
+ SelectContent,
14
+ SelectItem,
15
+ SelectTrigger,
16
+ SelectValue,
17
+ } from "@/components/ui/select"
18
+ import { Package } from "fake-snippets-api/lib/db/schema"
8
19
 
9
20
  export const SearchPage = () => {
10
- const [searchResults, setSearchResults] = useState<any[]>([])
21
+ const axios = useAxios()
22
+ const apiBaseUrl = useSnippetsBaseApiUrl()
23
+ const [searchParams, setSearchParams] = useSearchParams()
24
+
25
+ const [searchQuery, setSearchQuery] = useState(searchParams.get("q") || "")
26
+ const [category, setCategory] = useState(
27
+ searchParams.get("category") || "all",
28
+ )
29
+ const [sortBy, setSortBy] = useState(searchParams.get("sort") || "stars")
30
+
31
+ useEffect(() => {
32
+ const params = new URLSearchParams()
33
+ if (searchQuery) params.set("q", searchQuery)
34
+ if (category !== "all") params.set("category", category)
35
+ if (sortBy !== "stars") params.set("sort", sortBy)
36
+ setSearchParams(params)
37
+ }, [searchQuery, category, sortBy, setSearchParams])
38
+
39
+ const {
40
+ data: packages,
41
+ isLoading,
42
+ error,
43
+ } = useQuery(
44
+ ["packageSearch", searchQuery, category],
45
+ async () => {
46
+ const params = new URLSearchParams()
47
+ if (searchQuery) params.append("q", searchQuery)
48
+ if (category !== "all") params.append("category", category)
49
+
50
+ const response = await axios.post(`/packages/search`, {
51
+ query: searchQuery,
52
+ })
53
+ return response.data.packages
54
+ },
55
+ { enabled: Boolean(searchQuery), keepPreviousData: true },
56
+ )
57
+
58
+ const filteredPackages = packages
59
+ ?.filter((pkg: Package) => {
60
+ if (!searchQuery) return true
61
+
62
+ const query = searchQuery.toLowerCase().trim()
63
+ const searchableFields = [
64
+ pkg.unscoped_name.toLowerCase(),
65
+ (pkg.owner_github_username || "").toLowerCase(),
66
+ (pkg.description || "").toLowerCase(),
67
+ pkg.description?.toLowerCase(),
68
+ ]
69
+
70
+ return searchableFields.some((field) => {
71
+ const queryWords = query.split(/\s+/).filter((word) => word.length > 0)
72
+ if (!field) return false
73
+ return queryWords.every((word) => field.includes(word))
74
+ })
75
+ })
76
+ ?.sort((a: Package, b: Package) => {
77
+ if (sortBy === "stars") {
78
+ return (b.star_count || 0) - (a.star_count || 0)
79
+ } else if (sortBy === "newest") {
80
+ return (
81
+ new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
82
+ )
83
+ } else if (sortBy === "oldest") {
84
+ return (
85
+ new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime()
86
+ )
87
+ }
88
+ return 0
89
+ })
11
90
 
12
91
  return (
13
92
  <div className="min-h-screen flex flex-col">
@@ -17,26 +96,46 @@ export const SearchPage = () => {
17
96
  <div className="max-w-8xl mx-auto">
18
97
  <div className="mb-6">
19
98
  <div className="flex items-center gap-2 mb-3">
20
- <Search className="w-6 h-6 text-blue-500" />
21
99
  <h1 className="text-3xl font-bold text-gray-900">
22
100
  Search tscircuit Packages
23
101
  </h1>
24
102
  </div>
25
- <div className="flex flex-wrap gap-3">
26
- <PrefetchPageLink href="/trending">
27
- <Badge
28
- variant="secondary"
29
- className="px-3 py-1 cursor-pointer hover:bg-gray-200"
30
- >
31
- <Tag className="w-3.5 h-3.5 mr-1" />
32
- <span>Browse Packages</span>
33
- </Badge>
34
- </PrefetchPageLink>
103
+ <div className="flex flex-col sm:flex-row gap-4 mb-4">
104
+ <div className="relative flex-grow">
105
+ <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
106
+ <Input
107
+ type="search"
108
+ placeholder="Search packages..."
109
+ className="pl-10"
110
+ value={searchQuery}
111
+ onChange={(e) => setSearchQuery(e.target.value)}
112
+ aria-label="Search packages"
113
+ role="searchbox"
114
+ />
115
+ </div>
116
+ <Select value={sortBy} onValueChange={setSortBy}>
117
+ <SelectTrigger className="w-[140px]">
118
+ <SelectValue placeholder="Sort By" />
119
+ </SelectTrigger>
120
+ <SelectContent>
121
+ <SelectItem value="stars">Most Starred</SelectItem>
122
+ <SelectItem value="newest">Newest</SelectItem>
123
+ <SelectItem value="oldest">Oldest</SelectItem>
124
+ </SelectContent>
125
+ </Select>
35
126
  </div>
36
127
  </div>
37
128
 
38
- <PageSearchComponent
39
- onResultsFetched={(results) => setSearchResults(results)}
129
+ <PackageSearchResults
130
+ isLoading={isLoading}
131
+ error={error}
132
+ filteredPackages={filteredPackages}
133
+ apiBaseUrl={apiBaseUrl}
134
+ emptyStateMessage={
135
+ searchQuery
136
+ ? `No packages match your search for "${searchQuery}".`
137
+ : "Please enter a search query to find packages."
138
+ }
40
139
  />
41
140
  </div>
42
141
  </div>
@@ -45,3 +144,5 @@ export const SearchPage = () => {
45
144
  </div>
46
145
  )
47
146
  }
147
+
148
+ export default SearchPage
@@ -14,16 +14,14 @@ import {
14
14
  SelectTrigger,
15
15
  SelectValue,
16
16
  } from "@/components/ui/select"
17
- import { PackageCardSkeleton } from "@/components/PackageCardSkeleton"
18
17
  import { Package } from "fake-snippets-api/lib/db/schema"
19
- import { PackageCard } from "@/components/PackageCard"
18
+ import PackageSearchResults from "@/components/PackageSearchResults"
20
19
 
21
20
  const TrendingPage: React.FC = () => {
22
21
  const axios = useAxios()
23
22
  const apiBaseUrl = useSnippetsBaseApiUrl()
24
23
  const [searchParams, setSearchParams] = useSearchParams()
25
24
 
26
- // Initialize state from URL params or defaults
27
25
  const [searchQuery, setSearchQuery] = useState(searchParams.get("q") || "")
28
26
  const [category, setCategory] = useState(
29
27
  searchParams.get("category") || "all",
@@ -33,7 +31,6 @@ const TrendingPage: React.FC = () => {
33
31
  )
34
32
  const [sortBy, setSortBy] = useState(searchParams.get("sort") || "stars")
35
33
 
36
- // Update URL params when filters change
37
34
  useEffect(() => {
38
35
  const params = new URLSearchParams()
39
36
  if (searchQuery) params.set("q", searchQuery)
@@ -47,7 +44,6 @@ const TrendingPage: React.FC = () => {
47
44
  data: packages,
48
45
  isLoading,
49
46
  error,
50
- refetch,
51
47
  } = useQuery<Package[]>(
52
48
  ["trendingPackages", category, time_period],
53
49
  async () => {
@@ -70,7 +66,6 @@ const TrendingPage: React.FC = () => {
70
66
  if (!searchQuery) return true
71
67
 
72
68
  const query = searchQuery.toLowerCase().trim()
73
-
74
69
  const searchableFields = [
75
70
  pkg.unscoped_name.toLowerCase(),
76
71
  (pkg.owner_github_username || "").toLowerCase(),
@@ -175,58 +170,19 @@ const TrendingPage: React.FC = () => {
175
170
  </Select>
176
171
  </div>
177
172
  </div>
178
-
179
- {isLoading ? (
180
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
181
- {[...Array(6)].map((_, i) => (
182
- <PackageCardSkeleton key={i} />
183
- ))}
184
- </div>
185
- ) : error ? (
186
- <div className="bg-red-50 border border-red-200 text-red-700 p-6 rounded-xl shadow-sm max-w-2xl mx-auto">
187
- <div className="flex items-start">
188
- <div className="mr-4 bg-red-100 p-2 rounded-full">
189
- <Search className="w-6 h-6 text-red-600" />
190
- </div>
191
- <div>
192
- <h3 className="text-lg font-semibold mb-2">
193
- Error Loading packages
194
- </h3>
195
- <p className="text-red-600">
196
- We couldn't load the trending packages. Please try again
197
- later.
198
- </p>
199
- </div>
200
- </div>
201
- </div>
202
- ) : filteredPackages?.length === 0 ? (
203
- <div className="text-center py-12 px-4">
204
- <div className="bg-slate-50 inline-flex rounded-full p-4 mb-4">
205
- <Search className="w-8 h-8 text-slate-400" />
206
- </div>
207
- <h3 className="text-xl font-medium text-slate-900 mb-2">
208
- No Matching Packages
209
- </h3>
210
- <p className="text-slate-500 max-w-md mx-auto mb-6">
211
- {searchQuery
212
- ? `No packages match your search for "${searchQuery}".`
213
- : category !== "all"
214
- ? `No ${category} packages found in the trending list.`
215
- : "There are no trending packages at the moment."}
216
- </p>
217
- </div>
218
- ) : (
219
- <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
220
- {filteredPackages?.map((pkg) => (
221
- <PackageCard
222
- key={pkg.package_id}
223
- pkg={pkg}
224
- baseUrl={apiBaseUrl}
225
- showOwner={true}
226
- />
227
- ))}
228
- </div>
229
- )}
173
+ <PackageSearchResults
174
+ isLoading={isLoading}
175
+ error={error}
176
+ filteredPackages={filteredPackages}
177
+ apiBaseUrl={apiBaseUrl}
178
+ emptyStateMessage={
179
+ searchQuery
180
+ ? `No packages match your search for "${searchQuery}".`
181
+ : category !== "all"
182
+ ? `No ${category} packages found in the trending list.`
183
+ : "There are no trending packages at the moment."
184
+ }
185
+ />
230
186
  </main>
231
187
  <Footer />
232
188
  </div>
@@ -23,6 +23,7 @@ import {
23
23
  SelectValue,
24
24
  } from "@/components/ui/select"
25
25
  import { Box, Star } from "lucide-react"
26
+ import { PackageCardSkeleton } from "@/components/PackageCardSkeleton"
26
27
 
27
28
  export const UserProfilePage = () => {
28
29
  const { username } = useParams()
@@ -159,10 +160,10 @@ export const UserProfilePage = () => {
159
160
  </Select>
160
161
  </div>
161
162
  {isLoading ? (
162
- <div>
163
- {activeTab === "starred"
164
- ? "Loading Starred Packages..."
165
- : "Loading User Packages..."}
163
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
164
+ {[...Array(6)].map((_, i) => (
165
+ <PackageCardSkeleton key={i} />
166
+ ))}
166
167
  </div>
167
168
  ) : (
168
169
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
@@ -184,16 +185,20 @@ export const UserProfilePage = () => {
184
185
  <div className="flex flex-col items-center py-12 text-gray-500">
185
186
  {activeTab === "starred" ? (
186
187
  <>
187
- <Star />
188
+ <Star className="mb-2" size={24} />
188
189
  <span className="text-lg font-medium">
189
- No starred packages
190
+ {searchQuery.trim()
191
+ ? `No starred packages matching '${searchQuery.trim()}'`
192
+ : "No starred packages"}
190
193
  </span>
191
194
  </>
192
195
  ) : (
193
196
  <>
194
- <Box />
197
+ <Box className="mb-2" size={24} />
195
198
  <span className="text-lg font-medium">
196
- No packages available
199
+ {searchQuery.trim()
200
+ ? `No packages matching '${searchQuery.trim()}'`
201
+ : "No packages available"}
197
202
  </span>
198
203
  </>
199
204
  )}
@@ -1,84 +0,0 @@
1
- import { getTestServer } from "bun-tests/fake-snippets-api/fixtures/get-test-server"
2
- import { expect, test } from "bun:test"
3
-
4
- test("add star to snippet", async () => {
5
- const { axios } = await getTestServer()
6
-
7
- // Create a test snippet using the create endpoint
8
- const newSnippetData = {
9
- code: "Test Content",
10
- snippet_type: "package",
11
- description: "Test Description",
12
- }
13
- const createResponse = await axios.post(
14
- "/api/snippets/create",
15
- newSnippetData,
16
- )
17
- expect(createResponse.status).toBe(200)
18
- const createdSnippet = createResponse.data.snippet
19
-
20
- // Star the snippet
21
- const response = await axios.post("/api/snippets/add_star", {
22
- snippet_id: createdSnippet.snippet_id,
23
- })
24
-
25
- expect(response.status).toBe(200)
26
- expect(response.data.ok).toBe(true)
27
-
28
- // Verify star was added by checking the snippet again
29
- const getResponse = await axios.get("/api/snippets/get", {
30
- params: { snippet_id: createdSnippet.snippet_id },
31
- })
32
-
33
- expect(getResponse.status).toBe(200)
34
- expect(getResponse.data.snippet.is_starred).toBe(true)
35
- })
36
-
37
- test("add star to non-existent snippet", async () => {
38
- const { axios } = await getTestServer()
39
-
40
- try {
41
- await axios.post("/api/snippets/add_star", {
42
- snippet_id: "non-existent-id",
43
- })
44
- expect(true).toBe(false) // Should not reach here
45
- } catch (error: any) {
46
- expect(error.status).toBe(404)
47
- expect(error.data.error.message).toBe("Snippet not found")
48
- }
49
- })
50
-
51
- test("add star to already starred snippet", async () => {
52
- const { axios } = await getTestServer()
53
-
54
- // Create a test snippet using the create endpoint
55
- const newSnippetData = {
56
- code: "Test Content",
57
- snippet_type: "package",
58
- description: "Test Description",
59
- }
60
- const createResponse = await axios.post(
61
- "/api/snippets/create",
62
- newSnippetData,
63
- )
64
- expect(createResponse.status).toBe(200)
65
- const createdSnippet = createResponse.data.snippet
66
-
67
- // Star the snippet first time
68
- await axios.post("/api/snippets/add_star", {
69
- snippet_id: createdSnippet.snippet_id,
70
- })
71
-
72
- // Try to star again
73
- try {
74
- await axios.post("/api/snippets/add_star", {
75
- snippet_id: createdSnippet.snippet_id,
76
- })
77
- expect(true).toBe(false) // Should not reach here
78
- } catch (error: any) {
79
- expect(error.status).toBe(400)
80
- expect(error.data.error.message).toBe(
81
- "You have already starred this snippet",
82
- )
83
- }
84
- })
@@ -1,53 +0,0 @@
1
- import { getTestServer } from "bun-tests/fake-snippets-api/fixtures/get-test-server"
2
- import { expect, test } from "bun:test"
3
-
4
- test("create snippet", async () => {
5
- const { axios } = await getTestServer()
6
-
7
- const response = await axios.post("/api/snippets/create", {
8
- unscoped_name: "TestSnippet",
9
- code: "Test Content",
10
- snippet_type: "package",
11
- description: "Test Description",
12
- })
13
-
14
- expect(response.status).toBe(200)
15
- expect(response.data.snippet.unscoped_name).toBe("TestSnippet")
16
- expect(response.data.snippet.owner_name).toBe("testuser")
17
- expect(response.data.snippet.code).toBe("Test Content")
18
- expect(response.data.snippet.snippet_type).toBe("package")
19
- expect(response.data.snippet.description).toBe("Test Description")
20
- })
21
-
22
- test("create snippet and call package get to verify it exists", async () => {
23
- const { axios, db } = await getTestServer()
24
-
25
- const response = await axios.post("/api/snippets/create", {
26
- unscoped_name: "example-package",
27
- code: "console.log('Hello, world!');",
28
- snippet_type: "package",
29
- description: "Test Description",
30
- })
31
- const packageResponse = await axios.get(`/api/packages/get`, {
32
- params: {
33
- package_id: response.data.snippet.snippet_id,
34
- },
35
- })
36
- expect(packageResponse.status).toBe(200)
37
- expect(packageResponse.data.package.unscoped_name).toBe("example-package")
38
- expect(packageResponse.data.package.owner_github_username).toBe("testuser")
39
- expect(packageResponse.data.package.description).toBe("Test Description")
40
-
41
- // Add package file verification
42
- const packageFileResponse = await axios.post(`/api/package_files/get`, {
43
- package_release_id: packageResponse.data.package.latest_package_release_id,
44
- file_path: "index.tsx",
45
- })
46
-
47
- expect(packageFileResponse.status).toBe(200)
48
- expect(packageFileResponse.data.ok).toBe(true)
49
- expect(packageFileResponse.data.package_file).toBeDefined()
50
- expect(packageFileResponse.data.package_file.content_text).toBe(
51
- "console.log('Hello, world!');",
52
- )
53
- })
@@ -1,82 +0,0 @@
1
- import { getTestServer } from "bun-tests/fake-snippets-api/fixtures/get-test-server"
2
- import { test, expect } from "bun:test"
3
-
4
- test("delete snippet", async () => {
5
- const { axios, db } = await getTestServer()
6
-
7
- // Add a test snippet
8
- const snippet = {
9
- unscoped_name: "TestSnippet",
10
- owner_name: "testuser",
11
- code: "Test Content",
12
- created_at: "2023-01-01T00:00:00Z",
13
- updated_at: "2023-01-01T00:00:00Z",
14
- name: "testuser/TestSnippet",
15
- snippet_type: "package",
16
- description: "Test Description",
17
- }
18
- const addedSnippet: any = db.addSnippet(snippet as any)
19
-
20
- // Delete the snippet
21
- const response = await axios.post("/api/snippets/delete", {
22
- snippet_id: addedSnippet.snippet_id,
23
- })
24
-
25
- expect(response.status).toBe(200)
26
- expect(response.data.ok).toBe(true)
27
-
28
- // Verify the snippet was deleted from the database
29
- const deletedSnippet = db.getSnippetById(addedSnippet.snippet_id)
30
- expect(deletedSnippet).toBeUndefined()
31
-
32
- // List all the snippets and verify the deleted snippet is not in the list
33
- const listResponse = await axios.get("/api/snippets/list")
34
-
35
- expect(listResponse.status).toBe(200)
36
- expect(listResponse.data.snippets).toHaveLength(0)
37
- })
38
-
39
- test("delete non-existent snippet", async () => {
40
- const { axios } = await getTestServer()
41
-
42
- try {
43
- await axios.post("/api/snippets/delete", {
44
- snippet_id: "non-existent-id",
45
- })
46
- // If the request doesn't throw an error, fail the test
47
- expect(true).toBe(false)
48
- } catch (error: any) {
49
- expect(error.status).toBe(404)
50
- expect(error.data.error.message).toBe("Snippet not found")
51
- }
52
- })
53
-
54
- test("delete snippet without permission", async () => {
55
- const { axios, db } = await getTestServer()
56
-
57
- // Add a test snippet with a different owner
58
- const snippet = {
59
- unscoped_name: "TestSnippet",
60
- owner_name: "otheruser",
61
- code: "Test Content",
62
- created_at: "2023-01-01T00:00:00Z",
63
- updated_at: "2023-01-01T00:00:00Z",
64
- name: "otheruser/TestSnippet",
65
- snippet_type: "package",
66
- description: "Test Description",
67
- }
68
- const addedSnippet: any = db.addSnippet(snippet as any)
69
-
70
- try {
71
- await axios.post("/api/snippets/delete", {
72
- snippet_id: addedSnippet.snippet_id,
73
- })
74
- // If the request doesn't throw an error, fail the test
75
- expect(true).toBe(false)
76
- } catch (error: any) {
77
- expect(error.status).toBe(403)
78
- expect(error.data.error.message).toBe(
79
- "You don't have permission to delete this snippet",
80
- )
81
- }
82
- })