Commit graph

438 commits

Author SHA1 Message Date
Johannes Millan
9e65a70be4 fix(sync): sync tag.taskIds when task.tagIds changes via LWW Update
Extend the lwwUpdateMetaReducer to also sync tag.taskIds arrays when
a task's tagIds changes during LWW conflict resolution.

When LWW Update syncs a task's tagIds change to remote clients, the
reducer now:
- Removes task from tags that were removed from task.tagIds
- Adds task to tags that were added to task.tagIds

This maintains bidirectional consistency between task.tagIds and
tag.taskIds, similar to the project.taskIds fix.

Also adds:
- 7 unit tests for project.taskIds sync (project move fix)
- 8 unit tests for tag.taskIds sync (new tag fix)
- E2E test for concurrent tag changes (skipped - env dialog issues)
2025-12-27 15:50:33 +01:00
Johannes Millan
c6e9e2ee84 test(e2e): add 5 high-priority E2E tests for SuperSync
Add comprehensive E2E tests covering core sync functionality gaps:

1. Multiple Conflicts on Same Entity (supersync-lww-conflict.spec.ts)
   - Verifies LWW uses MAX timestamp across all operations
   - Tests 3 ops from each client on same task

2. Import Invalidates Pending Remote Ops (supersync-import-clean-slate.spec.ts)
   - Tests clean slate semantics for SYNC_IMPORT
   - Pending ops from other clients are filtered as CONCURRENT

3. Partial Sync Failure with Retry (supersync-network-failure.spec.ts)
   - Creates 10 tasks, fails mid-batch, retries
   - Verifies all tasks sync without duplicates

4. Tag Deletion Atomic Cleanup (supersync-models.spec.ts)
   - Creates tag with 10 tasks
   - Deletes tag, verifies atomic removal from all tasks

5. Concurrent Project Move (supersync-lww-conflict.spec.ts)
   - Tests moving same task to different projects concurrently
   - NOTE: Currently reveals bug - task projectId becomes inconsistent

Tests 1-4 pass. Test 5 exposes a real sync bug to investigate.
2025-12-27 15:16:52 +01:00
Johannes Millan
c9e78b79d7 test(sync): make e2e test work again 2025-12-27 10:38:18 +01:00
Johannes Millan
dd5741faa7 fix(sync): prevent orphan subtasks when archiving via remote sync
Add defensive fix for race condition where subtasks could become
orphaned during archive sync:
1. Client A adds subtask to parent
2. Client B does SYNC_IMPORT before parent.subTaskIds synced
3. Client A archives parent (with stale subTaskIds in operation)
4. Client B receives archive - subtask left orphaned

The fix in deleteTaskHelper now looks up subtasks from state by
parentId in addition to the payload's subTaskIds, ensuring all
subtasks are removed even if the operation payload is stale.

Adds devError logging when orphan subtasks are detected to help
diagnose upstream issues.

Tests added:
- Unit tests for orphan subtask removal in task.reducer.spec.ts
- Integration tests documenting the race condition scenario
- E2E tests for archive subtask sync across clients
2025-12-26 19:54:49 +01:00
Johannes Millan
3bf1cc348f fix(export): read archiveYoung/archiveOld from ModelCtrl for export
The PfapiStoreDelegateService was reading archive data from NgRx store,
but archives are stored in ModelCtrl (pf database), not NgRx. The NgRx
archive state is only populated on loadAllData (import) and is never
updated when ArchiveService writes to ModelCtrl during finish day.

This caused exports to contain empty/stale archiveYoung data after
archiving tasks via "Finish Day", resulting in lost subtasks.

The fix reads archiveYoung and archiveOld from ModelCtrl (via
pfapiService.m.archiveYoung.load()) instead of NgRx selectors, since
that's where the actual archive data lives.

Includes E2E test to verify subtasks are preserved in archive after
legacy data import and finish day flow.
2025-12-26 18:43:46 +01:00
Johannes Millan
6191c782f0 test(archive): add failing tests for legacy import subtask loss
Add E2E and integration tests documenting a bug where tasks with
subtasks are lost when:
1. Importing legacy data (pre-operation logs)
2. Archiving via "Finish Day"
3. Exporting again

