Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 131 additions & 4 deletions apps/sim/blocks/blocks/gitlab.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ describe('GitLabBlock access operations', () => {
}
})

it('exposes the named access-level dropdown with GitLab integer ids', () => {
it('exposes the named access-level combobox with GitLab integer ids', () => {
const accessLevel = block.subBlocks.find((s) => s.id === 'accessLevel')
expect(accessLevel?.type).toBe('dropdown')
// A combobox (not a dropdown) so the level can be bound to a runtime reference.
expect(accessLevel?.type).toBe('combobox')
const options = typeof accessLevel?.options === 'function' ? undefined : accessLevel?.options
expect(options?.map((o) => o.id)).toEqual(['0', '5', '10', '15', '20', '25', '30', '40', '50'])
expect(accessLevel?.value?.()).toBe('30')
})

it('coerces the selected access level from the dropdown string to an integer at execution time', () => {
it('coerces the selected access level from the combobox string to an integer at execution time', () => {
const addParams = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_add_member',
Expand All @@ -55,6 +56,69 @@ describe('GitLabBlock access operations', () => {
expect(typeof addParams?.accessLevel).toBe('number')
})

it('accepts an access level bound by name (from a resolved reference) and coerces it', () => {
const byName = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_add_member',
resourceType: 'group',
resourceId: '42',
userId: '7',
accessLevel: 'Developer',
})
expect(byName).toMatchObject({ userId: 7, accessLevel: 30 })
expect(typeof byName?.accessLevel).toBe('number')
})

it('accepts a runtime-resolved numeric 0 ("No access") on a required op', () => {
// A reference can resolve to the number 0; a truthiness guard would wrongly
// reject it as missing. It must pass and coerce to 0.
const byZero = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_add_member',
resourceType: 'group',
resourceId: '42',
userId: '7',
accessLevel: 0,
})
expect(byZero).toMatchObject({ userId: 7, accessLevel: 0 })
expect(byZero?.accessLevel).toBe(0)
})

it('sends a numeric 0 on optional ops instead of silently omitting it', () => {
const approve = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_approve_access_request',
resourceType: 'group',
resourceId: '42',
userId: '7',
accessLevel: 0,
})
expect(approve?.accessLevel).toBe(0)

const invite = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_update_invitation',
resourceType: 'group',
resourceId: '42',
email: 'a@b.com',
invitationAccessLevel: 0,
})
expect(invite?.accessLevel).toBe(0)
})

it('throws loudly when a resolved access level is not a valid GitLab level', () => {
expect(() =>
block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_add_member',
resourceType: 'group',
resourceId: '42',
userId: '7',
accessLevel: 'root',
})
).toThrow(/access level/i)
})

it('defaults list members to inherited members (directOnly falsy)', () => {
const listParams = block.tools.config.params?.({
accessToken: 'pat',
Expand Down Expand Up @@ -117,7 +181,7 @@ describe('GitLabBlock access operations', () => {

it('exposes an optional access-level dropdown for update invitation that defaults to unchanged', () => {
const invAccess = block.subBlocks.find((s) => s.id === 'invitationAccessLevel')
expect(invAccess?.type).toBe('dropdown')
expect(invAccess?.type).toBe('combobox')
expect(invAccess?.value?.()).toBe('')
const options = typeof invAccess?.options === 'function' ? undefined : invAccess?.options
expect(options?.[0]).toEqual({ label: 'Leave unchanged', id: '' })
Expand Down Expand Up @@ -158,3 +222,66 @@ describe('GitLabBlock access operations', () => {
).toThrow()
})
})

describe('GitLabBlock group operations', () => {
it('registers and routes the new group/membership operations', () => {
for (const toolId of [
'gitlab_list_groups',
'gitlab_get_group',
'gitlab_list_user_memberships',
]) {
expect(block.tools.access).toContain(toolId)
expect(block.tools.config.tool?.({ operation: toolId })).toBe(toolId)
}
})

it('maps list-groups filters to tool params', () => {
const params = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_list_groups',
owned: true,
searchQuery: 'plat',
groupsTopLevelOnly: true,
perPage: '50',
page: '2',
})
expect(params).toMatchObject({
owned: true,
search: 'plat',
topLevelOnly: true,
perPage: 50,
page: 2,
})
})

it('requires a group id for get group', () => {
expect(() =>
block.tools.config.params?.({ accessToken: 'pat', operation: 'gitlab_get_group' })
).toThrow(/group id/i)

const params = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_get_group',
groupId: ' parent/child ',
})
expect(params).toMatchObject({ groupId: 'parent/child' })
})

it('requires a user id for list user memberships and forwards the type filter', () => {
expect(() =>
block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_list_user_memberships',
})
).toThrow(/user id/i)

const params = block.tools.config.params?.({
accessToken: 'pat',
operation: 'gitlab_list_user_memberships',
userId: '7',
membershipType: 'Namespace',
perPage: '25',
})
expect(params).toMatchObject({ userId: '7', membershipType: 'Namespace', perPage: 25 })
})
})
Loading