Skip to content

Commit

Permalink
feat: allow user to request membership (#1424)
Browse files Browse the repository at this point in the history
* feat: allow user to request membership

* feat: update membership request table
  • Loading branch information
pyphilia authored Sep 23, 2024
1 parent c99b9d1 commit ddb0012
Show file tree
Hide file tree
Showing 65 changed files with 2,298 additions and 1,311 deletions.
10 changes: 4 additions & 6 deletions cypress/e2e/invitations/editInvitation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PermissionLevel } from '@graasp/sdk';
import { buildItemPath } from '../../../src/config/paths';
import {
ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS,
buildInvitationTableRowSelector,
buildInvitationTableRowId,
buildPermissionOptionId,
buildShareButtonId,
} from '../../../src/config/selectors';
Expand All @@ -19,13 +19,11 @@ const editInvitation = ({
permission: PermissionLevel;
}) => {
cy.get(`#${buildShareButtonId(itemId)}`).click();
const select = cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS}`,
);
cy.get(`#${buildInvitationTableRowId(id)} [aria-label="Edit"]`).click();
const select = cy.get(`.${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS}`);
select.click();
select.get(`#${buildPermissionOptionId(permission)}`).click();
cy.get('button[type="submit"]').click();
};

describe('Edit Invitation', () => {
Expand Down
96 changes: 47 additions & 49 deletions cypress/e2e/invitations/viewInvitation.cy.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,84 @@
import { buildItemPath } from '../../../src/config/paths';
import { PackedFolderItemFactory, PermissionLevel } from '@graasp/sdk';
import { namespaces } from '@graasp/translations';

import i18n from '@/config/i18n';

import { buildItemPath, buildItemSharePath } from '../../../src/config/paths';
import {
ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS,
ITEM_RESEND_INVITATION_BUTTON_CLASS,
buildInvitationTableRowSelector,
buildInvitationTableRowId,
buildItemInvitationRowDeleteButtonId,
buildShareButtonId,
} from '../../../src/config/selectors';
import {
ITEMS_WITH_INVITATIONS,
ITEM_WITH_INVITATIONS_WRITE_ACCESS,
} from '../../fixtures/invitations';
import { ITEMS_WITH_INVITATIONS } from '../../fixtures/invitations';
import { CURRENT_USER, MEMBERS } from '../../fixtures/members';

describe('View Invitations', () => {
beforeEach(() => {
cy.setUpApi(ITEMS_WITH_INVITATIONS);
});

it('view invitation in share item modal', () => {
i18n.changeLanguage(CURRENT_USER.extra.lang);
const item = ITEMS_WITH_INVITATIONS.items[1];
const { invitations } = item;
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();
cy.visit(buildItemSharePath(item.id));

invitations.forEach(
({ item: { path: itemPath }, id, email, permission }) => {
cy.get(buildInvitationTableRowSelector(id)).should('contain', email);

if (itemPath !== item.path) {
cy.get(`#${buildItemInvitationRowDeleteButtonId(id)}`).should(
'be.disabled',
);
}
cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS} input`,
).should('have.value', permission);
cy.get(`#${buildInvitationTableRowId(id)}`)
.should('contain', email)
.should('contain', i18n.t(permission, { ns: namespaces.enums }));

cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_RESEND_INVITATION_BUTTON_CLASS}`,
`#${buildInvitationTableRowId(id)} .${ITEM_RESEND_INVITATION_BUTTON_CLASS}`,
).should('exist');
},
);
});
});

