From 5ccc9059f0ff120e4b4686366e22f3eb8d2df15c Mon Sep 17 00:00:00 2001 From: Erik Michelson Date: Fri, 13 Oct 2023 17:02:41 +0200 Subject: [PATCH] tests(permissions): add cypress tests for permission alert icon Signed-off-by: Erik Michelson --- frontend/cypress/e2e/permissions.spec.ts | 115 ++++++++++++++++++ frontend/cypress/support/visit-test-editor.ts | 52 ++++---- .../permission-entry-special-group.tsx | 4 + .../permissions-modal/permission-modal.tsx | 8 +- .../permission-section-owner.tsx | 5 +- .../permissions-sidebar-entry.tsx | 8 +- frontend/src/pages/api/private/users/mock.ts | 18 +++ 7 files changed, 182 insertions(+), 28 deletions(-) create mode 100644 frontend/cypress/e2e/permissions.spec.ts create mode 100644 frontend/src/pages/api/private/users/mock.ts diff --git a/frontend/cypress/e2e/permissions.spec.ts b/frontend/cypress/e2e/permissions.spec.ts new file mode 100644 index 000000000..52c3ed117 --- /dev/null +++ b/frontend/cypress/e2e/permissions.spec.ts @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import type { NotePermissions } from '@hedgedoc/commons' + +const mockPermissionChangeApiRoutes = (permission: NotePermissions) => { + cy.intercept('PUT', 'api/private/notes/mock-note/metadata/permissions/groups/_EVERYONE', { + statusCode: 200, + body: permission + }) + cy.intercept('DELETE', 'api/private/notes/mock-note/metadata/permissions/groups/_EVERYONE', { + statusCode: 200, + body: permission + }) + cy.intercept('PUT', 'api/private/notes/mock-note/metadata/permissions/groups/_LOGGED_IN', { + statusCode: 200, + body: permission + }) + cy.intercept('DELETE', 'api/private/notes/mock-note/metadata/permissions/groups/_LOGGED_IN', { + statusCode: 200, + body: permission + }) +} + +describe('The permission settings modal', () => { + beforeEach(() => { + cy.visitTestNote() + cy.getByCypressId('sidebar-permission-btn').click() + }) + + it('can be displayed', () => { + cy.getByCypressId('permission-modal').should('be.visible') + cy.getByCypressId('permission-owner-name').contains('Mock User') + cy.getByCypressId('permission-setting-deny_LOGGED_IN').should('have.class', 'btn-secondary') + cy.getByCypressId('permission-setting-deny_EVERYONE').should('have.class', 'btn-secondary') + }) + + it('shows alert icon on invalid settings in special groups', () => { + cy.getByCypressId('permission-setting-deny_LOGGED_IN').should('have.class', 'btn-secondary') + mockPermissionChangeApiRoutes({ + owner: 'mock', + sharedToUsers: [], + sharedToGroups: [ + { + groupName: '_EVERYONE', + canEdit: false + } + ] + }) + cy.getByCypressId('permission-setting-read_EVERYONE').click() + cy.get('svg.text-warning.me-2').should('be.visible') + mockPermissionChangeApiRoutes({ + owner: 'mock', + sharedToUsers: [], + sharedToGroups: [ + { + groupName: '_EVERYONE', + canEdit: true + } + ] + }) + cy.getByCypressId('permission-setting-write_EVERYONE').click() + cy.get('svg.text-warning.me-2').should('be.visible') + mockPermissionChangeApiRoutes({ + owner: 'mock', + sharedToUsers: [], + sharedToGroups: [ + { + groupName: '_EVERYONE', + canEdit: false + }, + { + groupName: '_LOGGED_IN', + canEdit: false + } + ] + }) + cy.getByCypressId('permission-setting-read_LOGGED_IN').click() + cy.get('svg.text-warning.me-2').should('not.exist') + mockPermissionChangeApiRoutes({ + owner: 'mock', + sharedToUsers: [], + sharedToGroups: [ + { + groupName: '_EVERYONE', + canEdit: true + }, + { + groupName: '_LOGGED_IN', + canEdit: false + } + ] + }) + cy.getByCypressId('permission-setting-write_EVERYONE').click() + cy.get('svg.text-warning.me-2').should('be.visible') + mockPermissionChangeApiRoutes({ + owner: 'mock', + sharedToUsers: [], + sharedToGroups: [ + { + groupName: '_EVERYONE', + canEdit: true + }, + { + groupName: '_LOGGED_IN', + canEdit: true + } + ] + }) + cy.getByCypressId('permission-setting-write_LOGGED_IN').click() + cy.get('svg.text-warning.me-2').should('not.exist') + }) +}) diff --git a/frontend/cypress/support/visit-test-editor.ts b/frontend/cypress/support/visit-test-editor.ts index b844f9e55..952470528 100644 --- a/frontend/cypress/support/visit-test-editor.ts +++ b/frontend/cypress/support/visit-test-editor.ts @@ -6,35 +6,37 @@ import type { Note } from '../../src/api/notes/types' export const testNoteId = 'test' +const mockMetadata = { + id: testNoteId, + aliases: [ + { + name: 'mock-note', + primaryAlias: true, + noteId: testNoteId + } + ], + primaryAddress: 'mock-note', + title: 'Mock Note', + description: 'Mocked note for testing', + tags: ['test', 'mock', 'cypress'], + updatedAt: '2021-04-24T09:27:51.000Z', + updateUsername: null, + viewCount: 0, + version: 2, + createdAt: '2021-04-24T09:27:51.000Z', + editedBy: [], + permissions: { + owner: 'mock', + sharedToUsers: [], + sharedToGroups: [] + } +} beforeEach(() => { cy.intercept(`api/private/notes/${testNoteId}`, { content: '', - metadata: { - id: testNoteId, - aliases: [ - { - name: 'mock-note', - primaryAlias: true, - noteId: testNoteId - } - ], - primaryAddress: 'mock-note', - title: 'Mock Note', - description: 'Mocked note for testing', - tags: ['test', 'mock', 'cypress'], - updatedAt: '2021-04-24T09:27:51.000Z', - updateUsername: null, - viewCount: 0, - version: 2, - createdAt: '2021-04-24T09:27:51.000Z', - editedBy: [], - permissions: { - owner: 'mock', - sharedToUsers: [], - sharedToGroups: [] - } - }, + metadata: mockMetadata, editedByAtPosition: [] } as Note) + cy.intercept(`api/private/notes/${testNoteId}/metadata`, mockMetadata) }) diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx index 06fb19c08..344faf513 100644 --- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx +++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-entry-special-group.tsx @@ -16,6 +16,7 @@ import { ToggleButtonGroup } from 'react-bootstrap' import { Eye as IconEye, Pencil as IconPencil, SlashCircle as IconSlashCircle } from 'react-bootstrap-icons' import { useTranslation } from 'react-i18next' import { PermissionInconsistentAlert } from './permission-inconsistent-alert' +import { cypressId } from '../../../../../../utils/cypress-attribute' export interface PermissionEntrySpecialGroupProps { level: AccessLevel @@ -101,6 +102,7 @@ export const PermissionEntrySpecialGroup: React.FC diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx index da59e74e5..c747b4691 100644 --- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx +++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-modal.tsx @@ -11,6 +11,7 @@ import { PermissionSectionSpecialGroups } from './permission-section-special-gro import { PermissionSectionUsers } from './permission-section-users' import React from 'react' import { Modal } from 'react-bootstrap' +import { cypressId } from '../../../../../../utils/cypress-attribute' /** * Modal for viewing and managing the permissions of the note. @@ -21,7 +22,12 @@ import { Modal } from 'react-bootstrap' export const PermissionModal: React.FC = ({ show, onHide }) => { const isOwner = useIsOwner() return ( - + diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx index 0da3a8cc3..6d49466e4 100644 --- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx +++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-modal/permission-section-owner.tsx @@ -12,6 +12,7 @@ import { PermissionOwnerChange } from './permission-owner-change' import { PermissionOwnerInfo } from './permission-owner-info' import React, { Fragment, useCallback, useState } from 'react' import { Trans } from 'react-i18next' +import { cypressId } from '../../../../../../utils/cypress-attribute' /** * Section in the permissions modal for managing the owner of a note. @@ -50,7 +51,9 @@ export const PermissionSectionOwner: React.FC = ({ disa
    -
  • +
  • {changeOwner ? ( ) : ( diff --git a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx index 6f6e89cbf..dd35f4d95 100644 --- a/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx +++ b/frontend/src/components/editor-page/sidebar/specific-sidebar-entries/permissions-sidebar-entry/permissions-sidebar-entry.tsx @@ -10,6 +10,7 @@ import { PermissionModal } from './permissions-modal/permission-modal' import React, { Fragment } from 'react' import { Lock as IconLock } from 'react-bootstrap-icons' import { Trans, useTranslation } from 'react-i18next' +import { cypressId } from '../../../../../utils/cypress-attribute' /** * Renders a button to open the permission modal for the sidebar. @@ -23,7 +24,12 @@ export const PermissionsSidebarEntry: React.FC = ({ c return ( - + diff --git a/frontend/src/pages/api/private/users/mock.ts b/frontend/src/pages/api/private/users/mock.ts new file mode 100644 index 000000000..2a790f40e --- /dev/null +++ b/frontend/src/pages/api/private/users/mock.ts @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import type { UserInfo } from '../../../../api/users/types' +import { HttpMethod, respondToMatchingRequest } from '../../../../handler-utils/respond-to-matching-request' +import type { NextApiRequest, NextApiResponse } from 'next' + +const handler = (req: NextApiRequest, res: NextApiResponse): void => { + respondToMatchingRequest(HttpMethod.GET, req, res, { + username: 'mock', + displayName: 'Mock User', + photoUrl: '' + }) +} + +export default handler