first commit
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { expect } from 'chai'
|
||||
import { screen, render } from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
|
||||
import LeaveModalContent from '../../../../../../frontend/js/features/settings/components/leave/modal-content'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
describe('<LeaveModalContent />', function () {
|
||||
beforeEach(function () {
|
||||
Object.assign(getMeta('ol-ExposedSettings'), { isOverleaf: true })
|
||||
window.metaAttributesCache.set('ol-hasPassword', true)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
})
|
||||
|
||||
it('disable delete button if form is not valid', function () {
|
||||
render(
|
||||
<LeaveModalContent
|
||||
handleHide={() => {}}
|
||||
inFlight={false}
|
||||
setInFlight={() => {}}
|
||||
/>
|
||||
)
|
||||
screen.getByLabelText('Email')
|
||||
|
||||
const deleteButton = screen.getByRole('button', {
|
||||
name: 'Delete',
|
||||
})
|
||||
expect(deleteButton.hasAttribute('disabled')).to.be.true
|
||||
})
|
||||
|
||||
it('shows no password message', function () {
|
||||
window.metaAttributesCache.set('ol-isSaas', true)
|
||||
window.metaAttributesCache.set('ol-hasPassword', false)
|
||||
render(
|
||||
<LeaveModalContent
|
||||
handleHide={() => {}}
|
||||
inFlight={false}
|
||||
setInFlight={() => {}}
|
||||
/>
|
||||
)
|
||||
|
||||
const link = screen.getByRole('link', {
|
||||
name: 'Please use the password reset form to set a password before deleting your account',
|
||||
})
|
||||
expect(link.getAttribute('href')).to.equal('/user/password/reset')
|
||||
})
|
||||
})
|
@@ -0,0 +1,196 @@
|
||||
import { expect } from 'chai'
|
||||
import sinon from 'sinon'
|
||||
import { fireEvent, screen, render, waitFor } from '@testing-library/react'
|
||||
import fetchMock, { type FetchMock } from 'fetch-mock'
|
||||
|
||||
import LeaveModalForm from '../../../../../../frontend/js/features/settings/components/leave/modal-form'
|
||||
import * as useLocationModule from '../../../../../../frontend/js/shared/hooks/use-location'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
describe('<LeaveModalForm />', function () {
|
||||
beforeEach(function () {
|
||||
window.metaAttributesCache.set('ol-usersEmail', 'foo@bar.com')
|
||||
Object.assign(getMeta('ol-ExposedSettings'), { isOverleaf: true })
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
})
|
||||
|
||||
it('validates form', async function () {
|
||||
const setIsFormValid = sinon.stub()
|
||||
render(
|
||||
<LeaveModalForm
|
||||
setInFlight={() => {}}
|
||||
isFormValid={false}
|
||||
setIsFormValid={setIsFormValid}
|
||||
/>
|
||||
)
|
||||
|
||||
const emailInput = screen.getByLabelText('Email')
|
||||
fireEvent.change(emailInput, { target: { value: 'FOO@bar.com' } })
|
||||
|
||||
const passwordInput = screen.getByLabelText('Password')
|
||||
fireEvent.change(passwordInput, { target: { value: 'foobar' } })
|
||||
|
||||
const checkbox = screen.getByLabelText(
|
||||
'I understand this will delete all projects in my Overleaf account with email address foo@bar.com'
|
||||
)
|
||||
fireEvent.click(checkbox)
|
||||
|
||||
const setIsFormValidCalls = setIsFormValid.getCalls()
|
||||
const lastSetIsFormValidCall = setIsFormValidCalls.pop()
|
||||
expect(lastSetIsFormValidCall!.args[0]).to.be.true
|
||||
|
||||
for (const setIsFormValidCall of setIsFormValidCalls) {
|
||||
expect(setIsFormValidCall.args[0]).to.be.false
|
||||
}
|
||||
})
|
||||
|
||||
describe('submits', async function () {
|
||||
let setInFlight: sinon.SinonStub
|
||||
let setIsFormValid: sinon.SinonStub
|
||||
let deleteMock: FetchMock
|
||||
let assignStub: sinon.SinonStub
|
||||
|
||||
beforeEach(function () {
|
||||
setInFlight = sinon.stub()
|
||||
setIsFormValid = sinon.stub()
|
||||
deleteMock = fetchMock.post('/user/delete', 200)
|
||||
assignStub = sinon.stub()
|
||||
this.locationStub = sinon.stub(useLocationModule, 'useLocation').returns({
|
||||
assign: assignStub,
|
||||
replace: sinon.stub(),
|
||||
reload: sinon.stub(),
|
||||
setHash: sinon.stub(),
|
||||
})
|
||||
Object.assign(getMeta('ol-ExposedSettings'), { isOverleaf: true })
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
this.locationStub.restore()
|
||||
})
|
||||
|
||||
it('with valid form', async function () {
|
||||
render(
|
||||
<LeaveModalForm
|
||||
setInFlight={setInFlight}
|
||||
isFormValid
|
||||
setIsFormValid={setIsFormValid}
|
||||
/>
|
||||
)
|
||||
|
||||
fireEvent.submit(screen.getByLabelText('Email'))
|
||||
|
||||
sinon.assert.calledOnce(setInFlight)
|
||||
sinon.assert.calledWithMatch(setInFlight, true)
|
||||
expect(deleteMock.callHistory.called()).to.be.true
|
||||
await waitFor(() => {
|
||||
sinon.assert.calledTwice(setInFlight)
|
||||
sinon.assert.calledWithMatch(setInFlight, false)
|
||||
sinon.assert.calledOnce(assignStub)
|
||||
sinon.assert.calledWith(assignStub, '/')
|
||||
})
|
||||
})
|
||||
|
||||
it('with invalid form', async function () {
|
||||
render(
|
||||
<LeaveModalForm
|
||||
setInFlight={setInFlight}
|
||||
isFormValid={false}
|
||||
setIsFormValid={setIsFormValid}
|
||||
/>
|
||||
)
|
||||
|
||||
fireEvent.submit(screen.getByLabelText('Email'))
|
||||
|
||||
expect(deleteMock.callHistory.called()).to.be.false
|
||||
sinon.assert.notCalled(setInFlight)
|
||||
})
|
||||
})
|
||||
|
||||
it('handles credentials error without Saas tip', async function () {
|
||||
Object.assign(getMeta('ol-ExposedSettings'), { isOverleaf: false })
|
||||
fetchMock.post('/user/delete', 403)
|
||||
render(
|
||||
<LeaveModalForm
|
||||
setInFlight={() => {}}
|
||||
isFormValid
|
||||
setIsFormValid={() => {}}
|
||||
/>
|
||||
)
|
||||
|
||||
fireEvent.submit(screen.getByLabelText('Email'))
|
||||
|
||||
await waitFor(() => {
|
||||
screen.getByText(/Your email or password is incorrect. Please try again/)
|
||||
})
|
||||
expect(screen.queryByText(/If you cannot remember your password/)).to.not
|
||||
.exist
|
||||
})
|
||||
|
||||
it('handles credentials error with Saas tip', async function () {
|
||||
fetchMock.post('/user/delete', 403)
|
||||
render(
|
||||
<LeaveModalForm
|
||||
setInFlight={() => {}}
|
||||
isFormValid
|
||||
setIsFormValid={() => {}}
|
||||
/>
|
||||
)
|
||||
|
||||
fireEvent.submit(screen.getByLabelText('Email'))
|
||||
|
||||
await waitFor(() => {
|
||||
screen.getByText(/Your email or password is incorrect. Please try again/)
|
||||
})
|
||||
screen.getByText(/If you cannot remember your password/)
|
||||
const link = screen.getByRole('link', { name: 'reset your password' })
|
||||
expect(link.getAttribute('href')).to.equal('/user/password/reset')
|
||||
})
|
||||
|
||||
it('handles subscription error', async function () {
|
||||
fetchMock.post('/user/delete', {
|
||||
status: 422,
|
||||
body: {
|
||||
error: 'SubscriptionAdminDeletionError',
|
||||
},
|
||||
})
|
||||
|
||||
render(
|
||||
<LeaveModalForm
|
||||
setInFlight={() => {}}
|
||||
isFormValid
|
||||
setIsFormValid={() => {}}
|
||||
/>
|
||||
)
|
||||
|
||||
fireEvent.submit(screen.getByLabelText('Email'))
|
||||
|
||||
await waitFor(() => {
|
||||
screen.getByText(
|
||||
'You cannot delete your account while on a subscription. Please cancel your subscription and try again. If you keep seeing this message please contact us.'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('handles generic error', async function () {
|
||||
fetchMock.post('/user/delete', 500)
|
||||
render(
|
||||
<LeaveModalForm
|
||||
setInFlight={() => {}}
|
||||
isFormValid
|
||||
setIsFormValid={() => {}}
|
||||
/>
|
||||
)
|
||||
|
||||
fireEvent.submit(screen.getByLabelText('Email'))
|
||||
|
||||
await waitFor(() => {
|
||||
screen.getByText(
|
||||
'Sorry, something went wrong deleting your account. Please try again in a minute.'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
@@ -0,0 +1,66 @@
|
||||
import sinon from 'sinon'
|
||||
import { fireEvent, screen, render, waitFor } from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
|
||||
import LeaveModal from '../../../../../../frontend/js/features/settings/components/leave/modal'
|
||||
import getMeta from '@/utils/meta'
|
||||
|
||||
describe('<LeaveModal />', function () {
|
||||
beforeEach(function () {
|
||||
window.metaAttributesCache.set('ol-usersEmail', 'foo@bar.com')
|
||||
Object.assign(getMeta('ol-ExposedSettings'), { isOverleaf: true })
|
||||
window.metaAttributesCache.set('ol-hasPassword', true)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
})
|
||||
|
||||
it('closes modal on cancel', async function () {
|
||||
const handleClose = sinon.stub()
|
||||
render(<LeaveModal isOpen handleClose={handleClose} />)
|
||||
|
||||
const cancelButton = screen.getByRole('button', {
|
||||
name: 'Cancel',
|
||||
})
|
||||
fireEvent.click(cancelButton)
|
||||
|
||||
sinon.assert.calledOnce(handleClose)
|
||||
})
|
||||
|
||||
it('does not close modal while in flight', async function () {
|
||||
fetchMock.post('/user/delete', new Promise(() => {}))
|
||||
const handleClose = sinon.stub()
|
||||
render(<LeaveModal isOpen handleClose={handleClose} />)
|
||||
|
||||
fillValidForm()
|
||||
|
||||
const deleteButton = screen.getByRole('button', {
|
||||
name: 'Delete',
|
||||
})
|
||||
fireEvent.click(deleteButton)
|
||||
|
||||
await waitFor(() => {
|
||||
screen.getByRole('button', {
|
||||
name: 'Deleting…',
|
||||
})
|
||||
})
|
||||
|
||||
const cancelButton = screen.getByRole('button', {
|
||||
name: 'Cancel',
|
||||
})
|
||||
fireEvent.click(cancelButton)
|
||||
|
||||
sinon.assert.notCalled(handleClose)
|
||||
})
|
||||
})
|
||||
|
||||
function fillValidForm() {
|
||||
fireEvent.change(screen.getByLabelText('Email'), {
|
||||
target: { value: 'foo@bar.com' },
|
||||
})
|
||||
fireEvent.change(screen.getByLabelText('Password'), {
|
||||
target: { value: 'foobar' },
|
||||
})
|
||||
fireEvent.click(screen.getByLabelText(/I understand/))
|
||||
}
|
Reference in New Issue
Block a user