The archiveYoung ends up empty in the export. Tests will pass
once the bug is fixed.

Files added:
- e2e/fixtures/legacy-archive-subtasks-backup.json
- e2e/tests/import-export/legacy-archive-subtasks.spec.ts
- integration/legacy-archive-subtasks.integration.spec.ts
2025-12-26 16:02:34 +01:00
Johannes Millan
5d6c211f11 test(e2e): add clean slate semantics tests for SYNC_IMPORT
Add E2E tests verifying that SYNC_IMPORT operations properly implement
clean slate semantics:

1. "Import drops ALL concurrent work from both clients" - verifies that
   when Client A imports a backup, all pre-import tasks from both
   Client A and Client B are dropped after sync propagates.

2. "Late joiner synced ops are dropped after import" - verifies that
   even if Client B synced its work before Client A imported, those
   operations are NOT replayed after receiving the SYNC_IMPORT.

These tests validate the intentional design where imports represent
explicit user actions to restore ALL clients to a specific state.
2025-12-26 12:30:40 +01:00
Johannes Millan
22ded5e048 test(e2e): improve password change test reliability
- Make snackbar detection more resilient (allow quick auto-dismiss)
- Use dialog close as primary success indicator
- Re-enable password change e2e test (was skipped)
- Use distinct task names to avoid substring matching issues
2025-12-24 21:13:50 +01:00
Johannes Millan
6a26d914b5 test: skip tmp 2025-12-24 16:27:12 +01:00
Johannes Millan
72608a4aaa feat(migration): implement pre-migration dialog and backup functionality 2025-12-24 13:49:37 +01:00
Johannes Millan
1bd96a9182 fix(sync): refresh storage cache after cleanup and add serverTime to response
Address two issues identified in code review:

1. Storage cache not refreshed after cleanup:
   - Modified deleteOldSyncedOpsForAllUsers() to return { totalDeleted, affectedUserIds }
   - Cleanup job now calls updateStorageUsage() for each affected user
   - Prevents stale quota checks after nightly cleanup

2. serverTime missing from download response:
   - Added serverTime: Date.now() to DownloadOpsResponse
   - Enables client-side clock drift detection

Tests:
- Added serverTime response test in sync-fixes.spec.ts
- Added deleteOldSyncedOpsForAllUsers return structure tests
- Updated legacy SQLite tests for new return type (excluded from CI)
2025-12-23 18:31:57 +01:00
Johannes Millan
a405b6ee6d fix: address code review issues from sync and UX changes
Critical fixes:
- fix(sync): handle empty newOps with hasMorePiggyback flag
- fix(sync): handle skippedOps (stale operations) in sync service
- fix(tasks): replace requestAnimationFrame with RxJS delay(0)

High priority fixes:
- fix(sync): add rollback recovery for password change failures
- fix(e2e): improve password change verification robustness
- fix(sync): add try-catch to WebDAV test connection
- fix(sync): improve encrypted restore error message with guidance
- fix(android): add startWith() to fix pairwise() initial state

Medium priority fixes:
- fix(sync): add diagnostics to flush timeout error
- docs: document focus delay constants and rationale
- docs: add TODO for Android reminder native action handlers
2025-12-22 21:09:18 +01:00
Johannes Millan
064c2452ca fix(sync): handle piggyback limit in high-volume sync
When syncing 100+ operations, the server's piggyback limit (100 ops)
was causing Client B to miss operations. The server returned 100 piggybacked
ops but latestSeq was set to the actual server sequence (e.g., 199).
Client B then updated lastServerSeq to 199, so subsequent download got 0 ops.

Changes:
- Server: Add hasMorePiggyback flag to UploadOpsResponse when piggyback limit
  is reached and more ops exist
- Client: When hasMorePiggyback is true, store lastServerSeq as the max
  piggybacked op's serverSeq instead of latestSeq, ensuring subsequent
  download fetches remaining ops
- Effects: Change switchMap to mergeMap in autoAddTodayTagOnMarkAsDone to
  ensure ALL mark-as-done actions trigger planTasksForToday
