Project.test.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import { render, screen } from '@testing-library/react'
  2. import type { ReactNode } from 'react'
  3. import { beforeEach, describe, expect, it, vi } from 'vitest'
  4. import { Project } from './Project'
  5. const { mockUseIsFeatureEnabled, mockUseProjectPauseStatusQuery, mockUseSelectedProjectQuery } =
  6. vi.hoisted(() => ({
  7. mockUseIsFeatureEnabled: vi.fn(),
  8. mockUseProjectPauseStatusQuery: vi.fn(),
  9. mockUseSelectedProjectQuery: vi.fn(),
  10. }))
  11. vi.mock('next/link', () => ({
  12. default: ({ href, children }: { href: string; children: ReactNode }) => (
  13. <a href={href}>{children}</a>
  14. ),
  15. }))
  16. vi.mock('ui', () => ({
  17. Button: ({
  18. children,
  19. asChild,
  20. type: _type,
  21. ...props
  22. }: {
  23. children: ReactNode
  24. asChild?: boolean
  25. type?: string
  26. }) => (asChild ? <>{children}</> : <button {...props}>{children}</button>),
  27. Card: ({ children }: { children: ReactNode }) => <div>{children}</div>,
  28. CardContent: ({ children }: { children: ReactNode }) => <div>{children}</div>,
  29. }))
  30. vi.mock('ui-patterns/PageSection', () => ({
  31. PageSection: ({ children, id }: { children: ReactNode; id?: string }) => (
  32. <section id={id}>{children}</section>
  33. ),
  34. PageSectionContent: ({ children }: { children: ReactNode }) => <div>{children}</div>,
  35. PageSectionDescription: ({ children }: { children: ReactNode }) => <p>{children}</p>,
  36. PageSectionMeta: ({ children }: { children: ReactNode }) => <div>{children}</div>,
  37. PageSectionSummary: ({ children }: { children: ReactNode }) => <div>{children}</div>,
  38. PageSectionTitle: ({ children }: { children: ReactNode }) => <h2>{children}</h2>,
  39. }))
  40. vi.mock('@/components/interfaces/Project/ResumeProjectButton', () => ({
  41. ResumeProjectButton: () => <div>ResumeProjectButton</div>,
  42. }))
  43. vi.mock('./Infrastructure/PauseProjectButton', () => ({
  44. default: () => <div>PauseProjectButton</div>,
  45. }))
  46. vi.mock('./Infrastructure/RestartServerButton', () => ({
  47. default: () => <div>RestartServerButton</div>,
  48. }))
  49. vi.mock('@/data/projects/project-pause-status-query', () => ({
  50. useProjectPauseStatusQuery: mockUseProjectPauseStatusQuery,
  51. }))
  52. vi.mock('@/hooks/misc/useIsFeatureEnabled', () => ({
  53. useIsFeatureEnabled: mockUseIsFeatureEnabled,
  54. }))
  55. vi.mock('@/hooks/misc/useSelectedProject', () => ({
  56. useSelectedProjectQuery: mockUseSelectedProjectQuery,
  57. }))
  58. describe('Project settings availability', () => {
  59. beforeEach(() => {
  60. vi.clearAllMocks()
  61. mockUseIsFeatureEnabled.mockReturnValue({
  62. projectSettingsRestartProject: true,
  63. })
  64. mockUseProjectPauseStatusQuery.mockReturnValue({
  65. data: undefined,
  66. isError: false,
  67. isSuccess: false,
  68. })
  69. })
  70. it('shows the restart action for active projects', () => {
  71. mockUseSelectedProjectQuery.mockReturnValue({
  72. data: {
  73. parent_project_ref: null,
  74. ref: 'active-project',
  75. status: 'ACTIVE_HEALTHY',
  76. },
  77. })
  78. render(<Project />)
  79. expect(screen.getByText('Restart project')).toBeInTheDocument()
  80. expect(screen.getByText('RestartServerButton')).toBeInTheDocument()
  81. expect(screen.getByText('Pause project')).toBeInTheDocument()
  82. expect(screen.getByText('PauseProjectButton')).toBeInTheDocument()
  83. expect(screen.queryByText('ResumeProjectButton')).not.toBeInTheDocument()
  84. })
  85. it('shows the shared resume action for paused projects that can still be restored', () => {
  86. mockUseSelectedProjectQuery.mockReturnValue({
  87. data: {
  88. parent_project_ref: null,
  89. ref: 'paused-project',
  90. status: 'INACTIVE',
  91. },
  92. })
  93. mockUseProjectPauseStatusQuery.mockReturnValue({
  94. data: { can_restore: true },
  95. isError: false,
  96. isSuccess: true,
  97. })
  98. render(<Project />)
  99. expect(screen.getByText('Resume project')).toBeInTheDocument()
  100. expect(screen.getByText('Bring your paused project back online.')).toBeInTheDocument()
  101. expect(screen.getByText('ResumeProjectButton')).toBeInTheDocument()
  102. expect(screen.queryByText('Pause project')).not.toBeInTheDocument()
  103. expect(screen.queryByText('PauseProjectButton')).not.toBeInTheDocument()
  104. expect(screen.queryByText('RestartServerButton')).not.toBeInTheDocument()
  105. })
  106. it('links back to the dashboard when the paused project can no longer be restored', () => {
  107. mockUseSelectedProjectQuery.mockReturnValue({
  108. data: {
  109. parent_project_ref: null,
  110. ref: 'paused-project',
  111. status: 'INACTIVE',
  112. },
  113. })
  114. mockUseProjectPauseStatusQuery.mockReturnValue({
  115. data: { can_restore: false },
  116. isError: false,
  117. isSuccess: true,
  118. })
  119. render(<Project />)
  120. expect(screen.getAllByText('View project dashboard')).toHaveLength(2)
  121. expect(
  122. screen.getByText(
  123. 'This project can no longer be resumed here. Open the dashboard to download backups and view recovery options.'
  124. )
  125. ).toBeInTheDocument()
  126. expect(screen.getByRole('link', { name: 'View project dashboard' })).toHaveAttribute(
  127. 'href',
  128. '/project/paused-project'
  129. )
  130. expect(screen.queryByText('Pause project')).not.toBeInTheDocument()
  131. expect(screen.queryByText('PauseProjectButton')).not.toBeInTheDocument()
  132. expect(screen.queryByText('ResumeProjectButton')).not.toBeInTheDocument()
  133. })
  134. })