mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
fix(test): fix CI test failures on Windows and macOS
- Windows: ArchiveStoreService now includes complete DB upgrade logic to create all object stores when it opens the database first. This fixes 411 IndexedDB "object store not found" errors that occurred when browser state was cleared between test runs. - macOS: Increase timing threshold in lock.service.spec.ts from 200ms to 500ms to account for CI machine variability in the "should not starve any request" test.
This commit is contained in:
parent
9d77aa2d3f
commit
b987fecb7c
2 changed files with 51 additions and 15 deletions
|
|
@ -1,7 +1,13 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { IDBPDatabase, openDB } from 'idb';
|
||||
import { ArchiveModel } from '../../features/time-tracking/time-tracking.model';
|
||||
import { DB_NAME, DB_VERSION, STORE_NAMES, SINGLETON_KEY } from './db-keys.const';
|
||||
import {
|
||||
DB_NAME,
|
||||
DB_VERSION,
|
||||
STORE_NAMES,
|
||||
SINGLETON_KEY,
|
||||
OPS_INDEXES,
|
||||
} from './db-keys.const';
|
||||
|
||||
/**
|
||||
* Entry stored in archive_young or archive_old object stores.
|
||||
|
|
@ -56,23 +62,51 @@ export class ArchiveStoreService {
|
|||
/**
|
||||
* Opens the SUP_OPS database for archive operations.
|
||||
*
|
||||
* IMPORTANT: This includes an upgrade callback to ensure archive stores are created
|
||||
* even if ArchiveStoreService opens the database before OperationLogStoreService.
|
||||
* IMPORTANT: This includes the COMPLETE upgrade callback to ensure ALL stores
|
||||
* are created if ArchiveStoreService opens the database before OperationLogStoreService.
|
||||
* IndexedDB only runs ONE upgrade callback per version transition, so whichever
|
||||
* service opens the DB first will create the stores.
|
||||
* service opens the DB first MUST create all stores.
|
||||
*
|
||||
* This is critical for test environments where browser state may be cleared between
|
||||
* test runs, causing a fresh database to be created by whichever service initializes first.
|
||||
*/
|
||||
private async _init(): Promise<void> {
|
||||
this._db = await openDB<ArchiveDBSchema>(DB_NAME, DB_VERSION, {
|
||||
upgrade: (db, oldVersion) => {
|
||||
// Version 4: Add archive stores (same logic as OperationLogStoreService)
|
||||
// This ensures stores are created even if this service opens the DB first.
|
||||
upgrade: (db, oldVersion, _newVersion, transaction) => {
|
||||
// IMPORTANT: This must mirror OperationLogStoreService.init() upgrade logic exactly!
|
||||
// If this service opens the DB first, it must create ALL stores.
|
||||
|
||||
// Version 1: Create initial stores
|
||||
if (oldVersion < 1) {
|
||||
const opStore = db.createObjectStore(STORE_NAMES.OPS, {
|
||||
keyPath: 'seq',
|
||||
autoIncrement: true,
|
||||
});
|
||||
opStore.createIndex(OPS_INDEXES.BY_ID, 'op.id', { unique: true });
|
||||
opStore.createIndex(OPS_INDEXES.BY_SYNCED_AT, 'syncedAt');
|
||||
|
||||
db.createObjectStore(STORE_NAMES.STATE_CACHE, { keyPath: 'id' });
|
||||
db.createObjectStore(STORE_NAMES.IMPORT_BACKUP, { keyPath: 'id' });
|
||||
}
|
||||
|
||||
// Version 2: Add vector_clock store for atomic writes
|
||||
if (oldVersion < 2) {
|
||||
db.createObjectStore(STORE_NAMES.VECTOR_CLOCK);
|
||||
}
|
||||
|
||||
// Version 3: Add compound index for efficient source+status queries
|
||||
if (oldVersion < 3) {
|
||||
const opStore = transaction.objectStore(STORE_NAMES.OPS);
|
||||
opStore.createIndex(OPS_INDEXES.BY_SOURCE_AND_STATUS, [
|
||||
'source',
|
||||
'applicationStatus',
|
||||
]);
|
||||
}
|
||||
|
||||
// Version 4: Add archive stores for archiveYoung and archiveOld
|
||||
if (oldVersion < 4) {
|
||||
if (!db.objectStoreNames.contains(STORE_NAMES.ARCHIVE_YOUNG)) {
|
||||
db.createObjectStore(STORE_NAMES.ARCHIVE_YOUNG, { keyPath: 'id' });
|
||||
}
|
||||
if (!db.objectStoreNames.contains(STORE_NAMES.ARCHIVE_OLD)) {
|
||||
db.createObjectStore(STORE_NAMES.ARCHIVE_OLD, { keyPath: 'id' });
|
||||
}
|
||||
db.createObjectStore(STORE_NAMES.ARCHIVE_YOUNG, { keyPath: 'id' });
|
||||
db.createObjectStore(STORE_NAMES.ARCHIVE_OLD, { keyPath: 'id' });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -316,9 +316,11 @@ describe('LockService', () => {
|
|||
expect(startTimes.size).toBe(10);
|
||||
expect(endTimes.size).toBe(10);
|
||||
|
||||
// Check no request waited unreasonably long (more than 200ms for 10 requests)
|
||||
// Check no request waited unreasonably long (more than 500ms for 10 requests)
|
||||
// Note: Using 500ms threshold to account for CI machine variability
|
||||
// Theoretical max is ~63ms (sum of work times), but CI can add significant overhead
|
||||
const maxWait = Math.max(...Array.from(startTimes.values()));
|
||||
expect(maxWait).toBeLessThan(200);
|
||||
expect(maxWait).toBeLessThan(500);
|
||||
});
|
||||
|
||||
it('should maintain correct execution order for FIFO-like behavior', async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue