Browse Source

fix: improve type safety and fix Playwright test dialog handling

**Type Safety Improvements:**
- Replace `unknown[]` with proper `SqlValue[]` type in database query methods
- Add `SqlValue` import to PlatformServiceMixin.ts for better type definitions
- Update interface definitions for `$dbGetOneRow` and `$one` methods
- Fix database row mapping to use `Array<SqlValue>` instead of `unknown[]`

**Test Reliability Fix:**
- Add backup seed modal handling to 60-new-activity.spec.ts
- Follow established dialog handling pattern from 00-noid-tests.spec.ts
- Use `waitForFunction` to detect backup seed modal appearance
- Gracefully handle modal dismissal with "No, Remind me Later" button
- Add error handling for cases where backup modal doesn't appear

**Files Changed:**
- src/utils/PlatformServiceMixin.ts: Enhanced type safety for database operations
- test-playwright/60-new-activity.spec.ts: Fixed dialog interception causing test failures

**Impact:**
- Eliminates TypeScript linting errors for database query types
- Resolves Playwright test timeout caused by backup seed modal blocking clicks
- Improves test reliability by following established dialog handling patterns
- Maintains backward compatibility while enhancing type safety

**Testing:**
- TypeScript compilation passes without errors
- Linting checks pass with improved type definitions
- Playwright test now handles backup seed modal properly
pull/188/head
Matthew Raymer 1 week ago
parent
commit
ccb1f29df4
  1. 28
      src/utils/PlatformServiceMixin.ts
  2. 16
      test-playwright/60-new-activity.spec.ts

28
src/utils/PlatformServiceMixin.ts

@ -52,7 +52,11 @@ import { logger } from "@/utils/logger";
import { Contact, ContactMaybeWithJsonStrings } from "@/db/tables/contacts";
import { Account } from "@/db/tables/accounts";
import { Temp } from "@/db/tables/temp";
import { QueryExecResult, DatabaseExecResult } from "@/interfaces/database";
import {
QueryExecResult,
DatabaseExecResult,
SqlValue,
} from "@/interfaces/database";
import {
generateInsertStatement,
generateUpdateStatement,
@ -285,7 +289,7 @@ export const PlatformServiceMixin = {
return [];
}
return result.values.map((row: unknown[]) => row[0] as string);
return result.values.map((row: SqlValue[]) => row[0] as string);
} catch (error) {
logger.error(
"[PlatformServiceMixin] Error getting available account DIDs:",
@ -498,7 +502,10 @@ export const PlatformServiceMixin = {
/**
* Enhanced database single row query method with error handling
*/
async $dbGetOneRow(sql: string, params?: unknown[]) {
async $dbGetOneRow(
sql: string,
params?: unknown[],
): Promise<SqlValue[] | undefined> {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return await (this as any).platformService.dbGetOneRow(sql, params);
@ -699,7 +706,7 @@ export const PlatformServiceMixin = {
if (availableAccounts?.values?.length) {
const accountDids = availableAccounts.values.map(
(row: unknown[]) => row[0] as string,
(row: SqlValue[]) => row[0] as string,
);
logger.debug(
"[PlatformServiceMixin] Available accounts for user selection:",
@ -749,7 +756,9 @@ export const PlatformServiceMixin = {
const result = await this.$dbQuery(
"SELECT did FROM accounts ORDER BY dateCreated, did",
);
return result?.values?.map((row: unknown[]) => row[0] as string) || [];
return (
result?.values?.map((row: Array<SqlValue>) => row[0] as string) || []
);
},
/**
@ -856,7 +865,7 @@ export const PlatformServiceMixin = {
async $one(
sql: string,
params: unknown[] = [],
): Promise<unknown[] | undefined> {
): Promise<SqlValue[] | undefined> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return await (this as any).platformService.dbGetOneRow(sql, params);
},
@ -1900,7 +1909,10 @@ export interface IPlatformServiceMixin {
params?: unknown[],
): Promise<QueryExecResult | undefined>;
$dbExec(sql: string, params?: unknown[]): Promise<DatabaseExecResult>;
$dbGetOneRow(sql: string, params?: unknown[]): Promise<unknown[] | undefined>;
$dbGetOneRow(
sql: string,
params?: unknown[],
): Promise<SqlValue[] | undefined>;
$getMasterSettings(fallback?: Settings | null): Promise<Settings | null>;
$getMergedSettings(
defaultKey: string,
@ -2004,7 +2016,7 @@ declare module "@vue/runtime-core" {
// Ultra-concise database methods (shortest possible names)
$db(sql: string, params?: unknown[]): Promise<QueryExecResult | undefined>;
$exec(sql: string, params?: unknown[]): Promise<DatabaseExecResult>;
$one(sql: string, params?: unknown[]): Promise<unknown[] | undefined>;
$one(sql: string, params?: unknown[]): Promise<SqlValue[] | undefined>;
// Query + mapping combo methods
$query<T = Record<string, unknown>>(

16
test-playwright/60-new-activity.spec.ts

@ -71,6 +71,22 @@ test('New offers for another user', async ({ page }) => {
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss info alert
await expect(page.locator('div[role="alert"] button > svg.fa-xmark')).toBeHidden(); // ensure alert is gone
// Handle backup seed modal if it appears (following 00-noid-tests.spec.ts pattern)
try {
// Wait for backup seed modal to appear
await page.waitForFunction(() => {
const alert = document.querySelector('div[role="alert"]');
return alert && alert.textContent?.includes('Backup Your Identifier Seed');
}, { timeout: 3000 });
// Dismiss backup seed modal
await page.getByRole('button', { name: 'No, Remind me Later' }).click();
await expect(page.locator('div[role="alert"]').filter({ hasText: 'Backup Your Identifier Seed' })).toBeHidden();
} catch (error) {
// Backup modal might not appear, that's okay
console.log('Backup seed modal did not appear, continuing...');
}
// make another offer to user 1
const randomString2 = Math.random().toString(36).substring(2, 5);
await page.getByTestId('offerButton').click();

Loading…
Cancel
Save