Spaces:
Running
Running
wuyiqunLu
commited on
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": "pnpm@9.1.1"
|
| 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": "pnpm@9.1.1"
|
| 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(tailwindcss@3.4.
|
| 162 |
'@types/node':
|
| 163 |
specifier: ^20.11.5
|
| 164 |
version: 20.12.7
|
|
@@ -194,7 +197,7 @@ importers:
|
|
| 194 |
version: 9.1.0(eslint@8.57.0)
|
| 195 |
eslint-plugin-tailwindcss:
|
| 196 |
specifier: ^3.14.0
|
| 197 |
-
version: 3.15.1(tailwindcss@3.4.
|
| 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(tailwindcss@3.4.
|
| 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/helper-string-parser@7.24.
|
| 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/parser@7.24.
|
| 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/types@7.24.
|
| 463 |
-
resolution: {integrity: sha512
|
| 464 |
engines: {node: '>=6.9.0'}
|
| 465 |
|
| 466 |
'@emnapi/runtime@1.1.1':
|
|
@@ -730,6 +733,11 @@ packages:
|
|
| 730 |
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
| 731 |
engines: {node: '>=14'}
|
| 732 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 733 |
'@prisma/client@5.14.0':
|
| 734 |
resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==}
|
| 735 |
engines: {node: '>=16.13'}
|
|
@@ -2209,6 +2217,11 @@ packages:
|
|
| 2209 |
fs.realpath@1.0.0:
|
| 2210 |
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
| 2211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2212 |
fsevents@2.3.3:
|
| 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 |
possible-typed-array-names@1.0.0:
|
| 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 |
-
seroval-plugins@1.0.
|
| 3446 |
-
resolution: {integrity: sha512-
|
| 3447 |
engines: {node: '>=10'}
|
| 3448 |
peerDependencies:
|
| 3449 |
seroval: ^1.0
|
| 3450 |
|
| 3451 |
-
seroval@1.0.
|
| 3452 |
-
resolution: {integrity: sha512-
|
| 3453 |
engines: {node: '>=10'}
|
| 3454 |
|
| 3455 |
set-function-length@1.2.2:
|
|
@@ -3621,16 +3644,16 @@ packages:
|
|
| 3621 |
tabbable@6.2.0:
|
| 3622 |
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
| 3623 |
|
| 3624 |
-
tailwind-merge@2.
|
| 3625 |
-
resolution: {integrity: sha512-
|
| 3626 |
|
| 3627 |
tailwindcss-animate@1.0.7:
|
| 3628 |
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
|
| 3629 |
peerDependencies:
|
| 3630 |
tailwindcss: '>=3.0.0 || insiders'
|
| 3631 |
|
| 3632 |
-
tailwindcss@3.4.
|
| 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/helper-string-parser@7.24.
|
| 4564 |
|
| 4565 |
-
'@babel/helper-validator-identifier@7.
|
| 4566 |
|
| 4567 |
-
'@babel/parser@7.24.
|
| 4568 |
dependencies:
|
| 4569 |
-
'@babel/types': 7.24.
|
| 4570 |
|
| 4571 |
'@babel/runtime@7.24.4':
|
| 4572 |
dependencies:
|
| 4573 |
regenerator-runtime: 0.14.1
|
| 4574 |
|
| 4575 |
-
'@babel/types@7.24.
|
| 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/runtime@1.1.1':
|
|
@@ -4794,6 +4817,10 @@ snapshots:
|
|
| 4794 |
'@pkgjs/parseargs@0.11.0':
|
| 4795 |
optional: true
|
| 4796 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4797 |
'@prisma/client@5.14.0(prisma@5.14.0)':
|
| 4798 |
optionalDependencies:
|
| 4799 |
prisma: 5.14.0
|
|
@@ -5536,13 +5563,13 @@ snapshots:
|
|
| 5536 |
dependencies:
|
| 5537 |
defer-to-connect: 2.0.1
|
| 5538 |
|
| 5539 |
-
'@tailwindcss/typography@0.5.12(tailwindcss@3.4.
|
| 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/cacheable-request@6.0.3':
|
| 5548 |
dependencies:
|
|
@@ -5683,7 +5710,7 @@ snapshots:
|
|
| 5683 |
|
| 5684 |
'@vue/compiler-core@3.4.23':
|
| 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/compiler-sfc@3.4.23':
|
| 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 |
-
eslint-plugin-tailwindcss@3.15.1(tailwindcss@3.4.
|
| 6430 |
dependencies:
|
| 6431 |
fast-glob: 3.3.2
|
| 6432 |
postcss: 8.4.38
|
| 6433 |
-
tailwindcss: 3.4.
|
| 6434 |
|
| 6435 |
eslint-scope@7.2.2:
|
| 6436 |
dependencies:
|
|
@@ -6615,6 +6642,9 @@ snapshots:
|
|
| 6615 |
|
| 6616 |
fs.realpath@1.0.0: {}
|
| 6617 |
|
|
|
|
|
|
|
|
|
|
| 6618 |
fsevents@2.3.3:
|
| 6619 |
optional: true
|
| 6620 |
|
|
@@ -7717,6 +7747,14 @@ snapshots:
|
|
| 7717 |
|
| 7718 |
pirates@4.0.6: {}
|
| 7719 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7720 |
possible-typed-array-names@1.0.0: {}
|
| 7721 |
|
| 7722 |
postcss-import@15.1.0(postcss@8.4.38):
|
|
@@ -8084,11 +8122,11 @@ snapshots:
|
|
| 8084 |
dependencies:
|
| 8085 |
lru-cache: 6.0.0
|
| 8086 |
|
| 8087 |
-
seroval-plugins@1.0.
|
| 8088 |
dependencies:
|
| 8089 |
-
seroval: 1.0.
|
| 8090 |
|
| 8091 |
-
seroval@1.0.
|
| 8092 |
|
| 8093 |
set-function-length@1.2.2:
|
| 8094 |
dependencies:
|
|
@@ -8156,8 +8194,8 @@ snapshots:
|
|
| 8156 |
solid-js@1.8.16:
|
| 8157 |
dependencies:
|
| 8158 |
csstype: 3.1.3
|
| 8159 |
-
seroval: 1.0.
|
| 8160 |
-
seroval-plugins: 1.0.
|
| 8161 |
|
| 8162 |
solid-swr-store@0.10.7(solid-js@1.8.16)(swr-store@0.10.6):
|
| 8163 |
dependencies:
|
|
@@ -8306,15 +8344,15 @@ snapshots:
|
|
| 8306 |
|
| 8307 |
tabbable@6.2.0: {}
|
| 8308 |
|
| 8309 |
-
tailwind-merge@2.
|
| 8310 |
dependencies:
|
| 8311 |
'@babel/runtime': 7.24.4
|
| 8312 |
|
| 8313 |
-
tailwindcss-animate@1.0.7(tailwindcss@3.4.
|
| 8314 |
dependencies:
|
| 8315 |
-
tailwindcss: 3.4.
|
| 8316 |
|
| 8317 |
-
tailwindcss@3.4.
|
| 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(tailwindcss@3.4.4)
|
| 165 |
'@types/node':
|
| 166 |
specifier: ^20.11.5
|
| 167 |
version: 20.12.7
|
|
|
|
| 197 |
version: 9.1.0(eslint@8.57.0)
|
| 198 |
eslint-plugin-tailwindcss:
|
| 199 |
specifier: ^3.14.0
|
| 200 |
+
version: 3.15.1(tailwindcss@3.4.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(tailwindcss@3.4.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/helper-string-parser@7.24.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/parser@7.24.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/types@7.24.7':
|
| 466 |
+
resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==}
|
| 467 |
engines: {node: '>=6.9.0'}
|
| 468 |
|
| 469 |
'@emnapi/runtime@1.1.1':
|
|
|
|
| 733 |
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
| 734 |
engines: {node: '>=14'}
|
| 735 |
|
| 736 |
+
'@playwright/test@1.44.1':
|
| 737 |
+
resolution: {integrity: sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==}
|
| 738 |
+
engines: {node: '>=16'}
|
| 739 |
+
hasBin: true
|
| 740 |
+
|
| 741 |
'@prisma/client@5.14.0':
|
| 742 |
resolution: {integrity: sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==}
|
| 743 |
engines: {node: '>=16.13'}
|
|
|
|
| 2217 |
fs.realpath@1.0.0:
|
| 2218 |
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
| 2219 |
|
| 2220 |
+
fsevents@2.3.2:
|
| 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 |
fsevents@2.3.3:
|
| 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 |
+
playwright-core@1.44.1:
|
| 3125 |
+
resolution: {integrity: sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==}
|
| 3126 |
+
engines: {node: '>=16'}
|
| 3127 |
+
hasBin: true
|
| 3128 |
+
|
| 3129 |
+
playwright@1.44.1:
|
| 3130 |
+
resolution: {integrity: sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==}
|
| 3131 |
+
engines: {node: '>=16'}
|
| 3132 |
+
hasBin: true
|
| 3133 |
+
|
| 3134 |
possible-typed-array-names@1.0.0:
|
| 3135 |
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
|
| 3136 |
engines: {node: '>= 0.4'}
|
|
|
|
| 3465 |
engines: {node: '>=10'}
|
| 3466 |
hasBin: true
|
| 3467 |
|
| 3468 |
+
seroval-plugins@1.0.7:
|
| 3469 |
+
resolution: {integrity: sha512-GO7TkWvodGp6buMEX9p7tNyIkbwlyuAWbI6G9Ec5bhcm7mQdu3JOK1IXbEUwb3FVzSc363GraG/wLW23NSavIw==}
|
| 3470 |
engines: {node: '>=10'}
|
| 3471 |
peerDependencies:
|
| 3472 |
seroval: ^1.0
|
| 3473 |
|
| 3474 |
+
seroval@1.0.7:
|
| 3475 |
+
resolution: {integrity: sha512-n6ZMQX5q0Vn19Zq7CIKNIo7E75gPkGCFUEqDpa8jgwpYr/vScjqnQ6H09t1uIiZ0ZSK0ypEGvrYK2bhBGWsGdw==}
|
| 3476 |
engines: {node: '>=10'}
|
| 3477 |
|
| 3478 |
set-function-length@1.2.2:
|
|
|
|
| 3644 |
tabbable@6.2.0:
|
| 3645 |
resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
|
| 3646 |
|
| 3647 |
+
tailwind-merge@2.3.0:
|
| 3648 |
+
resolution: {integrity: sha512-vkYrLpIP+lgR0tQCG6AP7zZXCTLc1Lnv/CCRT3BqJ9CZ3ui2++GPaGb1x/ILsINIMSYqqvrpqjUFsMNLlW99EA==}
|
| 3649 |
|
| 3650 |
tailwindcss-animate@1.0.7:
|
| 3651 |
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
|
| 3652 |
peerDependencies:
|
| 3653 |
tailwindcss: '>=3.0.0 || insiders'
|
| 3654 |
|
| 3655 |
+
tailwindcss@3.4.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/helper-string-parser@7.24.7': {}
|
| 4587 |
|
| 4588 |
+
'@babel/helper-validator-identifier@7.24.7': {}
|
| 4589 |
|
| 4590 |
+
'@babel/parser@7.24.7':
|
| 4591 |
dependencies:
|
| 4592 |
+
'@babel/types': 7.24.7
|
| 4593 |
|
| 4594 |
'@babel/runtime@7.24.4':
|
| 4595 |
dependencies:
|
| 4596 |
regenerator-runtime: 0.14.1
|
| 4597 |
|
| 4598 |
+
'@babel/types@7.24.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/runtime@1.1.1':
|
|
|
|
| 4817 |
'@pkgjs/parseargs@0.11.0':
|
| 4818 |
optional: true
|
| 4819 |
|
| 4820 |
+
'@playwright/test@1.44.1':
|
| 4821 |
+
dependencies:
|
| 4822 |
+
playwright: 1.44.1
|
| 4823 |
+
|
| 4824 |
'@prisma/client@5.14.0(prisma@5.14.0)':
|
| 4825 |
optionalDependencies:
|
| 4826 |
prisma: 5.14.0
|
|
|
|
| 5563 |
dependencies:
|
| 5564 |
defer-to-connect: 2.0.1
|
| 5565 |
|
| 5566 |
+
'@tailwindcss/typography@0.5.12(tailwindcss@3.4.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/cacheable-request@6.0.3':
|
| 5575 |
dependencies:
|
|
|
|
| 5710 |
|
| 5711 |
'@vue/compiler-core@3.4.23':
|
| 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/compiler-sfc@3.4.23':
|
| 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 |
+
eslint-plugin-tailwindcss@3.15.1(tailwindcss@3.4.4):
|
| 6457 |
dependencies:
|
| 6458 |
fast-glob: 3.3.2
|
| 6459 |
postcss: 8.4.38
|
| 6460 |
+
tailwindcss: 3.4.4
|
| 6461 |
|
| 6462 |
eslint-scope@7.2.2:
|
| 6463 |
dependencies:
|
|
|
|
| 6642 |
|
| 6643 |
fs.realpath@1.0.0: {}
|
| 6644 |
|
| 6645 |
+
fsevents@2.3.2:
|
| 6646 |
+
optional: true
|
| 6647 |
+
|
| 6648 |
fsevents@2.3.3:
|
| 6649 |
optional: true
|
| 6650 |
|
|
|
|
| 7747 |
|
| 7748 |
pirates@4.0.6: {}
|
| 7749 |
|
| 7750 |
+
playwright-core@1.44.1: {}
|
| 7751 |
+
|
| 7752 |
+
playwright@1.44.1:
|
| 7753 |
+
dependencies:
|
| 7754 |
+
playwright-core: 1.44.1
|
| 7755 |
+
optionalDependencies:
|
| 7756 |
+
fsevents: 2.3.2
|
| 7757 |
+
|
| 7758 |
possible-typed-array-names@1.0.0: {}
|
| 7759 |
|
| 7760 |
postcss-import@15.1.0(postcss@8.4.38):
|
|
|
|
| 8122 |
dependencies:
|
| 8123 |
lru-cache: 6.0.0
|
| 8124 |
|
| 8125 |
+
seroval-plugins@1.0.7(seroval@1.0.7):
|
| 8126 |
dependencies:
|
| 8127 |
+
seroval: 1.0.7
|
| 8128 |
|
| 8129 |
+
seroval@1.0.7: {}
|
| 8130 |
|
| 8131 |
set-function-length@1.2.2:
|
| 8132 |
dependencies:
|
|
|
|
| 8194 |
solid-js@1.8.16:
|
| 8195 |
dependencies:
|
| 8196 |
csstype: 3.1.3
|
| 8197 |
+
seroval: 1.0.7
|
| 8198 |
+
seroval-plugins: 1.0.7(seroval@1.0.7)
|
| 8199 |
|
| 8200 |
solid-swr-store@0.10.7(solid-js@1.8.16)(swr-store@0.10.6):
|
| 8201 |
dependencies:
|
|
|
|
| 8344 |
|
| 8345 |
tabbable@6.2.0: {}
|
| 8346 |
|
| 8347 |
+
tailwind-merge@2.3.0:
|
| 8348 |
dependencies:
|
| 8349 |
'@babel/runtime': 7.24.4
|
| 8350 |
|
| 8351 |
+
tailwindcss-animate@1.0.7(tailwindcss@3.4.4):
|
| 8352 |
dependencies:
|
| 8353 |
+
tailwindcss: 3.4.4
|
| 8354 |
|
| 8355 |
+
tailwindcss@3.4.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 |
+
});
|