Files
openchamber/packages/web/server/lib/opencode/pwa-manifest-routes.test.js
bot-hermes b464500310 fix: PWA improvements — clean up SW, fix chin bar, add shortcuts, improve mobile support
- Remove dead precache manifest from SW (no fetch handler to consume it)
- Set empty globPatterns in vite-plugin-pwa config
- Fix bottom chin bar padding: use scaled safe-area token instead of raw inset
- Add 'New Session' PWA shortcut (client + server manifest)
- Add PWA meta tags to mobile.html (manifest, Apple icons, theme-color)
- Fix static site.webmanifest: add id/scope, correct description
- Remove duplicate apple-mobile-web-app-title from index.html
- Move SW registration to module scope (earlier, no window.load delay)
- Update manifest route tests for new shortcut order
2026-09-07 21:37:06 +00:00

141 lines
4.3 KiB
JavaScript

import { describe, expect, it } from 'vitest';
import { registerPwaManifestRoute } from './pwa-manifest-routes.js';
const createResponse = () => ({
headers: new Map(),
contentType: '',
body: '',
setHeader(name, value) {
this.headers.set(name, value);
return this;
},
type(value) {
this.contentType = value;
return this;
},
send(value) {
this.body = value;
return this;
},
});
describe('PWA manifest route', () => {
it('does not fall back to unrelated global session shortcuts for scoped manifests', async () => {
const routes = new Map();
const app = {
get(route, handler) {
routes.set(route, handler);
},
};
const originalFetch = globalThis.fetch;
const fetchCalls = [];
globalThis.fetch = async (url) => {
fetchCalls.push(String(url));
const sessions = String(url).includes('?directory=')
? []
: [
{
id: 'other-session',
title: 'Other project',
directory: '/workspace/other',
time: { updated: 2 },
},
];
return {
ok: true,
json: async () => sessions,
};
};
try {
registerPwaManifestRoute(app, {
process: { platform: 'darwin' },
resolveProjectDirectory: async () => ({ directory: '/workspace/app' }),
buildOpenCodeUrl: (route) => route,
getOpenCodeAuthHeaders: () => ({}),
readSettingsFromDiskMigrated: async () => ({}),
normalizePwaAppName: (value, fallback) => typeof value === 'string' && value.trim() ? value.trim() : fallback,
normalizePwaOrientation: (value, fallback) => typeof value === 'string' && value.trim() ? value.trim() : fallback,
});
const handler = routes.get('/manifest.webmanifest');
const res = createResponse();
await handler({ query: {} }, res);
const manifest = JSON.parse(res.body);
expect(fetchCalls).toHaveLength(2);
expect(manifest.shortcuts).toEqual([
{
name: 'New Session',
short_name: 'New',
description: 'Start a new coding session',
url: '/',
icons: [{ src: '/pwa-192.png', sizes: '192x192', type: 'image/png' }],
},
{
name: 'Appearance Settings',
short_name: 'Settings',
description: 'Open appearance settings',
url: '/?settings=appearance',
icons: [{ src: '/pwa-192.png', sizes: '192x192', type: 'image/png' }],
},
]);
} finally {
globalThis.fetch = originalFetch;
}
});
it('includes child session shortcuts for root-scoped manifests', async () => {
const routes = new Map();
const app = {
get(route, handler) {
routes.set(route, handler);
},
};
const originalFetch = globalThis.fetch;
const fetchCalls = [];
globalThis.fetch = async (url) => {
fetchCalls.push(String(url));
return {
ok: true,
json: async () => [
{
id: 'root-child',
title: 'Root child',
directory: '/workspace/app',
time: { updated: 2 },
},
],
};
};
try {
registerPwaManifestRoute(app, {
process: { platform: 'darwin' },
resolveProjectDirectory: async () => ({ directory: '/' }),
buildOpenCodeUrl: (route) => route,
getOpenCodeAuthHeaders: () => ({}),
readSettingsFromDiskMigrated: async () => ({}),
normalizePwaAppName: (value, fallback) => typeof value === 'string' && value.trim() ? value.trim() : fallback,
normalizePwaOrientation: (value, fallback) => typeof value === 'string' && value.trim() ? value.trim() : fallback,
});
const handler = routes.get('/manifest.webmanifest');
const res = createResponse();
await handler({ query: {} }, res);
const manifest = JSON.parse(res.body);
expect(fetchCalls).toEqual(['/session?directory=%2F']);
expect(manifest.shortcuts).toContainEqual({
name: 'Root child',
short_name: 'Root child',
description: 'Open recent session',
url: '/?session=root-child',
icons: [{ src: '/pwa-192.png', sizes: '192x192', type: 'image/png' }],
});
} finally {
globalThis.fetch = originalFetch;
}
});
});