sso-widget.test.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { expect } from 'chai'
  2. import sinon from 'sinon'
  3. import {
  4. screen,
  5. fireEvent,
  6. render,
  7. waitFor,
  8. within,
  9. } from '@testing-library/react'
  10. import { FetchError } from '../../../../../../frontend/js/infrastructure/fetch-json'
  11. import { SSOLinkingWidget } from '../../../../../../frontend/js/features/settings/components/linking/sso-widget'
  12. describe('<SSOLinkingWidget />', function () {
  13. const defaultProps = {
  14. providerId: 'integration_id',
  15. title: 'integration',
  16. description: 'integration description',
  17. helpPath: '/help/integration',
  18. linkPath: '/integration/link',
  19. onUnlink: () => Promise.resolve(),
  20. }
  21. it('should render', function () {
  22. render(<SSOLinkingWidget {...defaultProps} />)
  23. screen.getByText('integration')
  24. screen.getByText('integration description')
  25. expect(
  26. screen.getByRole('link', { name: /learn more/i }).getAttribute('href')
  27. ).to.equal('/help/integration')
  28. })
  29. describe('when unlinked', function () {
  30. it('should render a link to `linkPath`', function () {
  31. render(<SSOLinkingWidget {...defaultProps} linked={false} />)
  32. expect(
  33. screen.getByRole('button', { name: /link/i }).getAttribute('href')
  34. ).to.equal('/integration/link?intent=link')
  35. })
  36. })
  37. describe('when linked', function () {
  38. let unlinkFunction: sinon.SinonStub
  39. beforeEach(function () {
  40. unlinkFunction = sinon.stub()
  41. render(
  42. <SSOLinkingWidget {...defaultProps} linked onUnlink={unlinkFunction} />
  43. )
  44. })
  45. it('should display an `unlink` button', function () {
  46. screen.getByRole('button', { name: /unlink/i })
  47. })
  48. it('should open a modal to confirm integration unlinking', function () {
  49. fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
  50. screen.getByText('Unlink integration Account')
  51. screen.getByText(
  52. 'Warning: When you unlink your account from integration you will not be able to sign in using integration anymore.'
  53. )
  54. })
  55. it('should cancel unlinking when clicking cancel in the confirmation modal', async function () {
  56. fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
  57. const cancelBtn = screen.getByRole('button', {
  58. name: 'Cancel',
  59. hidden: false,
  60. })
  61. fireEvent.click(cancelBtn)
  62. await screen.findByRole('button', { name: 'Cancel', hidden: true })
  63. expect(unlinkFunction).not.to.have.been.called
  64. })
  65. })
  66. describe('unlinking an account', function () {
  67. let confirmBtn: HTMLElement, unlinkFunction: sinon.SinonStub
  68. beforeEach(function () {
  69. unlinkFunction = sinon.stub()
  70. render(
  71. <SSOLinkingWidget {...defaultProps} linked onUnlink={unlinkFunction} />
  72. )
  73. fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
  74. confirmBtn = within(screen.getByRole('dialog')).getByRole('button', {
  75. name: /unlink/i,
  76. hidden: false,
  77. })
  78. })
  79. it('should make an `unlink` request', function () {
  80. unlinkFunction.resolves()
  81. fireEvent.click(confirmBtn)
  82. expect(unlinkFunction).to.have.been.called
  83. })
  84. it('should display feedback while the request is inflight', async function () {
  85. unlinkFunction.returns(
  86. new Promise<void>(resolve => {
  87. setTimeout(resolve, 500)
  88. })
  89. )
  90. fireEvent.click(confirmBtn)
  91. await waitFor(() =>
  92. expect(screen.getByRole('button', { name: 'Unlinking' }))
  93. )
  94. })
  95. })
  96. describe('when unlinking fails', function () {
  97. beforeEach(function () {
  98. const unlinkFunction = sinon
  99. .stub()
  100. .rejects(new FetchError('unlinking failed', ''))
  101. render(
  102. <SSOLinkingWidget {...defaultProps} linked onUnlink={unlinkFunction} />
  103. )
  104. fireEvent.click(screen.getByRole('button', { name: /unlink/i }))
  105. const confirmBtn = within(screen.getByRole('dialog')).getByRole(
  106. 'button',
  107. {
  108. name: /unlink/i,
  109. hidden: false,
  110. }
  111. )
  112. fireEvent.click(confirmBtn)
  113. })
  114. it('should display an error message ', async function () {
  115. await screen.findByText('Something went wrong. Please try again.')
  116. })
  117. it('should display the unlink button ', async function () {
  118. await screen.findByRole('button', { name: /unlink/i })
  119. })
  120. })
  121. })