Files
TREK/client/src/api/oauthScopes.test.ts
T
jubnl da39b570eb feat(mcp): align MCP surface with current app state
- Add Journey addon tools (list, get, entries, contributors, suggestions,
  available trips, create/update/delete journey and entries, reorder,
  contributors CRUD, preferences, share link management)
- Add Journey resources (trek://journeys and sub-resources)
- Split transport (flight/train/car/cruise) into dedicated tools with
  endpoints[] and needs_review support; narrow reservation types to
  non-transport only
- Add airport lookup tools (search_airports, get_airport) under geo:read
- Add import_places_from_url and bulk_delete_places to places tools
- Add journey:read/write/share OAuth scopes (27 total) with translations
  across all 15 locales
- Default end_day to start_day when creating a transport (MCP + UI)
- Fix MCP.md drift: addon gates, removed files resource, corrected
  get_trip_summary description, todos under Packing addon
2026-04-19 16:03:32 +02:00

103 lines
3.6 KiB
TypeScript

// FE-OAUTH-SCOPES-001 to FE-OAUTH-SCOPES-010
import { describe, it, expect } from 'vitest'
import { SCOPE_GROUPS, ALL_SCOPES, SCOPE_GROUP_NAMES, getScopesByGroup } from './oauthScopes'
describe('SCOPE_GROUPS', () => {
it('FE-OAUTH-SCOPES-001: contains all expected scope keys', () => {
const expected = [
'trips:read', 'trips:write', 'trips:delete', 'trips:share',
'places:read', 'places:write',
'atlas:read', 'atlas:write',
'packing:read', 'packing:write',
'todos:read', 'todos:write',
'budget:read', 'budget:write',
'reservations:read', 'reservations:write',
'collab:read', 'collab:write',
'notifications:read', 'notifications:write',
'vacay:read', 'vacay:write',
'geo:read', 'weather:read',
]
for (const scope of expected) {
expect(SCOPE_GROUPS).toHaveProperty(scope)
}
})
it('FE-OAUTH-SCOPES-002: each scope entry has labelKey, descriptionKey, groupKey', () => {
for (const [scope, keys] of Object.entries(SCOPE_GROUPS)) {
expect(keys.labelKey, `${scope} missing labelKey`).toBeTruthy()
expect(keys.descriptionKey, `${scope} missing descriptionKey`).toBeTruthy()
expect(keys.groupKey, `${scope} missing groupKey`).toBeTruthy()
}
})
})
describe('ALL_SCOPES', () => {
it('FE-OAUTH-SCOPES-003: contains exactly 27 scopes', () => {
expect(ALL_SCOPES).toHaveLength(27)
})
it('FE-OAUTH-SCOPES-004: matches Object.keys(SCOPE_GROUPS)', () => {
expect(ALL_SCOPES).toEqual(Object.keys(SCOPE_GROUPS))
})
})
describe('SCOPE_GROUP_NAMES', () => {
it('FE-OAUTH-SCOPES-005: contains no duplicate group names', () => {
expect(SCOPE_GROUP_NAMES).toHaveLength(new Set(SCOPE_GROUP_NAMES).size)
})
it('FE-OAUTH-SCOPES-006: contains expected groups', () => {
const expected = [
'oauth.scope.group.trips',
'oauth.scope.group.places',
'oauth.scope.group.packing',
'oauth.scope.group.budget',
]
for (const g of expected) {
expect(SCOPE_GROUP_NAMES).toContain(g)
}
})
})
describe('getScopesByGroup', () => {
const identity = (key: string) => key
it('FE-OAUTH-SCOPES-007: groups all scopes under the correct group key', () => {
const groups = getScopesByGroup(identity)
// Every scope must appear exactly once across all groups
const allScopesInGroups = Object.values(groups).flat().map(s => s.scope)
expect(allScopesInGroups).toHaveLength(ALL_SCOPES.length)
for (const scope of ALL_SCOPES) {
expect(allScopesInGroups).toContain(scope)
}
})
it('FE-OAUTH-SCOPES-008: each item has scope, label, description, group', () => {
const groups = getScopesByGroup(identity)
for (const items of Object.values(groups)) {
for (const item of items) {
expect(item.scope).toBeTruthy()
expect(item.label).toBeTruthy()
expect(item.description).toBeTruthy()
expect(item.group).toBeTruthy()
}
}
})
it('FE-OAUTH-SCOPES-009: trips group contains trips:read and trips:write', () => {
const groups = getScopesByGroup(identity)
const tripsGroup = groups['oauth.scope.group.trips']
expect(tripsGroup).toBeDefined()
const scopeNames = tripsGroup.map(s => s.scope)
expect(scopeNames).toContain('trips:read')
expect(scopeNames).toContain('trips:write')
})
it('FE-OAUTH-SCOPES-010: uses translated group name as key', () => {
const t = (key: string) => key === 'oauth.scope.group.trips' ? 'Trips' : key
const groups = getScopesByGroup(t)
expect(groups['Trips']).toBeDefined()
expect(groups['oauth.scope.group.trips']).toBeUndefined()
})
})