Refactored frontend directory
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 2m46s
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 2m46s
This commit is contained in:
@@ -44,15 +44,15 @@ jobs:
|
||||
with:
|
||||
node-version: "20.19.0"
|
||||
cache: "npm"
|
||||
cache-dependency-path: frontend/vue-app/package-lock.json
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Install frontend dependencies
|
||||
run: npm ci
|
||||
working-directory: frontend/vue-app
|
||||
working-directory: frontend
|
||||
|
||||
- name: Run frontend unit tests
|
||||
run: npm run test:unit --if-present
|
||||
working-directory: frontend/vue-app
|
||||
working-directory: frontend
|
||||
|
||||
- name: Build Backend Docker Image
|
||||
run: |
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
- name: Build Frontend Docker Image
|
||||
run: |
|
||||
docker build -t git.ryankegel.com:3000/kegel/chores/frontend:${{ steps.vars.outputs.tag }} ./frontend/vue-app
|
||||
docker build -t git.ryankegel.com:3000/kegel/chores/frontend:${{ steps.vars.outputs.tag }} ./frontend
|
||||
|
||||
- name: Log in to Registry
|
||||
uses: docker/login-action@v2
|
||||
|
||||
2
.github/agents/ui-planner.agent.md
vendored
2
.github/agents/ui-planner.agent.md
vendored
@@ -17,7 +17,7 @@ You are a Senior UI/UX Architect specializing in clean, highly reactive web appl
|
||||
|
||||
This is the **Reward** app — a family chore/reward tracker. Vue 3 (Composition API / `<script setup lang="ts">`) frontend. Key files:
|
||||
|
||||
- Theme tokens: `frontend/vue-app/src/assets/colors.css` — **always read this first** when reviewing a component.
|
||||
- Theme tokens: `frontend/src/assets/colors.css` — **always read this first** when reviewing a component.
|
||||
- Layout wrappers: `ParentLayout` (admin views) and `ChildLayout` (child dashboard views).
|
||||
- All `.vue` files use `<style scoped>`. Child component styling uses `:deep()` selectors.
|
||||
- File order within `.vue` files: `<template>`, then `<script>`, then `<style>`.
|
||||
|
||||
18
.github/copilot-instructions.md
vendored
18
.github/copilot-instructions.md
vendored
@@ -5,7 +5,7 @@
|
||||
- **Stack**: Flask (Python, backend) + Vue 3 (TypeScript, frontend) + TinyDB (JSON, thread-safe, see `db/`).
|
||||
- **API**: RESTful endpoints in `api/`, grouped by entity (child, reward, task, user, image, etc). Each API file maps to a business domain.
|
||||
- **Nginx Proxy**: Frontend nginx proxies `/api/*` to backend, stripping the `/api` prefix. Backend endpoints should NOT include `/api` in their route definitions. Example: Backend defines `@app.route('/user')`, frontend calls `/api/user`.
|
||||
- **Models**: Maintain strict 1:1 mapping between Python `@dataclass`es (`backend/models/`) and TypeScript interfaces (`frontend/vue-app/src/common/models.ts`).
|
||||
- **Models**: Maintain strict 1:1 mapping between Python `@dataclass`es (`backend/models/`) and TypeScript interfaces (`frontend/src/common/models.ts`).
|
||||
- **Database**: Use TinyDB with `from_dict()`/`to_dict()` for serialization. All logic should operate on model instances, not raw dicts.
|
||||
- **Events**: Real-time updates via Server-Sent Events (SSE). Every mutation (add/edit/delete/trigger) must call `send_event_for_current_user` (see `backend/events/`).
|
||||
- **Changes**: Do not use comments to replace code. All changes must be reflected in both backend and frontend files as needed.
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
## 🚦 Frontend Logic & Event Bus
|
||||
|
||||
- **SSE Event Management**: Register listeners in `onMounted`, clean up in `onUnmounted`. Listen for events like `child_task_triggered`, `child_reward_request`, `task_modified`, etc. See `frontend/vue-app/src/common/backendEvents.ts` and `components/BackendEventsListener.vue`.
|
||||
- **SSE Event Management**: Register listeners in `onMounted`, clean up in `onUnmounted`. Listen for events like `child_task_triggered`, `child_reward_request`, `task_modified`, etc. See `frontend/src/common/backendEvents.ts` and `components/BackendEventsListener.vue`.
|
||||
- **Layout Hierarchy**: Use `ParentLayout` for admin/management, `ChildLayout` for dashboard/focus views.
|
||||
|
||||
## ⚖️ Business Logic & Safeguards
|
||||
@@ -37,9 +37,9 @@
|
||||
|
||||
- **Backend**: Run Flask with `python -m flask run --host=0.0.0.0 --port=5000` from the `backend/` directory. Main entry: `backend/main.py`.
|
||||
- **Virtual Env**: Python is running from a virtual environment located at `backend/.venv/`.
|
||||
- **Frontend**: From `frontend/vue-app/`, run `npm install` then `npm run dev`.
|
||||
- **Tests**: Run backend tests with `pytest` in `backend/tests/`. Frontend component tests: `npm run test` in `frontend/vue-app/components/__tests__/`. E2E tests: `npx playwright test` from `frontend/vue-app/` — requires both servers running (use the `flask-backend` and `vue-frontend` skills).
|
||||
- **E2E Setup**: Playwright config is at `frontend/vue-app/playwright.config.ts`. Tests live in `frontend/vue-app/tests/`. The `globalSetup` in `playwright.config.ts` seeds the database and logs in once; all tests receive a pre-authenticated session via `storageState` — do NOT navigate to `/auth/login` in tests. Import `E2E_EMAIL` and `E2E_PASSWORD` from `tests/global-setup.ts` rather than hardcoding credentials. The backend must be started with `DB_ENV=e2e DATA_ENV=e2e` (the `flask-backend` skill does this) so test data goes to `backend/test_data/` and never touches production data.
|
||||
- **Frontend**: From `frontend/`, run `npm install` then `npm run dev`.
|
||||
- **Tests**: Run backend tests with `pytest` in `backend/tests/`. Frontend component tests: `npm run test` in `frontend/components/__tests__/`. E2E tests: `npx playwright test` from `frontend/` — requires both servers running (use the `flask-backend` and `vue-frontend` skills).
|
||||
- **E2E Setup**: Playwright config is at `frontend/playwright.config.ts`. Tests live in `frontend/tests/`. The `globalSetup` in `playwright.config.ts` seeds the database and logs in once; all tests receive a pre-authenticated session via `storageState` — do NOT navigate to `/auth/login` in tests. Import `E2E_EMAIL` and `E2E_PASSWORD` from `tests/global-setup.ts` rather than hardcoding credentials. The backend must be started with `DB_ENV=e2e DATA_ENV=e2e` (the `flask-backend` skill does this) so test data goes to `backend/test_data/` and never touches production data.
|
||||
- **Debugging**: Use VS Code launch configs or run Flask/Vue dev servers directly. For SSE, use browser dev tools to inspect event streams.
|
||||
|
||||
## 📁 Key Files & Directories
|
||||
@@ -48,10 +48,10 @@
|
||||
- `backend/models/` — Python dataclasses (business logic, serialization)
|
||||
- `backend/db/` — TinyDB setup and helpers
|
||||
- `backend/events/` — SSE event types, broadcaster, payloads
|
||||
- `frontend/vue-app/` — Vue 3 frontend (see `src/common/`, `src/components/`, `src/layout/`) - Where tests are run from
|
||||
- `frontend/vue-app/src/common/models.ts` — TypeScript interfaces (mirror Python models)
|
||||
- `frontend/vue-app/src/common/api.ts` — API helpers, error parsing, validation
|
||||
- `frontend/vue-app/src/common/backendEvents.ts` — SSE event types and handlers
|
||||
- `frontend/` — Vue 3 frontend (see `src/common/`, `src/components/`, `src/layout/`) - Where tests are run from
|
||||
- `frontend/src/common/models.ts` — TypeScript interfaces (mirror Python models)
|
||||
- `frontend/src/common/api.ts` — API helpers, error parsing, validation
|
||||
- `frontend/src/common/backendEvents.ts` — SSE event types and handlers
|
||||
|
||||
## 🧠 Integration & Cross-Component Patterns
|
||||
|
||||
|
||||
4
.github/skills/vue-frontend/SKILL.md
vendored
4
.github/skills/vue-frontend/SKILL.md
vendored
@@ -8,10 +8,10 @@ disable-model-invocation: true
|
||||
|
||||
Use this skill when the user wants to "start the frontend," "run vue," or "launch the dev server."
|
||||
|
||||
1. **Verify Directory:** Navigate to `./frontend/vue-app`.
|
||||
1. **Verify Directory:** Navigate to `./frontend`.
|
||||
- _Self-Correction:_ If the directory doesn't exist, search the workspace for `package.json` files and ask for clarification.
|
||||
|
||||
2. **Check Dependencies:** - Before running, check if `node_modules` exists in `./frontend/vue-app`.
|
||||
2. **Check Dependencies:** - Before running, check if `node_modules` exists in `./frontend`.
|
||||
- If missing, ask the user: "Should I run `npm install` first?"
|
||||
|
||||
3. **Execution:** - Run the command: `npm run dev`
|
||||
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,12 +1,12 @@
|
||||
.env
|
||||
backend/test_data/
|
||||
logs/
|
||||
frontend/vue-app/resources/
|
||||
frontend/vue-app/playwright-report/
|
||||
frontend/vue-app/test-results/
|
||||
frontend/resources/
|
||||
frontend/playwright-report/
|
||||
frontend/test-results/
|
||||
backend/test-results/
|
||||
.vscode/keybindings.json
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
frontend/vue-app/cert.pem
|
||||
frontend/vue-app/key.pem
|
||||
frontend/cert.pem
|
||||
frontend/key.pem
|
||||
|
||||
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@@ -35,7 +35,7 @@
|
||||
"run",
|
||||
"dev"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/frontend/vue-app",
|
||||
"cwd": "${workspaceFolder}/frontend",
|
||||
"console": "integratedTerminal",
|
||||
"serverReadyAction": {
|
||||
"pattern": "Local:.*https://localhost:([0-9]+)",
|
||||
@@ -48,7 +48,7 @@
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:5173",
|
||||
"webRoot": "${workspaceFolder}/frontend/vue-app"
|
||||
"webRoot": "${workspaceFolder}/frontend"
|
||||
},
|
||||
{
|
||||
"name": "Python: Backend Tests",
|
||||
@@ -76,7 +76,7 @@
|
||||
"run",
|
||||
"test:unit"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/frontend/vue-app",
|
||||
"cwd": "${workspaceFolder}/frontend",
|
||||
"console": "integratedTerminal",
|
||||
"osx": {
|
||||
"env": {
|
||||
|
||||
6
.vscode/launch.json.bak
vendored
6
.vscode/launch.json.bak
vendored
@@ -28,7 +28,7 @@
|
||||
"run",
|
||||
"dev"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/frontend/vue-app",
|
||||
"cwd": "${workspaceFolder}/frontend",
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
@@ -36,7 +36,7 @@
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "https://localhost:5173", // or your Vite dev server port
|
||||
"webRoot": "${workspaceFolder}/frontend/vue-app"
|
||||
"webRoot": "${workspaceFolder}/frontend"
|
||||
},
|
||||
{
|
||||
"name": "Python: Backend Tests",
|
||||
@@ -60,7 +60,7 @@
|
||||
"runtimeArgs": [
|
||||
"vitest"
|
||||
],
|
||||
"cwd": "${workspaceFolder}/frontend/vue-app",
|
||||
"cwd": "${workspaceFolder}/frontend",
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
],
|
||||
|
||||
2
.vscode/mcp.json
vendored
2
.vscode/mcp.json
vendored
@@ -8,7 +8,7 @@
|
||||
"run-test-mcp-server",
|
||||
"--config=playwright.config.ts"
|
||||
],
|
||||
"cwd": "frontend/vue-app"
|
||||
"cwd": "frontend"
|
||||
}
|
||||
},
|
||||
"inputs": []
|
||||
|
||||
22
.vscode/tasks.json
vendored
22
.vscode/tasks.json
vendored
@@ -44,56 +44,56 @@
|
||||
{
|
||||
"label": "PW: Task Modification Tests",
|
||||
"type": "shell",
|
||||
"command": "cd \"${workspaceFolder}/frontend/vue-app\" && npx playwright test e2e/mode_parent/task-modification --project=chromium-task-modification",
|
||||
"command": "cd \"${workspaceFolder}/frontend\" && npx playwright test e2e/mode_parent/task-modification --project=chromium-task-modification",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"label": "PW: Task Modification Tests (PS)",
|
||||
"type": "shell",
|
||||
"command": "powershell -Command \"cd '$env:APPDATA/../../../d/Python Utilities/Reward/frontend/vue-app'; npx playwright test e2e/mode_parent/task-modification --project=chromium-task-modification\"",
|
||||
"command": "powershell -Command \"cd '$env:APPDATA/../../../d/Python Utilities/Reward/frontend'; npx playwright test e2e/mode_parent/task-modification --project=chromium-task-modification\"",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"label": "PW: Task Modification Tests (cmd)",
|
||||
"type": "shell",
|
||||
"command": "cmd /c \"cd /d \\\"D:\\Python Utilities\\Reward\\frontend\\vue-app\\\" && npx playwright test e2e/mode_parent/task-modification --project=chromium-task-modification 2>&1\"",
|
||||
"command": "cmd /c \"cd /d \\\"D:\\Python Utilities\\Reward\\frontend\\\" && npx playwright test e2e/mode_parent/task-modification --project=chromium-task-modification 2>&1\"",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"label": "PW: User Profile Tests",
|
||||
"type": "shell",
|
||||
"command": "cd \"${workspaceFolder}/frontend/vue-app\" && npx playwright test e2e/mode_parent/user-profile --project=chromium-user-profile --project=chromium-user-profile-pin --project=chromium-user-profile-delete",
|
||||
"command": "cd \"${workspaceFolder}/frontend\" && npx playwright test e2e/mode_parent/user-profile --project=chromium-user-profile --project=chromium-user-profile-pin --project=chromium-user-profile-delete",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"label": "PW: User Profile Tests 2",
|
||||
"type": "shell",
|
||||
"command": "cd \"${workspaceFolder}/frontend/vue-app\" && npx playwright test e2e/mode_parent/user-profile --project=chromium-user-profile --project=chromium-user-profile-pin --project=chromium-user-profile-delete",
|
||||
"command": "cd \"${workspaceFolder}/frontend\" && npx playwright test e2e/mode_parent/user-profile --project=chromium-user-profile --project=chromium-user-profile-pin --project=chromium-user-profile-delete",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"label": "PW: User Profile Tests Final",
|
||||
"type": "shell",
|
||||
"command": "cd \"${workspaceFolder}/frontend/vue-app\" && npx playwright test e2e/mode_parent/user-profile --project=chromium-user-profile --project=chromium-user-profile-pin --project=chromium-user-profile-delete",
|
||||
"command": "cd \"${workspaceFolder}/frontend\" && npx playwright test e2e/mode_parent/user-profile --project=chromium-user-profile --project=chromium-user-profile-pin --project=chromium-user-profile-delete",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"label": "PW: Full Test Suite",
|
||||
"type": "shell",
|
||||
"command": "cd \"${workspaceFolder}/frontend/vue-app\" && npx playwright test --reporter=line",
|
||||
"command": "cd \"${workspaceFolder}/frontend\" && npx playwright test --reporter=line",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"label": "PW: Full Suite",
|
||||
"type": "shell",
|
||||
"command": "cd \"${workspaceFolder}/frontend/vue-app\" && npx playwright test --reporter=line",
|
||||
"command": "cd \"${workspaceFolder}/frontend\" && npx playwright test --reporter=line",
|
||||
"isBackground": false,
|
||||
"group": "test"
|
||||
},
|
||||
@@ -104,7 +104,7 @@
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
"cd 'D:\\Python Utilities\\Reward\\frontend\\vue-app'; npx playwright test --reporter=line 2>&1"
|
||||
"cd 'D:\\Python Utilities\\Reward\\frontend'; npx playwright test --reporter=line 2>&1"
|
||||
],
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
@@ -119,7 +119,7 @@
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
"cd 'D:\\Python Utilities\\Reward\\frontend\\vue-app'; npx playwright test e2e/mode_parent/tasks/penalty-default.spec.ts --project=chromium-default-tasks --reporter=line 2>&1"
|
||||
"cd 'D:\\Python Utilities\\Reward\\frontend'; npx playwright test e2e/mode_parent/tasks/penalty-default.spec.ts --project=chromium-default-tasks --reporter=line 2>&1"
|
||||
],
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
@@ -134,7 +134,7 @@
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
"cd 'D:\\Python Utilities\\Reward\\frontend\\vue-app'; npx playwright test e2e/mode_parent/user-profile/profile-editing.spec.ts --project=chromium-user-profile --reporter=line 2>&1"
|
||||
"cd 'D:\\Python Utilities\\Reward\\frontend'; npx playwright test e2e/mode_parent/user-profile/profile-editing.spec.ts --project=chromium-user-profile --reporter=line 2>&1"
|
||||
],
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
|
||||
@@ -24,7 +24,7 @@ python -m flask run --host=0.0.0.0 --port=5000
|
||||
### Frontend
|
||||
|
||||
```bash
|
||||
cd frontend/vue-app
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
@@ -114,7 +114,7 @@ pytest tests/
|
||||
### Frontend Tests
|
||||
|
||||
```bash
|
||||
cd frontend/vue-app
|
||||
cd frontend
|
||||
npm run test
|
||||
```
|
||||
|
||||
@@ -151,7 +151,6 @@ npm run test
|
||||
│ ├── tests/ # Backend tests
|
||||
│ └── utils/ # Utilities (scheduler, etc)
|
||||
├── frontend/
|
||||
│ └── vue-app/
|
||||
│ └── src/
|
||||
│ ├── common/ # Shared utilities
|
||||
│ ├── components/ # Vue components
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# vue-app
|
||||
# frontend
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
@@ -2,20 +2,20 @@
|
||||
"cookies": [
|
||||
{
|
||||
"name": "refresh_token",
|
||||
"value": "yQZhoeeYUidDfolHE467zNEWguWXzMIinFT1LNLU5yM",
|
||||
"value": "oh4sQB_Q1Se4xydZHTIolU6FhvlKPIlDPsxfd_qe4wQ",
|
||||
"domain": "localhost",
|
||||
"path": "/api/auth",
|
||||
"expires": 1784509278.633774,
|
||||
"expires": 1784867824.852037,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "Strict"
|
||||
},
|
||||
{
|
||||
"name": "access_token",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiI4ZmZkYTMyNC01MDE1LTRiYjktODY3Yi1jZjFlNTU1NjBjMzciLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzY3MzQxNzh9.YvFGLV1bdoRpRb8z5YtO19dpD7vkC0p5XMhGJgSJol8",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1jY0B0ZXN0LmNvbSIsInVzZXJfaWQiOiI4NGY1Y2I3NS05NWU1LTRjMTItOTExOS02MzdkYjJlMWY1MGYiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzcwOTI3MjR9.7-d4EvJEYtYSi_5ZFiU7tuxgc4ilVMBxhwzgAQZNTvY",
|
||||
"domain": "localhost",
|
||||
"path": "/",
|
||||
"expires": 1776734178.633726,
|
||||
"expires": 1777092724.851439,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "Lax"
|
||||
@@ -27,11 +27,11 @@
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "authSyncEvent",
|
||||
"value": "{\"type\":\"logout\",\"at\":1776733278500}"
|
||||
"value": "{\"type\":\"logout\",\"at\":1777091824594}"
|
||||
},
|
||||
{
|
||||
"name": "parentAuth",
|
||||
"value": "{\"expiresAt\":1776906078798}"
|
||||
"value": "{\"expiresAt\":1777264625262}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,20 +2,20 @@
|
||||
"cookies": [
|
||||
{
|
||||
"name": "refresh_token",
|
||||
"value": "j90QCKu8d9QvNG-k-m31G5PoxU0yBuz-wyx8NPYCOG8",
|
||||
"value": "lIhurtvmo0oGcimN_8v59h9y3CrglEAloQO1QFw8RsQ",
|
||||
"domain": "localhost",
|
||||
"path": "/api/auth",
|
||||
"expires": 1784509278.541961,
|
||||
"expires": 1784867824.995155,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "Strict"
|
||||
},
|
||||
{
|
||||
"name": "access_token",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1kZWxldGVAdGVzdC5jb20iLCJ1c2VyX2lkIjoiNzA3ZGYwYmUtOWQxMy00MGVlLWI3M2QtYzYwZmFmNDg2NmU2IiwidG9rZW5fdmVyc2lvbiI6MCwiZXhwIjoxNzc2NzM0MTc4fQ.cEKtxo4zVTd7kBZzfjjI_uxqez32gUxmZYuUa8-RYdc",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZS1kZWxldGVAdGVzdC5jb20iLCJ1c2VyX2lkIjoiOWYzYTljNWMtM2IwMy00YTZlLTliNmUtYjE0MTQzZWNhMzNkIiwidG9rZW5fdmVyc2lvbiI6MCwiZXhwIjoxNzc3MDkyNzI0fQ.UB5MCIZ2PHbn3UyohNzmFbOCb3TR-KHxJPWB9qkWwCQ",
|
||||
"domain": "localhost",
|
||||
"path": "/",
|
||||
"expires": 1776734178.541918,
|
||||
"expires": 1777092724.99406,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "Lax"
|
||||
@@ -27,11 +27,11 @@
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "authSyncEvent",
|
||||
"value": "{\"type\":\"logout\",\"at\":1776733278395}"
|
||||
"value": "{\"type\":\"logout\",\"at\":1777091824687}"
|
||||
},
|
||||
{
|
||||
"name": "parentAuth",
|
||||
"value": "{\"expiresAt\":1776906078675}"
|
||||
"value": "{\"expiresAt\":1777264625511}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2,20 +2,20 @@
|
||||
"cookies": [
|
||||
{
|
||||
"name": "refresh_token",
|
||||
"value": "RETiHvb_RUs2-0xb-klx8BwvSwr2TMtz1D-NmB5825Y",
|
||||
"value": "uMExObHukEdFnlszorcDq2XlbRW0AeIV71x_vSovEF4",
|
||||
"domain": "localhost",
|
||||
"path": "/api/auth",
|
||||
"expires": 1784509276.929905,
|
||||
"expires": 1784867821.107956,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "Strict"
|
||||
},
|
||||
{
|
||||
"name": "access_token",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiJhNjZmYjdjNy04ZDI5LTRkNjAtYmVjNi0zMmEzODg1MGI1OGIiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzY3MzQxNzZ9.WSka-ZbN1ZKbD_Q4UpoP9qfN1i73G51nrx88F2TbbOE",
|
||||
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImUyZUB0ZXN0LmNvbSIsInVzZXJfaWQiOiI2ZWE5YWZmZC1jMGExLTRkMzUtOGJmYS1mZDBkOWY5NzFmOWQiLCJ0b2tlbl92ZXJzaW9uIjowLCJleHAiOjE3NzcwOTI3MjF9.rb64zKqS6uXqkgX_4kke37Rc6om68elt4Qa24Fy9NPo",
|
||||
"domain": "localhost",
|
||||
"path": "/",
|
||||
"expires": 1776734176.929863,
|
||||
"expires": 1777092721.107403,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "Lax"
|
||||
@@ -27,11 +27,11 @@
|
||||
"localStorage": [
|
||||
{
|
||||
"name": "authSyncEvent",
|
||||
"value": "{\"type\":\"logout\",\"at\":1776733276784}"
|
||||
"value": "{\"type\":\"logout\",\"at\":1777091820880}"
|
||||
},
|
||||
{
|
||||
"name": "parentAuth",
|
||||
"value": "{\"expiresAt\":1776906077058}"
|
||||
"value": "{\"expiresAt\":1777264621275}"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 409 KiB After Width: | Height: | Size: 409 KiB |
@@ -98,8 +98,9 @@ test.describe('Digest Action Token — Approve Chore', () => {
|
||||
test('Approve-chore action is performed: points awarded and confirmation removed', async ({
|
||||
request,
|
||||
}) => {
|
||||
// Wait for action to complete
|
||||
await new Promise((r) => setTimeout(r, 300))
|
||||
// Execute the action via authenticated POST (GET only redirects, POST consumes the token)
|
||||
const execRes = await request.post(`/api/digest-action/${approveToken}`)
|
||||
expect(execRes.status()).toBe(200)
|
||||
|
||||
const childRes = await request.get(`/api/child/list`)
|
||||
const children = (await childRes.json()).children ?? []
|
||||
@@ -93,7 +93,9 @@ test.describe('Digest Action Token — Approve Reward', () => {
|
||||
|
||||
// 7.6 Approve-reward action: reward triggered, child points deducted
|
||||
test('Approve-reward action: reward triggered and child points deducted', async ({ request }) => {
|
||||
await new Promise((r) => setTimeout(r, 300))
|
||||
// Execute the action via authenticated POST (GET only redirects, POST consumes the token)
|
||||
const execRes = await request.post(`/api/digest-action/${approveToken}`)
|
||||
expect(execRes.status()).toBe(200)
|
||||
|
||||
const childRes = await request.get('/api/child/list')
|
||||
const children = (await childRes.json()).children ?? []
|
||||
@@ -87,7 +87,9 @@ test.describe('Digest Action Token — Deny Chore', () => {
|
||||
test('Deny-chore action is performed: confirmation removed, points unchanged', async ({
|
||||
request,
|
||||
}) => {
|
||||
await new Promise((r) => setTimeout(r, 300))
|
||||
// Execute the action via authenticated POST (GET only redirects, POST consumes the token)
|
||||
const execRes = await request.post(`/api/digest-action/${denyToken}`)
|
||||
expect(execRes.status()).toBe(200)
|
||||
|
||||
const childRes = await request.get(`/api/child/list`)
|
||||
const children = (await childRes.json()).children ?? []
|
||||
@@ -92,7 +92,9 @@ test.describe('Digest Action Token — Deny Reward', () => {
|
||||
|
||||
// 7.8 Deny-reward action: pending request removed, points unchanged
|
||||
test('Deny-reward action: pending request removed and points unchanged', async ({ request }) => {
|
||||
await new Promise((r) => setTimeout(r, 300))
|
||||
// Execute the action via authenticated POST (GET only redirects, POST consumes the token)
|
||||
const execRes = await request.post(`/api/digest-action/${denyToken}`)
|
||||
expect(execRes.status()).toBe(200)
|
||||
|
||||
const childRes = await request.get('/api/child/list')
|
||||
const children = (await childRes.json()).children ?? []
|
||||
@@ -94,11 +94,11 @@ test.describe('Digest Action Token — Error Paths', () => {
|
||||
|
||||
const unauthCtx = await getUnauthContext(playwright)
|
||||
|
||||
// First use — should succeed (302)
|
||||
const first = await unauthCtx.get(`/api/digest-action/${token}`, { maxRedirects: 0 })
|
||||
expect(first.status()).toBe(302)
|
||||
// First use — authenticated POST executes and consumes the token
|
||||
const first = await request.post(`/api/digest-action/${token}`)
|
||||
expect(first.status()).toBe(200)
|
||||
|
||||
// Second use — token is consumed
|
||||
// Second use — token is consumed, unauthenticated GET should return 400
|
||||
const second = await unauthCtx.get(`/api/digest-action/${token}`, { maxRedirects: 0 })
|
||||
expect(second.status()).toBe(400)
|
||||
await unauthCtx.dispose()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user