Files
WeHub Mirror 6bf8bebf51
CI / Test and Build (push) Failing after 1s
CI / Migrate Dev DB (push) Has been skipped
CI / Migrate DB (push) Has been skipped
CodeQL / Analyze actions (push) Has been cancelled
CodeQL / Analyze javascript-typescript (push) Has been cancelled
CI / Detect Version (push) Has been cancelled
CI / Detect Desktop Changes (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/cron.Dockerfile, ubuntu-latest, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build AMD64 (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build AMD64 (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/cron.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/db.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/pii.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-4vcpu-ubuntu-2404-arm, ./docker/realtime.Dockerfile, ubuntu-24.04-arm, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (blacksmith-8vcpu-ubuntu-2404-arm, ./docker/app.Dockerfile, linux-arm64-8-core, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
Helm Chart / Lint, test, and validate chart (push) Has been cancelled
Helm Chart / Chart version bumped (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Build Dev ECR (blacksmith-8vcpu-ubuntu-2404, ./docker/app.Dockerfile, ECR_APP, linux-x64-8-core) (push) Has been cancelled
CI / Promote Images (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/cron) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-2vcpu-ubuntu-2404, ./docker/db.Dockerfile, ECR_MIGRATIONS, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/pii.Dockerfile, ECR_PII, ubuntu-latest) (push) Has been cancelled
CI / Build Dev ECR (blacksmith-4vcpu-ubuntu-2404, ./docker/realtime.Dockerfile, ECR_REALTIME, ubuntu-latest) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Check Desktop Signing Secrets (push) Has been cancelled
CI / Desktop Release (push) Has been cancelled
CI / Create Desktop Prerelease (push) Has been cancelled
CI / Desktop Prerelease Build (push) Has been cancelled
CI / Publish Desktop Prerelease (push) Has been cancelled
CI / Prune Desktop Prereleases (push) Has been cancelled
Helm Chart / Install on kind and run helm test (push) Has been cancelled
WeHub snapshot of cb28d14c6f2c081de7a0d8729a8c816c9adef67a
2026-08-10 11:17:50 +08:00

188 lines
5.7 KiB
TypeScript

/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import { gitlabGetGroupTool } from '@/tools/gitlab/get_group'
import { gitlabListGroupsTool } from '@/tools/gitlab/list_groups'
import { gitlabListUserMembershipsTool } from '@/tools/gitlab/list_user_memberships'
interface MockResponseOptions {
ok?: boolean
status?: number
json?: unknown
text?: string
headers?: Record<string, string>
}
function mockResponse({
ok = true,
status = 200,
json,
text = '',
headers = {},
}: MockResponseOptions): Response {
return {
ok,
status,
json: async () => json,
text: async () => text,
headers: {
get: (key: string) => headers[key.toLowerCase()] ?? null,
},
} as unknown as Response
}
describe('gitlab_get_group', () => {
it('builds the group endpoint and URL-encodes a namespaced path', () => {
expect(gitlabGetGroupTool.request.url({ accessToken: 'pat', groupId: '42' })).toBe(
'https://gitlab.com/api/v4/groups/42'
)
expect(gitlabGetGroupTool.request.url({ accessToken: 'pat', groupId: 'parent/child' })).toBe(
'https://gitlab.com/api/v4/groups/parent%2Fchild'
)
})
it('honors a self-managed host', () => {
expect(
gitlabGetGroupTool.request.url({
accessToken: 'pat',
host: 'gitlab.example.com',
groupId: '7',
})
).toBe('https://gitlab.example.com/api/v4/groups/7')
})
it('returns the group on success', async () => {
const result = await gitlabGetGroupTool.transformResponse?.(
mockResponse({ json: { id: 42, name: 'Platform' } }),
{} as never
)
expect(result?.success).toBe(true)
expect(result?.output.group).toEqual({ id: 42, name: 'Platform' })
})
it('surfaces API errors', async () => {
const result = await gitlabGetGroupTool.transformResponse?.(
mockResponse({ ok: false, status: 404, text: 'Not found' }),
{} as never
)
expect(result?.success).toBe(false)
expect(result?.error).toContain('404')
})
})
describe('gitlab_list_groups', () => {
it('lists groups with no filters', () => {
expect(gitlabListGroupsTool.request.url({ accessToken: 'pat' })).toBe(
'https://gitlab.com/api/v4/groups'
)
})
it('forwards filters and pagination', () => {
const url = gitlabListGroupsTool.request.url({
accessToken: 'pat',
owned: true,
search: 'plat',
topLevelOnly: true,
orderBy: 'name',
sort: 'asc',
perPage: 50,
page: 2,
})
expect(url).toBe(
'https://gitlab.com/api/v4/groups?owned=true&search=plat&top_level_only=true&order_by=name&sort=asc&per_page=50&page=2'
)
})
it('forwards the documented visibility, min-access-level, and all-available filters', () => {
const url = gitlabListGroupsTool.request.url({
accessToken: 'pat',
visibility: 'private',
minAccessLevel: 30,
allAvailable: true,
})
expect(url).toBe(
'https://gitlab.com/api/v4/groups?visibility=private&min_access_level=30&all_available=true'
)
})
it('rejects an out-of-enum minimum access level instead of sending it to GitLab', () => {
expect(() =>
gitlabListGroupsTool.request.url({ accessToken: 'pat', minAccessLevel: 31 })
).toThrow(/Invalid GitLab access level/)
expect(() =>
gitlabListGroupsTool.request.url({ accessToken: 'pat', minAccessLevel: 0 })
).toThrow(/Invalid GitLab access level/)
})
it('rejects similarity ordering without a search term, but allows it with one', () => {
expect(() =>
gitlabListGroupsTool.request.url({ accessToken: 'pat', orderBy: 'similarity' })
).toThrow(/similarity/)
expect(
gitlabListGroupsTool.request.url({
accessToken: 'pat',
orderBy: 'similarity',
search: 'plat',
})
).toBe('https://gitlab.com/api/v4/groups?search=plat&order_by=similarity')
})
it('reads the total from the x-total header, falling back to length', async () => {
const withHeader = await gitlabListGroupsTool.transformResponse?.(
mockResponse({ json: [{ id: 1 }, { id: 2 }], headers: { 'x-total': '17' } }),
{} as never
)
expect(withHeader?.output.total).toBe(17)
const withoutHeader = await gitlabListGroupsTool.transformResponse?.(
mockResponse({ json: [{ id: 1 }, { id: 2 }] }),
{} as never
)
expect(withoutHeader?.output.total).toBe(2)
})
})
describe('gitlab_list_user_memberships', () => {
it('builds the admin memberships endpoint', () => {
expect(gitlabListUserMembershipsTool.request.url({ accessToken: 'pat', userId: '7' })).toBe(
'https://gitlab.com/api/v4/users/7/memberships'
)
})
it('forwards the type filter and pagination', () => {
const url = gitlabListUserMembershipsTool.request.url({
accessToken: 'pat',
userId: '7',
membershipType: 'Namespace',
perPage: 25,
page: 3,
})
expect(url).toBe(
'https://gitlab.com/api/v4/users/7/memberships?type=Namespace&per_page=25&page=3'
)
})
it('returns memberships on success', async () => {
const result = await gitlabListUserMembershipsTool.transformResponse?.(
mockResponse({
json: [{ source_id: 1, source_name: 'grp', source_type: 'Namespace', access_level: 30 }],
headers: { 'x-total': '1' },
}),
{} as never
)
expect(result?.success).toBe(true)
expect(result?.output.memberships).toHaveLength(1)
expect(result?.output.total).toBe(1)
})
it('surfaces a 403 for a non-admin token', async () => {
const result = await gitlabListUserMembershipsTool.transformResponse?.(
mockResponse({ ok: false, status: 403, text: 'Forbidden' }),
{} as never
)
expect(result?.success).toBe(false)
expect(result?.error).toContain('403')
})
})