- Flush service: Implement two-phase wait strategy (poll queue + acquire lock)
  to ensure all pending writes complete before upload
- Add diagnostic logging for operation counts at key stages

Test: High volume sync with 50 tasks + 49 mark-as-done (197 ops total)
now correctly syncs all done states via piggyback (100) + download (97).
2025-12-22 20:31:35 +01:00
Johannes Millan
c4cc32da29 feat(sync): add encryption password change feature for SuperSync
Implements the ability to change the encryption password by deleting
all server data and uploading a fresh snapshot with the new password.

Server changes:
- Add DELETE /api/sync/data endpoint to delete all user sync data
- Add deleteAllUserData() method to SyncService

Client changes:
- Add deleteAllData() to OperationSyncCapable interface
- Implement deleteAllData() in SuperSync provider
- Add EncryptionPasswordChangeService to orchestrate password change
- Add DialogChangeEncryptionPasswordComponent with validation
- Add "Change Encryption Password" button to sync settings (visible
  when encryption is enabled)
- Add translations for all new UI strings

Testing:
- Add 10 unit tests for EncryptionPasswordChangeService
- Add 14 unit tests for DialogChangeEncryptionPasswordComponent
- Add 5 E2E tests for complete password change flow
- Add changeEncryptionPassword() helper to SuperSyncPage

Also fixes:
- Add missing deleteAllData() to MockOperationSyncProvider
- Fix typo S_FINISH_DAY_SYNC_ERROR -> FINISH_DAY_SYNC_ERROR
2025-12-22 13:31:19 +01:00
Johannes Millan
c757ff500d test(sync): re-enable sync after import in tests and adjust baseURL fallback 2025-12-22 12:08:04 +01:00
Johannes Millan
329a50957b test(e2e): add comprehensive SuperSync encryption tests
Add 4 new E2E tests for SuperSync encryption coverage:
- Multiple tasks sync correctly with encryption
- Bidirectional sync works with encryption
- Task update syncs correctly with encryption
- Long encryption password works correctly

Also clean up outdated TODO comments from header - encryption
is now working correctly.
2025-12-22 12:06:35 +01:00
Johannes Millan
58fc0b65b3 refactor(e2e): fix and improve supersync stress tests
- Fix selector bug: .check-btn -> .task-done-btn for marking tasks done
- Add required .hover() before clicking done button
- Add waitForTask() verification for stability
- Create createQuietClient() helper to suppress non-error console logs
- Reduce task counts to ensure reliable test completion
- Move stress tests from supersync-edge-cases.spec.ts to supersync-stress.spec.ts
- Bulk sync test: 10 tasks, 13 operations (~30s)
- High volume test: 20 tasks, 39 operations (~60s)
2025-12-20 11:41:56 +01:00
Johannes Millan
155e03b84c docs: remove outdated sync documentation and deprecated file
- Delete docs/ai/sync/server-sync-architecture.md which incorrectly
  stated "Status: Not Started" when server sync is fully implemented
- Delete deprecated src/app/features/time-tracking/store/archive.effects.ts
  which was empty and marked for removal
- Update local-actions.token.ts comment to reference the correct
  archive-operation-handler.effects.ts file
2025-12-20 11:09:49 +01:00
Johannes Millan
c1ea6f27b0 fix(sync): prevent deadlock when repair operation needs lock
The sp_op_log lock is non-reentrant. When validation/repair code was
called from inside the lock (during sync or conflict resolution),
createRepairOperation() tried to acquire the lock again, causing a
deadlock.

Add callerHoldsLock/skipLock parameter through the call chain:
- operation-log-sync.service.ts passes callerHoldsLock: true when inside lock
- conflict-resolution.service.ts passes callerHoldsLock: true
- validate-state.service.ts accepts and forwards the flag
- repair-operation.service.ts skips lock when skipLock: true

Also adds high-volume sync E2E test (499 operations) and fixes test
isolation in meta-reducer-ordering integration tests.
2025-12-20 10:15:38 +01:00
Johannes Millan
61e32e72b3 fix(sync): prevent false clock drift warnings and cascade conflicts
Two critical sync fixes:

