Merge tests
This commit is contained in:
parent
3c081843f0
commit
2586f30548
File diff suppressed because it is too large
Load Diff
|
@ -1,534 +0,0 @@
|
|||
import tk from "timekeeper"
|
||||
import _ from "lodash"
|
||||
import { mocks, structures } from "@budibase/backend-core/tests"
|
||||
import {
|
||||
ScimGroupResponse,
|
||||
ScimUpdateRequest,
|
||||
ScimUserResponse,
|
||||
} from "@budibase/types"
|
||||
import { TestConfiguration } from "../../../../../tests"
|
||||
|
||||
mocks.licenses.useScimIntegration()
|
||||
|
||||
describe("/api/global/scim/v2/groups", () => {
|
||||
beforeEach(() => {
|
||||
tk.freeze(mocks.date.MOCK_DATE)
|
||||
|
||||
mocks.licenses.useScimIntegration()
|
||||
})
|
||||
|
||||
const config = new TestConfiguration()
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.beforeAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await config.afterAll()
|
||||
})
|
||||
|
||||
const featureDisabledResponse = {
|
||||
error: {
|
||||
code: "feature_disabled",
|
||||
featureName: "scim",
|
||||
},
|
||||
message: "scim is not currently enabled",
|
||||
status: 400,
|
||||
}
|
||||
|
||||
describe("GET /api/global/scim/v2/groups", () => {
|
||||
const getScimGroups = config.api.scimGroupsAPI.get
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await getScimGroups({
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await getScimGroups({ expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
describe("no groups exist", () => {
|
||||
it("should retrieve empty list", async () => {
|
||||
const response = await getScimGroups()
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: [],
|
||||
itemsPerPage: 0,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 1,
|
||||
totalResults: 0,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("multiple groups exist", () => {
|
||||
const groupCount = 25
|
||||
let groups: ScimGroupResponse[]
|
||||
|
||||
beforeAll(async () => {
|
||||
groups = []
|
||||
|
||||
for (let i = 0; i < groupCount; i++) {
|
||||
const body = structures.scim.createGroupRequest()
|
||||
groups.push(await config.api.scimGroupsAPI.post({ body }))
|
||||
}
|
||||
|
||||
groups = groups.sort((a, b) => (a.id > b.id ? 1 : -1))
|
||||
})
|
||||
|
||||
it("can fetch all groups without filters", async () => {
|
||||
const response = await getScimGroups()
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: expect.arrayContaining(groups),
|
||||
itemsPerPage: 25,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 1,
|
||||
totalResults: groupCount,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /api/global/scim/v2/groups", () => {
|
||||
const postScimGroup = config.api.scimGroupsAPI.post
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.useNewTenant()
|
||||
})
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await postScimGroup(
|
||||
{ body: {} as any },
|
||||
{
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
}
|
||||
)
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await postScimGroup({ body: {} as any }, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
describe("no groups exist", () => {
|
||||
it("a new group can be created and persisted", async () => {
|
||||
const mockedTime = new Date(structures.generator.timestamp())
|
||||
tk.freeze(mockedTime)
|
||||
|
||||
const groupData = {
|
||||
externalId: structures.uuid(),
|
||||
displayName: structures.generator.word(),
|
||||
}
|
||||
const body = structures.scim.createGroupRequest(groupData)
|
||||
|
||||
const response = await postScimGroup({ body })
|
||||
|
||||
const expectedScimGroup = {
|
||||
schemas: ["urn:ietf:params:scim:schemas:core:2.0:Group"],
|
||||
id: expect.any(String),
|
||||
externalId: groupData.externalId,
|
||||
displayName: groupData.displayName,
|
||||
meta: {
|
||||
resourceType: "Group",
|
||||
created: mockedTime.toISOString(),
|
||||
lastModified: mockedTime.toISOString(),
|
||||
},
|
||||
members: [],
|
||||
}
|
||||
expect(response).toEqual(expectedScimGroup)
|
||||
|
||||
const persistedGroups = await config.api.scimGroupsAPI.get()
|
||||
expect(persistedGroups).toEqual(
|
||||
expect.objectContaining({
|
||||
totalResults: 1,
|
||||
Resources: [expectedScimGroup],
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("GET /api/global/scim/v2/groups/:id", () => {
|
||||
let group: ScimGroupResponse
|
||||
|
||||
beforeEach(async () => {
|
||||
const body = structures.scim.createGroupRequest()
|
||||
|
||||
group = await config.api.scimGroupsAPI.post({ body })
|
||||
})
|
||||
|
||||
const findScimGroup = config.api.scimGroupsAPI.find
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await findScimGroup(group.id, {
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await findScimGroup(group.id, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
it("should return existing group", async () => {
|
||||
const response = await findScimGroup(group.id)
|
||||
|
||||
expect(response).toEqual(group)
|
||||
})
|
||||
|
||||
it("should return 404 when requesting unexisting group id", async () => {
|
||||
const response = await findScimGroup(structures.uuid(), { expect: 404 })
|
||||
|
||||
expect(response).toEqual({
|
||||
message: "missing",
|
||||
status: 404,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("DELETE /api/global/scim/v2/groups/:id", () => {
|
||||
const deleteScimGroup = config.api.scimGroupsAPI.delete
|
||||
|
||||
let group: ScimGroupResponse
|
||||
|
||||
beforeEach(async () => {
|
||||
const body = structures.scim.createGroupRequest()
|
||||
|
||||
group = await config.api.scimGroupsAPI.post({ body })
|
||||
})
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await deleteScimGroup(group.id, {
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await deleteScimGroup(group.id, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
it("an existing group can be deleted", async () => {
|
||||
const response = await deleteScimGroup(group.id, { expect: 204 })
|
||||
|
||||
expect(response).toEqual({})
|
||||
|
||||
await config.api.scimGroupsAPI.find(group.id, { expect: 404 })
|
||||
})
|
||||
|
||||
it("an non existing group can not be deleted", async () => {
|
||||
await deleteScimGroup(structures.uuid(), { expect: 404 })
|
||||
})
|
||||
})
|
||||
|
||||
describe("PATCH /api/global/scim/v2/groups/:id", () => {
|
||||
const patchScimGroup = config.api.scimGroupsAPI.patch
|
||||
|
||||
let group: ScimGroupResponse
|
||||
let users: ScimUserResponse[]
|
||||
|
||||
beforeAll(async () => {
|
||||
users = []
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const body = structures.scim.createUserRequest()
|
||||
users.push(await config.api.scimUsersAPI.post({ body }))
|
||||
}
|
||||
|
||||
users = users.sort((a, b) => (a.id > b.id ? 1 : -1))
|
||||
|
||||
const body = structures.scim.createGroupRequest()
|
||||
group = await config.api.scimGroupsAPI.post({ body })
|
||||
})
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await patchScimGroup({} as any, {
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await patchScimGroup({} as any, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
it("an existing group can be updated", async () => {
|
||||
const newDisplayName = structures.generator.word()
|
||||
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Replace",
|
||||
path: "displayName",
|
||||
value: newDisplayName,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimGroup({ id: group.id, body })
|
||||
|
||||
const expectedScimGroup = {
|
||||
...group,
|
||||
displayName: newDisplayName,
|
||||
}
|
||||
expect(response).toEqual(expectedScimGroup)
|
||||
|
||||
const persistedGroup = await config.api.scimGroupsAPI.find(group.id)
|
||||
expect(persistedGroup).toEqual(expectedScimGroup)
|
||||
})
|
||||
|
||||
describe("adding users", () => {
|
||||
beforeAll(async () => {
|
||||
const body = structures.scim.createGroupRequest()
|
||||
group = await config.api.scimGroupsAPI.post({ body })
|
||||
})
|
||||
|
||||
it("a new user can be added to an existing group", async () => {
|
||||
const userToAdd = users[0]
|
||||
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Add",
|
||||
path: "members",
|
||||
value: [
|
||||
{
|
||||
$ref: null,
|
||||
value: userToAdd.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimGroup({ id: group.id, body })
|
||||
|
||||
const expectedScimGroup: ScimGroupResponse = {
|
||||
...group,
|
||||
members: [
|
||||
{
|
||||
value: userToAdd.id,
|
||||
},
|
||||
],
|
||||
}
|
||||
expect(response).toEqual(expectedScimGroup)
|
||||
|
||||
const persistedGroup = await config.api.scimGroupsAPI.find(group.id)
|
||||
expect(persistedGroup).toEqual(expectedScimGroup)
|
||||
})
|
||||
|
||||
it("multiple users can be added to an existing group", async () => {
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Add",
|
||||
path: "members",
|
||||
value: [
|
||||
{
|
||||
$ref: null,
|
||||
value: users[1].id,
|
||||
},
|
||||
{
|
||||
$ref: null,
|
||||
value: users[2].id,
|
||||
},
|
||||
{
|
||||
$ref: null,
|
||||
value: users[3].id,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimGroup({ id: group.id, body })
|
||||
|
||||
const expectedScimGroup: ScimGroupResponse = {
|
||||
...group,
|
||||
members: [
|
||||
{
|
||||
value: users[0].id,
|
||||
},
|
||||
{
|
||||
value: users[1].id,
|
||||
},
|
||||
{
|
||||
value: users[2].id,
|
||||
},
|
||||
{
|
||||
value: users[3].id,
|
||||
},
|
||||
],
|
||||
}
|
||||
expect(response).toEqual(expectedScimGroup)
|
||||
|
||||
const persistedGroup = await config.api.scimGroupsAPI.find(group.id)
|
||||
expect(persistedGroup).toEqual(expectedScimGroup)
|
||||
})
|
||||
|
||||
it("existing users can be removed from to an existing group", async () => {
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Remove",
|
||||
path: "members",
|
||||
value: [
|
||||
{
|
||||
$ref: null,
|
||||
value: users[0].id,
|
||||
},
|
||||
{
|
||||
$ref: null,
|
||||
value: users[2].id,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimGroup({ id: group.id, body })
|
||||
|
||||
const expectedScimGroup: ScimGroupResponse = {
|
||||
...group,
|
||||
members: expect.arrayContaining([
|
||||
{
|
||||
value: users[1].id,
|
||||
},
|
||||
{
|
||||
value: users[3].id,
|
||||
},
|
||||
]),
|
||||
}
|
||||
expect(response).toEqual(expectedScimGroup)
|
||||
|
||||
const persistedGroup = await config.api.scimGroupsAPI.find(group.id)
|
||||
expect(persistedGroup).toEqual(expectedScimGroup)
|
||||
})
|
||||
|
||||
it("adding and removing can be added in a single operation", async () => {
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Remove",
|
||||
path: "members",
|
||||
value: [
|
||||
{
|
||||
$ref: null,
|
||||
value: users[1].id,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
op: "Add",
|
||||
path: "members",
|
||||
value: [
|
||||
{
|
||||
$ref: null,
|
||||
value: users[4].id,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimGroup({ id: group.id, body })
|
||||
|
||||
const expectedScimGroup: ScimGroupResponse = {
|
||||
...group,
|
||||
members: expect.arrayContaining([
|
||||
{
|
||||
value: users[3].id,
|
||||
},
|
||||
{
|
||||
value: users[4].id,
|
||||
},
|
||||
]),
|
||||
}
|
||||
expect(response).toEqual(expectedScimGroup)
|
||||
|
||||
const persistedGroup = await config.api.scimGroupsAPI.find(group.id)
|
||||
expect(persistedGroup).toEqual(expectedScimGroup)
|
||||
})
|
||||
|
||||
it("adding members and updating fields can performed in a single operation", async () => {
|
||||
const newDisplayName = structures.generator.word()
|
||||
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Replace",
|
||||
path: "displayName",
|
||||
value: newDisplayName,
|
||||
},
|
||||
{
|
||||
op: "Add",
|
||||
path: "members",
|
||||
value: [
|
||||
{
|
||||
$ref: null,
|
||||
value: users[5].id,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimGroup({ id: group.id, body })
|
||||
|
||||
const expectedScimGroup: ScimGroupResponse = {
|
||||
...group,
|
||||
displayName: newDisplayName,
|
||||
members: expect.arrayContaining([
|
||||
{
|
||||
value: users[3].id,
|
||||
},
|
||||
{
|
||||
value: users[4].id,
|
||||
},
|
||||
{
|
||||
value: users[5].id,
|
||||
},
|
||||
]),
|
||||
}
|
||||
expect(response).toEqual(expectedScimGroup)
|
||||
|
||||
const persistedGroup = await config.api.scimGroupsAPI.find(group.id)
|
||||
expect(persistedGroup).toEqual(expectedScimGroup)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,500 +0,0 @@
|
|||
import tk from "timekeeper"
|
||||
import _ from "lodash"
|
||||
import { events } from "@budibase/backend-core"
|
||||
import { mocks, structures } from "@budibase/backend-core/tests"
|
||||
import { ScimUpdateRequest, ScimUserResponse } from "@budibase/types"
|
||||
import { TestConfiguration } from "../../../../../tests"
|
||||
|
||||
mocks.licenses.useScimIntegration()
|
||||
|
||||
describe("/api/global/scim/v2/users", () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks()
|
||||
mocks.licenses.useScimIntegration()
|
||||
})
|
||||
|
||||
const config = new TestConfiguration()
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.beforeAll()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await config.afterAll()
|
||||
})
|
||||
|
||||
const featureDisabledResponse = {
|
||||
error: {
|
||||
code: "feature_disabled",
|
||||
featureName: "scim",
|
||||
},
|
||||
message: "scim is not currently enabled",
|
||||
status: 400,
|
||||
}
|
||||
|
||||
describe("GET /api/global/scim/v2/users", () => {
|
||||
const getScimUsers = config.api.scimUsersAPI.get
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await getScimUsers({
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await getScimUsers({ expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
describe("no users exist", () => {
|
||||
it("should retrieve empty list", async () => {
|
||||
const response = await getScimUsers()
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: [],
|
||||
itemsPerPage: 20,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 1,
|
||||
totalResults: 0,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("multiple users exist", () => {
|
||||
const userCount = 30
|
||||
let users: ScimUserResponse[]
|
||||
|
||||
beforeAll(async () => {
|
||||
users = []
|
||||
|
||||
for (let i = 0; i < userCount; i++) {
|
||||
const body = structures.scim.createUserRequest()
|
||||
users.push(await config.api.scimUsersAPI.post({ body }))
|
||||
}
|
||||
|
||||
users = users.sort((a, b) => (a.id > b.id ? 1 : -1))
|
||||
})
|
||||
|
||||
it("fetches full first page", async () => {
|
||||
const response = await getScimUsers()
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: expect.arrayContaining(users.slice(0, 20)),
|
||||
itemsPerPage: 20,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 1,
|
||||
totalResults: userCount,
|
||||
})
|
||||
})
|
||||
|
||||
it("fetches second page", async () => {
|
||||
const response = await getScimUsers({ params: { startIndex: 20 } })
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: users.slice(20),
|
||||
itemsPerPage: 20,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 21,
|
||||
totalResults: userCount,
|
||||
})
|
||||
})
|
||||
|
||||
it("can filter by user name", async () => {
|
||||
const userToFetch = _.sample(users)
|
||||
|
||||
const response = await getScimUsers({
|
||||
params: {
|
||||
filter: encodeURI(`userName eq "${userToFetch?.userName}"`),
|
||||
},
|
||||
})
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: [userToFetch],
|
||||
itemsPerPage: 20,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 1,
|
||||
totalResults: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it("can filter by external id", async () => {
|
||||
const userToFetch = _.sample(users)
|
||||
|
||||
const response = await getScimUsers({
|
||||
params: {
|
||||
filter: encodeURI(`externalId eq "${userToFetch?.externalId}"`),
|
||||
},
|
||||
})
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: [userToFetch],
|
||||
itemsPerPage: 20,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 1,
|
||||
totalResults: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it("can filter by email", async () => {
|
||||
const userToFetch = _.sample(users)
|
||||
|
||||
const response = await getScimUsers({
|
||||
params: {
|
||||
filter: encodeURI(
|
||||
`emails[type eq "work"].value eq "${userToFetch?.emails[0].value}"`
|
||||
),
|
||||
},
|
||||
})
|
||||
|
||||
expect(response).toEqual({
|
||||
Resources: [userToFetch],
|
||||
itemsPerPage: 20,
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||
startIndex: 1,
|
||||
totalResults: 1,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /api/global/scim/v2/users", () => {
|
||||
const postScimUser = config.api.scimUsersAPI.post
|
||||
|
||||
beforeAll(async () => {
|
||||
await config.useNewTenant()
|
||||
})
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await postScimUser(
|
||||
{ body: {} as any },
|
||||
{
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
}
|
||||
)
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await postScimUser({ body: {} as any }, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
describe("no users exist", () => {
|
||||
it("a new user can be created and persisted", async () => {
|
||||
const mockedTime = new Date(structures.generator.timestamp())
|
||||
tk.freeze(mockedTime)
|
||||
|
||||
const userData = {
|
||||
externalId: structures.uuid(),
|
||||
email: structures.generator.email(),
|
||||
firstName: structures.generator.first(),
|
||||
lastName: structures.generator.last(),
|
||||
username: structures.generator.name(),
|
||||
}
|
||||
const body = structures.scim.createUserRequest(userData)
|
||||
|
||||
const response = await postScimUser({ body })
|
||||
|
||||
const expectedScimUser = {
|
||||
schemas: ["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
id: expect.any(String),
|
||||
externalId: userData.externalId,
|
||||
meta: {
|
||||
resourceType: "User",
|
||||
created: mockedTime.toISOString(),
|
||||
lastModified: mockedTime.toISOString(),
|
||||
},
|
||||
userName: userData.username,
|
||||
name: {
|
||||
formatted: `${userData.firstName} ${userData.lastName}`,
|
||||
familyName: userData.lastName,
|
||||
givenName: userData.firstName,
|
||||
},
|
||||
active: true,
|
||||
emails: [
|
||||
{
|
||||
value: userData.email,
|
||||
type: "work",
|
||||
primary: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
expect(response).toEqual(expectedScimUser)
|
||||
|
||||
const persistedUsers = await config.api.scimUsersAPI.get()
|
||||
expect(persistedUsers).toEqual(
|
||||
expect.objectContaining({
|
||||
totalResults: 1,
|
||||
Resources: [expectedScimUser],
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("an event is dispatched", async () => {
|
||||
const body = structures.scim.createUserRequest()
|
||||
|
||||
await postScimUser({ body })
|
||||
|
||||
expect(events.user.created).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("GET /api/global/scim/v2/users/:id", () => {
|
||||
let user: ScimUserResponse
|
||||
|
||||
beforeEach(async () => {
|
||||
const body = structures.scim.createUserRequest()
|
||||
|
||||
user = await config.api.scimUsersAPI.post({ body })
|
||||
})
|
||||
|
||||
const findScimUser = config.api.scimUsersAPI.find
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await findScimUser(user.id, {
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await findScimUser(user.id, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
it("should return existing user", async () => {
|
||||
const response = await findScimUser(user.id)
|
||||
|
||||
expect(response).toEqual(user)
|
||||
})
|
||||
|
||||
it("should return 404 when requesting unexisting user id", async () => {
|
||||
const response = await findScimUser(structures.uuid(), { expect: 404 })
|
||||
|
||||
expect(response).toEqual({
|
||||
message: "missing",
|
||||
status: 404,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("PATCH /api/global/scim/v2/users/:id", () => {
|
||||
const patchScimUser = config.api.scimUsersAPI.patch
|
||||
|
||||
let user: ScimUserResponse
|
||||
|
||||
beforeEach(async () => {
|
||||
const body = structures.scim.createUserRequest()
|
||||
|
||||
user = await config.api.scimUsersAPI.post({ body })
|
||||
})
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await patchScimUser({} as any, {
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await patchScimUser({} as any, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
it("an existing user can be updated", async () => {
|
||||
const newUserName = structures.generator.name()
|
||||
const newFamilyName = structures.generator.last()
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Replace",
|
||||
path: "userName",
|
||||
value: newUserName,
|
||||
},
|
||||
{
|
||||
op: "Replace",
|
||||
path: "name.familyName",
|
||||
value: newFamilyName,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimUser({ id: user.id, body })
|
||||
|
||||
const expectedScimUser: ScimUserResponse = {
|
||||
...user,
|
||||
userName: newUserName,
|
||||
name: {
|
||||
...user.name,
|
||||
familyName: newFamilyName,
|
||||
formatted: `${user.name.givenName} ${newFamilyName}`,
|
||||
},
|
||||
}
|
||||
expect(response).toEqual(expectedScimUser)
|
||||
|
||||
const persistedUser = await config.api.scimUsersAPI.find(user.id)
|
||||
expect(persistedUser).toEqual(expectedScimUser)
|
||||
})
|
||||
|
||||
it.each([false, "false", "False"])(
|
||||
"can deactive an active user (sending %s)",
|
||||
async activeValue => {
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [{ op: "Replace", path: "active", value: activeValue }],
|
||||
}
|
||||
|
||||
const response = await patchScimUser({ id: user.id, body })
|
||||
|
||||
const expectedScimUser: ScimUserResponse = {
|
||||
...user,
|
||||
active: false,
|
||||
}
|
||||
expect(response).toEqual(expectedScimUser)
|
||||
|
||||
const persistedUser = await config.api.scimUsersAPI.find(user.id)
|
||||
expect(persistedUser).toEqual(expectedScimUser)
|
||||
}
|
||||
)
|
||||
|
||||
it.each([true, "true", "True"])(
|
||||
"can activate an inactive user (sending %s)",
|
||||
async activeValue => {
|
||||
// Deactivate user
|
||||
await patchScimUser({
|
||||
id: user.id,
|
||||
body: {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [{ op: "Replace", path: "active", value: true }],
|
||||
},
|
||||
})
|
||||
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [{ op: "Replace", path: "active", value: activeValue }],
|
||||
}
|
||||
|
||||
const response = await patchScimUser({ id: user.id, body })
|
||||
|
||||
const expectedScimUser: ScimUserResponse = {
|
||||
...user,
|
||||
active: true,
|
||||
}
|
||||
expect(response).toEqual(expectedScimUser)
|
||||
|
||||
const persistedUser = await config.api.scimUsersAPI.find(user.id)
|
||||
expect(persistedUser).toEqual(expectedScimUser)
|
||||
}
|
||||
)
|
||||
|
||||
it("supports updating unmapped fields", async () => {
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Add",
|
||||
path: "displayName",
|
||||
value: structures.generator.name(),
|
||||
},
|
||||
{
|
||||
op: "Add",
|
||||
path: "preferredLanguage",
|
||||
value: structures.generator.letter(),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await patchScimUser({ id: user.id, body })
|
||||
|
||||
const expectedScimUser: ScimUserResponse = {
|
||||
...user,
|
||||
}
|
||||
expect(response).toEqual(expectedScimUser)
|
||||
|
||||
const persistedUser = await config.api.scimUsersAPI.find(user.id)
|
||||
expect(persistedUser).toEqual(expectedScimUser)
|
||||
})
|
||||
|
||||
it("an event is dispatched", async () => {
|
||||
const body: ScimUpdateRequest = {
|
||||
schemas: ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
Operations: [
|
||||
{
|
||||
op: "Replace",
|
||||
path: "userName",
|
||||
value: structures.generator.name(),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
await patchScimUser({ id: user.id, body })
|
||||
|
||||
expect(events.user.updated).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe("DELETE /api/global/scim/v2/users/:id", () => {
|
||||
const deleteScimUser = config.api.scimUsersAPI.delete
|
||||
|
||||
let user: ScimUserResponse
|
||||
|
||||
beforeEach(async () => {
|
||||
const body = structures.scim.createUserRequest()
|
||||
|
||||
user = await config.api.scimUsersAPI.post({ body })
|
||||
})
|
||||
|
||||
it("unauthorised calls are not allowed", async () => {
|
||||
const response = await deleteScimUser(user.id, {
|
||||
setHeaders: false,
|
||||
expect: 403,
|
||||
})
|
||||
|
||||
expect(response).toEqual({ message: "Tenant id not set", status: 403 })
|
||||
})
|
||||
|
||||
it("cannot be called when feature is disabled", async () => {
|
||||
mocks.licenses.useCloudFree()
|
||||
const response = await deleteScimUser(user.id, { expect: 400 })
|
||||
|
||||
expect(response).toEqual(featureDisabledResponse)
|
||||
})
|
||||
|
||||
it("an existing user can be deleted", async () => {
|
||||
const response = await deleteScimUser(user.id, { expect: 204 })
|
||||
|
||||
expect(response).toEqual({})
|
||||
|
||||
await config.api.scimUsersAPI.find(user.id, { expect: 404 })
|
||||
})
|
||||
|
||||
it("an non existing user can not be deleted", async () => {
|
||||
await deleteScimUser(structures.uuid(), { expect: 404 })
|
||||
})
|
||||
|
||||
it("an event is dispatched", async () => {
|
||||
await deleteScimUser(user.id, { expect: 204 })
|
||||
|
||||
expect(events.user.deleted).toBeCalledTimes(1)
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue