Spaces:
Running
Running
wuyiqunLu
commited on
Commit
•
06bd1d1
1
Parent(s):
466a263
feat: add playwright e2e test for chat page with new and old data structure (#99)
Browse filesYou can run npx playwright test --ui locally to check the test
<img width="1582" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/3f6d2db5-c2d4-4190-92e9-b152894788bc">
<img width="1264" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/2429efe1-56e0-4f3f-9694-599475097f83">
- .github/workflows/playwright.yml +34 -0
- .gitignore +5 -1
- app/page.tsx +2 -18
- components/CodeResultDisplay.tsx +21 -5
- components/chat/ChatMessage.tsx +40 -6
- components/ui/Dialog.tsx +2 -1
- lib/constants.ts +23 -1
- package.json +6 -4
- playwright.config.ts +69 -0
- pnpm-lock.yaml +83 -45
- tests/e2e/index.spec.ts +85 -0
.github/workflows/playwright.yml
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Playwright Tests
|
2 |
+
on:
|
3 |
+
deployment_status:
|
4 |
+
jobs:
|
5 |
+
run-e2es:
|
6 |
+
timeout-minutes: 5
|
7 |
+
runs-on: ubuntu-latest
|
8 |
+
if: github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success'
|
9 |
+
steps:
|
10 |
+
- uses: actions/checkout@v4
|
11 |
+
- name: Setup pnpm
|
12 |
+
uses: pnpm/action-setup@v4
|
13 |
+
with:
|
14 |
+
version: 9.1.1
|
15 |
+
- name: Use Node.js ${{ matrix.node-version }}
|
16 |
+
uses: actions/setup-node@v4
|
17 |
+
with:
|
18 |
+
node-version: ${{ matrix.node-version }}
|
19 |
+
cache: 'pnpm'
|
20 |
+
- name: Install dependencies
|
21 |
+
run: pnpm i --frozen-lockfile
|
22 |
+
- name: Install Playwright Browsers
|
23 |
+
run: pnpm exec playwright install --with-deps
|
24 |
+
- name: Run Playwright tests
|
25 |
+
run: pnpm exec playwright test
|
26 |
+
env:
|
27 |
+
BASE_URL: ${{ github.event.deployment_status.environment_url }}
|
28 |
+
VERCEL_AUTOMATION_BYPASS_SECRET: ${{ secrets.VERCEL_AUTOMATION_BYPASS_SECRET }}
|
29 |
+
- uses: actions/upload-artifact@v4
|
30 |
+
if: always()
|
31 |
+
with:
|
32 |
+
name: playwright-report
|
33 |
+
path: playwright-report/
|
34 |
+
retention-days: 7
|
.gitignore
CHANGED
@@ -39,4 +39,8 @@ yarn-error.log*
|
|
39 |
|
40 |
# ts
|
41 |
tsconfig.tsbuildinfo
|
42 |
-
certificates
|
|
|
|
|
|
|
|
|
|
39 |
|
40 |
# ts
|
41 |
tsconfig.tsbuildinfo
|
42 |
+
certificates
|
43 |
+
/test-results/
|
44 |
+
/playwright-report/
|
45 |
+
/blob-report/
|
46 |
+
/playwright/.cache/
|
app/page.tsx
CHANGED
@@ -2,29 +2,13 @@
|
|
2 |
|
3 |
import { useRouter } from 'next/navigation';
|
4 |
|
5 |
-
import { useRef
|
6 |
import Composer, { ComposerRef } from '@/components/chat/Composer';
|
7 |
import { dbPostCreateChat } from '@/lib/db/functions';
|
8 |
import { nanoid } from '@/lib/utils';
|
9 |
import Chip from '@/components/ui/Chip';
|
10 |
import { IconArrowUpRight } from '@/components/ui/Icons';
|
11 |
-
|
12 |
-
const EXAMPLES = [
|
13 |
-
{
|
14 |
-
title: 'Counting flowers in image',
|
15 |
-
mediaUrl:
|
16 |
-
'https://vision-agent-dev.s3.us-east-2.amazonaws.com/examples/flower.png',
|
17 |
-
prompt:
|
18 |
-
'Detect flowers in this image, draw boxes and output the image, also return total number of flowers',
|
19 |
-
},
|
20 |
-
{
|
21 |
-
title: 'Detecting sharks in video',
|
22 |
-
mediaUrl:
|
23 |
-
'https://vision-agent-dev.s3.us-east-2.amazonaws.com/examples/shark3_short.mp4',
|
24 |
-
prompt:
|
25 |
-
'Can you detect any surfboards or sharks in the video, draw a green line between the shark and the nearest surfboard and add the distance between them in meters assuming 30 pixels is 1 meter. Make the line red if the shark is within 10 meters of a surfboard. Sample the video at 1 frames per second and save the output video as output.mp4.',
|
26 |
-
},
|
27 |
-
];
|
28 |
|
29 |
export default function Page() {
|
30 |
const router = useRouter();
|
|
|
2 |
|
3 |
import { useRouter } from 'next/navigation';
|
4 |
|
5 |
+
import { useRef } from 'react';
|
6 |
import Composer, { ComposerRef } from '@/components/chat/Composer';
|
7 |
import { dbPostCreateChat } from '@/lib/db/functions';
|
8 |
import { nanoid } from '@/lib/utils';
|
9 |
import Chip from '@/components/ui/Chip';
|
10 |
import { IconArrowUpRight } from '@/components/ui/Icons';
|
11 |
+
import { EXAMPLES } from '@/lib/constants';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
export default function Page() {
|
14 |
const router = useRouter();
|
components/CodeResultDisplay.tsx
CHANGED
@@ -53,13 +53,21 @@ const CodeResultDisplay: React.FC<{
|
|
53 |
const finalResult = results?.find(_ => _.is_main_result)?.text;
|
54 |
|
55 |
return (
|
56 |
-
<div
|
|
|
|
|
|
|
57 |
<CodeBlock language="python" value={code} />
|
58 |
<div className="rounded-lg relative">
|
59 |
<div className="absolute left-1/2 -translate-x-1/2 -top-4 z-10">
|
60 |
<Dialog>
|
61 |
<DialogTrigger asChild>
|
62 |
-
<Button
|
|
|
|
|
|
|
|
|
|
|
63 |
<IconTerminalWindow className="text-teal-500 size-4" />
|
64 |
</Button>
|
65 |
</DialogTrigger>
|
@@ -111,7 +119,11 @@ const CodeResultDisplay: React.FC<{
|
|
111 |
<p>image output</p>
|
112 |
<Dialog>
|
113 |
<DialogTrigger asChild>
|
114 |
-
<Button
|
|
|
|
|
|
|
|
|
115 |
View all
|
116 |
</Button>
|
117 |
</DialogTrigger>
|
@@ -120,7 +132,11 @@ const CodeResultDisplay: React.FC<{
|
|
120 |
<CarouselContent>
|
121 |
{imageResults.map((png, index) => (
|
122 |
<CarouselItem key={'png' + index}>
|
123 |
-
<Img
|
|
|
|
|
|
|
|
|
124 |
</CarouselItem>
|
125 |
))}
|
126 |
</CarouselContent>
|
@@ -136,7 +152,7 @@ const CodeResultDisplay: React.FC<{
|
|
136 |
key={'png' + index}
|
137 |
src={png!}
|
138 |
width={200}
|
139 |
-
alt=
|
140 |
/>
|
141 |
))}
|
142 |
</div>
|
|
|
53 |
const finalResult = results?.find(_ => _.is_main_result)?.text;
|
54 |
|
55 |
return (
|
56 |
+
<div
|
57 |
+
className="rounded-lg overflow-hidden relative max-w-5xl"
|
58 |
+
data-testid="code-result-display-container"
|
59 |
+
>
|
60 |
<CodeBlock language="python" value={code} />
|
61 |
<div className="rounded-lg relative">
|
62 |
<div className="absolute left-1/2 -translate-x-1/2 -top-4 z-10">
|
63 |
<Dialog>
|
64 |
<DialogTrigger asChild>
|
65 |
+
<Button
|
66 |
+
data-testid="open-final-test-code-dialog-button"
|
67 |
+
variant="ghost"
|
68 |
+
size="icon"
|
69 |
+
className="size-8"
|
70 |
+
>
|
71 |
<IconTerminalWindow className="text-teal-500 size-4" />
|
72 |
</Button>
|
73 |
</DialogTrigger>
|
|
|
119 |
<p>image output</p>
|
120 |
<Dialog>
|
121 |
<DialogTrigger asChild>
|
122 |
+
<Button
|
123 |
+
variant="outline"
|
124 |
+
size="sm"
|
125 |
+
data-testid="view-all-result-images-button"
|
126 |
+
>
|
127 |
View all
|
128 |
</Button>
|
129 |
</DialogTrigger>
|
|
|
132 |
<CarouselContent>
|
133 |
{imageResults.map((png, index) => (
|
134 |
<CarouselItem key={'png' + index}>
|
135 |
+
<Img
|
136 |
+
src={png!}
|
137 |
+
width={1200}
|
138 |
+
alt={`detail-result-image-${index}`}
|
139 |
+
/>
|
140 |
</CarouselItem>
|
141 |
))}
|
142 |
</CarouselContent>
|
|
|
152 |
key={'png' + index}
|
153 |
src={png!}
|
154 |
width={200}
|
155 |
+
alt={`result-image-${index}`}
|
156 |
/>
|
157 |
))}
|
158 |
</div>
|
components/chat/ChatMessage.tsx
CHANGED
@@ -29,6 +29,14 @@ import { Message } from '@prisma/client';
|
|
29 |
import { Separator } from '../ui/Separator';
|
30 |
import { cn } from '@/lib/utils';
|
31 |
import toast from 'react-hot-toast';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
export interface ChatMessageProps {
|
34 |
message: Message;
|
@@ -218,16 +226,42 @@ const ChunkTypeToText: React.FC<{
|
|
218 |
? `(${Math.round(displayMs / 100) / 10}s)`
|
219 |
: '';
|
220 |
|
221 |
-
if (type === 'plans')
|
222 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
223 |
if (type === 'code' && status === 'started')
|
224 |
-
return
|
|
|
|
|
|
|
|
|
225 |
if (type === 'code' && status === 'running')
|
226 |
-
return
|
|
|
|
|
|
|
|
|
227 |
if (type === 'code' && status === 'completed')
|
228 |
-
return
|
|
|
|
|
|
|
|
|
229 |
if (type === 'code' && status === 'failed')
|
230 |
-
return
|
|
|
|
|
|
|
|
|
231 |
|
232 |
return null;
|
233 |
};
|
|
|
29 |
import { Separator } from '../ui/Separator';
|
30 |
import { cn } from '@/lib/utils';
|
31 |
import toast from 'react-hot-toast';
|
32 |
+
import {
|
33 |
+
EXECUTE_CODE_FAILURE_TITLE,
|
34 |
+
EXECUTE_CODE_SUCCESS_TITLE,
|
35 |
+
EXECUTE_CODE_TITLE,
|
36 |
+
GENERATE_CODE_TITLE,
|
37 |
+
PLAN_TITLE,
|
38 |
+
TOOLS_TITLE,
|
39 |
+
} from '@/lib/constants';
|
40 |
|
41 |
export interface ChatMessageProps {
|
42 |
message: Message;
|
|
|
226 |
? `(${Math.round(displayMs / 100) / 10}s)`
|
227 |
: '';
|
228 |
|
229 |
+
if (type === 'plans')
|
230 |
+
return (
|
231 |
+
<p>
|
232 |
+
{PLAN_TITLE} {durationDisplay}
|
233 |
+
</p>
|
234 |
+
);
|
235 |
+
if (type === 'tools')
|
236 |
+
return (
|
237 |
+
<p>
|
238 |
+
{TOOLS_TITLE} {durationDisplay}
|
239 |
+
</p>
|
240 |
+
);
|
241 |
if (type === 'code' && status === 'started')
|
242 |
+
return (
|
243 |
+
<p>
|
244 |
+
{GENERATE_CODE_TITLE} {durationDisplay}
|
245 |
+
</p>
|
246 |
+
);
|
247 |
if (type === 'code' && status === 'running')
|
248 |
+
return (
|
249 |
+
<p>
|
250 |
+
{EXECUTE_CODE_TITLE} {durationDisplay}
|
251 |
+
</p>
|
252 |
+
);
|
253 |
if (type === 'code' && status === 'completed')
|
254 |
+
return (
|
255 |
+
<p>
|
256 |
+
{EXECUTE_CODE_SUCCESS_TITLE} {durationDisplay}
|
257 |
+
</p>
|
258 |
+
);
|
259 |
if (type === 'code' && status === 'failed')
|
260 |
+
return (
|
261 |
+
<p>
|
262 |
+
{EXECUTE_CODE_FAILURE_TITLE} {durationDisplay}
|
263 |
+
</p>
|
264 |
+
);
|
265 |
|
266 |
return null;
|
267 |
};
|
components/ui/Dialog.tsx
CHANGED
@@ -38,9 +38,10 @@ const DialogContent: React.ForwardRefExoticComponent<
|
|
38 |
<DialogPrimitive.Content
|
39 |
ref={ref}
|
40 |
className={cn(
|
41 |
-
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg
|
42 |
className,
|
43 |
)}
|
|
|
44 |
{...props}
|
45 |
>
|
46 |
{children}
|
|
|
38 |
<DialogPrimitive.Content
|
39 |
ref={ref}
|
40 |
className={cn(
|
41 |
+
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg overflow-auto -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
42 |
className,
|
43 |
)}
|
44 |
+
style={{ maxHeight: '100vh' }}
|
45 |
{...props}
|
46 |
>
|
47 |
{children}
|
lib/constants.ts
CHANGED
@@ -1 +1,23 @@
|
|
1 |
-
export const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export const EXAMPLES = [
|
2 |
+
{
|
3 |
+
title: 'Counting flowers in image',
|
4 |
+
mediaUrl:
|
5 |
+
'https://vision-agent-dev.s3.us-east-2.amazonaws.com/examples/flower.png',
|
6 |
+
prompt:
|
7 |
+
'Detect flowers in this image, draw boxes and output the image, also return total number of flowers',
|
8 |
+
},
|
9 |
+
{
|
10 |
+
title: 'Detecting sharks in video',
|
11 |
+
mediaUrl:
|
12 |
+
'https://vision-agent-dev.s3.us-east-2.amazonaws.com/examples/shark3_short.mp4',
|
13 |
+
prompt:
|
14 |
+
'Can you detect any surfboards or sharks in the video, draw a green line between the shark and the nearest surfboard and add the distance between them in meters assuming 30 pixels is 1 meter. Make the line red if the shark is within 10 meters of a surfboard. Sample the video at 1 frames per second and save the output video as output.mp4.',
|
15 |
+
},
|
16 |
+
];
|
17 |
+
|
18 |
+
export const PLAN_TITLE = 'Creating instructions';
|
19 |
+
export const TOOLS_TITLE = 'Retrieving tools';
|
20 |
+
export const GENERATE_CODE_TITLE = 'Generating code';
|
21 |
+
export const EXECUTE_CODE_TITLE = 'Executing code';
|
22 |
+
export const EXECUTE_CODE_SUCCESS_TITLE = 'Code execution success';
|
23 |
+
export const EXECUTE_CODE_FAILURE_TITLE = 'Code execution failure';
|
package.json
CHANGED
@@ -11,7 +11,8 @@
|
|
11 |
"preview": "next build && next start",
|
12 |
"type-check": "tsc --noEmit",
|
13 |
"format:write": "prettier --write \"{app,lib,components}/**/*.{ts,tsx,mdx}\" --cache",
|
14 |
-
"format:check": "prettier --check \"{app,lib,components}**/*.{ts,tsx,mdx}\" --cache"
|
|
|
15 |
},
|
16 |
"dependencies": {
|
17 |
"@aws-sdk/client-s3": "^3.556.0",
|
@@ -65,6 +66,7 @@
|
|
65 |
"uuid": "^9.0.1"
|
66 |
},
|
67 |
"devDependencies": {
|
|
|
68 |
"@tailwindcss/typography": "^0.5.10",
|
69 |
"@types/node": "^20.11.5",
|
70 |
"@types/react": "^18.2.48",
|
@@ -80,10 +82,10 @@
|
|
80 |
"eslint-plugin-tailwindcss": "^3.14.0",
|
81 |
"postcss": "^8.4.33",
|
82 |
"prettier": "^3.2.4",
|
83 |
-
"tailwind-merge": "^2.
|
84 |
-
"tailwindcss": "^3.4.
|
85 |
"tailwindcss-animate": "^1.0.7",
|
86 |
"typescript": "^5.3.3"
|
87 |
},
|
88 |
"packageManager": "[email protected]"
|
89 |
-
}
|
|
|
11 |
"preview": "next build && next start",
|
12 |
"type-check": "tsc --noEmit",
|
13 |
"format:write": "prettier --write \"{app,lib,components}/**/*.{ts,tsx,mdx}\" --cache",
|
14 |
+
"format:check": "prettier --check \"{app,lib,components}**/*.{ts,tsx,mdx}\" --cache",
|
15 |
+
"test:e2e": "playwright test"
|
16 |
},
|
17 |
"dependencies": {
|
18 |
"@aws-sdk/client-s3": "^3.556.0",
|
|
|
66 |
"uuid": "^9.0.1"
|
67 |
},
|
68 |
"devDependencies": {
|
69 |
+
"@playwright/test": "^1.44.1",
|
70 |
"@tailwindcss/typography": "^0.5.10",
|
71 |
"@types/node": "^20.11.5",
|
72 |
"@types/react": "^18.2.48",
|
|
|
82 |
"eslint-plugin-tailwindcss": "^3.14.0",
|
83 |
"postcss": "^8.4.33",
|
84 |
"prettier": "^3.2.4",
|
85 |
+
"tailwind-merge": "^2.3.0",
|
86 |
+
"tailwindcss": "^3.4.4",
|
87 |
"tailwindcss-animate": "^1.0.7",
|
88 |
"typescript": "^5.3.3"
|
89 |
},
|
90 |
"packageManager": "[email protected]"
|
91 |
+
}
|
playwright.config.ts
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { defineConfig, devices } from '@playwright/test';
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Read environment variables from file.
|
5 |
+
* https://github.com/motdotla/dotenv
|
6 |
+
*/
|
7 |
+
// require('dotenv').config();
|
8 |
+
|
9 |
+
const BASE_URL = process.env.BASE_URL || `http://localhost:3000`;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* See https://playwright.dev/docs/test-configuration.
|
13 |
+
*/
|
14 |
+
export default defineConfig({
|
15 |
+
testDir: './tests/e2e',
|
16 |
+
/* Run tests in files in parallel */
|
17 |
+
fullyParallel: true,
|
18 |
+
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
19 |
+
forbidOnly: !!process.env.CI,
|
20 |
+
/* Retry on CI only */
|
21 |
+
retries: process.env.CI ? 2 : 0,
|
22 |
+
/* Opt out of parallel tests on CI. */
|
23 |
+
workers: process.env.CI ? 1 : undefined,
|
24 |
+
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
25 |
+
reporter: 'html',
|
26 |
+
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
27 |
+
use: {
|
28 |
+
/* Base URL to use in actions like `await page.goto('/')`. */
|
29 |
+
baseURL: BASE_URL,
|
30 |
+
|
31 |
+
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
32 |
+
trace: 'on-first-retry',
|
33 |
+
},
|
34 |
+
|
35 |
+
/* Configure projects for major browsers */
|
36 |
+
projects: [
|
37 |
+
{
|
38 |
+
name: 'chromium',
|
39 |
+
use: { ...devices['Desktop Chrome'] },
|
40 |
+
},
|
41 |
+
|
42 |
+
/* Test against mobile viewports. */
|
43 |
+
// {
|
44 |
+
// name: 'Mobile Chrome',
|
45 |
+
// use: { ...devices['Pixel 5'] },
|
46 |
+
// },
|
47 |
+
// {
|
48 |
+
// name: 'Mobile Safari',
|
49 |
+
// use: { ...devices['iPhone 12'] },
|
50 |
+
// },
|
51 |
+
|
52 |
+
/* Test against branded browsers. */
|
53 |
+
// {
|
54 |
+
// name: 'Microsoft Edge',
|
55 |
+
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
56 |
+
// },
|
57 |
+
{
|
58 |
+
name: 'Google Chrome',
|
59 |
+
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
60 |
+
},
|
61 |
+
],
|
62 |
+
|
63 |
+
/* Run your local dev server before starting the tests */
|
64 |
+
webServer: {
|
65 |
+
command: 'pnpm dev',
|
66 |
+
url: BASE_URL,
|
67 |
+
reuseExistingServer: true,
|
68 |
+
},
|
69 |
+
});
|
pnpm-lock.yaml
CHANGED
@@ -156,9 +156,12 @@ importers:
|
|
156 |
specifier: ^9.0.1
|
157 |
version: 9.0.1
|
158 |
devDependencies:
|
|
|
|
|
|
|
159 |
'@tailwindcss/typography':
|
160 |
specifier: ^0.5.10
|
161 |
-
version: 0.5.12([email protected].
|
162 |
'@types/node':
|
163 |
specifier: ^20.11.5
|
164 |
version: 20.12.7
|
@@ -194,7 +197,7 @@ importers:
|
|
194 |
version: 9.1.0([email protected])
|
195 |
eslint-plugin-tailwindcss:
|
196 |
specifier: ^3.14.0
|
197 |
-
version: 3.15.1([email protected].
|
198 |
postcss:
|
199 |
specifier: ^8.4.33
|
200 |
version: 8.4.38
|
@@ -202,14 +205,14 @@ importers:
|
|
202 |
specifier: ^3.2.4
|
203 |
version: 3.2.5
|
204 |
tailwind-merge:
|
205 |
-
specifier: ^2.
|
206 |
-
version: 2.
|
207 |
tailwindcss:
|
208 |
-
specifier: ^3.4.
|
209 |
-
version: 3.4.
|
210 |
tailwindcss-animate:
|
211 |
specifier: ^1.0.7
|
212 |
-
version: 1.0.7([email protected].
|
213 |
typescript:
|
214 |
specifier: ^5.3.3
|
215 |
version: 5.4.5
|
@@ -442,16 +445,16 @@ packages:
|
|
442 |
resolution: {integrity: sha512-VXAq/Jz8KIrU84+HqsOJhIKZqG0PNTdi6n6PFQ4xJf44ZQHD/5C7ouH4qCFX5XgZXcgbRIcMVVYGC6Jye0dRng==}
|
443 |
engines: {node: '>=14.0.0'}
|
444 |
|
445 |
-
'@babel/[email protected].
|
446 |
-
resolution: {integrity: sha512-
|
447 |
engines: {node: '>=6.9.0'}
|
448 |
|
449 |
-
'@babel/helper-validator-identifier@7.
|
450 |
-
resolution: {integrity: sha512-
|
451 |
engines: {node: '>=6.9.0'}
|
452 |
|
453 |
-
'@babel/[email protected].
|
454 |
-
resolution: {integrity: sha512-
|
455 |
engines: {node: '>=6.0.0'}
|
456 |
hasBin: true
|
457 |
|
@@ -459,8 +462,8 @@ packages:
|
|
459 |
resolution: {integrity: sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==}
|
460 |
engines: {node: '>=6.9.0'}
|
461 |
|
462 |
-
'@babel/[email protected].
|
463 |
-
resolution: {integrity: sha512
|
464 |
engines: {node: '>=6.9.0'}
|
465 |
|
466 |
'@emnapi/[email protected]':
|
@@ -730,6 +733,11 @@ packages:
|
|
730 |
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
731 |
engines: {node: '>=14'}
|
732 |
|
|
|
|
|
|
|
|
|
|
|
733 |
'@prisma/[email protected]':
|
734 |
resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==}
|
735 |
engines: {node: '>=16.13'}
|
@@ -2209,6 +2217,11 @@ packages:
|
|
2209 | |
2210 |
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
2211 |
|
|
|
|
|
|
|
|
|
|
|
2212 | |
2213 |
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
2214 |
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
@@ -3108,6 +3121,16 @@ packages:
|
|
3108 |
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
3109 |
engines: {node: '>= 6'}
|
3110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3111 | |
3112 |
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
|
3113 |
engines: {node: '>= 0.4'}
|
@@ -3442,14 +3465,14 @@ packages:
|
|
3442 |
engines: {node: '>=10'}
|
3443 |
hasBin: true
|
3444 |
|
3445 |
-
[email protected].
|
3446 |
-
resolution: {integrity: sha512-
|
3447 |
engines: {node: '>=10'}
|
3448 |
peerDependencies:
|
3449 |
seroval: ^1.0
|
3450 |
|
3451 |
-
[email protected].
|
3452 |
-
resolution: {integrity: sha512-
|
3453 |
engines: {node: '>=10'}
|
3454 |
|
3455 | |
@@ -3621,16 +3644,16 @@ packages:
|
|
3621 | |
3622 |
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
3623 |
|
3624 |
-
tailwind-merge@2.
|
3625 |
-
resolution: {integrity: sha512-
|
3626 |
|
3627 | |
3628 |
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
|
3629 |
peerDependencies:
|
3630 |
tailwindcss: '>=3.0.0 || insiders'
|
3631 |
|
3632 |
-
[email protected].
|
3633 |
-
resolution: {integrity: sha512-
|
3634 |
engines: {node: '>=14.0.0'}
|
3635 |
hasBin: true
|
3636 |
|
@@ -4560,22 +4583,22 @@ snapshots:
|
|
4560 |
'@smithy/types': 2.12.0
|
4561 |
tslib: 2.6.2
|
4562 |
|
4563 |
-
'@babel/[email protected].
|
4564 |
|
4565 |
-
'@babel/helper-validator-identifier@7.
|
4566 |
|
4567 |
-
'@babel/[email protected].
|
4568 |
dependencies:
|
4569 |
-
'@babel/types': 7.24.
|
4570 |
|
4571 |
'@babel/[email protected]':
|
4572 |
dependencies:
|
4573 |
regenerator-runtime: 0.14.1
|
4574 |
|
4575 |
-
'@babel/[email protected].
|
4576 |
dependencies:
|
4577 |
-
'@babel/helper-string-parser': 7.24.
|
4578 |
-
'@babel/helper-validator-identifier': 7.
|
4579 |
to-fast-properties: 2.0.0
|
4580 |
|
4581 |
'@emnapi/[email protected]':
|
@@ -4794,6 +4817,10 @@ snapshots:
|
|
4794 |
'@pkgjs/[email protected]':
|
4795 |
optional: true
|
4796 |
|
|
|
|
|
|
|
|
|
4797 |
'@prisma/[email protected]([email protected])':
|
4798 |
optionalDependencies:
|
4799 |
prisma: 5.14.0
|
@@ -5536,13 +5563,13 @@ snapshots:
|
|
5536 |
dependencies:
|
5537 |
defer-to-connect: 2.0.1
|
5538 |
|
5539 |
-
'@tailwindcss/[email protected]([email protected].
|
5540 |
dependencies:
|
5541 |
lodash.castarray: 4.4.0
|
5542 |
lodash.isplainobject: 4.0.6
|
5543 |
lodash.merge: 4.6.2
|
5544 |
postcss-selector-parser: 6.0.10
|
5545 |
-
tailwindcss: 3.4.
|
5546 |
|
5547 |
'@types/[email protected]':
|
5548 |
dependencies:
|
@@ -5683,7 +5710,7 @@ snapshots:
|
|
5683 |
|
5684 |
'@vue/[email protected]':
|
5685 |
dependencies:
|
5686 |
-
'@babel/parser': 7.24.
|
5687 |
'@vue/shared': 3.4.23
|
5688 |
entities: 4.5.0
|
5689 |
estree-walker: 2.0.2
|
@@ -5696,7 +5723,7 @@ snapshots:
|
|
5696 |
|
5697 |
'@vue/[email protected]':
|
5698 |
dependencies:
|
5699 |
-
'@babel/parser': 7.24.
|
5700 |
'@vue/compiler-core': 3.4.23
|
5701 |
'@vue/compiler-dom': 3.4.23
|
5702 |
'@vue/compiler-ssr': 3.4.23
|
@@ -6426,11 +6453,11 @@ snapshots:
|
|
6426 |
semver: 6.3.1
|
6427 |
string.prototype.matchall: 4.0.11
|
6428 |
|
6429 | |
6430 |
dependencies:
|
6431 |
fast-glob: 3.3.2
|
6432 |
postcss: 8.4.38
|
6433 |
-
tailwindcss: 3.4.
|
6434 |
|
6435 | |
6436 |
dependencies:
|
@@ -6615,6 +6642,9 @@ snapshots:
|
|
6615 |
|
6616 | |
6617 |
|
|
|
|
|
|
|
6618 | |
6619 |
optional: true
|
6620 |
|
@@ -7717,6 +7747,14 @@ snapshots:
|
|
7717 |
|
7718 | |
7719 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7720 | |
7721 |
|
7722 | |
@@ -8084,11 +8122,11 @@ snapshots:
|
|
8084 |
dependencies:
|
8085 |
lru-cache: 6.0.0
|
8086 |
|
8087 |
-
[email protected].
|
8088 |
dependencies:
|
8089 |
-
seroval: 1.0.
|
8090 |
|
8091 |
-
[email protected].
|
8092 |
|
8093 | |
8094 |
dependencies:
|
@@ -8156,8 +8194,8 @@ snapshots:
|
|
8156 | |
8157 |
dependencies:
|
8158 |
csstype: 3.1.3
|
8159 |
-
seroval: 1.0.
|
8160 |
-
seroval-plugins: 1.0.
|
8161 |
|
8162 | |
8163 |
dependencies:
|
@@ -8306,15 +8344,15 @@ snapshots:
|
|
8306 |
|
8307 | |
8308 |
|
8309 |
-
tailwind-merge@2.
|
8310 |
dependencies:
|
8311 |
'@babel/runtime': 7.24.4
|
8312 |
|
8313 | |
8314 |
dependencies:
|
8315 |
-
tailwindcss: 3.4.
|
8316 |
|
8317 |
-
[email protected].
|
8318 |
dependencies:
|
8319 |
'@alloc/quick-lru': 5.2.0
|
8320 |
arg: 5.0.2
|
|
|
156 |
specifier: ^9.0.1
|
157 |
version: 9.0.1
|
158 |
devDependencies:
|
159 |
+
'@playwright/test':
|
160 |
+
specifier: ^1.44.1
|
161 |
+
version: 1.44.1
|
162 |
'@tailwindcss/typography':
|
163 |
specifier: ^0.5.10
|
164 |
+
version: 0.5.12([email protected].4)
|
165 |
'@types/node':
|
166 |
specifier: ^20.11.5
|
167 |
version: 20.12.7
|
|
|
197 |
version: 9.1.0([email protected])
|
198 |
eslint-plugin-tailwindcss:
|
199 |
specifier: ^3.14.0
|
200 |
+
version: 3.15.1([email protected].4)
|
201 |
postcss:
|
202 |
specifier: ^8.4.33
|
203 |
version: 8.4.38
|
|
|
205 |
specifier: ^3.2.4
|
206 |
version: 3.2.5
|
207 |
tailwind-merge:
|
208 |
+
specifier: ^2.3.0
|
209 |
+
version: 2.3.0
|
210 |
tailwindcss:
|
211 |
+
specifier: ^3.4.4
|
212 |
+
version: 3.4.4
|
213 |
tailwindcss-animate:
|
214 |
specifier: ^1.0.7
|
215 |
+
version: 1.0.7([email protected].4)
|
216 |
typescript:
|
217 |
specifier: ^5.3.3
|
218 |
version: 5.4.5
|
|
|
445 |
resolution: {integrity: sha512-VXAq/Jz8KIrU84+HqsOJhIKZqG0PNTdi6n6PFQ4xJf44ZQHD/5C7ouH4qCFX5XgZXcgbRIcMVVYGC6Jye0dRng==}
|
446 |
engines: {node: '>=14.0.0'}
|
447 |
|
448 |
+
'@babel/[email protected].7':
|
449 |
+
resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==}
|
450 |
engines: {node: '>=6.9.0'}
|
451 |
|
452 |
+
'@babel/helper-validator-identifier@7.24.7':
|
453 |
+
resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==}
|
454 |
engines: {node: '>=6.9.0'}
|
455 |
|
456 |
+
'@babel/[email protected].7':
|
457 |
+
resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==}
|
458 |
engines: {node: '>=6.0.0'}
|
459 |
hasBin: true
|
460 |
|
|
|
462 |
resolution: {integrity: sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==}
|
463 |
engines: {node: '>=6.9.0'}
|
464 |
|
465 |
+
'@babel/[email protected].7':
|
466 |
+
resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
|
467 |
engines: {node: '>=6.9.0'}
|
468 |
|
469 |
'@emnapi/[email protected]':
|
|
|
733 |
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
734 |
engines: {node: '>=14'}
|
735 |
|
736 |
+
'@playwright/[email protected]':
|
737 |
+
resolution: {integrity: sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==}
|
738 |
+
engines: {node: '>=16'}
|
739 |
+
hasBin: true
|
740 |
+
|
741 |
'@prisma/[email protected]':
|
742 |
resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==}
|
743 |
engines: {node: '>=16.13'}
|
|
|
2217 | |
2218 |
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
2219 |
|
2220 | |
2221 |
+
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
2222 |
+
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
2223 |
+
os: [darwin]
|
2224 |
+
|
2225 | |
2226 |
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
2227 |
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
|
|
3121 |
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
3122 |
engines: {node: '>= 6'}
|
3123 |
|
3124 | |
3125 |
+
resolution: {integrity: sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==}
|
3126 |
+
engines: {node: '>=16'}
|
3127 |
+
hasBin: true
|
3128 |
+
|
3129 | |
3130 |
+
resolution: {integrity: sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==}
|
3131 |
+
engines: {node: '>=16'}
|
3132 |
+
hasBin: true
|
3133 |
+
|
3134 | |
3135 |
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
|
3136 |
engines: {node: '>= 0.4'}
|
|
|
3465 |
engines: {node: '>=10'}
|
3466 |
hasBin: true
|
3467 |
|
3468 |
+
[email protected].7:
|
3469 |
+
resolution: {integrity: sha512-GO7TkWvodGp6buMEX9p7tNyIkbwlyuAWbI6G9Ec5bhcm7mQdu3JOK1IXbEUwb3FVzSc363GraG/wLW23NSavIw==}
|
3470 |
engines: {node: '>=10'}
|
3471 |
peerDependencies:
|
3472 |
seroval: ^1.0
|
3473 |
|
3474 |
+
[email protected].7:
|
3475 |
+
resolution: {integrity: sha512-n6ZMQX5q0Vn19Zq7CIKNIo7E75gPkGCFUEqDpa8jgwpYr/vScjqnQ6H09t1uIiZ0ZSK0ypEGvrYK2bhBGWsGdw==}
|
3476 |
engines: {node: '>=10'}
|
3477 |
|
3478 | |
|
|
3644 | |
3645 |
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
3646 |
|
3647 |
+
tailwind-merge@2.3.0:
|
3648 |
+
resolution: {integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==}
|
3649 |
|
3650 | |
3651 |
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
|
3652 |
peerDependencies:
|
3653 |
tailwindcss: '>=3.0.0 || insiders'
|
3654 |
|
3655 |
+
[email protected].4:
|
3656 |
+
resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==}
|
3657 |
engines: {node: '>=14.0.0'}
|
3658 |
hasBin: true
|
3659 |
|
|
|
4583 |
'@smithy/types': 2.12.0
|
4584 |
tslib: 2.6.2
|
4585 |
|
4586 |
+
'@babel/[email protected].7': {}
|
4587 |
|
4588 |
+
'@babel/helper-validator-identifier@7.24.7': {}
|
4589 |
|
4590 |
+
'@babel/[email protected].7':
|
4591 |
dependencies:
|
4592 |
+
'@babel/types': 7.24.7
|
4593 |
|
4594 |
'@babel/[email protected]':
|
4595 |
dependencies:
|
4596 |
regenerator-runtime: 0.14.1
|
4597 |
|
4598 |
+
'@babel/[email protected].7':
|
4599 |
dependencies:
|
4600 |
+
'@babel/helper-string-parser': 7.24.7
|
4601 |
+
'@babel/helper-validator-identifier': 7.24.7
|
4602 |
to-fast-properties: 2.0.0
|
4603 |
|
4604 |
'@emnapi/[email protected]':
|
|
|
4817 |
'@pkgjs/[email protected]':
|
4818 |
optional: true
|
4819 |
|
4820 |
+
'@playwright/[email protected]':
|
4821 |
+
dependencies:
|
4822 |
+
playwright: 1.44.1
|
4823 |
+
|
4824 |
'@prisma/[email protected]([email protected])':
|
4825 |
optionalDependencies:
|
4826 |
prisma: 5.14.0
|
|
|
5563 |
dependencies:
|
5564 |
defer-to-connect: 2.0.1
|
5565 |
|
5566 |
+
'@tailwindcss/[email protected]([email protected].4)':
|
5567 |
dependencies:
|
5568 |
lodash.castarray: 4.4.0
|
5569 |
lodash.isplainobject: 4.0.6
|
5570 |
lodash.merge: 4.6.2
|
5571 |
postcss-selector-parser: 6.0.10
|
5572 |
+
tailwindcss: 3.4.4
|
5573 |
|
5574 |
'@types/[email protected]':
|
5575 |
dependencies:
|
|
|
5710 |
|
5711 |
'@vue/[email protected]':
|
5712 |
dependencies:
|
5713 |
+
'@babel/parser': 7.24.7
|
5714 |
'@vue/shared': 3.4.23
|
5715 |
entities: 4.5.0
|
5716 |
estree-walker: 2.0.2
|
|
|
5723 |
|
5724 |
'@vue/[email protected]':
|
5725 |
dependencies:
|
5726 |
+
'@babel/parser': 7.24.7
|
5727 |
'@vue/compiler-core': 3.4.23
|
5728 |
'@vue/compiler-dom': 3.4.23
|
5729 |
'@vue/compiler-ssr': 3.4.23
|
|
|
6453 |
semver: 6.3.1
|
6454 |
string.prototype.matchall: 4.0.11
|
6455 |
|
6456 | |
6457 |
dependencies:
|
6458 |
fast-glob: 3.3.2
|
6459 |
postcss: 8.4.38
|
6460 |
+
tailwindcss: 3.4.4
|
6461 |
|
6462 | |
6463 |
dependencies:
|
|
|
6642 |
|
6643 | |
6644 |
|
6645 | |
6646 |
+
optional: true
|
6647 |
+
|
6648 | |
6649 |
optional: true
|
6650 |
|
|
|
7747 |
|
7748 | |
7749 |
|
7750 |
+
[email protected]: {}
|
7751 |
+
|
7752 | |
7753 |
+
dependencies:
|
7754 |
+
playwright-core: 1.44.1
|
7755 |
+
optionalDependencies:
|
7756 |
+
fsevents: 2.3.2
|
7757 |
+
|
7758 | |
7759 |
|
7760 | |
|
|
8122 |
dependencies:
|
8123 |
lru-cache: 6.0.0
|
8124 |
|
8125 |
+
[email protected].7([email protected].7):
|
8126 |
dependencies:
|
8127 |
+
seroval: 1.0.7
|
8128 |
|
8129 |
+
[email protected].7: {}
|
8130 |
|
8131 | |
8132 |
dependencies:
|
|
|
8194 | |
8195 |
dependencies:
|
8196 |
csstype: 3.1.3
|
8197 |
+
seroval: 1.0.7
|
8198 |
+
seroval-plugins: 1.0.7([email protected].7)
|
8199 |
|
8200 | |
8201 |
dependencies:
|
|
|
8344 |
|
8345 | |
8346 |
|
8347 |
+
tailwind-merge@2.3.0:
|
8348 |
dependencies:
|
8349 |
'@babel/runtime': 7.24.4
|
8350 |
|
8351 | |
8352 |
dependencies:
|
8353 |
+
tailwindcss: 3.4.4
|
8354 |
|
8355 |
+
[email protected].4:
|
8356 |
dependencies:
|
8357 |
'@alloc/quick-lru': 5.2.0
|
8358 |
arg: 5.0.2
|
tests/e2e/index.spec.ts
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import {
|
2 |
+
EXAMPLES,
|
3 |
+
EXECUTE_CODE_FAILURE_TITLE,
|
4 |
+
EXECUTE_CODE_SUCCESS_TITLE,
|
5 |
+
PLAN_TITLE,
|
6 |
+
TOOLS_TITLE,
|
7 |
+
} from '@/lib/constants';
|
8 |
+
import { test, expect, type Page } from '@playwright/test';
|
9 |
+
|
10 |
+
test.beforeEach(async ({ page }) => {
|
11 |
+
// https://vercel.com/docs/security/deployment-protection/methods-to-bypass-deployment-protection/protection-bypass-automation
|
12 |
+
await page.setExtraHTTPHeaders({
|
13 |
+
'x-vercel-protection-bypass':
|
14 |
+
process.env.VERCEL_AUTOMATION_BYPASS_SECRET ?? 'unknown',
|
15 |
+
});
|
16 |
+
});
|
17 |
+
|
18 |
+
test('Main page can be opened', async ({ page }) => {
|
19 |
+
await page.goto('/');
|
20 |
+
|
21 |
+
await expect(
|
22 |
+
page.getByRole('heading', { name: 'Vision Agent' }),
|
23 |
+
).toBeVisible();
|
24 |
+
|
25 |
+
await page.getByText(EXAMPLES[0].title).click();
|
26 |
+
await expect(page.getByPlaceholder('Message Vision Agent')).toHaveText(
|
27 |
+
EXAMPLES[0].prompt,
|
28 |
+
);
|
29 |
+
});
|
30 |
+
|
31 |
+
const TEST_EXAMPLE_1_CHAT_ID_1 = 'jN6q4YK';
|
32 |
+
const TEST_EXAMPLE_1_CHAT_ID_2 = 'w5ad73s';
|
33 |
+
|
34 |
+
const checkMainElementVisible = async (page: Page, hasFailingCase = false) => {
|
35 |
+
await expect(page.getByText(EXAMPLES[0].prompt)).toBeVisible();
|
36 |
+
await expect(
|
37 |
+
page.locator(`img[alt*="${EXAMPLES[0].mediaUrl}"]`),
|
38 |
+
).toBeVisible();
|
39 |
+
|
40 |
+
await expect(page.getByText(PLAN_TITLE)).toBeVisible();
|
41 |
+
await expect(page.getByText(TOOLS_TITLE)).toBeVisible();
|
42 |
+
if (hasFailingCase) {
|
43 |
+
await expect(page.getByText(EXECUTE_CODE_FAILURE_TITLE)).toBeVisible();
|
44 |
+
}
|
45 |
+
await expect(page.getByText(EXECUTE_CODE_SUCCESS_TITLE)).toBeVisible();
|
46 |
+
|
47 |
+
await expect(page.locator(`img[alt="result-image-0"]`).first()).toBeVisible();
|
48 |
+
|
49 |
+
const resultDisplayContainer = await page
|
50 |
+
.getByTestId('code-result-display-container')
|
51 |
+
.locator('visible=true');
|
52 |
+
await expect(resultDisplayContainer).toBeVisible();
|
53 |
+
|
54 |
+
await resultDisplayContainer
|
55 |
+
.getByTestId('open-final-test-code-dialog-button')
|
56 |
+
.click();
|
57 |
+
const dialog = await page.getByRole('dialog');
|
58 |
+
await expect(
|
59 |
+
dialog.getByRole('heading', { name: 'Test code' }),
|
60 |
+
).toBeVisible();
|
61 |
+
await dialog
|
62 |
+
.getByRole('button')
|
63 |
+
.filter({
|
64 |
+
hasText: 'Close',
|
65 |
+
})
|
66 |
+
.click();
|
67 |
+
await resultDisplayContainer
|
68 |
+
.getByTestId('view-all-result-images-button')
|
69 |
+
.click();
|
70 |
+
await expect(page.locator(`img[alt="detail-result-image-0"]`)).toBeVisible();
|
71 |
+
};
|
72 |
+
|
73 |
+
test.describe('Page with example 1 can be opened', () => {
|
74 |
+
test('Page with old data structiure can be opened', async ({ page }) => {
|
75 |
+
await page.goto(`/chat/${TEST_EXAMPLE_1_CHAT_ID_1}`);
|
76 |
+
|
77 |
+
await checkMainElementVisible(page, true);
|
78 |
+
});
|
79 |
+
|
80 |
+
test('Page with new data structiure can be opened', async ({ page }) => {
|
81 |
+
await page.goto(`/chat/${TEST_EXAMPLE_1_CHAT_ID_2}`);
|
82 |
+
|
83 |
+
await checkMainElementVisible(page);
|
84 |
+
});
|
85 |
+
});
|