mirror of
https://github.com/overleaf/overleaf.git
synced 2024-12-02 15:53:04 -05:00
f8094bbdb6
[web] Prevent updating password for managed users linked to group SSO GitOrigin-RevId: f40bba47575cfac1b1e42d3138112c0db4f7865c
214 lines
6.1 KiB
TypeScript
214 lines
6.1 KiB
TypeScript
import { expect } from 'chai'
|
||
import { fireEvent, screen, render } from '@testing-library/react'
|
||
import fetchMock from 'fetch-mock'
|
||
import PasswordSection from '../../../../../frontend/js/features/settings/components/password-section'
|
||
|
||
describe('<PasswordSection />', function () {
|
||
beforeEach(function () {
|
||
window.metaAttributesCache = window.metaAttributesCache || new Map()
|
||
window.metaAttributesCache.set('ol-ExposedSettings', {
|
||
isOverleaf: true,
|
||
})
|
||
window.metaAttributesCache.set(
|
||
'ol-isExternalAuthenticationSystemUsed',
|
||
false
|
||
)
|
||
window.metaAttributesCache.set('ol-hasPassword', true)
|
||
})
|
||
|
||
afterEach(function () {
|
||
window.metaAttributesCache = new Map()
|
||
fetchMock.reset()
|
||
})
|
||
|
||
it('shows password managed externally message', async function () {
|
||
window.metaAttributesCache.set('ol-ExposedSettings', {
|
||
isOverleaf: false,
|
||
})
|
||
window.metaAttributesCache.set(
|
||
'ol-isExternalAuthenticationSystemUsed',
|
||
true
|
||
)
|
||
render(<PasswordSection />)
|
||
|
||
screen.getByText('Password settings are managed externally')
|
||
})
|
||
|
||
it('shows no existing password message', async function () {
|
||
window.metaAttributesCache.set('ol-hasPassword', false)
|
||
render(<PasswordSection />)
|
||
|
||
screen.getByText('Please use the password reset form to set your password')
|
||
})
|
||
|
||
it('submits all inputs', async function () {
|
||
const updateMock = fetchMock.post('/user/password/update', 200)
|
||
render(<PasswordSection />)
|
||
submitValidForm()
|
||
|
||
expect(updateMock.called()).to.be.true
|
||
expect(JSON.parse(updateMock.lastCall()![1]!.body as string)).to.deep.equal(
|
||
{
|
||
currentPassword: 'foobar',
|
||
newPassword1: 'barbaz',
|
||
newPassword2: 'barbaz',
|
||
}
|
||
)
|
||
})
|
||
|
||
it('disables button on invalid form', async function () {
|
||
const updateMock = fetchMock.post('/user/password/update', 200)
|
||
render(<PasswordSection />)
|
||
|
||
fireEvent.click(
|
||
screen.getByRole('button', {
|
||
name: 'Change',
|
||
})
|
||
)
|
||
expect(updateMock.called()).to.be.false
|
||
})
|
||
|
||
it('validates inputs', async function () {
|
||
render(<PasswordSection />)
|
||
|
||
const button = screen.getByRole('button', {
|
||
name: 'Change',
|
||
}) as HTMLButtonElement
|
||
expect(button.disabled).to.be.true
|
||
|
||
fireEvent.change(screen.getByLabelText('Current Password'), {
|
||
target: { value: 'foobar' },
|
||
})
|
||
expect(button.disabled).to.be.true
|
||
|
||
fireEvent.change(screen.getByLabelText('New Password'), {
|
||
target: { value: 'barbaz' },
|
||
})
|
||
expect(button.disabled).to.be.true
|
||
|
||
fireEvent.change(screen.getByLabelText('Confirm New Password'), {
|
||
target: { value: 'bar' },
|
||
})
|
||
screen.getByText('Doesn’t match')
|
||
expect(button.disabled).to.be.true
|
||
|
||
fireEvent.change(screen.getByLabelText('Confirm New Password'), {
|
||
target: { value: 'barbaz' },
|
||
})
|
||
expect(button.disabled).to.be.false
|
||
})
|
||
|
||
it('sets browser validation attributes', async function () {
|
||
window.metaAttributesCache.set('ol-passwordStrengthOptions', {
|
||
length: {
|
||
min: 3,
|
||
},
|
||
})
|
||
render(<PasswordSection />)
|
||
|
||
const currentPasswordInput = screen.getByLabelText(
|
||
'Current Password'
|
||
) as HTMLInputElement
|
||
const newPassword1Input = screen.getByLabelText(
|
||
'New Password'
|
||
) as HTMLInputElement
|
||
const newPassword2Input = screen.getByLabelText(
|
||
'Confirm New Password'
|
||
) as HTMLInputElement
|
||
|
||
expect(newPassword1Input.minLength).to.equal(3)
|
||
|
||
// not required before changes
|
||
expect(currentPasswordInput.required).to.be.false
|
||
expect(newPassword1Input.required).to.be.false
|
||
expect(newPassword2Input.required).to.be.false
|
||
|
||
fireEvent.change(currentPasswordInput, {
|
||
target: { value: 'foobar' },
|
||
})
|
||
fireEvent.change(newPassword1Input, {
|
||
target: { value: 'barbaz' },
|
||
})
|
||
fireEvent.change(newPassword2Input, {
|
||
target: { value: 'barbaz' },
|
||
})
|
||
expect(currentPasswordInput.required).to.be.true
|
||
expect(newPassword1Input.required).to.be.true
|
||
expect(newPassword2Input.required).to.be.true
|
||
})
|
||
|
||
it('shows inflight state and success message', async function () {
|
||
let finishUpdateCall: (value: any) => void = () => {}
|
||
fetchMock.post(
|
||
'/user/password/update',
|
||
new Promise(resolve => (finishUpdateCall = resolve))
|
||
)
|
||
render(<PasswordSection />)
|
||
submitValidForm()
|
||
|
||
await screen.findByText('Saving…')
|
||
|
||
finishUpdateCall({
|
||
status: 200,
|
||
body: {
|
||
message: {
|
||
type: 'success',
|
||
email: 'tim.alby@overleaf.com',
|
||
text: 'Password changed',
|
||
},
|
||
},
|
||
})
|
||
await screen.findByRole('button', {
|
||
name: 'Change',
|
||
})
|
||
screen.getByText('Password changed')
|
||
})
|
||
|
||
it('shows server error', async function () {
|
||
fetchMock.post('/user/password/update', 500)
|
||
render(<PasswordSection />)
|
||
submitValidForm()
|
||
await screen.findByText('Something went wrong. Please try again.')
|
||
})
|
||
|
||
it('shows server error message', async function () {
|
||
fetchMock.post('/user/password/update', {
|
||
status: 400,
|
||
body: {
|
||
message: 'Your old password is wrong',
|
||
},
|
||
})
|
||
render(<PasswordSection />)
|
||
submitValidForm()
|
||
|
||
await screen.findByText('Your old password is wrong')
|
||
})
|
||
|
||
it('shows message when user cannot use password log in', async function () {
|
||
window.metaAttributesCache.set('ol-cannot-change-password', true)
|
||
render(<PasswordSection />)
|
||
await screen.findByRole('heading', { name: 'Change Password' })
|
||
screen.getByText(
|
||
'You can’t add or change your password because your group or organization uses',
|
||
{ exact: false }
|
||
)
|
||
screen.getByRole('link', { name: 'single sign-on (SSO)' })
|
||
})
|
||
})
|
||
|
||
function submitValidForm() {
|
||
fireEvent.change(screen.getByLabelText('Current Password'), {
|
||
target: { value: 'foobar' },
|
||
})
|
||
fireEvent.change(screen.getByLabelText('New Password'), {
|
||
target: { value: 'barbaz' },
|
||
})
|
||
fireEvent.change(screen.getByLabelText('Confirm New Password'), {
|
||
target: { value: 'barbaz' },
|
||
})
|
||
fireEvent.click(
|
||
screen.getByRole('button', {
|
||
name: 'Change',
|
||
})
|
||
)
|
||
}
|