mirror of
https://github.com/graphql-hive/console
synced 2026-04-27 09:27:17 +00:00
324 lines
11 KiB
TypeScript
324 lines
11 KiB
TypeScript
import { ProjectType, ResourceAssignmentModeType } from 'testkit/gql/graphql';
|
|
import { readProjectInfo, updateProjectSlug } from '../../../testkit/flow';
|
|
import { initSeed } from '../../../testkit/seed';
|
|
|
|
test.concurrent(
|
|
'creating a project should result in creating the development, staging and production targets',
|
|
async ({ expect }) => {
|
|
const { createOrg } = await initSeed().createOwner();
|
|
const { createProject } = await createOrg();
|
|
const { targets } = await createProject(ProjectType.Single);
|
|
|
|
expect(targets).toHaveLength(3);
|
|
expect(targets).toContainEqual(
|
|
expect.objectContaining({
|
|
slug: 'development',
|
|
name: 'development',
|
|
}),
|
|
);
|
|
expect(targets).toContainEqual(
|
|
expect.objectContaining({
|
|
slug: 'staging',
|
|
name: 'staging',
|
|
}),
|
|
);
|
|
expect(targets).toContainEqual(
|
|
expect.objectContaining({
|
|
slug: 'production',
|
|
name: 'production',
|
|
}),
|
|
);
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
'creating a project should return createdAt as a valid ISO date string',
|
|
async ({ expect }) => {
|
|
const { createOrg } = await initSeed().createOwner();
|
|
const { createProject } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
|
|
expect(project.createdAt).toBeDefined();
|
|
expect(typeof project.createdAt).toBe('string');
|
|
// Verify it's a valid ISO date string
|
|
const parsedDate = new Date(project.createdAt);
|
|
expect(parsedDate.toISOString()).toBe(project.createdAt);
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
'querying a project should return createdAt as a valid ISO date string',
|
|
async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
|
|
const result = await readProjectInfo(
|
|
{
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(result.project?.createdAt).toBeDefined();
|
|
expect(typeof result.project?.createdAt).toBe('string');
|
|
// Verify it matches the createdAt from the mutation
|
|
expect(result.project?.createdAt).toBe(project.createdAt);
|
|
},
|
|
);
|
|
|
|
test.concurrent(`changing a project's slug should result changing its name`, async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
|
|
const renameResult = await updateProjectSlug(
|
|
{
|
|
project: {
|
|
bySelector: {
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
},
|
|
slug: 'bar',
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(renameResult.updateProjectSlug.error).toBeNull();
|
|
expect(renameResult.updateProjectSlug.ok?.updatedProject.name).toBe('bar');
|
|
expect(renameResult.updateProjectSlug.ok?.updatedProject.slug).toBe('bar');
|
|
});
|
|
|
|
test.concurrent(
|
|
`changing a project's slug to the same value should keep the same slug`,
|
|
async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
|
|
const renameResult = await updateProjectSlug(
|
|
{
|
|
project: {
|
|
bySelector: {
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
},
|
|
slug: project.slug,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(renameResult.updateProjectSlug.error).toBeNull();
|
|
expect(renameResult.updateProjectSlug.ok?.updatedProject.name).toBe(project.slug);
|
|
expect(renameResult.updateProjectSlug.ok?.updatedProject.slug).toBe(project.slug);
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
`changing a project's slug to a taken value should result in an error`,
|
|
async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization, projects } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
const { project: project2 } = await createProject(ProjectType.Single);
|
|
|
|
const renameResult = await updateProjectSlug(
|
|
{
|
|
project: {
|
|
bySelector: {
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
},
|
|
slug: project2.slug,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(renameResult.updateProjectSlug.ok).toBeNull();
|
|
expect(renameResult.updateProjectSlug.error?.message).toBe('Project slug is already taken');
|
|
|
|
// Ensure the project slug was not changed
|
|
await expect(projects()).resolves.toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
id: project.id,
|
|
slug: project.slug,
|
|
name: project.slug,
|
|
}),
|
|
expect.objectContaining({
|
|
id: project2.id,
|
|
slug: project2.slug,
|
|
name: project2.slug,
|
|
}),
|
|
]),
|
|
);
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
`changing a project's slug to a slug taken by another organization should be possible`,
|
|
async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization } = await createOrg();
|
|
const { createProject: createProject2 } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
const { project: project2 } = await createProject2(ProjectType.Single);
|
|
|
|
const renameResult = await updateProjectSlug(
|
|
{
|
|
project: {
|
|
bySelector: {
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
},
|
|
slug: project2.slug,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(renameResult.updateProjectSlug.error).toBeNull();
|
|
expect(renameResult.updateProjectSlug.ok?.updatedProject.name).toBe(project2.slug);
|
|
expect(renameResult.updateProjectSlug.ok?.updatedProject.slug).toBe(project2.slug);
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
`changing a project's slug to "view" should result in an error`,
|
|
async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
|
|
const renameResult = await updateProjectSlug(
|
|
{
|
|
project: {
|
|
bySelector: {
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
},
|
|
slug: 'view',
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(renameResult.updateProjectSlug.ok).toBeNull();
|
|
expect(renameResult.updateProjectSlug.error?.message).toBeDefined();
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
`changing a project's slug to "new" should result in an error`,
|
|
async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
|
|
const renameResult = await updateProjectSlug(
|
|
{
|
|
project: {
|
|
bySelector: {
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
},
|
|
slug: 'new',
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(renameResult.updateProjectSlug.ok).toBeNull();
|
|
expect(renameResult.updateProjectSlug.error?.message).toBeDefined();
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
`changing a project's slug to "new" should result in an error`,
|
|
async ({ expect }) => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { createProject, organization } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
|
|
const renameResult = await updateProjectSlug(
|
|
{
|
|
project: {
|
|
bySelector: {
|
|
organizationSlug: organization.slug,
|
|
projectSlug: project.slug,
|
|
},
|
|
},
|
|
slug: 'new',
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(renameResult.updateProjectSlug.ok).toBeNull();
|
|
expect(renameResult.updateProjectSlug.error?.message).toBeDefined();
|
|
},
|
|
);
|
|
|
|
test.concurrent('prevent access to projects with assigned resources on member', async () => {
|
|
const { createOrg } = await initSeed().createOwner();
|
|
const { createProject, inviteAndJoinMember, projects: getProjects } = await createOrg();
|
|
const { project } = await createProject(ProjectType.Single);
|
|
// By default the viewer will have the "Viewer" role.
|
|
const { member, assignMemberRole, memberToken } = await inviteAndJoinMember();
|
|
|
|
// By default the user should have access to all the projects within the organization.
|
|
let projects = await getProjects(memberToken);
|
|
expect(projects).toHaveLength(1);
|
|
expect(projects.at(0)?.id).toEqual(project.id);
|
|
|
|
// Limit the users access to no projects using the "Viewer" role
|
|
await assignMemberRole({
|
|
roleId: member.role.id,
|
|
userId: member.user.id,
|
|
resources: {
|
|
mode: ResourceAssignmentModeType.Granular,
|
|
projects: [],
|
|
},
|
|
});
|
|
|
|
projects = await getProjects(memberToken);
|
|
expect(projects).toHaveLength(0);
|
|
});
|
|
|
|
test.concurrent('restrict access to single project with assigned resources on member', async () => {
|
|
const { createOrg } = await initSeed().createOwner();
|
|
const { createProject, inviteAndJoinMember, projects: getProjects } = await createOrg();
|
|
const { project: firstProject } = await createProject(ProjectType.Single);
|
|
const { project: secondProject } = await createProject(ProjectType.Single);
|
|
|
|
// By default the viewer will have the "Viewer" role.
|
|
const { member, assignMemberRole, memberToken } = await inviteAndJoinMember();
|
|
|
|
// By default the user should have access to all the projects within the organization.
|
|
let projects = await getProjects(memberToken);
|
|
expect(projects).toHaveLength(2);
|
|
expect(projects.at(0)?.id).toEqual(secondProject.id);
|
|
expect(projects.at(1)?.id).toEqual(firstProject.id);
|
|
|
|
// Limit the users access to a single project using the "Viewer" role
|
|
await assignMemberRole({
|
|
roleId: member.role.id,
|
|
userId: member.user.id,
|
|
resources: {
|
|
mode: ResourceAssignmentModeType.Granular,
|
|
projects: [
|
|
{
|
|
projectId: firstProject.id,
|
|
targets: { mode: ResourceAssignmentModeType.All },
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
projects = await getProjects(memberToken);
|
|
expect(projects).toHaveLength(1);
|
|
expect(projects.at(0)?.id).toEqual(firstProject.id);
|
|
});
|