1. Clock drift detection now uses serverTime from response instead of
   receivedAt from old operations. Previously, downloading 12-hour-old
   ops would falsely trigger "clock drift" warnings.

2. User interactions during sync are now blocked from creating operations.
   When HydrationStateService.startApplyingRemoteOps() is called, the
   operation-capture meta-reducer skips capturing local actions, preventing
   stale vector clocks and cascade conflicts on slow devices.

Includes comprehensive tests for both fixes and a bulk sync e2e test.
2025-12-20 01:31:07 +01:00
Johannes Millan
035f6c1baf test: fix 2025-12-19 21:21:58 +01:00
Johannes Millan
8a449fb944 fix(sync-server): compile scripts for production Docker image
ts-node is a devDependency and not available in production containers.
Updated tsconfig to compile scripts/ alongside src/, and changed npm
scripts to use compiled JS. Added monitor:dev for local development.
2025-12-19 15:58:21 +01:00
Johannes Millan
3d4bfb5637 fix(sync): improve robustness of sync and counter operations
Code review improvements addressing critical and high priority issues:

Archive Handler:
- Rollback BOTH archiveYoung and archiveOld on flush failure
- Prevents data loss when partial write occurs

Cache Invalidation:
- Add _unsyncedCache invalidation in deleteOpsWhere
- Prevents stale data when deleted ops include unsynced operations

Simple Counter:
- Extract _getCounterValue helper to reduce code duplication
- Use selectSimpleCounterById (O(1)) instead of selectAllSimpleCounters+find (O(n))
- Update tests to properly mock both selectors

Operation Log Sync:
- Add infinite loop prevention when force download returns no clocks
- Add GREATER_THAN corruption detection (treats as CONCURRENT to be safe)

ESLint Hydration Guard Rule:
- Fix combineLatest detection at root level vs nested in operator callbacks
- Add comprehensive test suite (17 test cases)

E2E Tests:
- Fix flaky reminders-schedule-page tests (tasks disappear after scheduling)
2025-12-19 11:42:56 +01:00
Johannes Millan
ab0371fac6 fix(e2e): improve supersync test stability and build compatibility
E2E test improvements:
- Increase timeouts for sync button and add task bar visibility checks
- Add retry logic for sync button wait in setupSuperSync
- Handle dialog close race conditions in save button click
- Fix simple counter test to work with collapsible sections and inline forms

Build fixes:
- Add es2022 lib/target and baseUrl to electron tsconfig
- Include window-ea.d.ts for proper type resolution
- Add @ts-ignore for import.meta.url in reminder service for Electron build
2025-12-19 09:59:44 +01:00
Johannes Millan
0d7b38db2d fix(sync): use absolute values for simple counter sync
- Click counters now sync immediately with absolute values instead of
  being batched every 5 minutes
- Stopwatch counters now sync absolute values instead of relative
  durations, fixing issue where remote clients would add duration to
  their existing value (e.g., 0:20 became 0:23)
- Remove _modifiedClickCounters batching mechanism (no longer needed)
- Add comprehensive unit tests for immediate sync behavior
- Add e2e test for simple counter sync between multiple clients
2025-12-18 17:15:17 +01:00
Johannes Millan
ea7e6cb8c9 fix(supersync): resolve e2e test failures and flakiness
- Disable server rate limiting in E2E test mode to prevent sync timeouts
- Improve SuperSync configuration dropdown stability in page object
- Add explicit waits for UI elements in daily summary tests
- Handle rate limit errors in sync wait logic defensively
2025-12-18 16:36:58 +01:00
Johannes Millan
bf65350dca fix(e2e): only treat snackbars with error keywords as sync errors
Informational snackbars like "Deleted task X Undo" and "addCreated task X"
were being incorrectly detected as sync errors. Now only snackbars containing
actual error keywords (error, failed, problem, could not, unable to) are
treated as sync failures.
2025-12-18 12:28:23 +01:00
Johannes Millan
ac36f5af67 fix(e2e): use correct nav-link selector for project navigation
The nav-item component renders a button with class 'nav-link', not an anchor tag.
Changed locators from '.nav-sidenav nav-item a:has-text(...)' to
'.nav-sidenav .nav-link:has-text(...)'.
2025-12-18 10:56:32 +01:00
Johannes Millan
144f16ae04 test(e2e): improve flaky edge case tests stability
- Use more specific nav-sidenav locators for project navigation
- Add retry logic for marking tasks as done
- Add waitForTask after task creation before syncing
- Increase settling time between operations
- Add debug logging throughout tests
2025-12-18 10:42:40 +01:00
Johannes Millan
b024d47c8b test(e2e): improve sync test stability and coverage
- Add wait calls after task creation for UI stability
- Add debug logging for test troubleshooting
- Add timeout after sync for UI to settle
- Improve test assertions with better waits
2025-12-18 10:36:22 +01:00
Johannes Millan
0b998459aa fix(e2e): fix failing tags test and flaky late-join test
- Tags test: Use right-click context menu approach instead of 'g' shortcut
  to avoid typing into editable task title
