tests(permissions): add cypress tests for permission alert icon

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Erik Michelson 2023-10-13 17:02:41 +02:00
parent 6d69b294cb
commit 5ccc9059f0
7 changed files with 182 additions and 28 deletions

View file

@ -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')
})
})

View file

@ -6,35 +6,37 @@
import type { Note } from '../../src/api/notes/types' import type { Note } from '../../src/api/notes/types'
export const testNoteId = 'test' 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(() => { beforeEach(() => {
cy.intercept(`api/private/notes/${testNoteId}`, { cy.intercept(`api/private/notes/${testNoteId}`, {
content: '', content: '',
metadata: { metadata: 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: []
}
},
editedByAtPosition: [] editedByAtPosition: []
} as Note) } as Note)
cy.intercept(`api/private/notes/${testNoteId}/metadata`, mockMetadata)
}) })

View file

@ -16,6 +16,7 @@ import { ToggleButtonGroup } from 'react-bootstrap'
import { Eye as IconEye, Pencil as IconPencil, SlashCircle as IconSlashCircle } from 'react-bootstrap-icons' import { Eye as IconEye, Pencil as IconPencil, SlashCircle as IconSlashCircle } from 'react-bootstrap-icons'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { PermissionInconsistentAlert } from './permission-inconsistent-alert' import { PermissionInconsistentAlert } from './permission-inconsistent-alert'
import { cypressId } from '../../../../../../utils/cypress-attribute'
export interface PermissionEntrySpecialGroupProps { export interface PermissionEntrySpecialGroupProps {
level: AccessLevel level: AccessLevel
@ -101,6 +102,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
onClick={onSetEntryDenied} onClick={onSetEntryDenied}
disabled={disabled} disabled={disabled}
className={'p-1'} className={'p-1'}
{...cypressId(`permission-setting-deny${type}`)}
/> />
<IconButton <IconButton
icon={IconEye} icon={IconEye}
@ -109,6 +111,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
onClick={onSetEntryReadOnly} onClick={onSetEntryReadOnly}
disabled={disabled} disabled={disabled}
className={'p-1'} className={'p-1'}
{...cypressId(`permission-setting-read${type}`)}
/> />
<IconButton <IconButton
icon={IconPencil} icon={IconPencil}
@ -117,6 +120,7 @@ export const PermissionEntrySpecialGroup: React.FC<PermissionEntrySpecialGroupPr
onClick={onSetEntryWriteable} onClick={onSetEntryWriteable}
disabled={disabled} disabled={disabled}
className={'p-1'} className={'p-1'}
{...cypressId(`permission-setting-write${type}`)}
/> />
</ToggleButtonGroup> </ToggleButtonGroup>
</div> </div>

View file

@ -11,6 +11,7 @@ import { PermissionSectionSpecialGroups } from './permission-section-special-gro
import { PermissionSectionUsers } from './permission-section-users' import { PermissionSectionUsers } from './permission-section-users'
import React from 'react' import React from 'react'
import { Modal } from 'react-bootstrap' import { Modal } from 'react-bootstrap'
import { cypressId } from '../../../../../../utils/cypress-attribute'
/** /**
* Modal for viewing and managing the permissions of the note. * Modal for viewing and managing the permissions of the note.
@ -21,7 +22,12 @@ import { Modal } from 'react-bootstrap'
export const PermissionModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => { export const PermissionModal: React.FC<ModalVisibilityProps> = ({ show, onHide }) => {
const isOwner = useIsOwner() const isOwner = useIsOwner()
return ( return (
<CommonModal show={show} onHide={onHide} showCloseButton={true} titleI18nKey={'editor.modal.permissions.title'}> <CommonModal
show={show}
onHide={onHide}
showCloseButton={true}
titleI18nKey={'editor.modal.permissions.title'}
{...cypressId('permission-modal')}>
<Modal.Body> <Modal.Body>
<PermissionSectionOwner disabled={!isOwner} /> <PermissionSectionOwner disabled={!isOwner} />
<PermissionSectionUsers disabled={!isOwner} /> <PermissionSectionUsers disabled={!isOwner} />

View file

@ -12,6 +12,7 @@ import { PermissionOwnerChange } from './permission-owner-change'
import { PermissionOwnerInfo } from './permission-owner-info' import { PermissionOwnerInfo } from './permission-owner-info'
import React, { Fragment, useCallback, useState } from 'react' import React, { Fragment, useCallback, useState } from 'react'
import { Trans } from 'react-i18next' import { Trans } from 'react-i18next'
import { cypressId } from '../../../../../../utils/cypress-attribute'
/** /**
* Section in the permissions modal for managing the owner of a note. * Section in the permissions modal for managing the owner of a note.
@ -50,7 +51,9 @@ export const PermissionSectionOwner: React.FC<PermissionDisabledProps> = ({ disa
<Trans i18nKey={'editor.modal.permissions.owner'} /> <Trans i18nKey={'editor.modal.permissions.owner'} />
</h5> </h5>
<ul className={'list-group'}> <ul className={'list-group'}>
<li className={'list-group-item d-flex flex-row align-items-center justify-content-between'}> <li
className={'list-group-item d-flex flex-row align-items-center justify-content-between'}
{...cypressId('permission-owner-name')}>
{changeOwner ? ( {changeOwner ? (
<PermissionOwnerChange onConfirmOwnerChange={onOwnerChange} /> <PermissionOwnerChange onConfirmOwnerChange={onOwnerChange} />
) : ( ) : (

View file

@ -10,6 +10,7 @@ import { PermissionModal } from './permissions-modal/permission-modal'
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import { Lock as IconLock } from 'react-bootstrap-icons' import { Lock as IconLock } from 'react-bootstrap-icons'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import { cypressId } from '../../../../../utils/cypress-attribute'
/** /**
* Renders a button to open the permission modal for the sidebar. * Renders a button to open the permission modal for the sidebar.
@ -23,7 +24,12 @@ export const PermissionsSidebarEntry: React.FC<SpecificSidebarEntryProps> = ({ c
return ( return (
<Fragment> <Fragment>
<SidebarButton hide={hide} className={className} icon={IconLock} onClick={showModal}> <SidebarButton
hide={hide}
className={className}
icon={IconLock}
onClick={showModal}
{...cypressId('sidebar-permission-btn')}>
<Trans i18nKey={'editor.modal.permissions.title'} /> <Trans i18nKey={'editor.modal.permissions.title'} />
</SidebarButton> </SidebarButton>
<PermissionModal show={modalVisibility} onHide={closeModal} /> <PermissionModal show={modalVisibility} onHide={closeModal} />

View file

@ -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<UserInfo>(HttpMethod.GET, req, res, {
username: 'mock',
displayName: 'Mock User',
photoUrl: ''
})
}
export default handler