mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 15:51:00 +00:00
8b6a65023f
Brings the native apps branch up to dev (NestJS-only server, MikroORM
repositories, tracked sessions, per-domain locales, the lint ratchets) and
ports its new code onto that architecture:
- server: /api/auth/native moves onto injected services. The session is
minted by the auth domain's new LoginSessionService (login bookkeeping and
SessionsService.issue in one transaction), the one-time codes live behind a
NativeHandoffStore port with a capped in-memory implementation that drops
expired codes on write instead of running a timer, both routes declare
response contracts, and the exchange answers { success: true }. Unit and
e2e suites run on createTestModule and the ORM factories.
- shared: native strings for az, et, sk and th, native wired into every
locale, the address placeholder as a full URL.
- client: the account and export changes go into dev's shared hooks
(useAccountSettings, useTripExport), the native server card is a
desktop/phone pair on useNativeServer, the hand-off call moves out of the
page hook into native/, best-effort native failures go through
reportError instead of the console, and the address screen is known to
knip and lint:i18n-keys.
- package-lock.json regenerated on Linux.
48 lines
2.1 KiB
TypeScript
48 lines
2.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { downloadBlob, downloadFile, openFile } from '../../../src/utils/fileDownload'
|
|
import { shareFile } from '../../../src/native/nativeFiles'
|
|
|
|
vi.mock('../../../src/db/offlineDb', () => ({ getCachedBlob: vi.fn() }))
|
|
vi.mock('../../../src/native/platform', () => ({ isNativeApp: () => true }))
|
|
vi.mock('../../../src/native/nativeFiles', async () => {
|
|
const actual = await vi.importActual<typeof import('../../../src/native/nativeFiles')>('../../../src/native/nativeFiles')
|
|
return { ...actual, shareFile: vi.fn() }
|
|
})
|
|
|
|
const pdf = new Blob(['%PDF'], { type: 'application/pdf' })
|
|
|
|
beforeEach(() => {
|
|
vi.mocked(shareFile).mockReset().mockResolvedValue()
|
|
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true, status: 200, blob: () => Promise.resolve(pdf) }))
|
|
})
|
|
|
|
describe('fileDownload inside the native app', () => {
|
|
it('hands an in-memory blob to the share sheet instead of an anchor', () => {
|
|
const click = vi.spyOn(HTMLAnchorElement.prototype, 'click')
|
|
downloadBlob(pdf, 'report.pdf')
|
|
expect(shareFile).toHaveBeenCalledWith(pdf, 'report.pdf')
|
|
expect(click).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('logs a share that failed rather than losing it', async () => {
|
|
const report = vi.fn()
|
|
vi.stubGlobal('reportError', report)
|
|
vi.mocked(shareFile).mockRejectedValue(new Error('no space'))
|
|
downloadBlob(pdf, 'report.pdf')
|
|
await vi.waitFor(() => expect(report).toHaveBeenCalledWith(expect.any(Error)))
|
|
})
|
|
|
|
it('shares a protected file under its given name, or the one from its URL', async () => {
|
|
await downloadFile('/api/trips/1/files/2/download', 'Boarding pass.pdf')
|
|
expect(shareFile).toHaveBeenLastCalledWith(pdf, 'Boarding pass.pdf')
|
|
|
|
await downloadFile('/uploads/files/ticket%20A.pdf')
|
|
expect(shareFile).toHaveBeenLastCalledWith(pdf, 'ticket A.pdf')
|
|
})
|
|
|
|
it('opens files through the share sheet too, since there is no tab to open them in', async () => {
|
|
await openFile('/api/trips/1/files/2/download')
|
|
expect(shareFile).toHaveBeenLastCalledWith(pdf, 'download')
|
|
})
|
|
})
|