describe('View Invitations Read-Only Mode', () => {
beforeEach(() => {
cy.setUpApi({ ...ITEM_WITH_INVITATIONS_WRITE_ACCESS });
});
describe('Cannot view Invitations for writers and readers', () => {
it('view invitation in share item modal write-only mode', () => {
const item = PackedFolderItemFactory(
{},
{ permission: PermissionLevel.Write },
);
const invitations = [
{
id: 'ecafbd2a-5688-11eb-be92-0242ac130005',
item,
permission: PermissionLevel.Write,
email: MEMBERS.CEDRIC.email,
createdAt: '2021-08-11T12:56:36.834Z',
updatedAt: '2021-08-11T12:56:36.834Z',
creator: MEMBERS.ANNA,
},
{
id: 'ecafbd1a-5688-11eb-be93-0242ac130006',
item,
permission: PermissionLevel.Read,
email: MEMBERS.DAVID.email,
createdAt: '2021-08-11T12:56:36.834Z',
updatedAt: '2021-08-11T12:56:36.834Z',
creator: MEMBERS.ANNA,
},
];
cy.setUpApi({ items: [{ ...item, invitations }] });

it('view invitation in share item modal read-only mode', () => {
const item = ITEM_WITH_INVITATIONS_WRITE_ACCESS.items[0];
const { invitations } = item;
cy.visit(buildItemPath(item.id));
cy.get(`#${buildShareButtonId(item.id)}`).click();

invitations.forEach(({ id, email, permission }) => {
cy.get(buildInvitationTableRowSelector(id))
.should('contain', email)
.should('contain', permission);

// delete invitation button should not exist
cy.get(`#${buildItemInvitationRowDeleteButtonId(id)}`).should(
'not.exist',
);

// check no permission select component exists
cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_MEMBERSHIP_PERMISSION_SELECT_CLASS} input`,
).should('not.exist');

// resend invitation button should not exist
cy.get(
`${buildInvitationTableRowSelector(
id,
)} .${ITEM_RESEND_INVITATION_BUTTON_CLASS}`,
).should('not.exist');
// should not contain given invitations
cy.get('tr').then((c) => {
invitations.forEach((inv) => {
expect(c[0]).not.to.contain(inv.email);
});
});
});
});
16 changes: 16 additions & 0 deletions cypress/e2e/item/authorization/forbidden.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { PackedFolderItemFactory } from '@graasp/sdk';

import { buildItemPath } from '@/config/paths';
import { ITEM_LOGIN_SCREEN_FORBIDDEN_ID } from '@/config/selectors';

it('User is logged out and item is private', () => {
const item = PackedFolderItemFactory({}, { permission: null });
cy.setUpApi({
items: [item],
currentMember: null,
});

cy.visit(buildItemPath(item.id));

cy.get(`#${ITEM_LOGIN_SCREEN_FORBIDDEN_ID}`).should('be.visible');
});
122 changes: 122 additions & 0 deletions cypress/e2e/item/authorization/itemLogin/itemLogin.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { ItemLoginSchemaType, PackedFolderItemFactory } from '@graasp/sdk';

import { SETTINGS_ITEM_LOGIN_DEFAULT } from '../../../../../src/config/constants';
import { buildItemPath } from '../../../../../src/config/paths';
import {
ENROLL_BUTTON_SELECTOR,
ITEM_LOGIN_SIGN_IN_BUTTON_ID,
ITEM_LOGIN_SIGN_IN_PASSWORD_ID,
ITEM_LOGIN_SIGN_IN_USERNAME_ID,
buildDataCyWrapper,
} from '../../../../../src/config/selectors';
import { MEMBERS, SIGNED_OUT_MEMBER } from '../../../../fixtures/members';
import { ITEM_LOGIN_PAUSE } from '../../../../support/constants';
import { addItemLoginSchema } from './utils';

const checkItemLoginScreenLayout = (
itemLoginSchema:
| ItemLoginSchemaType
| `${ItemLoginSchemaType}` = SETTINGS_ITEM_LOGIN_DEFAULT,
) => {
cy.get(`#${ITEM_LOGIN_SIGN_IN_USERNAME_ID}`).should('exist');
if (itemLoginSchema === ItemLoginSchemaType.UsernameAndPassword) {
cy.get(`#${ITEM_LOGIN_SIGN_IN_PASSWORD_ID}`).should('exist');
}
cy.get(`#${ITEM_LOGIN_SIGN_IN_BUTTON_ID}`).should('exist');
};

const fillItemLoginScreenLayout = ({
username,
password,
}: {
username?: string;
password?: string;
}) => {
cy.get(`#${ITEM_LOGIN_SIGN_IN_USERNAME_ID}`).clear().type(username);

if (password) {
cy.get(`#${ITEM_LOGIN_SIGN_IN_PASSWORD_ID}`).clear().type(password);
}
cy.get(`#${ITEM_LOGIN_SIGN_IN_BUTTON_ID}`).click();
};

describe('User is signed out', () => {
describe('Display Item Login Screen', () => {
it('username', () => {
const item = addItemLoginSchema(
PackedFolderItemFactory({}, { permission: null }),
ItemLoginSchemaType.Username,
);
cy.setUpApi({ items: [item], currentMember: SIGNED_OUT_MEMBER });

cy.visit(buildItemPath(item.id));
checkItemLoginScreenLayout(item.itemLoginSchema.type);
fillItemLoginScreenLayout({
username: 'username',
});
cy.wait('@postItemLogin');
});
it('username and password', () => {
const item = addItemLoginSchema(
PackedFolderItemFactory({}, { permission: null }),
ItemLoginSchemaType.UsernameAndPassword,
);
cy.setUpApi({ items: [item], currentMember: SIGNED_OUT_MEMBER });

cy.visit(buildItemPath(item.id));
checkItemLoginScreenLayout(item.itemLoginSchema.type);
fillItemLoginScreenLayout({
username: 'username',
password: 'password',
});
cy.wait('@postItemLogin');
});
});

describe('Error handling', () => {
it('error while signing in', () => {
const item = addItemLoginSchema(
PackedFolderItemFactory({}, { permission: null }),
ItemLoginSchemaType.UsernameAndPassword,
);
cy.setUpApi({
items: [item],
postItemLoginError: true,
currentMember: SIGNED_OUT_MEMBER,
});

// go to children item
cy.visit(buildItemPath(item.id));

fillItemLoginScreenLayout({
username: 'username',
password: 'password',
});

cy.wait(ITEM_LOGIN_PAUSE);

cy.get(`#${ITEM_LOGIN_SIGN_IN_USERNAME_ID}`).should('exist');
});
});
});

describe('User is signed in as normal user', () => {
it('Enroll to item automatically', () => {
const item = addItemLoginSchema(
PackedFolderItemFactory({}, { permission: null }),
ItemLoginSchemaType.UsernameAndPassword,
);
cy.setUpApi({ items: [item], currentMember: MEMBERS.BOB });
cy.visit(buildItemPath(item.id));

// avoid to detect intermediate screens because of loading
// to remove when requests loading time is properly managed
cy.wait(ITEM_LOGIN_PAUSE);

// enroll
cy.get(buildDataCyWrapper(ENROLL_BUTTON_SELECTOR)).click();
cy.wait('@enroll').then(({ request }) => {
expect(request.url).to.contain(item.id);
});
});
});
Loading

0 comments on commit ddb0012

Please sign in to comment.