- Tags test: Add robust dismissAllOverlays helper with multiple Escape
  presses and backdrop click fallback
- Late-join test: Improve conflict dialog handling with retry loop and
  wait for dialog to close
- Late-join test: Add extra sync cycle after conflict resolution for
  more reliable data propagation
- All files: Fix incorrect port in warning messages (1900 -> 1901)

All 48 supersync e2e tests pass consistently.
2025-12-17 21:56:53 +01:00
Johannes Millan
4b8edc91ab test(sync): add compaction, performance, and network failure tests
Add comprehensive tests for operation log sync functionality:
- Compaction integration tests: snapshot creation, tail replay,
  unsynced op preservation, emergency compaction, vector clock
  preservation
- Performance integration tests: large operation handling,
  hydration speed, sync batch performance, concurrent writes
- E2E network failure tests: upload/download failure recovery,
  server error handling, pending operations sync after recovery
2025-12-17 20:13:22 +01:00
Johannes Millan
cda5e1fe1f test(e2e): add task deletion sync test and improve documentation
- Add test for task deletion syncing between clients
- Document that scheduled task tests use dueDay, not actual repeat configs
- Reference integration tests for full repeat config sync testing
2025-12-17 18:24:19 +01:00
Johannes Millan
5992fad51b fix(sync): perform archive flush synchronously to prevent DB lock error
Previously, flushYoungToOld was dispatched as an action and handled by
an NgRx effect. This caused a race condition during finish day:
1. Action dispatched, effect queued
2. Method returned, sync started, DB locked
3. Effect ran, tried to write, blocked by DB lock

Fix follows the same pattern as moveToArchive:
- Perform the flush synchronously in ArchiveService before dispatching
- Dispatch action for op-log capture only (syncs to other clients)
- Handler skips local operations (only runs for remote)

Also adds comprehensive unit tests and e2e test for this scenario.
2025-12-17 16:42:59 +01:00
Johannes Millan
d5a0258c85 fix(sync): use vector clocks for SYNC_IMPORT filtering instead of UUIDv7
Replace UUIDv7 timestamp-based filtering with vector clock comparison
in _filterOpsInvalidatedBySyncImport(). This fixes a bug where client
clock drift could cause pre-import operations to bypass filtering.

Vector clocks track causality ("did this client know about the import?")
rather than wall-clock time, making the filtering immune to clock drift.

Operations are now filtered based on comparison result:
- GREATER_THAN or EQUAL: keep (client had knowledge of import)
- LESS_THAN or CONCURRENT: filter (created without knowledge)

Also fix E2E tests to properly skip when SuperSync server isn't
running in TEST_MODE by checking test endpoint availability.
2025-12-17 14:50:50 +01:00
Johannes Millan
b08774d7e6 test(worklog): update test expectations for alphabetical sorting
Update test expectations in map-archive-to-worklog.spec.ts and E2E tests
to match the new alphabetical sorting order for worklog entries.

