From 915e9ec353f5d6db4e705b8df8e3775649ea7110 Mon Sep 17 00:00:00 2001 From: spaenleh Date: Mon, 15 May 2023 13:35:11 +0200 Subject: [PATCH] test: pass --- cypress/e2e/header.cy.ts | 62 ++++---- cypress/e2e/pinned.cy.ts | 4 +- cypress/fixtures/apps.ts | 12 +- cypress/fixtures/chat.ts | 17 +++ cypress/fixtures/documents.ts | 36 ++--- cypress/fixtures/files.ts | 36 ++--- cypress/fixtures/items.ts | 12 +- cypress/fixtures/links.ts | 12 +- .../fixtures/useCases/staticElectricity.ts | 102 ++++++------- cypress/support/commands.ts | 33 ++--- cypress/support/server.ts | 134 +++++++++++++++--- cypress/support/utils.ts | 8 ++ package.json | 4 +- src/modules/item/Item.tsx | 81 +++++++---- yarn.lock | 13 +- 15 files changed, 355 insertions(+), 211 deletions(-) create mode 100644 cypress/fixtures/chat.ts diff --git a/cypress/e2e/header.cy.ts b/cypress/e2e/header.cy.ts index a7b940fd..e8320a56 100644 --- a/cypress/e2e/header.cy.ts +++ b/cypress/e2e/header.cy.ts @@ -1,14 +1,10 @@ -import { getCurrentSession } from '@graasp/sdk'; - import { HOME_PATH } from '../../src/config/paths'; import { HEADER_MEMBER_MENU_BUTTON_ID, - HEADER_MEMBER_MENU_SEE_PROFILE_BUTTON_ID, - HEADER_MEMBER_MENU_SIGN_IN_BUTTON_ID, - HEADER_MEMBER_MENU_SIGN_OUT_BUTTON_ID, - buildMemberMenuItemId, + HEADER_MEMBER_MENU_SEE_PROFILE_BUTTON_ID, // HEADER_MEMBER_MENU_SIGN_IN_BUTTON_ID, + HEADER_MEMBER_MENU_SIGN_OUT_BUTTON_ID, // buildMemberMenuItemId, } from '../../src/config/selectors'; -import { MOCK_SESSIONS } from '../fixtures/members'; +// import { MOCK_SESSIONS } from '../fixtures/members'; import { MEMBER_PROFILE_PATH, SIGN_IN_PATH } from '../support/constants'; // catch hook warning from react @@ -33,15 +29,16 @@ describe('Header', () => { cy.url().should('equal', MEMBER_PROFILE_PATH); }); - it('Sign in', () => { - cy.setUpApi(); - cy.visit(HOME_PATH); + // todo: not available currently because cookie is httpOnly + // it('Sign in', () => { + // cy.setUpApi(); + // cy.visit(HOME_PATH); - cy.wait('@getCurrentMember'); - cy.get(`#${HEADER_MEMBER_MENU_BUTTON_ID}`).click(); - cy.get(`#${HEADER_MEMBER_MENU_SIGN_IN_BUTTON_ID}`).click(); - cy.url().should('contain', SIGN_IN_PATH); - }); + // cy.wait('@getCurrentMember'); + // cy.get(`#${HEADER_MEMBER_MENU_BUTTON_ID}`).click(); + // cy.get(`#${HEADER_MEMBER_MENU_SIGN_IN_BUTTON_ID}`).click(); + // cy.url().should('contain', SIGN_IN_PATH); + // }); it('Sign out', () => { cy.setUpApi(); @@ -53,25 +50,26 @@ describe('Header', () => { cy.url().should('equal', SIGN_IN_PATH); }); - it('Switch users', () => { - cy.setUpApi({ storedSessions: MOCK_SESSIONS }); - cy.visit(HOME_PATH); + // todo: not available since cookie is httpOnly + // it('Switch users', () => { + // cy.setUpApi({ storedSessions: MOCK_SESSIONS }); + // cy.visit(HOME_PATH); - cy.wait('@getCurrentMember'); - cy.get(`#${HEADER_MEMBER_MENU_BUTTON_ID}`).click(); + // cy.wait('@getCurrentMember'); + // cy.get(`#${HEADER_MEMBER_MENU_BUTTON_ID}`).click(); - MOCK_SESSIONS.forEach(({ id }) => { - cy.get(`#${buildMemberMenuItemId(id)}`).should('be.visible'); - }); + // MOCK_SESSIONS.forEach(({ id }) => { + // cy.get(`#${buildMemberMenuItemId(id)}`).should('be.visible'); + // }); - // switch to first user - cy.get(`#${buildMemberMenuItemId(MOCK_SESSIONS[0].id)}`) - .click() - .then(() => { - // session cookie should be different - const currentCookie = getCurrentSession(); - expect(currentCookie).to.equal(MOCK_SESSIONS[0].token); - }); - }); + // // switch to first user + // cy.get(`#${buildMemberMenuItemId(MOCK_SESSIONS[0].id)}`) + // .click() + // .then(() => { + // // session cookie should be different + // const currentCookie = getCurrentSession(); + // expect(currentCookie).to.equal(MOCK_SESSIONS[0].token); + // }); + // }); }); }); diff --git a/cypress/e2e/pinned.cy.ts b/cypress/e2e/pinned.cy.ts index 3a2f5130..a6df1006 100644 --- a/cypress/e2e/pinned.cy.ts +++ b/cypress/e2e/pinned.cy.ts @@ -59,10 +59,10 @@ describe('Pinned Items', () => { }); it('If no items are pinned toggle pinned should not exist', () => { - const parent = FOLDER_WITH_SUBFOLDER_ITEM.items[0]; + const parent = FOLDER_WITH_SUBFOLDER_ITEM.items[2]; cy.visit(buildMainPath({ rootId: parent.id })); - cy.wait('@getChildren'); + cy.wait(['@getChildren', '@getItemTags']); cy.get(`#${ITEM_PINNED_BUTTON_ID}`).should('not.exist'); cy.get(`#${ITEM_PINNED_ID}`).should('not.exist'); }); diff --git a/cypress/fixtures/apps.ts b/cypress/fixtures/apps.ts index 9da30299..4df0d539 100644 --- a/cypress/fixtures/apps.ts +++ b/cypress/fixtures/apps.ts @@ -12,9 +12,9 @@ export const GRAASP_APP_ITEM: AppItemType = { name: 'graasp app', description: 'a description for graasp app', path: 'baefbd2a_5688_11eb_ae93_0242ac130002', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: { app: { url: 'https://graasp.eu' }, }, @@ -71,9 +71,9 @@ export const APP_USING_CONTEXT_ITEM: MockItem = { url: `${API_HOST}/${buildAppItemLinkForTest('app.html')}`, }, }, - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), }; export const GRAASP_APP_ITEMS_FIXTURE = [ diff --git a/cypress/fixtures/chat.ts b/cypress/fixtures/chat.ts new file mode 100644 index 00000000..cf14bb32 --- /dev/null +++ b/cypress/fixtures/chat.ts @@ -0,0 +1,17 @@ +import { ChatMessage } from '@graasp/sdk'; + +import { v4 } from 'uuid'; + +import { ITEM_WITH_CHAT_BOX } from './items'; + +// eslint-disable-next-line import/prefer-default-export +export const ITEM_CHAT_MESSAGES: ChatMessage[] = [ + { + id: v4(), + item: ITEM_WITH_CHAT_BOX, + creator: ITEM_WITH_CHAT_BOX.creator, + createdAt: new Date(), + updatedAt: new Date(), + body: 'a message', + }, +]; diff --git a/cypress/fixtures/documents.ts b/cypress/fixtures/documents.ts index 99a185ee..f5d02634 100644 --- a/cypress/fixtures/documents.ts +++ b/cypress/fixtures/documents.ts @@ -11,9 +11,9 @@ export const GRAASP_DOCUMENT_ITEM: DocumentItemType = { name: 'graasp text', description: 'a description for graasp text', path: 'ecafbd2a_5688_12eb_ae93_0242ac130002', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: buildDocumentExtra({ content: '

Some Title

', }), @@ -29,9 +29,9 @@ export const GRAASP_DOCUMENT_ITEM_VISIBLE: DocumentItemType = { name: 'Visible document', description: 'a description for graasp text', path: 'ecafbd2a_5688_11eb_ae93_0242ac130008.fdf09f5a_5688_11eb_ae93_0242ac130009', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: buildDocumentExtra({ content: '

Visible document

', }), @@ -49,9 +49,9 @@ export const GRAASP_DOCUMENT_ITEM_HIDDEN: DocumentItemType & { name: 'Hidden document', description: 'a description for graasp text', path: 'ecafbd2a_5688_11eb_ae93_0242ac130008.fdf09f5a_5688_11eb_ae93_0242ac130010', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: buildDocumentExtra({ content: '

Hidden document

', }), @@ -74,9 +74,9 @@ export const GRAASP_DOCUMENT_ITEM_PUBLIC_VISIBLE: DocumentItemType & { name: 'Public visible document', description: 'a description for graasp text', path: 'ecafbd2a_5688_11eb_ae93_0242ac130008.fdf09f5a_5688_11eb_ae93_0242ac130009', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: buildDocumentExtra({ content: '

Public visible document

', }), @@ -99,9 +99,9 @@ export const GRAASP_DOCUMENT_ITEM_PUBLIC_HIDDEN: DocumentItemType & { name: 'Public hidden document', description: 'a description for graasp text', path: 'ecafbd2a_5688_11eb_ae93_0242ac130008.fdf09f5a_5688_11eb_ae93_0242ac130010', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: buildDocumentExtra({ content: '

Public hidden document

', }), @@ -125,9 +125,9 @@ export const GRAASP_DOCUMENT_ITEM_WITH_CHAT_BOX: DocumentItemType = { name: 'graasp text', description: 'a description for graasp text', path: 'ecafbf2a_5688_12eb_ae93_0242ac130002', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: buildDocumentExtra({ content: '

Some Title

', }), diff --git a/cypress/fixtures/files.ts b/cypress/fixtures/files.ts index 2be00224..04cc5f84 100644 --- a/cypress/fixtures/files.ts +++ b/cypress/fixtures/files.ts @@ -19,9 +19,9 @@ export const IMAGE_ITEM_DEFAULT: LocalFileItemType & { filepath: string } = { description: 'a default image description', type: ItemType.LOCAL_FILE, path: 'bd5519a2_5ba9_4305_b221_185facbe6a99', - creator: CURRENT_USER.id, - createdAt: '2021-03-16T16:00:50.968Z', - updatedAt: '2021-03-16T16:00:52.655Z', + creator: CURRENT_USER, + createdAt: new Date(Date.parse('2021-03-16T16:00:50.968Z')), + updatedAt: new Date(Date.parse('2021-03-16T16:00:52.655Z')), extra: buildFileExtra({ name: 'icon.png', path: '9a95/e2e1/2a7b-1615910428274', @@ -42,9 +42,9 @@ export const VIDEO_ITEM_DEFAULT: LocalFileItemType & { filepath: string } = { description: 'a default video description', type: ItemType.LOCAL_FILE, path: 'qd5519a2_5ba9_4305_b221_185facbe6a99', - creator: CURRENT_USER.id, - createdAt: '2021-03-16T16:00:50.968Z', - updatedAt: '2021-03-16T16:00:52.655Z', + creator: CURRENT_USER, + createdAt: new Date(Date.parse('2021-03-16T16:00:50.968Z')), + updatedAt: new Date(Date.parse('2021-03-16T16:00:52.655Z')), extra: buildFileExtra({ name: 'video.mp4', path: '9a95/e2e1/2a7b-1615910428274', @@ -65,9 +65,9 @@ export const PDF_ITEM_DEFAULT: LocalFileItemType & { filepath: string } = { description: 'a default pdf description', type: ItemType.LOCAL_FILE, path: 'cd5519a2_5ba9_4305_b221_185facbe6a99', - creator: CURRENT_USER.id, - createdAt: '2021-03-16T16:00:50.968Z', - updatedAt: '2021-03-16T16:00:52.655Z', + creator: CURRENT_USER, + createdAt: new Date(Date.parse('2021-03-16T16:00:50.968Z')), + updatedAt: new Date(Date.parse('2021-03-16T16:00:52.655Z')), extra: buildFileExtra({ name: 'doc.pdf', path: '9a95/e2e1/2a7b-1615910428274', @@ -88,9 +88,9 @@ export const IMAGE_ITEM_S3: S3FileItemType = { description: 'a default image description', type: ItemType.S3_FILE, path: 'ad5519a2_5ba9_4305_b221_185facbe6a99', - creator: CURRENT_USER.id, - createdAt: '2021-03-16T16:00:50.968Z', - updatedAt: '2021-03-16T16:00:52.655Z', + creator: CURRENT_USER, + createdAt: new Date(Date.parse('2021-03-16T16:00:50.968Z')), + updatedAt: new Date(Date.parse('2021-03-16T16:00:52.655Z')), extra: buildS3FileExtra({ name: 'mock-image', path: MOCK_IMAGE_URL, // for testing @@ -109,9 +109,9 @@ export const VIDEO_ITEM_S3: S3FileItemType = { description: 'a default video description', type: ItemType.S3_FILE, path: 'qd5519a2_5ba9_4305_b221_185facbe6a93', - creator: CURRENT_USER.id, - createdAt: '2021-03-16T16:00:50.968Z', - updatedAt: '2021-03-16T16:00:52.655Z', + creator: CURRENT_USER, + createdAt: new Date(Date.parse('2021-03-16T16:00:50.968Z')), + updatedAt: new Date(Date.parse('2021-03-16T16:00:52.655Z')), extra: buildS3FileExtra({ name: 'mock-video', path: MOCK_VIDEO_URL, // for testing @@ -130,9 +130,9 @@ export const PDF_ITEM_S3: S3FileItemType = { description: 'a default pdf description', type: ItemType.S3_FILE, path: 'bd5519a2_5ba9_4305_b221_185facbe6a99', - creator: CURRENT_USER.id, - createdAt: '2021-03-16T16:00:50.968Z', - updatedAt: '2021-03-16T16:00:52.655Z', + creator: CURRENT_USER, + createdAt: new Date(Date.parse('2021-03-16T16:00:50.968Z')), + updatedAt: new Date(Date.parse('2021-03-16T16:00:52.655Z')), extra: buildS3FileExtra({ name: 'mock-pdf', path: MOCK_PDF_URL, // for testing diff --git a/cypress/fixtures/items.ts b/cypress/fixtures/items.ts index d5c5edad..8c39d2c2 100644 --- a/cypress/fixtures/items.ts +++ b/cypress/fixtures/items.ts @@ -13,6 +13,8 @@ const PUBLIC_TAG_ID = Cypress.env('PUBLIC_TAG_ID'); export type MockItem = DiscriminatedItem & { // for testing filepath?: string; + // path to a fixture file in cypress + filefixture?: string; memberships?: { memberId: string }[]; tags?: { tagId: string }[]; }; @@ -27,9 +29,9 @@ export const DEFAULT_FOLDER_ITEM: MockItem = { childrenOrder: [], }, }, - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.FOLDER, settings: { isPinned: false, @@ -37,7 +39,7 @@ export const DEFAULT_FOLDER_ITEM: MockItem = { }, }; -export const ITEM_WITH_CHAT_BOX = { +export const ITEM_WITH_CHAT_BOX: MockItem = { ...DEFAULT_FOLDER_ITEM, id: 'ecafbd2a-5688-11eb-ae93-0242ac130002', name: 'parent folder', @@ -48,7 +50,7 @@ export const ITEM_WITH_CHAT_BOX = { }, }; -export const ITEM_WITHOUT_CHAT_BOX = { +export const ITEM_WITHOUT_CHAT_BOX: MockItem = { ...DEFAULT_FOLDER_ITEM, id: 'fdf09f5a-5688-11eb-ae93-0242ac130003', name: 'child folder', diff --git a/cypress/fixtures/links.ts b/cypress/fixtures/links.ts index 7b779bc9..b31fb7b0 100644 --- a/cypress/fixtures/links.ts +++ b/cypress/fixtures/links.ts @@ -12,9 +12,9 @@ export const GRAASP_LINK_ITEM: EmbeddedLinkItemType = { name: 'graasp link', description: 'a description for graasp link', path: 'ecafbd2a_5688_11eb_ae93_0242ac130002', - creator: CURRENT_USER.id, - createdAt: new Date().toDateString(), - updatedAt: new Date().toDateString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), extra: buildEmbeddedLinkExtra({ url: 'https://graasp.eu', thumbnails: ['https://graasp.eu/img/epfl/logo-tile.png'], @@ -44,9 +44,9 @@ export const YOUTUBE_LINK_ITEM: EmbeddedLinkItemType = { type: ItemType.LINK, name: 'graasp youtube link', description: 'a description for graasp youtube link', - creator: CURRENT_USER.id, - createdAt: new Date().toDateString(), - updatedAt: new Date().toDateString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), path: 'gcafbd2a_5688_11eb_ae93_0242ac130002', extra: buildEmbeddedLinkExtra({ url: 'https://www.youtube.com/watch?v=FmiEgBMTPLo', diff --git a/cypress/fixtures/useCases/staticElectricity.ts b/cypress/fixtures/useCases/staticElectricity.ts index 55b99d0b..6a4256a8 100644 --- a/cypress/fixtures/useCases/staticElectricity.ts +++ b/cypress/fixtures/useCases/staticElectricity.ts @@ -21,9 +21,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003', name: 'Static Electricity', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.FOLDER, extra: { [ItemType.FOLDER]: { @@ -37,9 +37,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_5688_11eb_ae92_0242ac130015', name: 'Causes and experiences', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.FOLDER, extra: { [ItemType.FOLDER]: { @@ -59,9 +59,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_5688_11eb_ae92_0242ac130015.gcefbd2a_5688_11eb_ae92_0542bc120002', name: 'cat', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.DOCUMENT, extra: buildDocumentExtra({ content: @@ -74,9 +74,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_5688_11eb_ae92_0242ac130015.gcefbd2a_5688_11eb_fe32_0542bc120002', name: 'causes text', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.DOCUMENT, extra: buildDocumentExtra({ content: @@ -89,9 +89,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_5688_11eb_ae92_0242ac130015.gcefbd2a_5648_31eb_fe32_0542bc120002', name: 'causes link', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.LINK, extra: buildEmbeddedLinkExtra({ url: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Cat_demonstrating_static_cling_with_styrofoam_peanuts.jpg/310px-Cat_demonstrating_static_cling_with_styrofoam_peanuts.jpg', @@ -106,9 +106,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_5688_11eb_ae92_0242ac130015.gcefbd4e_5688_11eb_fe32_0542bc120002', name: 'pressure text', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.DOCUMENT, extra: buildDocumentExtra({ content: @@ -121,9 +121,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_5688_11eb_ae92_0242ac130015.gceffe4e_5688_11eb_fe32_0542bc120002', name: 'causes video link', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.LINK, extra: buildEmbeddedLinkExtra({ url: 'https://www.dailymotion.com/embed/video/xgh289?autoplay=1', @@ -138,9 +138,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_4218_31eb_fe32_0542bc120002', name: 'Introduction', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.FOLDER, extra: { [ItemType.FOLDER]: { @@ -158,9 +158,9 @@ export const STATIC_ELECTRICITY: { name: 'Balloons and Static Electricity Source', description: '

Grab a balloon to explore concepts of static electricity such as charge transfer, attraction, repulsion, and induced charge.

', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.APP, extra: { [ItemType.APP]: { @@ -174,9 +174,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcafbd2a_4218_31eb_fe32_0542bc120002.gcafbd2a_4118_31eb_fe32_1542bc120002', name: 'some text', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.DOCUMENT, extra: buildDocumentExtra({ content: @@ -189,9 +189,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcbffd2a_4218_31eb_fe32_0542bc120002', name: 'Removal and Prevention', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.FOLDER, extra: { [ItemType.FOLDER]: { @@ -208,9 +208,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcbffd2a_4218_31eb_fe32_0542bc120002.gcbffd2a_4218_31eb_fe32_0542bc121102', name: 'text', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.DOCUMENT, extra: buildDocumentExtra({ content: @@ -223,9 +223,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gcbffd2a_4218_31eb_fe32_0542bc120002.gcbffd2a_4218_31eb_fe32_0542bc121145', name: 'image link', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.LINK, extra: buildEmbeddedLinkExtra({ url: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/7b/Antistatic_bag.jpg/220px-Antistatic_bag.jpg', @@ -240,9 +240,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gfbfed2a_4218_31eb_fe32_0542bc120002', name: 'Static Discharge: Lightning', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.FOLDER, extra: { [ItemType.FOLDER]: { @@ -260,9 +260,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gfbfed2a_4218_31eb_fe32_0542bc120002.gfbfed2a_4218_31eb_fe32_0522bc120002', name: 'lightning image', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.LOCAL_FILE, extra: buildFileExtra({ name: 'icon.jpeg', @@ -279,9 +279,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gfbfed2a_4218_31eb_fe32_0542bc120002.gfbfed2a_4218_31eb_fe32_0522bc120065', name: 'lightning text', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.DOCUMENT, extra: buildDocumentExtra({ content: @@ -294,9 +294,9 @@ export const STATIC_ELECTRICITY: { path: 'fdf09f5a_5688_11eb_ae31_0242ac130003.gfbfed2a_4218_31eb_fe32_0542bc120002.gfbfed2a_4218_31eb_fe32_0522bc120265', name: 'youtube link', description: '', - creator: CURRENT_USER.id, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + creator: CURRENT_USER, + createdAt: new Date(), + updatedAt: new Date(), type: ItemType.LINK, extra: buildEmbeddedLinkExtra({ url: 'https://www.youtube.com/watch?v=9HS08L1EIjQ', diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index a7e95fe7..c51fe4e7 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -1,5 +1,5 @@ /// -import { COOKIE_KEYS, Member } from '@graasp/sdk'; +import { COOKIE_KEYS, ChatMessage, Member } from '@graasp/sdk'; import { MockItem } from '@/../cypress/fixtures/items'; @@ -13,13 +13,15 @@ import { mockGetAppLink, mockGetChildren, mockGetCurrentMember, + mockGetDescendants, mockGetItem, + mockGetItemChat, mockGetItemMembershipsForItem, mockGetItemTags, mockGetItemsTags, + mockGetLoginSchemaType, mockGetMemberBy, mockGetMembers, - mockGetPublicChildren, mockPatchAppData, mockPostAppData, mockProfilePage, @@ -30,49 +32,46 @@ Cypress.Commands.add( 'setUpApi', ({ items = [], + chatMessages = [], members = Object.values(MEMBERS), currentMember = CURRENT_USER, - storedSessions = [], getItemError = false, getMemberError = false, getAppLinkError = false, getCurrentMemberError = false, } = {}) => { - // why do we do this ??? - const cachedItems = items; - const cachedMembers = JSON.parse(JSON.stringify(members)); if (currentMember) { cy.setCookie(COOKIE_KEYS.SESSION_KEY, 'somecookie'); } - cy.setCookie( - COOKIE_KEYS.STORED_SESSIONS_KEY, - JSON.stringify(storedSessions), - ); mockGetItem( - { items: cachedItems, currentMember }, + { items, currentMember }, getItemError || getCurrentMemberError, ); + mockGetItemChat({ chatMessages }); mockGetItemMembershipsForItem(items, currentMember); // mockGetPublicItem({ items: cachedItems }); mockGetItemTags(items, currentMember); mockGetItemsTags(items, currentMember); + mockGetLoginSchemaType(items, currentMember); + + mockGetChildren(items, currentMember); + // mockGetPublicChildren(cachedItems); - mockGetChildren(cachedItems, currentMember); - mockGetPublicChildren(cachedItems); + mockGetDescendants(items, currentMember); - mockGetMemberBy(cachedMembers, getMemberError); + mockGetMemberBy(members, getMemberError); mockGetCurrentMember(currentMember, getCurrentMemberError); - mockDefaultDownloadFile({ items: cachedItems, currentMember }); + mockDefaultDownloadFile({ items, currentMember }); // mockPublicDefaultDownloadFile(cachedItems); mockSignOut(); - mockGetMembers(cachedMembers); + mockGetMembers(members); mockProfilePage(); mockAuthPage(); mockGetAppLink(getAppLinkError); @@ -116,6 +115,7 @@ declare global { setUpApi({ items, members, + chatMessages, currentMember, storedSessions, getItemError, @@ -125,6 +125,7 @@ declare global { }?: { items?: MockItem[]; members?: Member[]; + chatMessages?: ChatMessage[]; currentMember?: Member; storedSessions?: { id: string; token: string; createdAt: number }[]; getItemError?: boolean; diff --git a/cypress/support/server.ts b/cypress/support/server.ts index 94df3b58..15227208 100644 --- a/cypress/support/server.ts +++ b/cypress/support/server.ts @@ -1,5 +1,11 @@ import { API_ROUTES } from '@graasp/query-client'; -import { Member, PermissionLevel, isChildOf } from '@graasp/sdk'; +import { + ChatMessage, + Member, + PermissionLevel, + isChildOf, + isDescendantOf, +} from '@graasp/sdk'; import { StatusCodes } from 'http-status-codes'; import * as qs from 'qs'; @@ -18,6 +24,7 @@ import { DEFAULT_POST, EMAIL_FORMAT, ID_FORMAT, + getChatMessagesById, getItemById, parseStringToRegExp, } from './utils'; @@ -27,15 +34,17 @@ export const MEMBER_PROFILE_PATH = `${Cypress.env( )}/profile`; const { + buildDownloadFilesRoute, + buildGetItemChatRoute, + buildGetItemLoginSchemaRoute, + buildGetItemMembershipsForItemsRoute, buildGetItemRoute, - buildGetMembersBy, buildGetItemTagsRoute, + buildGetMembersBy, + buildGetMembersRoute, GET_CURRENT_MEMBER_ROUTE, - buildDownloadFilesRoute, GET_OWN_ITEMS_ROUTE, SIGN_OUT_ROUTE, - buildGetMembersRoute, - buildGetItemMembershipsForItemsRoute, } = API_ROUTES; const API_HOST = Cypress.env('API_HOST'); @@ -57,20 +66,25 @@ const checkMemberHasAccess = ({ const haveMembership = creator.id === member.id || item.memberships?.find(({ memberId }) => memberId === member.id); + const isPublic = item?.tags?.find(({ tagId }) => tagId === PUBLIC_TAG_ID); if (haveMembership) { return undefined; } + // check if item is public in which case return + if (isPublic) { + return undefined; + } return { statusCode: StatusCodes.FORBIDDEN }; }; -const checkIsPublic = (item: MockItem): { statusCode: number } | undefined => { - const isPublic = item?.tags?.find(({ tagId }) => tagId === PUBLIC_TAG_ID); - if (!isPublic) { - return { statusCode: StatusCodes.UNAUTHORIZED }; - } - return undefined; -}; +// const checkIsPublic = (item: MockItem): { statusCode: number } | undefined => { +// const isPublic = item?.tags?.find(({ tagId }) => tagId === PUBLIC_TAG_ID); +// if (!isPublic) { +// return { statusCode: StatusCodes.UNAUTHORIZED }; +// } +// return undefined; +// }; export const mockGetOwnItems = ({ items, @@ -150,6 +164,28 @@ export const mockGetItem = ( ).as('getItem'); }; +export const mockGetItemChat = ({ + chatMessages, +}: { + chatMessages: ChatMessage[]; +}): void => { + cy.intercept( + { + method: DEFAULT_GET.method, + url: new RegExp(`${API_HOST}/${buildGetItemChatRoute(ID_FORMAT)}$`), + }, + ({ url, reply }) => { + const itemId = url.slice(API_HOST.length).split('/')[2]; + const itemChat = getChatMessagesById(chatMessages, itemId); + + return reply({ + body: itemChat, + statusCode: StatusCodes.OK, + }); + }, + ).as('getItemChat'); +}; + export const mockGetItemMembershipsForItem = ( items: MockItem[], currentMember: Member, @@ -261,15 +297,16 @@ export const mockGetChildren = (items: MockItem[], member: Member): void => { ).as('getChildren'); }; -export const mockGetPublicChildren = (items: MockItem[]): void => { +export const mockGetDescendants = (items: MockItem[], member: Member): void => { cy.intercept( { method: DEFAULT_GET.method, - url: new RegExp(`${API_HOST}/p/items/${ID_FORMAT}/children`), + url: new RegExp(`${API_HOST}/items/${ID_FORMAT}/descendants`), }, ({ url, reply }) => { - const id = url.slice(API_HOST.length).split('/')[3]; + const id = url.slice(API_HOST.length).split('/')[2]; const item = items.find(({ id: thisId }) => id === thisId); + // item does not exist in db if (!item) { return reply({ @@ -277,19 +314,47 @@ export const mockGetPublicChildren = (items: MockItem[]): void => { }); } - const error = checkIsPublic(item); + const error = checkMemberHasAccess({ item, member }); if (isError(error)) { return reply(error); } - - const children = items.filter((testItem) => - isChildOf(testItem.path, item.path), + const descendants = items.filter((newItem) => + isDescendantOf(newItem.path, item.path), ); - return reply(children); + return reply(descendants); }, - ).as('getPublicChildren'); + ).as('getDescendants'); }; +// export const mockGetPublicChildren = (items: MockItem[]): void => { +// cy.intercept( +// { +// method: DEFAULT_GET.method, +// url: new RegExp(`${API_HOST}/p/items/${ID_FORMAT}/children`), +// }, +// ({ url, reply }) => { +// const id = url.slice(API_HOST.length).split('/')[3]; +// const item = items.find(({ id: thisId }) => id === thisId); +// // item does not exist in db +// if (!item) { +// return reply({ +// statusCode: StatusCodes.NOT_FOUND, +// }); +// } + +// const error = checkIsPublic(item); +// if (isError(error)) { +// return reply(error); +// } + +// const children = items.filter((testItem) => +// isChildOf(testItem.path, item.path), +// ); +// return reply(children); +// }, +// ).as('getPublicChildren'); +// }; + export const mockGetMemberBy = ( members: Member[], shouldThrowError?: boolean, @@ -332,7 +397,6 @@ export const mockDefaultDownloadFile = ( const id = url.slice(API_HOST.length).split('/')[2]; const item = items.find(({ id: thisId }) => id === thisId); const { replyUrl } = qs.parse(url.slice(url.indexOf('?') + 1)); - // item does not exist in db if (!item) { return reply({ @@ -351,7 +415,7 @@ export const mockDefaultDownloadFile = ( return reply({ url: item.filepath }); } - return reply({ fixture: item.filepath }); + return reply({ fixture: item.filefixture }); }, ).as('downloadFile'); }; @@ -451,6 +515,30 @@ export const mockGetItemsTags = (items: MockItem[], member: Member): void => { ).as('getItemsTags'); }; +export const mockGetLoginSchemaType = ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + items: MockItem[], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + member: Member, +): void => { + cy.intercept( + { + method: DEFAULT_GET.method, + url: new RegExp(`${API_HOST}/${buildGetItemLoginSchemaRoute(ID_FORMAT)}`), + }, + ({ reply, url }) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const itemId = url.slice(API_HOST.length).split('/')[2]; + + // todo: add response for itemLoginSchemaType + + reply({ + statusCode: StatusCodes.OK, + }); + }, + ).as('getLoginSchemaType'); +}; + export const redirectionReply = { headers: { 'content-type': 'text/html' }, statusCode: StatusCodes.OK, diff --git a/cypress/support/utils.ts b/cypress/support/utils.ts index d473e460..93400ee0 100644 --- a/cypress/support/utils.ts +++ b/cypress/support/utils.ts @@ -1,3 +1,5 @@ +import { ChatMessage } from '@graasp/sdk'; + import { MockItem } from '../fixtures/items'; // use simple id format for tests @@ -36,6 +38,12 @@ export const getItemById = ( targetId: string, ): MockItem | undefined => items.find(({ id }) => targetId === id); +export const getChatMessagesById = ( + chatMessages: ChatMessage[], + targetId: string, +): ChatMessage[] | undefined => + chatMessages.filter(({ item }) => targetId === item.id); + export const EMAIL_FORMAT = '[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+'; export const DEFAULT_GET = { diff --git a/package.json b/package.json index a03abbe9..7e274bcf 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "react-intersection-observer": "9.4.3", "react-router": "6.8.1", "react-router-dom": "6.8.1", - "react-toastify": "9.1.1" + "react-toastify": "9.1.1", + "uuid": "9.0.0" }, "devDependencies": { "@commitlint/config-conventional": "17.4.4", @@ -62,6 +63,7 @@ "@types/qs": "6.9.7", "@types/react": "^18.0.27", "@types/react-dom": "^18.0.10", + "@types/uuid": "9.0.1", "@typescript-eslint/eslint-plugin": "5.58.0", "@typescript-eslint/parser": "5.54.1", "@vitejs/plugin-react": "^3.1.0", diff --git a/src/modules/item/Item.tsx b/src/modules/item/Item.tsx index 7d155454..b9d7df53 100644 --- a/src/modules/item/Item.tsx +++ b/src/modules/item/Item.tsx @@ -5,7 +5,11 @@ import { Alert, Box, Container, Skeleton, Typography } from '@mui/material'; import { Api } from '@graasp/query-client'; import { Context, DEFAULT_LANG, ItemType, PermissionLevel } from '@graasp/sdk'; -import { EtherpadItemTypeRecord } from '@graasp/sdk/frontend'; +import { + EtherpadItemTypeRecord, + LocalFileItemTypeRecord, + S3FileItemTypeRecord, +} from '@graasp/sdk/frontend'; import { FAILURE_MESSAGES, PLAYER } from '@graasp/translations'; import { AppItem, @@ -45,7 +49,7 @@ const { useEtherpad, useItem, useChildren, - useFileContent, + useFileContentUrl, useItemTags, useChildrenPaginated, } = hooks; @@ -69,7 +73,7 @@ const EtherpadContent = ({ item }: EtherpadContentProps) => { if (etherpadQuery?.isLoading) { return ( @@ -104,6 +108,48 @@ const EtherpadContent = ({ item }: EtherpadContentProps) => { ); }; +type FileContentProps = { + item: S3FileItemTypeRecord | LocalFileItemTypeRecord; +}; +const FileContent = ({ item }: FileContentProps) => { + const { t: translateMessage } = useMessagesTranslation(); + // fetch file content if type is file + const { + data: file, + isLoading: isFileContentLoading, + isError: isFileError, + } = useFileContentUrl(item.id); + + if (isFileContentLoading) { + return ( + + ); + } + if (isFileError) { + return ( + + {translateMessage(FAILURE_MESSAGES.UNEXPECTED_ERROR)} + + ); + } + const fileItem = ( + + ); + + return fileItem; +}; + const Item = ({ id = '', isChildren = false, @@ -133,20 +179,6 @@ const Item = ({ getUpdates: isFolder, }); - // fetch file content if type is file - const { - data: file, - isLoading: isFileContentLoading, - isError: isFileError, - } = useFileContent(id, { - enabled: Boolean( - item && - ([ItemType.LOCAL_FILE, ItemType.S3_FILE] as string[]).includes( - item.type, - ), - ), - }); - const { data: childrenPaginated, isLoading: isChildrenPaginatedLoading, @@ -176,7 +208,6 @@ const Item = ({ isTagsLoading || isChildrenLoading || isChildrenPaginatedLoading || - isFileContentLoading || isLoadingMember ) { return ( @@ -205,7 +236,6 @@ const Item = ({ if ( isError || !item || - isFileError || isChildrenError || isChildrenPaginatedError || isErrorMember @@ -318,18 +348,7 @@ const Item = ({ } case ItemType.LOCAL_FILE: case ItemType.S3_FILE: { - const fileItem = ( - - ); - - return fileItem; + return ; } case ItemType.DOCUMENT: { const documentItem = ( diff --git a/yarn.lock b/yarn.lock index 1b49ebdd..149749e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1157,7 +1157,7 @@ __metadata: "@graasp/sdk@github:graasp/graasp-sdk#typeorm": version: 0.12.0 - resolution: "@graasp/sdk@https://github.com/graasp/graasp-sdk.git#commit=6c8b8bd1ada005605893429207093a0becc60a85" + resolution: "@graasp/sdk@https://github.com/graasp/graasp-sdk.git#commit=20daac0d8729bf5b5a1681426b6483b67510aaba" dependencies: "@fastify/secure-session": 5.3.0 "@graasp/etherpad-api": 2.1.1 @@ -1170,7 +1170,7 @@ __metadata: typeorm: 0.3.15 uuid: 9.0.0 validator: 13.9.0 - checksum: cf2e50b08e93e5531685689bd941d53aab6662384a1b206c36cbc8bd16695bd29c0b84f56a84f511890628d71e68d97225f2cebe699773007b5c5fc28932639a + checksum: 4b500d891414a2f81fa1021e65de129412cf5ea8e929c4334b2cd803061f61087f1872e64639e868f71dc8d20533c9361feae73385bce84455664373e9f0bc68 languageName: node linkType: hard @@ -1988,6 +1988,13 @@ __metadata: languageName: node linkType: hard +"@types/uuid@npm:9.0.1": + version: 9.0.1 + resolution: "@types/uuid@npm:9.0.1" + checksum: c472b8a77cbeded4bc529220b8611afa39bd64677f507838f8083d8aac8033b1f88cb9ddaa2f8589e0dcd2317291d0f6e1379f82d5ceebd6f74f3b4825288e00 + languageName: node + linkType: hard + "@types/yauzl@npm:^2.9.1": version: 2.10.0 resolution: "@types/yauzl@npm:2.10.0" @@ -5435,6 +5442,7 @@ __metadata: "@types/qs": 6.9.7 "@types/react": ^18.0.27 "@types/react-dom": ^18.0.10 + "@types/uuid": 9.0.1 "@typescript-eslint/eslint-plugin": 5.58.0 "@typescript-eslint/parser": 5.54.1 "@vitejs/plugin-react": ^3.1.0 @@ -5470,6 +5478,7 @@ __metadata: react-router-dom: 6.8.1 react-toastify: 9.1.1 typescript: ^4.9.5 + uuid: 9.0.0 vite: ^4.1.0 vite-plugin-checker: ^0.5.5 vite-plugin-istanbul: 4.0.1