@tscircuit/fake-snippets 0.0.4 → 0.0.5
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.
- package/bun-tests/fake-snippets-api/routes/package_releases/create.test.ts +131 -0
- package/bun-tests/fake-snippets-api/routes/package_releases/get.test.ts +89 -0
- package/bun-tests/fake-snippets-api/routes/package_releases/list.test.ts +157 -0
- package/bun-tests/fake-snippets-api/routes/package_releases/update.test.ts +189 -0
- package/bun.lock +16 -2
- package/dist/bundle.js +404 -132
- package/fake-snippets-api/lib/db/db-client.ts +30 -0
- package/fake-snippets-api/lib/db/schema.ts +2 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +10 -0
- package/fake-snippets-api/routes/api/package_releases/create.ts +83 -0
- package/fake-snippets-api/routes/api/package_releases/get.ts +34 -0
- package/fake-snippets-api/routes/api/package_releases/list.ts +77 -0
- package/fake-snippets-api/routes/api/package_releases/update.ts +96 -0
- package/package.json +3 -1
- package/playwright-tests/circuit-json-import.spec.ts +133 -0
- package/playwright-tests/exampleCircuitJson.ts +498 -0
- package/src/components/CircuitJsonImportDialog.tsx +186 -0
- package/src/pages/quickstart.tsx +24 -0
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
packageReleaseSchema,
|
|
18
18
|
packageSchema,
|
|
19
19
|
Package,
|
|
20
|
+
PackageRelease,
|
|
20
21
|
} from "./schema.ts"
|
|
21
22
|
import { combine } from "zustand/middleware"
|
|
22
23
|
import { seed as seedFn } from "./seed"
|
|
@@ -387,4 +388,33 @@ const initializer = combine(databaseSchema.parse({}), (set, get) => ({
|
|
|
387
388
|
...pkg,
|
|
388
389
|
}
|
|
389
390
|
},
|
|
391
|
+
getPackageReleaseById: (
|
|
392
|
+
package_release_id: string,
|
|
393
|
+
): PackageRelease | undefined => {
|
|
394
|
+
const state = get()
|
|
395
|
+
return state.packageReleases.find(
|
|
396
|
+
(pr) => pr.package_release_id === package_release_id,
|
|
397
|
+
)
|
|
398
|
+
},
|
|
399
|
+
addPackageRelease: (
|
|
400
|
+
packageRelease: Omit<PackageRelease, "package_release_id">,
|
|
401
|
+
): PackageRelease => {
|
|
402
|
+
const newPackageRelease = {
|
|
403
|
+
package_release_id: `package_release_${Date.now()}`,
|
|
404
|
+
...packageRelease,
|
|
405
|
+
}
|
|
406
|
+
set((state) => ({
|
|
407
|
+
packageReleases: [...state.packageReleases, newPackageRelease],
|
|
408
|
+
}))
|
|
409
|
+
return newPackageRelease
|
|
410
|
+
},
|
|
411
|
+
updatePackageRelease: (packageRelease: PackageRelease): void => {
|
|
412
|
+
set((state) => ({
|
|
413
|
+
packageReleases: state.packageReleases.map((pr) =>
|
|
414
|
+
pr.package_release_id === packageRelease.package_release_id
|
|
415
|
+
? packageRelease
|
|
416
|
+
: pr,
|
|
417
|
+
),
|
|
418
|
+
}))
|
|
419
|
+
},
|
|
390
420
|
}))
|
|
@@ -107,6 +107,8 @@ export const packageReleaseSchema = z.object({
|
|
|
107
107
|
is_locked: z.boolean(),
|
|
108
108
|
is_latest: z.boolean(),
|
|
109
109
|
created_at: z.string().datetime(),
|
|
110
|
+
commit_sha: z.string().nullable().optional(),
|
|
111
|
+
license: z.string().nullable().optional(),
|
|
110
112
|
})
|
|
111
113
|
export type PackageRelease = z.infer<typeof packageReleaseSchema>
|
|
112
114
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as ZT from "fake-snippets-api/lib/db/schema"
|
|
2
|
+
|
|
3
|
+
export const publicMapPackageRelease = (
|
|
4
|
+
internal_package_release: ZT.PackageRelease,
|
|
5
|
+
): ZT.PackageRelease => {
|
|
6
|
+
return {
|
|
7
|
+
...internal_package_release,
|
|
8
|
+
created_at: internal_package_release.created_at,
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { packageReleaseSchema } from "fake-snippets-api/lib/db/schema"
|
|
2
|
+
import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
|
|
3
|
+
import { publicMapPackageRelease } from "fake-snippets-api/lib/public-mapping/public-map-package-release"
|
|
4
|
+
import { z } from "zod"
|
|
5
|
+
|
|
6
|
+
export default withRouteSpec({
|
|
7
|
+
methods: ["POST"],
|
|
8
|
+
auth: "none",
|
|
9
|
+
jsonBody: z.object({
|
|
10
|
+
package_id: z.string().optional(),
|
|
11
|
+
version: z.string().optional(),
|
|
12
|
+
is_latest: z.boolean().optional(),
|
|
13
|
+
commit_sha: z.string().optional(),
|
|
14
|
+
package_name_with_version: z.string().optional(),
|
|
15
|
+
}),
|
|
16
|
+
jsonResponse: z.object({
|
|
17
|
+
ok: z.boolean(),
|
|
18
|
+
package_release: packageReleaseSchema,
|
|
19
|
+
}),
|
|
20
|
+
})(async (req, ctx) => {
|
|
21
|
+
let {
|
|
22
|
+
package_id,
|
|
23
|
+
is_latest = true,
|
|
24
|
+
version,
|
|
25
|
+
commit_sha,
|
|
26
|
+
package_name_with_version,
|
|
27
|
+
} = req.jsonBody
|
|
28
|
+
|
|
29
|
+
if (package_name_with_version && !version && !package_id) {
|
|
30
|
+
const [packageName, parsedVersion] = package_name_with_version.split("@")
|
|
31
|
+
const pkg = ctx.db.packages.find((p) => p.name === packageName)
|
|
32
|
+
|
|
33
|
+
if (!pkg) {
|
|
34
|
+
return ctx.error(404, {
|
|
35
|
+
error_code: "package_not_found",
|
|
36
|
+
message: `Package not found: ${packageName}`,
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
package_id = pkg.package_id
|
|
41
|
+
version = parsedVersion
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!package_id || !version) {
|
|
45
|
+
return ctx.error(400, {
|
|
46
|
+
error_code: "missing_options",
|
|
47
|
+
message: "package_id and version are required",
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check if version already exists
|
|
52
|
+
const existingRelease = ctx.db.packageReleases.find(
|
|
53
|
+
(pr) => pr.package_id === package_id && pr.version === version,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if (existingRelease) {
|
|
57
|
+
return ctx.error(400, {
|
|
58
|
+
error_code: "version_already_exists",
|
|
59
|
+
message: `Version ${version} already exists for this package`,
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Update previous latest if needed
|
|
64
|
+
if (is_latest) {
|
|
65
|
+
ctx.db.packageReleases
|
|
66
|
+
.filter((pr) => pr.package_id === package_id && pr.is_latest)
|
|
67
|
+
.forEach((pr) => (pr.is_latest = false))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const newPackageRelease = ctx.db.addPackageRelease({
|
|
71
|
+
package_id,
|
|
72
|
+
is_latest,
|
|
73
|
+
version,
|
|
74
|
+
is_locked: false,
|
|
75
|
+
created_at: new Date().toISOString(),
|
|
76
|
+
commit_sha: commit_sha ?? null,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
return ctx.json({
|
|
80
|
+
ok: true,
|
|
81
|
+
package_release: publicMapPackageRelease(newPackageRelease),
|
|
82
|
+
})
|
|
83
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as zt from "fake-snippets-api/lib/db/schema"
|
|
2
|
+
import { publicMapPackageRelease } from "fake-snippets-api/lib/public-mapping/public-map-package-release"
|
|
3
|
+
import { withRouteSpec } from "fake-snippets-api/lib/with-winter-spec"
|
|
4
|
+
import { z } from "zod"
|
|
5
|
+
|
|
6
|
+
export default withRouteSpec({
|
|
7
|
+
methods: ["POST"],
|
|
8
|
+
auth: "none",
|
|
9
|
+
jsonBody: z.object({
|
|
10
|
+
package_release_id: z.string().optional(),
|
|
11
|
+
package_name_with_version: z.string().optional(),
|
|
12
|
+
}),
|
|
13
|
+
jsonResponse: z.object({
|
|
14
|
+
ok: z.boolean(),
|
|
15
|
+
package_release: zt.packageReleaseSchema,
|
|
16
|
+
}),
|
|
17
|
+
})(async (req, ctx) => {
|
|
18
|
+
const { package_release_id } = req.jsonBody
|
|
19
|
+
|
|
20
|
+
const foundRelease =
|
|
21
|
+
package_release_id && ctx.db.getPackageReleaseById(package_release_id)
|
|
22
|
+
|
|
23
|
+
if (!foundRelease) {
|
|
24
|
+
return ctx.error(404, {
|
|
25
|
+
error_code: "package_release_not_found",
|
|
26
|
+
message: "Package release not found",
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return ctx.json({
|
|
31
|
+
ok: true,
|
|
32
|
+
package_release: publicMapPackageRelease(foundRelease),
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { packageReleaseSchema } from "fake-snippets-api/lib/db/schema"
|
|
2
|
+
import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
|
|
3
|
+
import { publicMapPackageRelease } from "fake-snippets-api/lib/public-mapping/public-map-package-release"
|
|
4
|
+
import { z } from "zod"
|
|
5
|
+
|
|
6
|
+
export default withRouteSpec({
|
|
7
|
+
methods: ["POST"],
|
|
8
|
+
auth: "none",
|
|
9
|
+
jsonBody: z
|
|
10
|
+
.object({
|
|
11
|
+
package_id: z.string().optional(),
|
|
12
|
+
package_name: z.string().optional(),
|
|
13
|
+
is_latest: z.boolean().optional(),
|
|
14
|
+
version: z.string().optional(),
|
|
15
|
+
commit_sha: z.string().optional(),
|
|
16
|
+
})
|
|
17
|
+
.refine(({ package_id, package_name }) => {
|
|
18
|
+
if (package_id && package_name) {
|
|
19
|
+
return false
|
|
20
|
+
}
|
|
21
|
+
return true
|
|
22
|
+
}, "package_id and package_name are mutually exclusive")
|
|
23
|
+
.refine(({ package_id, package_name }) => {
|
|
24
|
+
if (!package_id && !package_name) {
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
return true
|
|
28
|
+
}, "package_id or package_name is required"),
|
|
29
|
+
jsonResponse: z.object({
|
|
30
|
+
ok: z.boolean(),
|
|
31
|
+
package_releases: z.array(packageReleaseSchema),
|
|
32
|
+
}),
|
|
33
|
+
})(async (req, ctx) => {
|
|
34
|
+
const { package_id, package_name, is_latest, version, commit_sha } =
|
|
35
|
+
req.jsonBody
|
|
36
|
+
|
|
37
|
+
if (!package_id && !package_name && !is_latest && !version && !commit_sha) {
|
|
38
|
+
return ctx.error(400, {
|
|
39
|
+
error_code: "invalid_query",
|
|
40
|
+
message:
|
|
41
|
+
"At least one of package_id, package_name, is_latest, version or commit_sha is required",
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let releases = ctx.db.packageReleases
|
|
46
|
+
|
|
47
|
+
// Apply filters
|
|
48
|
+
if (package_id) {
|
|
49
|
+
releases = releases.filter((pr) => pr.package_id === package_id)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (package_name) {
|
|
53
|
+
const pkg = ctx.db.packages.find((p) => p.name === package_name)
|
|
54
|
+
if (pkg) {
|
|
55
|
+
releases = releases.filter((pr) => pr.package_id === pkg.package_id)
|
|
56
|
+
} else {
|
|
57
|
+
releases = []
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (is_latest !== undefined) {
|
|
62
|
+
releases = releases.filter((pr) => pr.is_latest === is_latest)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (version) {
|
|
66
|
+
releases = releases.filter((pr) => pr.version === version)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (commit_sha) {
|
|
70
|
+
releases = releases.filter((pr) => pr.commit_sha === commit_sha)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return ctx.json({
|
|
74
|
+
ok: true,
|
|
75
|
+
package_releases: releases.map((pr) => publicMapPackageRelease(pr)),
|
|
76
|
+
})
|
|
77
|
+
})
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { withRouteSpec } from "fake-snippets-api/lib/middleware/with-winter-spec"
|
|
2
|
+
import { z } from "zod"
|
|
3
|
+
|
|
4
|
+
export default withRouteSpec({
|
|
5
|
+
methods: ["POST"],
|
|
6
|
+
auth: "none",
|
|
7
|
+
jsonBody: z.object({
|
|
8
|
+
package_release_id: z.string().optional(),
|
|
9
|
+
package_name_with_version: z.string().optional(),
|
|
10
|
+
is_locked: z.boolean().optional(),
|
|
11
|
+
is_latest: z.boolean().optional(),
|
|
12
|
+
license: z.string().optional(),
|
|
13
|
+
}),
|
|
14
|
+
jsonResponse: z.object({
|
|
15
|
+
ok: z.boolean(),
|
|
16
|
+
}),
|
|
17
|
+
})(async (req, ctx) => {
|
|
18
|
+
const {
|
|
19
|
+
package_release_id,
|
|
20
|
+
package_name_with_version,
|
|
21
|
+
is_locked,
|
|
22
|
+
is_latest,
|
|
23
|
+
license,
|
|
24
|
+
} = req.jsonBody
|
|
25
|
+
let releaseId = package_release_id
|
|
26
|
+
|
|
27
|
+
// Handle package_name_with_version lookup
|
|
28
|
+
if (!releaseId && package_name_with_version) {
|
|
29
|
+
const [packageName, version] = package_name_with_version.split("@")
|
|
30
|
+
const pkg = ctx.db.packages.find((p) => p.name === packageName)
|
|
31
|
+
if (pkg) {
|
|
32
|
+
const release = ctx.db.packageReleases.find(
|
|
33
|
+
(pr) => pr.package_id === pkg.package_id && pr.version === version,
|
|
34
|
+
)
|
|
35
|
+
if (release) {
|
|
36
|
+
releaseId = release.package_release_id
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!releaseId) {
|
|
42
|
+
return ctx.error(404, {
|
|
43
|
+
error_code: "package_release_not_found",
|
|
44
|
+
message: "Package release not found",
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const delta = { is_locked, is_latest, license }
|
|
49
|
+
if (
|
|
50
|
+
Object.keys(delta).filter(
|
|
51
|
+
(k) => delta[k as keyof typeof delta] !== undefined,
|
|
52
|
+
).length === 0
|
|
53
|
+
) {
|
|
54
|
+
return ctx.error(400, {
|
|
55
|
+
error_code: "no_fields_provided",
|
|
56
|
+
message: "No fields provided to update",
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const release = ctx.db.packageReleases.find(
|
|
61
|
+
(pr) => pr.package_release_id === releaseId,
|
|
62
|
+
)
|
|
63
|
+
if (!release) {
|
|
64
|
+
return ctx.error(404, {
|
|
65
|
+
error_code: "package_release_not_found",
|
|
66
|
+
message: "Package release not found",
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Handle is_latest updates
|
|
71
|
+
if (is_latest !== undefined && is_latest) {
|
|
72
|
+
ctx.db.packageReleases
|
|
73
|
+
.filter(
|
|
74
|
+
(pr) =>
|
|
75
|
+
pr.package_id === release.package_id &&
|
|
76
|
+
pr.package_release_id !== releaseId &&
|
|
77
|
+
pr.is_latest,
|
|
78
|
+
)
|
|
79
|
+
.forEach((pr) => {
|
|
80
|
+
pr.is_latest = false
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Update the release
|
|
85
|
+
Object.assign(release, {
|
|
86
|
+
...(is_locked !== undefined && { is_locked }),
|
|
87
|
+
...(is_latest !== undefined && { is_latest }),
|
|
88
|
+
...(license !== undefined && { license }),
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
ctx.db.updatePackageRelease(release)
|
|
92
|
+
|
|
93
|
+
return ctx.json({
|
|
94
|
+
ok: true,
|
|
95
|
+
})
|
|
96
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"circuit-json-to-bom-csv": "^0.0.6",
|
|
81
81
|
"circuit-json-to-gerber": "^0.0.16",
|
|
82
82
|
"circuit-json-to-pnp-csv": "^0.0.6",
|
|
83
|
+
"circuit-json-to-tscircuit": "^0.0.4",
|
|
83
84
|
"circuit-json-to-readable-netlist": "^0.0.7",
|
|
84
85
|
"class-variance-authority": "^0.7.0",
|
|
85
86
|
"clsx": "^2.1.1",
|
|
@@ -135,6 +136,7 @@
|
|
|
135
136
|
"@types/babel__standalone": "^7.1.7",
|
|
136
137
|
"@types/bun": "^1.1.10",
|
|
137
138
|
"@types/country-list": "^2.1.4",
|
|
139
|
+
"@types/node": "^22.13.0",
|
|
138
140
|
"@types/prismjs": "^1.26.4",
|
|
139
141
|
"@types/react": "^18.3.9",
|
|
140
142
|
"@types/react-dom": "^18.3.0",
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { test, expect } from "@playwright/test"
|
|
2
|
+
import { exampleCircuitJson } from "./exampleCircuitJson"
|
|
3
|
+
|
|
4
|
+
async function loginToSite(page) {
|
|
5
|
+
const loginButton = page.getByRole("button", { name: "Log in" })
|
|
6
|
+
if (await loginButton.isVisible()) {
|
|
7
|
+
await loginButton.click()
|
|
8
|
+
await page.waitForLoadState("networkidle")
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
test.beforeEach(async ({ page }) => {
|
|
13
|
+
await page.goto("http://127.0.0.1:5177/quickstart")
|
|
14
|
+
await page.waitForTimeout(3000)
|
|
15
|
+
await loginToSite(page).catch(() => {})
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test("should open and close the Circuit Json Import Dialog", async ({
|
|
19
|
+
page,
|
|
20
|
+
}) => {
|
|
21
|
+
const importButton = page.locator('button:has-text("Import Circuit JSON")')
|
|
22
|
+
await importButton.click()
|
|
23
|
+
|
|
24
|
+
const dialog = page.getByRole("dialog")
|
|
25
|
+
await expect(dialog).toBeVisible()
|
|
26
|
+
|
|
27
|
+
const closeButton = dialog.getByRole("button", { name: "Close" })
|
|
28
|
+
await closeButton.click()
|
|
29
|
+
|
|
30
|
+
await expect(dialog).not.toBeVisible()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test("should handle valid Circuit JSON input", async ({ page }) => {
|
|
34
|
+
const importButton = page.getByRole("button", { name: "Import Circuit JSON" })
|
|
35
|
+
await importButton.click()
|
|
36
|
+
const textarea = page.locator(
|
|
37
|
+
'textarea[placeholder="Paste the Circuit JSON."]',
|
|
38
|
+
)
|
|
39
|
+
await textarea.fill(JSON.stringify(exampleCircuitJson))
|
|
40
|
+
|
|
41
|
+
const importDialogButton = page.getByRole("button", { name: "Import" })
|
|
42
|
+
await importDialogButton.click()
|
|
43
|
+
|
|
44
|
+
const successToast = page.locator(
|
|
45
|
+
'div.text-sm.font-semibold:has-text("Import Successful")',
|
|
46
|
+
)
|
|
47
|
+
await successToast.waitFor({ state: "visible", timeout: 5000 })
|
|
48
|
+
await expect(successToast).toBeVisible()
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test("should handle valid Circuit JSON file upload", async ({ page }) => {
|
|
52
|
+
const importButton = page.locator('button:has-text("Import Circuit JSON")')
|
|
53
|
+
await importButton.click()
|
|
54
|
+
|
|
55
|
+
const fileInput = page.locator('input[type="file"]')
|
|
56
|
+
|
|
57
|
+
await fileInput.setInputFiles({
|
|
58
|
+
name: "circuit.json",
|
|
59
|
+
mimeType: "application/json",
|
|
60
|
+
// @ts-expect-error didnt add node types to tsconfig
|
|
61
|
+
buffer: Buffer.from(JSON.stringify(exampleCircuitJson)),
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const importDialogButton = page.getByRole("button", { name: "Import" })
|
|
65
|
+
await importDialogButton.click()
|
|
66
|
+
const successToast = page.locator(
|
|
67
|
+
'div.text-sm.font-semibold:has-text("Import Successful")',
|
|
68
|
+
)
|
|
69
|
+
await successToast.waitFor({ state: "visible", timeout: 5000 })
|
|
70
|
+
await expect(successToast).toBeVisible()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test("should handle invalid Circuit JSON input", async ({ page }) => {
|
|
74
|
+
const importButton = page.locator('button:has-text("Import Circuit JSON")')
|
|
75
|
+
await importButton.click()
|
|
76
|
+
|
|
77
|
+
const textarea = page.locator(
|
|
78
|
+
'textarea[placeholder="Paste the Circuit JSON."]',
|
|
79
|
+
)
|
|
80
|
+
await textarea.fill("invalid json content")
|
|
81
|
+
|
|
82
|
+
const importDialogButton = page.getByRole("button", { name: "Import" })
|
|
83
|
+
await importDialogButton.click()
|
|
84
|
+
|
|
85
|
+
const errorToast = page.locator(
|
|
86
|
+
'div.text-sm.font-semibold:has-text("Invalid Input")',
|
|
87
|
+
)
|
|
88
|
+
await errorToast.waitFor({ state: "visible", timeout: 5000 })
|
|
89
|
+
await expect(errorToast).toBeVisible()
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test("should handle invalid Circuit JSON file upload", async ({ page }) => {
|
|
93
|
+
const importButton = page.locator('button:has-text("Import Circuit JSON")')
|
|
94
|
+
await importButton.click()
|
|
95
|
+
|
|
96
|
+
const fileInput = page.locator('input[type="file"]')
|
|
97
|
+
await fileInput.setInputFiles({
|
|
98
|
+
name: "circuit.json",
|
|
99
|
+
mimeType: "application/json",
|
|
100
|
+
// @ts-expect-error didnt add node types to tsconfig
|
|
101
|
+
buffer: Buffer.from(JSON.stringify({})),
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const importDialogButton = page.getByRole("button", { name: "Import" })
|
|
105
|
+
await importDialogButton.click()
|
|
106
|
+
|
|
107
|
+
const errorToast = page.locator(
|
|
108
|
+
'div.text-sm.font-semibold:has-text("Import Failed")',
|
|
109
|
+
)
|
|
110
|
+
await errorToast.waitFor({ state: "visible", timeout: 5000 })
|
|
111
|
+
await expect(errorToast).toBeVisible()
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test("should handle non-JSON file upload", async ({ page }) => {
|
|
115
|
+
const importButton = page.locator('button:has-text("Import Circuit JSON")')
|
|
116
|
+
await importButton.click()
|
|
117
|
+
|
|
118
|
+
const fileInput = page.locator('input[type="file"]')
|
|
119
|
+
await fileInput.setInputFiles({
|
|
120
|
+
name: "circuit.txt",
|
|
121
|
+
mimeType: "application/text",
|
|
122
|
+
// @ts-expect-error didnt add node types to tsconfig
|
|
123
|
+
buffer: Buffer.from(""),
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
const importDialogButton = page.getByRole("button", { name: "Import" })
|
|
127
|
+
await importDialogButton.click()
|
|
128
|
+
|
|
129
|
+
const errorToast = page.locator(
|
|
130
|
+
'div.pb-4 > p:has-text("Please select a valid JSON file.")',
|
|
131
|
+
)
|
|
132
|
+
await expect(errorToast).toBeVisible()
|
|
133
|
+
})
|