The sorting feature sorts tasks alphabetically while keeping subtasks
grouped with their parent tasks. This changes the expected order in tests:
- Parent tasks now sorted alphabetically (MT1 before PT1)
- Subtasks sorted alphabetically within their group (SUB_B before SUB_C)
2025-12-16 21:03:13 +01:00
Johannes Millan
ff9012b724 fix(sync): handle LWW Update actions and immediate re-upload
Two key fixes for LWW conflict resolution sync flow:

1. Add lwwUpdateMetaReducer to handle [ENTITY_TYPE] LWW Update actions
   - When Client B receives an LWW Update from Client A, the meta-reducer
     updates the NgRx store so the UI reflects changes without reload
   - Supports TASK, PROJECT, TAG, NOTE, SIMPLE_COUNTER, TASK_REPEAT_CFG

2. Propagate needsReupload flag through sync flow
   - autoResolveConflictsLWW now returns { localWinOpsCreated: number }
   - downloadRemoteOps returns needsReupload flag when local-win ops created
   - sync.service triggers second upload when needsReupload is true
   - Ensures local-win operations are uploaded in the same sync cycle

Tests added:
- Unit tests for lwwUpdateMetaReducer (10 tests)
- Integration tests for LWW Update store application (12 tests)
- E2E tests for LWW conflict resolution scenarios (6 tests)
2025-12-16 20:37:14 +01:00
Johannes Millan
4d96c8ffff feat(sync): implement LWW conflict auto-resolution
Replace manual conflict resolution dialogs with automatic Last-Write-Wins
(LWW) resolution based on operation timestamps:

- Add autoResolveConflictsLWW() to ConflictResolutionService
- When remote timestamp >= local: remote wins, local op rejected
- When local timestamp > remote: local wins, create new UPDATE op
  with current entity state and merged vector clock
- Show non-blocking snackbar notification after resolution
- Create safety backup before resolving conflicts

Includes comprehensive test coverage:
- Unit tests for ConflictResolutionService
- Integration tests for LWW timestamp comparison and vector clock merging
- E2E tests for multi-client convergence scenarios

Add detailed LWW documentation with Mermaid diagrams explaining the
algorithm, outcomes, and tradeoffs vs manual resolution.
2025-12-16 16:22:53 +01:00
Johannes Millan
f51973ee92 fix(sync): update vector clock tests to expect error on overflow
Tests were expecting silent reset to 1 on overflow, but the implementation
correctly throws an error since resetting would break causality.
2025-12-15 20:00:58 +01:00
Johannes Millan
d6db1c2885 fix(sync): use timestamp comparison for same-millisecond UUIDv7 operations
When filtering operations after a SYNC_IMPORT, the previous string
comparison `op.id > latestImport.id` could incorrectly filter out
operations created in the same millisecond due to random bits in UUIDv7.

This caused repeatable task instances to not sync when created
immediately after an import operation.

Fix: Extract the 48-bit timestamp from UUIDv7 and use >= comparison
to ensure same-millisecond operations are kept.
2025-12-15 18:27:44 +01:00
Johannes Millan
289a57b21d refactor(e2e): clean up webdav-sync-expansion test
- Remove debug console.log statements
- Extract magic numbers to named constants
- Remove unused clientName parameter from setupClient
2025-12-13 20:42:24 +01:00
Johannes Millan
d16c8f7df3 fix(e2e): scroll task into view before clicking attachment button
The task may be outside the viewport after sync on Client B.
2025-12-13 20:41:09 +01:00
Johannes Millan
4eb03914c6 fix(e2e): update snackbar undo button selector
The snackbar uses snack-custom component with button.action class,
not simple-snack-bar. Also increased timeout to 5s for reliability.
2025-12-13 20:15:42 +01:00
Johannes Millan
b1e1c1d10b fix(sync): resolve WebDAV sync regression for multi-client scenarios
- Await all saves in updateLocalMainModelsFromRemoteMetaFile() using
  Promise.all() to ensure data is fully persisted before sync completes
- Remove unreliable early return optimization in sync() that compared
  metaRev timestamps, causing incorrect InSync returns
- Add cache-busting (cache: 'no-store') to WebDAV HTTP adapter to
  prevent stale responses
- Fix E2E tests by removing page reloads that broke sync provider
  re-initialization
