diff --git a/services/web/frontend/js/features/project-list/components/dropdown/actions-dropdown.tsx b/services/web/frontend/js/features/project-list/components/dropdown/actions-dropdown.tsx
index 0fbdc4b30f..c6f13e8e2c 100644
--- a/services/web/frontend/js/features/project-list/components/dropdown/actions-dropdown.tsx
+++ b/services/web/frontend/js/features/project-list/components/dropdown/actions-dropdown.tsx
@@ -160,18 +160,28 @@ function ActionsDropdown({ project }: ActionDropdownProps) {
)}
- {text => (
+ {(text, handleOpenModal) => (
-
+
{text}
)}
- {text => (
+ {(text, handleOpenModal) => (
-
+
{text}
diff --git a/services/web/test/frontend/features/project-list/components/table/cells/actions-dropdown.test.tsx b/services/web/test/frontend/features/project-list/components/table/cells/actions-dropdown.test.tsx
new file mode 100644
index 0000000000..7543031e5b
--- /dev/null
+++ b/services/web/test/frontend/features/project-list/components/table/cells/actions-dropdown.test.tsx
@@ -0,0 +1,85 @@
+import { expect } from 'chai'
+import { fireEvent, screen, waitFor } from '@testing-library/react'
+import fetchMock from 'fetch-mock'
+import ActionsDropdown from '../../../../../../../frontend/js/features/project-list/components/dropdown/actions-dropdown'
+import {
+ trashedProject,
+ trashedAndNotOwnedProject,
+} from '../../../fixtures/projects-data'
+import {
+ renderWithProjectListContext,
+ resetProjectListContextFetch,
+} from '../../../helpers/render-with-context'
+
+describe('', function () {
+ afterEach(function () {
+ resetProjectListContextFetch()
+ window.metaAttributesCache.clear()
+ })
+
+ describe('Delete button for trashed project (mobile view)', function () {
+ it('opens the delete modal when clicking Delete in the dropdown', async function () {
+ window.metaAttributesCache.set('ol-user_id', trashedProject.owner?.id)
+ const project = Object.assign({}, trashedProject)
+ const deleteProjectMock = fetchMock.delete(
+ `express:/project/:projectId`,
+ { status: 200 },
+ { delay: 0 }
+ )
+
+ renderWithProjectListContext()
+
+ const toggle = screen.getByRole('button', { name: 'Actions' })
+ fireEvent.click(toggle)
+
+ const deleteBtn = await screen.findByRole('menuitem', { name: /delete/i })
+ fireEvent.click(deleteBtn)
+
+ await screen.findByText('Delete Projects')
+
+ const confirmBtn = screen.getByRole('button', {
+ name: 'Confirm',
+ }) as HTMLButtonElement
+ fireEvent.click(confirmBtn)
+
+ await waitFor(
+ () =>
+ expect(deleteProjectMock.callHistory.called(`/project/${project.id}`))
+ .to.be.true
+ )
+ })
+ })
+
+ describe('Leave button for trashed non-owned project (mobile view)', function () {
+ it('opens the leave modal when clicking Leave in the dropdown', async function () {
+ const project = Object.assign({}, trashedAndNotOwnedProject)
+ const leaveProjectMock = fetchMock.post(
+ `express:/project/${project.id}/leave`,
+ { status: 200 },
+ { delay: 0 }
+ )
+
+ renderWithProjectListContext()
+
+ const toggle = screen.getByRole('button', { name: 'Actions' })
+ fireEvent.click(toggle)
+
+ const leaveBtn = await screen.findByRole('menuitem', { name: /leave/i })
+ fireEvent.click(leaveBtn)
+
+ await screen.findByText('Leave Projects')
+
+ const confirmBtn = screen.getByRole('button', {
+ name: 'Confirm',
+ }) as HTMLButtonElement
+ fireEvent.click(confirmBtn)
+
+ await waitFor(
+ () =>
+ expect(
+ leaveProjectMock.callHistory.called(`/project/${project.id}/leave`)
+ ).to.be.true
+ )
+ })
+ })
+})