Files
SCM-Manager/scm-ui/ui-api/src/permissions.test.ts

346 lines
10 KiB
TypeScript
Raw Normal View History

/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { setIndexLink } from "./tests/indexLinks";
import createInfiniteCachingClient from "./tests/createInfiniteCachingClient";
import {
Namespace,
Permission,
PermissionCollection,
Repository,
RepositoryRole,
RepositoryRoleCollection,
RepositoryVerbs
} from "@scm-manager/ui-types";
import fetchMock from "fetch-mock-jest";
import { renderHook } from "@testing-library/react-hooks";
import createWrapper from "./tests/createWrapper";
import {
useAvailablePermissions,
useCreatePermission,
useDeletePermission,
usePermissions,
useRepositoryVerbs,
useUpdatePermission
} from "./permissions";
import { act } from "react-test-renderer";
describe("permission hooks test", () => {
const readRole: RepositoryRole = {
name: "READ",
verbs: ["read", "pull"],
_links: {}
};
const roleCollection: RepositoryRoleCollection = {
_embedded: {
repositoryRoles: [readRole]
},
_links: {},
page: 1,
pageTotal: 1
};
const verbCollection: RepositoryVerbs = {
verbs: ["read", "pull"],
_links: {}
};
const readPermission: Permission = {
name: "trillian",
role: "READ",
verbs: [],
groupPermission: false,
_links: {
update: {
href: "/p/trillian"
}
}
};
const writePermission: Permission = {
name: "dent",
role: "WRITE",
verbs: [],
groupPermission: false,
_links: {
delete: {
href: "/p/dent"
}
}
};
const permissionsRead: PermissionCollection = {
_embedded: {
permissions: [readPermission]
},
_links: {}
};
const permissionsWrite: PermissionCollection = {
_embedded: {
permissions: [writePermission]
},
_links: {}
};
const namespace: Namespace = {
namespace: "spaceships",
_links: {
permissions: {
href: "/ns/spaceships/permissions"
}
}
};
const repository: Repository = {
namespace: "spaceships",
name: "heart-of-gold",
type: "git",
_links: {
permissions: {
href: "/r/heart-of-gold/permissions"
}
}
};
const queryClient = createInfiniteCachingClient();
beforeEach(() => {
queryClient.clear();
fetchMock.reset();
});
describe("useRepositoryVerbs tests", () => {
it("should return available verbs", async () => {
setIndexLink(queryClient, "repositoryVerbs", "/verbs");
fetchMock.get("/api/v2/verbs", verbCollection);
const { result, waitFor } = renderHook(() => useRepositoryVerbs(), {
wrapper: createWrapper(undefined, queryClient)
});
await waitFor(() => {
return !!result.current.data;
});
expect(result.current.data).toEqual(verbCollection);
});
});
describe("useAvailablePermissions tests", () => {
it("should return available roles and verbs", async () => {
queryClient.setQueryData("index", {
version: "x.y.z",
_links: {
repositoryRoles: {
href: "/roles"
},
repositoryVerbs: {
href: "/verbs"
}
}
});
fetchMock.get("/api/v2/roles", roleCollection);
fetchMock.get("/api/v2/verbs", verbCollection);
const { result, waitFor } = renderHook(() => useAvailablePermissions(), {
wrapper: createWrapper(undefined, queryClient)
});
await waitFor(() => {
return !!result.current.data;
});
expect(result.current.data?.repositoryRoles).toEqual(roleCollection._embedded.repositoryRoles);
expect(result.current.data?.repositoryVerbs).toEqual(verbCollection.verbs);
});
});
describe("usePermissions tests", () => {
const fetchPermissions = async (namespaceOrRepository: Namespace | Repository) => {
const { result, waitFor } = renderHook(() => usePermissions(namespaceOrRepository), {
wrapper: createWrapper(undefined, queryClient)
});
await waitFor(() => {
return !!result.current.data;
});
return result.current.data;
};
it("should return permissions from namespace", async () => {
fetchMock.getOnce("/api/v2/ns/spaceships/permissions", permissionsRead);
const data = await fetchPermissions(namespace);
expect(data).toEqual(permissionsRead);
});
it("should cache permissions for namespace", async () => {
fetchMock.getOnce("/api/v2/ns/spaceships/permissions", permissionsRead);
await fetchPermissions(namespace);
const data = queryClient.getQueryData(["namespace", "spaceships", "permissions"]);
expect(data).toEqual(permissionsRead);
});
it("should return permissions from repository", async () => {
fetchMock.getOnce("/api/v2/r/heart-of-gold/permissions", permissionsWrite);
const data = await fetchPermissions(repository);
expect(data).toEqual(permissionsWrite);
});
it("should cache permissions for repository", async () => {
fetchMock.getOnce("/api/v2/r/heart-of-gold/permissions", permissionsWrite);
await fetchPermissions(repository);
const data = queryClient.getQueryData(["repository", "spaceships", "heart-of-gold", "permissions"]);
expect(data).toEqual(permissionsWrite);
});
});
describe("useCreatePermission tests", () => {
const createAndFetch = async () => {
fetchMock.postOnce("/api/v2/ns/spaceships/permissions", {
status: 201,
headers: {
Location: "/ns/spaceships/permissions/42"
}
});
fetchMock.getOnce("/api/v2/ns/spaceships/permissions/42", readPermission);
const { result, waitForNextUpdate } = renderHook(() => useCreatePermission(namespace), {
wrapper: createWrapper(undefined, queryClient)
});
await act(() => {
const { create } = result.current;
create(readPermission);
return waitForNextUpdate();
});
return result.current;
};
it("should create permission", async () => {
const data = await createAndFetch();
expect(data.permission).toEqual(readPermission);
});
it("should fail without location header", async () => {
fetchMock.postOnce("/api/v2/ns/spaceships/permissions", {
status: 201
});
const { result, waitForNextUpdate } = renderHook(() => useCreatePermission(namespace), {
wrapper: createWrapper(undefined, queryClient)
});
await act(() => {
const { create } = result.current;
create(readPermission);
return waitForNextUpdate();
});
expect(result.current.error).toBeDefined();
});
it("should invalidate namespace cache", async () => {
const key = ["namespace", "spaceships", "permissions"];
queryClient.setQueryData(key, permissionsRead);
await createAndFetch();
const state = queryClient.getQueryState(key);
expect(state?.isInvalidated).toBe(true);
});
});
describe("useDeletePermission tests", () => {
const deletePermission = async () => {
fetchMock.deleteOnce("/api/v2/p/dent", {
status: 204
});
const { result, waitForNextUpdate } = renderHook(() => useDeletePermission(repository), {
wrapper: createWrapper(undefined, queryClient)
});
await act(() => {
const { remove } = result.current;
remove(writePermission);
return waitForNextUpdate();
});
return result.current;
};
const shouldInvalidateQuery = async (queryKey: string[], data: unknown) => {
queryClient.setQueryData(queryKey, data);
await deletePermission();
const queryState = queryClient.getQueryState(queryKey);
expect(queryState?.isInvalidated).toBe(true);
};
it("should delete permission", async () => {
const { isDeleted } = await deletePermission();
expect(isDeleted).toBe(true);
});
it("should invalidate permission cache", async () => {
await shouldInvalidateQuery(["repository", "spaceships", "heart-of-gold", "permissions"], permissionsWrite);
});
});
describe("useUpdatePermission tests", () => {
const updatePermission = async () => {
fetchMock.putOnce("/api/v2/p/trillian", {
status: 204
});
const { result, waitForNextUpdate } = renderHook(() => useUpdatePermission(repository), {
wrapper: createWrapper(undefined, queryClient)
});
await act(() => {
const { update } = result.current;
update(readPermission);
return waitForNextUpdate();
});
return result.current;
};
const shouldInvalidateQuery = async (queryKey: string[], data: unknown) => {
queryClient.setQueryData(queryKey, data);
await updatePermission();
const queryState = queryClient.getQueryState(queryKey);
expect(queryState?.isInvalidated).toBe(true);
};
it("should update permission", async () => {
const { isUpdated } = await updatePermission();
expect(isUpdated).toBe(true);
});
it("should invalidate permission cache", async () => {
await shouldInvalidateQuery(["repository", "spaceships", "heart-of-gold", "permissions"], permissionsRead);
});
});
});