- Improve waitForSync test helper to properly detect new sync cycles
- Add debug logging for vector clock comparisons in sync status checks

The sync now properly detects remote changes via vector clock comparison
and uploads/downloads data correctly between multiple clients.
2025-12-13 20:10:07 +01:00
Johannes Millan
581626be34 test(e2e): add basic undo task delete test
Adds a non-sync e2e test to verify the undo delete functionality:
- Create task
- Delete task via context menu
- Click Undo in snackbar
- Verify task is restored
2025-12-13 17:59:49 +01:00
Johannes Millan
82870601a6 test(sync): add comprehensive tests for undo task delete sync
Unit tests (8 new tests in task-shared-crud.reducer.spec.ts):
- Preserve timeSpentOnDay data when restoring
- Preserve attachments when restoring
- Preserve notes, issueId, reminderId, dueWithTime
- Idempotent project restore (no duplicates on replay)
- Subtasks with their own tags restored correctly
- Position-aware restore (middle position)
- Position clamping when array shrinks

E2E test (supersync-edge-cases.spec.ts):
- Undo task delete syncs restored task to other client
- Tests full flow: create→sync→delete→undo→sync→verify
2025-12-13 17:57:30 +01:00
Johannes Millan
d6f4e6b298 test(e2e): skip failing webdav sync tests pending regression investigation
WebDAV sync expansion tests pass on master but fail on feat/operation-logs.
The sync appears to complete but remote data is not being applied.

- Skip 'should sync projects' and 'should sync task done state' tests
- Improve waitForSync with stable count fallback pattern
- Add missing dismissTour calls after page reload
2025-12-13 16:28:30 +01:00
Johannes Millan
ba49276791 test(sync): add comprehensive edge case tests for cascading deletes and data integrity
- Add unit tests for deleteTag/deleteTags in tag-shared.reducer.spec.ts:
  - Orphaned task deletion when tag is sole assignment
  - Cascade delete subtasks of orphaned parents
  - Cleanup task repeat configs referencing deleted tags
  - Cleanup time tracking state for deleted tags

- Add unit tests for project time tracking cleanup in project-shared.reducer.spec.ts

- Add E2E tests in supersync-advanced-edge-cases.spec.ts:
  - Bulk task creation (10 tasks) syncs without data loss
  - Stale client reconnection after many changes
  - Special characters in task names sync correctly

Note: Complex cascading delete E2E tests were removed as the scenarios
are better covered by unit tests due to UI timing fragility.
2025-12-13 15:13:01 +01:00
Johannes Millan
06a6b5b29b test(e2e): remove unsyncable undo and field-level merge tests
Remove two E2E tests that test functionality not currently supported:

1. "Undo propagation syncs correctly" - The undoDeleteTask action
   doesn't include task data in its payload. The restoration happens
   via a meta-reducer using locally cached state, so the undo cannot
   sync to other clients. Fixing this requires architectural changes.

2. "Field-level merging syncs correctly" - The app uses row-level
   conflict detection. Concurrent edits to different fields of the
   same entity trigger a conflict dialog rather than auto-merging.
   This is by design for the current sync architecture.

Both tests were marked with base.fixme() and have been removed rather
than kept as skipped tests since they document aspirational behavior
that would require significant changes to implement.
2025-12-13 14:18:35 +01:00
Johannes Millan
b79e8f8838 fix(sync): route ImmediateUploadService through SyncService for migration detection
When a client switches to a new/empty server, the full state snapshot
(SYNC_IMPORT) was not being uploaded because ImmediateUploadService
was calling OperationLogUploadService.uploadPendingOps() directly,
bypassing the migration detection callback in OperationLogSyncService.

Changes:
- Update OperationLogSyncService.uploadPendingOps() to return UploadResult | null
- Change ImmediateUploadService to call _syncService.uploadPendingOps()
  instead of _uploadService.uploadPendingOps() directly
- Update unit tests to reflect the new call chain
- Re-enable server-migration E2E tests (now passing)

This ensures the migration detection callback runs during immediate upload,
creating a SYNC_IMPORT when switching to a new/empty server so that other
clients joining the new server receive all data.
2025-12-13 13:54:02 +01:00