Files
TREK/client/tests/helpers/mobileAdmin.ts
T
Maurice 31859651d7 feat(help): rewrite the help center for v5 with a Tours section, new pictures in every language, and fix the tour planner bugs it surfaced
Every help screen checked against the v5 redesign. Tours is documented for
the first time, as a screen of its own with twelve screens under it, and
notifications get help of their own. All pictures are taken again on a
realistic demo trip, with short loops where a still cannot show the motion.
The English is plain and every language is written naturally rather than
word for word.

The switcher shows two levels at most, a screen's overview lists its
sub-screens as cards above its guides, each wiki page is linked once, and
the help sidebar is wider.

Fixes found along the way: Save to Collection keeps a tour's route, a track
dropped on the places column opens the Tours import, tour Share on desktop,
the unsaved tour draft lives on the account, a route click no longer adds
an end point, Trip places leaves the trip's tours out, Escape closes a
stage's day menu, confirms before destructive deletes, DWD warnings sharing
one id kept apart, a booking's date moves with it, and smaller fixes across
notifications, bookings, the day plan, stays, Atlas, Collections, Vacay and
the admin screens.
2026-10-22 22:29:35 +02:00

200 lines
6.0 KiB
TypeScript

import { vi } from 'vitest';
import type { useAdmin } from '../../src/pages/admin/useAdmin';
import type { AdminUser } from '../../src/pages/admin/adminModel';
/**
* Fixture for the mobile admin sections. MAdminUsersSection, MAdminSettingsSection
* and MAdminSheets are pure presentation over the useAdmin() bag, so tests render
* them with this builder instead of mounting MAdmin and its data loading.
*
* Defaults are the "nothing configured yet" state; every setter and handler is a
* spy so tests can assert the exact call, including state updater functions.
*/
export type AdminHook = ReturnType<typeof useAdmin>;
export function buildAdminUser(overrides: Partial<AdminUser> = {}): AdminUser {
return {
id: 1,
username: 'admin',
email: 'admin@example.com',
role: 'admin',
created_at: '2025-01-01T00:00:00.000Z',
avatar_url: null,
...overrides,
};
}
export function buildAdminToast(): Record<string, ReturnType<typeof vi.fn>> {
return { success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn() };
}
export function buildAdminHook(overrides: Record<string, unknown> = {}): AdminHook {
const base: Record<string, unknown> = {
// store-derived
demoMode: false,
serverTimezone: 'UTC',
hour12: false,
mcpEnabled: false,
devMode: false,
managed: false,
currentUser: buildAdminUser(),
updateApiKeys: vi.fn(async () => undefined),
setAppRequireMfa: vi.fn(),
setTripRemindersEnabled: vi.fn(),
setPlacesPhotosEnabled: vi.fn(),
setPlacesAutocompleteEnabled: vi.fn(),
setPlacesDetailsEnabled: vi.fn(),
setPlacesEnrichEnabled: vi.fn(),
logout: vi.fn(async () => undefined),
navigate: vi.fn(),
toast: buildAdminToast(),
// users
activeTab: 'users',
setActiveTab: vi.fn(),
users: [] as AdminUser[],
setUsers: vi.fn(),
stats: null,
isLoading: false,
editingUser: null,
setEditingUser: vi.fn(),
editForm: { username: '', email: '', role: 'user', password: '' },
setEditForm: vi.fn(),
showCreateUser: false,
setShowCreateUser: vi.fn(),
createForm: { username: '', email: '', password: '', role: 'user' },
setCreateForm: vi.fn(),
// feature flags
bagTrackingEnabled: false,
setBagTrackingEnabled: vi.fn(),
placesPhotosEnabled: false,
setPlacesPhotosEnabledState: vi.fn(),
placesAutocompleteEnabled: false,
setPlacesAutocompleteEnabledState: vi.fn(),
placesDetailsEnabled: false,
setPlacesDetailsEnabledState: vi.fn(),
placesEnrichEnabled: true,
placesGoogleOnly: false,
handleTogglePlacesGoogleOnly: vi.fn(),
setPlacesEnrichEnabledState: vi.fn(),
// Fail-open on the server, so the harness starts where an unset row lands.
trekPlacesEnabled: true,
setTrekPlacesEnabledState: vi.fn(),
placeShadowEnabled: false,
setPlaceShadowEnabledState: vi.fn(),
collabFeatures: { chat: true, notes: true, polls: true, whatsnext: true },
setCollabFeatures: vi.fn(),
// auth / OIDC
oidcConfig: {
issuer: '',
client_id: '',
client_secret: '',
client_secret_set: false,
display_name: '',
discovery_url: '',
},
setOidcConfig: vi.fn(),
savingOidc: false,
setSavingOidc: vi.fn(),
passwordLogin: true,
setPasswordLogin: vi.fn(),
passwordRegistration: true,
setPasswordRegistration: vi.fn(),
oidcLogin: false,
setOidcLogin: vi.fn(),
oidcRegistration: false,
setOidcRegistration: vi.fn(),
envOverrideOidcOnly: false,
setEnvOverrideOidcOnly: vi.fn(),
oidcConfigured: false,
setOidcConfigured: vi.fn(),
requireMfa: false,
setRequireMfa: vi.fn(),
passkeyLogin: false,
setPasskeyLogin: vi.fn(),
passkeyConfigured: false,
webauthnRpId: '',
setWebauthnRpId: vi.fn(),
webauthnOrigins: '',
setWebauthnOrigins: vi.fn(),
savingWebauthn: false,
handleSaveWebauthn: vi.fn(),
// invites
invites: [] as unknown[],
setInvites: vi.fn(),
inviteTrips: [] as { id: number; title: string }[],
showCreateInvite: false,
setShowCreateInvite: vi.fn(),
inviteForm: { max_uses: 1, expires_in_days: 7, trip_id: '' },
setInviteForm: vi.fn(),
// misc settings
allowedFileTypes: 'jpg,png,pdf',
setAllowedFileTypes: vi.fn(),
savingFileTypes: false,
setSavingFileTypes: vi.fn(),
smtpValues: {},
setSmtpValues: vi.fn(),
smtpLoaded: true,
mapsKey: '',
setMapsKey: vi.fn(),
weatherKey: '',
setWeatherKey: vi.fn(),
unsplashKey: '',
setUnsplashKey: vi.fn(),
amapKey: '',
setAmapKey: vi.fn(),
hasMapsKey: false,
hasAmapKey: false,
// No key set by the environment unless a test says so (#1881).
keyInputProps: () => ({ disabled: false, placeholder: 'Enter key...' }),
placesProvider: 'auto',
savingPlacesProvider: false,
showKeys: {},
setShowKeys: vi.fn(),
savingKeys: false,
validating: {},
validation: {},
// update / danger zone
updateInfo: null,
setUpdateInfo: vi.fn(),
showUpdateModal: false,
setShowUpdateModal: vi.fn(),
showRotateJwtModal: false,
setShowRotateJwtModal: vi.fn(),
rotatingJwt: false,
setRotatingJwt: vi.fn(),
// handlers
loadData: vi.fn(),
loadAppConfig: vi.fn(),
loadApiKeys: vi.fn(),
handleToggleAuthSetting: vi.fn(),
handleToggleRequireMfa: vi.fn(),
toggleKey: vi.fn(),
handleSaveApiKeys: vi.fn(),
handleValidateKeys: vi.fn(),
handleValidateKey: vi.fn(),
handleSavePlacesProvider: vi.fn(),
handleCreateUser: vi.fn(),
handleCreateInvite: vi.fn(),
handleDeleteInvite: vi.fn(),
inviteToDelete: null,
setInviteToDelete: vi.fn(),
copyInviteLink: vi.fn(),
handleEditUser: vi.fn(),
handleSaveUser: vi.fn(),
handleDeleteUser: vi.fn(),
};
// Derived like the hook does, so a test that only sets mapsKey keeps its Test button.
const merged = { ...base, ...overrides };
if (!('mapsKeyTestable' in overrides)) merged.mapsKeyTestable = !!merged.mapsKey;
return merged as unknown as AdminHook;
}