mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
425 lines
13 KiB
TypeScript
425 lines
13 KiB
TypeScript
import { OrganizationAccessScope, ProjectAccessScope, TargetAccessScope } from '@app/gql/graphql';
|
|
import {
|
|
answerOrganizationTransferRequest,
|
|
getOrganizationTransferRequest,
|
|
requestOrganizationTransfer,
|
|
} from '../../../testkit/flow';
|
|
import { initSeed } from '../../../testkit/seed';
|
|
|
|
test.concurrent(
|
|
'accessing non-existing ownership transfer request should result in null',
|
|
async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization } = await createOrg();
|
|
|
|
const transferRequestResult = await getOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code: 'non-existing-code',
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(transferRequestResult.organizationTransferRequest).toBeNull();
|
|
},
|
|
);
|
|
|
|
test.concurrent('owner should be able to request the ownership transfer to a member', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member, memberEmail } = await inviteAndJoinMember();
|
|
|
|
const transferRequestResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(transferRequestResult.requestOrganizationTransfer.ok?.email).toBe(memberEmail);
|
|
});
|
|
|
|
test.concurrent('non-owner should not be able to request the ownership transfer', async () => {
|
|
const { createOrg, ownerEmail } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember, members } = await createOrg();
|
|
const { memberToken } = await inviteAndJoinMember();
|
|
const orgMembers = await members();
|
|
|
|
const errors = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: orgMembers.find(u => u.user.email === ownerEmail)!.id,
|
|
},
|
|
memberToken,
|
|
).then(r => r.expectGraphQLErrors());
|
|
|
|
expect(errors).toBeDefined();
|
|
expect(errors.length).toBe(1);
|
|
});
|
|
|
|
test.concurrent(
|
|
'owner should not be able to request the ownership transfer to non-member',
|
|
async () => {
|
|
const { createOrg } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { memberToken, member } = await inviteAndJoinMember();
|
|
|
|
const transferRequestResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
memberToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(transferRequestResult.requestOrganizationTransfer?.error?.message).toBeDefined();
|
|
},
|
|
);
|
|
|
|
test.concurrent('non-member should not be able to access the transfer request', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const { ownerToken: nonMemberToken } = await initSeed().createOwner();
|
|
|
|
const errors = await getOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
},
|
|
nonMemberToken,
|
|
).then(r => r.expectGraphQLErrors());
|
|
|
|
expect(errors).toBeDefined();
|
|
expect(errors.length).toBe(1);
|
|
});
|
|
|
|
test.concurrent('non-recipient should not be able to access the transfer request', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member } = await inviteAndJoinMember();
|
|
const { memberToken: lonelyMemberToken } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const requestResult = await getOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
},
|
|
lonelyMemberToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(requestResult.organizationTransferRequest).toBeNull();
|
|
});
|
|
|
|
test.concurrent('recipient should be able to access the transfer request', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member, memberToken } = await inviteAndJoinMember();
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const requestResult = await getOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
},
|
|
memberToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(requestResult.organizationTransferRequest).not.toBeNull();
|
|
});
|
|
|
|
test.concurrent('recipient should be able to answer the ownership transfer', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member, memberToken } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const answerResult = await answerOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
accept: true,
|
|
},
|
|
memberToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(answerResult.answerOrganizationTransferRequest.ok?.accepted).toBe(true);
|
|
});
|
|
|
|
test.concurrent('non-member should not be able to answer the ownership transfer', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member } = await inviteAndJoinMember();
|
|
const { memberToken: lonelyMemberToken } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const answerResult = await answerOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
accept: true,
|
|
},
|
|
lonelyMemberToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(answerResult.answerOrganizationTransferRequest.error?.message).toBeDefined();
|
|
});
|
|
|
|
test.concurrent('owner should not be able to answer the ownership transfer', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const answerResult = await answerOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
accept: true,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(answerResult.answerOrganizationTransferRequest.error?.message).toBeDefined();
|
|
});
|
|
|
|
test.concurrent('non-member should not be able to answer the ownership transfer', async () => {
|
|
const { createOrg, ownerToken } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember } = await createOrg();
|
|
const { member } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const { ownerToken: nonMemberToken } = await initSeed().createOwner();
|
|
const answerResult = await answerOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
accept: true,
|
|
},
|
|
nonMemberToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(answerResult.answerOrganizationTransferRequest.error?.message).toBeDefined();
|
|
});
|
|
|
|
test.concurrent(
|
|
'previous owner should keep the ownership until the new owner accepts the transfer',
|
|
async () => {
|
|
const { createOrg, ownerToken, ownerEmail } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember, members } = await createOrg();
|
|
const { member } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const orgMembers = await members();
|
|
|
|
if (!orgMembers) {
|
|
throw new Error('Could not get members');
|
|
}
|
|
|
|
// current owner
|
|
const owner = orgMembers.find(m => m.user.email === ownerEmail)!;
|
|
expect(orgMembers.find(m => m.id === owner.id)).toEqual(
|
|
expect.objectContaining({
|
|
organizationAccessScopes: owner.organizationAccessScopes,
|
|
projectAccessScopes: owner.projectAccessScopes,
|
|
targetAccessScopes: owner.targetAccessScopes,
|
|
}),
|
|
);
|
|
|
|
// potential new owner
|
|
expect(orgMembers.find(m => m.id === member.id)).toEqual(
|
|
expect.objectContaining({
|
|
organizationAccessScopes: member.organizationAccessScopes,
|
|
projectAccessScopes: member.projectAccessScopes,
|
|
targetAccessScopes: member.targetAccessScopes,
|
|
}),
|
|
);
|
|
},
|
|
);
|
|
|
|
test.concurrent(
|
|
'previous owner should lose only "delete" rights, new owner should get all access',
|
|
async () => {
|
|
const { createOrg, ownerToken, ownerEmail } = await initSeed().createOwner();
|
|
const { organization, inviteAndJoinMember, members } = await createOrg();
|
|
const { member, memberToken } = await inviteAndJoinMember();
|
|
const { member: lonelyMember } = await inviteAndJoinMember();
|
|
|
|
const requestTransferResult = await requestOrganizationTransfer(
|
|
{
|
|
organization: organization.cleanId,
|
|
user: member.id,
|
|
},
|
|
ownerToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
const code = requestTransferResult.requestOrganizationTransfer.ok?.code;
|
|
|
|
if (!code) {
|
|
throw new Error('Could not create transfer request');
|
|
}
|
|
|
|
const answerResult = await answerOrganizationTransferRequest(
|
|
{
|
|
organization: organization.cleanId,
|
|
code,
|
|
accept: true,
|
|
},
|
|
memberToken,
|
|
).then(r => r.expectNoGraphQLErrors());
|
|
|
|
expect(answerResult.answerOrganizationTransferRequest.ok?.accepted).toBe(true);
|
|
|
|
const orgMembers = await members();
|
|
|
|
if (!orgMembers) {
|
|
throw new Error('Could not get members');
|
|
}
|
|
|
|
// previous owner should lose only "delete" rights
|
|
const owner = orgMembers.find(m => m.user.email === ownerEmail)!;
|
|
expect(orgMembers.find(m => m.id === owner.id)).toEqual(
|
|
expect.objectContaining({
|
|
organizationAccessScopes: owner.organizationAccessScopes.filter(
|
|
s => s !== OrganizationAccessScope.Delete,
|
|
),
|
|
projectAccessScopes: owner.projectAccessScopes.filter(s => s !== ProjectAccessScope.Delete),
|
|
targetAccessScopes: owner.targetAccessScopes.filter(s => s !== TargetAccessScope.Delete),
|
|
}),
|
|
);
|
|
|
|
// new owner should get all access
|
|
expect(orgMembers.find(m => m.id === member.id)).toEqual(
|
|
expect.objectContaining({
|
|
organizationAccessScopes: expect.arrayContaining([
|
|
...owner.organizationAccessScopes,
|
|
OrganizationAccessScope.Delete,
|
|
]),
|
|
projectAccessScopes: expect.arrayContaining([
|
|
...owner.projectAccessScopes,
|
|
ProjectAccessScope.Delete,
|
|
]),
|
|
targetAccessScopes: expect.arrayContaining([
|
|
...owner.targetAccessScopes,
|
|
TargetAccessScope.Delete,
|
|
]),
|
|
}),
|
|
);
|
|
|
|
// other members should not be affected
|
|
expect(orgMembers.find(m => m.id === lonelyMember.id)).toEqual(
|
|
expect.objectContaining({
|
|
organizationAccessScopes: lonelyMember.organizationAccessScopes,
|
|
projectAccessScopes: lonelyMember.projectAccessScopes,
|
|
targetAccessScopes: lonelyMember.targetAccessScopes,
|
|
}),
|
|
);
|
|
},
|
|
);
|