style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
@@ -11,23 +11,23 @@
|
||||
* They will turn GREEN in Plan 03-06 when the implementation is added.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
||||
import { renderHook, act } from '@testing-library/react'
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
|
||||
// This import fails (RED) — InstallPrompt.tsx does not exist yet.
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore intentional RED import
|
||||
import { isIOSSafariNonStandalone, useAndroidInstallPrompt } from './InstallPrompt.js'
|
||||
import { isIOSSafariNonStandalone, useAndroidInstallPrompt } from './InstallPrompt.js';
|
||||
|
||||
// Capture the original navigator descriptors so we can restore them
|
||||
const originalUserAgent = navigator.userAgent
|
||||
const originalUserAgent = navigator.userAgent;
|
||||
|
||||
function setUserAgent(ua: string) {
|
||||
Object.defineProperty(navigator, 'userAgent', {
|
||||
value: ua,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function setStandalone(value: boolean) {
|
||||
@@ -36,7 +36,7 @@ function setStandalone(value: boolean) {
|
||||
value,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
describe('isIOSSafariNonStandalone', () => {
|
||||
@@ -46,91 +46,91 @@ describe('isIOSSafariNonStandalone', () => {
|
||||
value: originalUserAgent,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
})
|
||||
});
|
||||
// Remove standalone mock
|
||||
Object.defineProperty(navigator, 'standalone', {
|
||||
value: undefined,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it('returns true for an iOS Safari non-standalone UA', () => {
|
||||
setUserAgent(
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_4 like Mac OS X) ' +
|
||||
'AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Mobile/15E148 Safari/604.1',
|
||||
)
|
||||
setStandalone(false)
|
||||
);
|
||||
setStandalone(false);
|
||||
|
||||
expect(isIOSSafariNonStandalone()).toBe(true)
|
||||
})
|
||||
expect(isIOSSafariNonStandalone()).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when running in standalone mode (PWA installed)', () => {
|
||||
setUserAgent(
|
||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_4 like Mac OS X) ' +
|
||||
'AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Mobile/15E148 Safari/604.1',
|
||||
)
|
||||
setStandalone(true)
|
||||
);
|
||||
setStandalone(true);
|
||||
|
||||
expect(isIOSSafariNonStandalone()).toBe(false)
|
||||
})
|
||||
expect(isIOSSafariNonStandalone()).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for an Android Chrome UA', () => {
|
||||
setUserAgent(
|
||||
'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 ' +
|
||||
'(KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36',
|
||||
)
|
||||
setStandalone(false)
|
||||
);
|
||||
setStandalone(false);
|
||||
|
||||
expect(isIOSSafariNonStandalone()).toBe(false)
|
||||
})
|
||||
})
|
||||
expect(isIOSSafariNonStandalone()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useAndroidInstallPrompt', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('sets canInstall=true when a beforeinstallprompt event is dispatched', () => {
|
||||
const { result } = renderHook(() => useAndroidInstallPrompt())
|
||||
expect(result.current.canInstall).toBe(false)
|
||||
const { result } = renderHook(() => useAndroidInstallPrompt());
|
||||
expect(result.current.canInstall).toBe(false);
|
||||
|
||||
const mockPromptEvent = new Event('beforeinstallprompt') as Event & {
|
||||
prompt: () => Promise<void>
|
||||
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>
|
||||
}
|
||||
mockPromptEvent.prompt = vi.fn().mockResolvedValue(undefined)
|
||||
mockPromptEvent.userChoice = Promise.resolve({ outcome: 'accepted' })
|
||||
prompt: () => Promise<void>;
|
||||
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
|
||||
};
|
||||
mockPromptEvent.prompt = vi.fn().mockResolvedValue(undefined);
|
||||
mockPromptEvent.userChoice = Promise.resolve({ outcome: 'accepted' });
|
||||
|
||||
act(() => {
|
||||
window.dispatchEvent(mockPromptEvent)
|
||||
})
|
||||
window.dispatchEvent(mockPromptEvent);
|
||||
});
|
||||
|
||||
expect(result.current.canInstall).toBe(true)
|
||||
})
|
||||
expect(result.current.canInstall).toBe(true);
|
||||
});
|
||||
|
||||
it('sets canInstall=false when appinstalled event fires', () => {
|
||||
const { result } = renderHook(() => useAndroidInstallPrompt())
|
||||
const { result } = renderHook(() => useAndroidInstallPrompt());
|
||||
|
||||
// First fire beforeinstallprompt to set canInstall=true
|
||||
const mockPromptEvent = new Event('beforeinstallprompt') as Event & {
|
||||
prompt: () => Promise<void>
|
||||
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>
|
||||
}
|
||||
mockPromptEvent.prompt = vi.fn().mockResolvedValue(undefined)
|
||||
mockPromptEvent.userChoice = Promise.resolve({ outcome: 'dismissed' })
|
||||
prompt: () => Promise<void>;
|
||||
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
|
||||
};
|
||||
mockPromptEvent.prompt = vi.fn().mockResolvedValue(undefined);
|
||||
mockPromptEvent.userChoice = Promise.resolve({ outcome: 'dismissed' });
|
||||
|
||||
act(() => {
|
||||
window.dispatchEvent(mockPromptEvent)
|
||||
})
|
||||
window.dispatchEvent(mockPromptEvent);
|
||||
});
|
||||
|
||||
expect(result.current.canInstall).toBe(true)
|
||||
expect(result.current.canInstall).toBe(true);
|
||||
|
||||
// Now fire appinstalled — should reset canInstall to false
|
||||
act(() => {
|
||||
window.dispatchEvent(new Event('appinstalled'))
|
||||
})
|
||||
window.dispatchEvent(new Event('appinstalled'));
|
||||
});
|
||||
|
||||
expect(result.current.canInstall).toBe(false)
|
||||
})
|
||||
})
|
||||
expect(result.current.canInstall).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user