docs(05): add UAT, UI-SPEC, deferred items, debug notes; refine plans 09-11
Plan refinements: Vitest tests added to 09/10 must-haves, explicit mock_flow two-tuple pattern in 10, test_admin_api.py fixture usage in 11. New artifacts: UAT checklist, UI-SPEC, deferred-items, debug investigation for cloud-doc-operations-fail. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ files_modified:
|
||||
- frontend/src/components/cloud/CloudCredentialModal.vue
|
||||
- frontend/src/components/ui/ConfirmBlock.vue
|
||||
- backend/tests/test_cloud.py
|
||||
- frontend/src/components/settings/__tests__/SettingsCloudTab.test.js
|
||||
autonomous: true
|
||||
requirements: [CLOUD-01, CLOUD-04]
|
||||
gap_closure: true
|
||||
@@ -20,6 +21,7 @@ must_haves:
|
||||
- "Nextcloud custom endpoint is preserved when re-editing an existing connection"
|
||||
- "Edit button appears on ERROR-state Nextcloud/WebDAV rows"
|
||||
- "Disconnect confirmation text renders fully within its container without overflow"
|
||||
- "handleConnect on OAuth providers calls initiateOAuth and navigates to the returned URL (verified by Vitest)"
|
||||
artifacts:
|
||||
- path: "backend/api/cloud.py"
|
||||
provides: "oauth_initiate returns JSON {url} (200) instead of RedirectResponse (302)"
|
||||
@@ -29,6 +31,8 @@ must_haves:
|
||||
provides: "watch handler detects custom endpoint on edit and repopulates showAdvanced + customEndpoint"
|
||||
- path: "frontend/src/components/ui/ConfirmBlock.vue"
|
||||
provides: "break-words on message paragraph"
|
||||
- path: "frontend/src/components/settings/__tests__/SettingsCloudTab.test.js"
|
||||
provides: "Vitest test asserting handleConnect calls initiateOAuth and sets window.location.href"
|
||||
key_links:
|
||||
- from: "frontend/src/components/settings/SettingsCloudTab.vue"
|
||||
to: "/api/cloud/oauth/initiate/{provider}"
|
||||
@@ -112,7 +116,7 @@ From frontend/src/components/ui/ConfirmBlock.vue:
|
||||
In backend/tests/test_cloud.py, add test `test_oauth_initiate_returns_json_url`:
|
||||
- Creates a regular user + token.
|
||||
- Mocks Redis setex (the app state redis client).
|
||||
- For google_drive provider: mocks `google_auth_oauthlib.flow.Flow.from_client_config` to return a mock whose `authorization_url` returns ("https://accounts.google.com/test", "state123").
|
||||
- For google_drive provider: mocks `google_auth_oauthlib.flow.Flow.from_client_config` to return a mock flow object. Set the mock explicitly: `mock_flow.authorization_url.return_value = ("https://accounts.google.com/test", "state123")` — do not use a generic "returns a URL" — this exact two-tuple assignment is required because `flow.authorization_url(...)` returns `(url, state)` and the handler unpacks both values.
|
||||
- Calls GET /api/cloud/oauth/initiate/google_drive with Bearer header.
|
||||
- Asserts response.status_code == 200.
|
||||
- Asserts response.json()["url"].startswith("https://accounts.google.com/").
|
||||
@@ -125,8 +129,8 @@ From frontend/src/components/ui/ConfirmBlock.vue:
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Frontend OAuth fetch, Nextcloud edit fix, Edit on ERROR, text overflow</name>
|
||||
<files>frontend/src/components/settings/SettingsCloudTab.vue, frontend/src/components/cloud/CloudCredentialModal.vue, frontend/src/components/ui/ConfirmBlock.vue, frontend/src/api/client.js</files>
|
||||
<name>Task 2: Frontend OAuth fetch, Nextcloud edit fix, Edit on ERROR, text overflow + Vitest test</name>
|
||||
<files>frontend/src/components/settings/SettingsCloudTab.vue, frontend/src/components/cloud/CloudCredentialModal.vue, frontend/src/components/ui/ConfirmBlock.vue, frontend/src/api/client.js, frontend/src/components/settings/__tests__/SettingsCloudTab.test.js</files>
|
||||
<action>
|
||||
### 1. client.js — add initiateOAuth helper
|
||||
Export `initiateOAuth(provider)` that calls `request(`/api/cloud/oauth/initiate/${provider}`)`. This uses the existing `request()` helper which injects the Bearer header and handles 401 → refresh → retry.
|
||||
@@ -165,11 +169,22 @@ From frontend/src/components/ui/ConfirmBlock.vue:
|
||||
|
||||
### 6. ConfirmBlock.vue — add break-words to message paragraph
|
||||
Change `<p class="text-sm text-gray-700">` to `<p class="text-sm text-gray-700 break-words">`.
|
||||
|
||||
### 7. SettingsCloudTab.test.js — add Vitest test for handleConnect OAuth flow
|
||||
The file `frontend/src/components/settings/__tests__/SettingsCloudTab.test.js` already exists. Add a new test asserting the corrected OAuth connect flow:
|
||||
- Mock `initiateOAuth` from `../../../../api/client.js` using `vi.mock`: `vi.mock('../../../../api/client.js', () => ({ initiateOAuth: vi.fn() }))`.
|
||||
- In the test, set `initiateOAuth.mockResolvedValue({ url: 'https://accounts.google.com/o/oauth2/auth?state=xyz' })`.
|
||||
- Assign `window.location = { href: '' }` (use `Object.defineProperty` or `vi.stubGlobal` to make `window.location.href` writable in the test environment).
|
||||
- Mount `SettingsCloudTab` with a stubbed auth store that has a valid accessToken.
|
||||
- Find a Connect button for a provider with `key === 'google_drive'` and trigger a click event simulating `handleConnect({ key: 'google_drive' })`.
|
||||
- Assert: `initiateOAuth` was called with `'google_drive'`.
|
||||
- Assert: `window.location.href` was set to `'https://accounts.google.com/o/oauth2/auth?state=xyz'` (the exact URL returned by the mock — confirming the component navigates to `data.url` and not directly to `/api/cloud/...`).
|
||||
- Use `afterEach(() => vi.restoreAllMocks())`.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /Users/nik/Documents/Progamming/document_scanner/frontend && npm run build 2>&1 | tail -5</automated>
|
||||
<automated>cd /Users/nik/Documents/Progamming/document_scanner/frontend && npm run test -- --reporter=verbose --run src/components/settings/__tests__/SettingsCloudTab.test.js 2>&1 | tail -20 && npm run build 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>Frontend build passes with zero errors. All four UI changes are applied: OAuth uses fetch, ERROR rows have Edit button, Nextcloud watch handler preserves custom endpoint, ConfirmBlock message has break-words.</done>
|
||||
<done>Vitest test for handleConnect OAuth flow passes. Frontend build passes with zero errors. All four UI changes are applied: OAuth uses fetch, ERROR rows have Edit button, Nextcloud watch handler preserves custom endpoint, ConfirmBlock message has break-words.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
@@ -196,6 +211,7 @@ From frontend/src/components/ui/ConfirmBlock.vue:
|
||||
<verification>
|
||||
After both tasks complete:
|
||||
- `pytest backend/tests/test_cloud.py::test_oauth_initiate_returns_json_url backend/tests/test_cloud.py::test_oauth_initiate_requires_auth -v`
|
||||
- `npm run test -- --run src/components/settings/__tests__/SettingsCloudTab.test.js` — Vitest test for handleConnect OAuth flow passes
|
||||
- `npm run build` — zero errors
|
||||
- Manual: click Connect on Google Drive — browser navigates to accounts.google.com (not localhost 401)
|
||||
- Manual: edit Nextcloud connection with custom endpoint — Advanced section opens with endpoint pre-filled
|
||||
@@ -205,8 +221,9 @@ After both tasks complete:
|
||||
|
||||
<success_criteria>
|
||||
- oauth_initiate returns 200 JSON {url} (not 302 redirect)
|
||||
- Two new pytest tests pass for OAuth initiate
|
||||
- Two new pytest tests pass for OAuth initiate; mock uses explicit `mock_flow.authorization_url.return_value = ("https://accounts.google.com/test", "state123")` two-tuple
|
||||
- handleConnect in SettingsCloudTab uses fetch() + initiateOAuth(); no window.location.href to /api path
|
||||
- Vitest test asserts initiateOAuth called with provider key and window.location.href set to returned URL
|
||||
- ERROR status template block has Edit button for non-OAuth providers
|
||||
- CloudCredentialModal watch handler repopulates customEndpoint and showAdvanced when stored URL differs from auto-constructed pattern
|
||||
- ConfirmBlock message paragraph has break-words class
|
||||
|
||||
Reference in New Issue
Block a user