test: migrate LoginForm component test to vitest

Cypress has some limitations:
- its vue 2 supported was removed
- it fails with our vue 3 migration due to 2 different vue versions
  being present
- its slow compared to vitest

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
Ferdinand Thiessen 2025-09-30 23:02:42 +02:00
parent 678a8a75ad
commit ba01412389
No known key found for this signature in database
GPG key ID: 45FAE7268762B400
6 changed files with 109 additions and 82 deletions

View file

@ -1,76 +0,0 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import LoginForm from './LoginForm.vue'
describe('core: LoginForm', { testIsolation: true }, () => {
beforeEach(() => {
// Mock the required global state
cy.window().then(($window) => {
$window.OC = {
theme: {
name: 'J\'s cloud',
},
requestToken: 'request-token',
}
})
})
/**
* Ensure that characters like ' are not double HTML escaped.
* This was a bug in https://github.com/nextcloud/server/issues/34990
*/
it('does not double escape special characters in product name', () => {
cy.mount(LoginForm, {
propsData: {
username: 'test-user',
},
})
cy.get('h2').contains('J\'s cloud')
})
it('fills username from props into form', () => {
cy.mount(LoginForm, {
propsData: {
username: 'test-user',
},
})
cy.get('input[name="user"]')
.should('exist')
.and('have.attr', 'id', 'user')
cy.get('input[name="user"]')
.should('have.value', 'test-user')
})
it('clears password after timeout', () => {
// mock timeout of 5 seconds
cy.window().then(($window) => {
const state = $window.document.createElement('input')
state.type = 'hidden'
state.id = 'initial-state-core-loginTimeout'
state.value = btoa(JSON.stringify(5))
$window.document.body.appendChild(state)
})
// mount forms
cy.mount(LoginForm)
cy.get('input[name="password"]')
.should('exist')
.type('MyPassword')
cy.get('input[name="password"]')
.should('have.value', 'MyPassword')
// Wait for timeout
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(5100)
cy.get('input[name="password"]')
.should('have.value', '')
})
})

View file

@ -194,10 +194,10 @@ export default {
}
},
data() {
data(props) {
return {
loading: false,
user: '',
user: props.username,
password: '',
}
},
@ -262,7 +262,7 @@ export default {
},
emailEnabled() {
return this.emailStates ? this.emailStates.every((state) => state === '1') : 1
return this.emailStates.every((state) => state === '1')
},
loginText() {
@ -286,7 +286,6 @@ export default {
if (this.username === '') {
this.$refs.user.$refs.inputField.$refs.input.focus()
} else {
this.user = this.username
this.$refs.password.$refs.inputField.$refs.input.focus()
}
},

View file

@ -0,0 +1,102 @@
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { cleanup, render } from '@testing-library/vue'
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
import LoginForm from '../../../components/login/LoginForm.vue'
describe('core: LoginForm', () => {
afterEach(cleanup)
beforeEach(() => {
// Mock the required global state
window.OC = {
theme: {
name: 'J\'s cloud',
},
requestToken: 'request-token',
}
})
/**
* Ensure that characters like ' are not double HTML escaped.
* This was a bug in https://github.com/nextcloud/server/issues/34990
*/
it('does not double escape special characters in product name', () => {
const page = render(LoginForm, {
props: {
username: 'test-user',
},
})
const heading = page.getByRole('heading', { level: 2 })
expect(heading.textContent).toContain('J\'s cloud')
})
it('offers email as login name by default', async () => {
const page = render(LoginForm)
const input = await page.findByRole('textbox', { name: /Account name or email/ })
expect(input).toBeInstanceOf(HTMLInputElement)
})
it('offers only account name if email is not enabled', async () => {
const page = render(LoginForm, {
propsData: {
emailStates: ['0', '1'],
},
})
await expect(async () => page.findByRole('textbox', { name: /Account name or email/ })).rejects.toThrow()
await expect(page.findByRole('textbox', { name: /Account name/ })).resolves.not.toThrow()
})
it('fills username from props into form', () => {
const page = render(LoginForm, {
props: {
username: 'test-user',
},
})
page.debug()
const input: HTMLInputElement = page.getByRole('textbox', { name: /Account name or email/ })
expect(input.id).toBe('user')
expect(input.name).toBe('user')
expect(input.value).toBe('test-user')
})
describe('', () => {
beforeAll(() => {
vi.useFakeTimers()
// mock timeout of 5 seconds
const state = document.createElement('input')
state.type = 'hidden'
state.id = 'initial-state-core-loginTimeout'
state.value = btoa(JSON.stringify(5))
document.body.appendChild(state)
})
afterAll(() => {
vi.useRealTimers()
document.querySelector('#initial-state-core-loginTimeout')?.remove()
})
it('clears password after timeout', () => {
// mount forms
const page = render(LoginForm)
const input: HTMLInputElement = page.getByLabelText('Password', { selector: 'input' })
input.dispatchEvent(new InputEvent('input', { data: 'MyPassword' }))
vi.advanceTimersByTime(2500)
// see its still the value
expect(input.value).toBe('')
// Wait for timeout
vi.advanceTimersByTime(2600)
expect(input.value).toBe('')
})
})
})

View file

@ -63,6 +63,8 @@ export default defineConfig([
rules: {
'no-console': 'off',
'jsdoc/require-jsdoc': 'off',
'jsdoc/require-param-type': 'off',
'jsdoc/require-param-description': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
},

2
package-lock.json generated
View file

@ -104,7 +104,7 @@
"@testing-library/cypress": "^10.1.0",
"@testing-library/jest-dom": "^6.6.4",
"@testing-library/user-event": "^14.6.1",
"@testing-library/vue": "^5.8.3",
"@testing-library/vue": "^5.9.0",
"@types/dockerode": "^3.3.44",
"@types/wait-on": "^5.3.4",
"@vitejs/plugin-vue2": "^2.3.3",

View file

@ -141,7 +141,7 @@
"@testing-library/cypress": "^10.1.0",
"@testing-library/jest-dom": "^6.6.4",
"@testing-library/user-event": "^14.6.1",
"@testing-library/vue": "^5.8.3",
"@testing-library/vue": "^5.9.0",
"@types/dockerode": "^3.3.44",
"@types/wait-on": "^5.3.4",
"@vitejs/plugin-vue2": "^2.3.3",