mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-03-01 12:44:17 +00:00
setup cypress with initial login tests
This commit is contained in:
parent
0ac046e6da
commit
9206848bd2
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,5 @@
|
||||
.claude/
|
||||
data/
|
||||
cypress/node:modules/
|
||||
cypress/reports/
|
||||
cypress/runner-results/
|
||||
|
||||
50
cypress/cypress.config.ts
Normal file
50
cypress/cypress.config.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { defineConfig } from 'cypress'
|
||||
const cypressSplit = require('cypress-split')
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:8080',
|
||||
viewportWidth: 1280,
|
||||
viewportHeight: 720,
|
||||
|
||||
specPattern: 'e2e/**/*.cy.ts',
|
||||
supportFile: false,
|
||||
screenshotsFolder: 'reports/screenshots',
|
||||
videosFolder: 'reports/videos',
|
||||
video: false,
|
||||
screenshotOnRunFailure: true,
|
||||
|
||||
defaultCommandTimeout: 10000,
|
||||
requestTimeout: 10000,
|
||||
responseTimeout: 10000,
|
||||
pageLoadTimeout: 30000,
|
||||
|
||||
testIsolation: true,
|
||||
|
||||
retries: {
|
||||
runMode: 2,
|
||||
openMode: 0
|
||||
},
|
||||
|
||||
env: {
|
||||
apiUrl: 'http://localhost:8055',
|
||||
validEmail: 'admin@it4c.dev',
|
||||
validPassword: 'admin123',
|
||||
invalidEmail: 'invalid@example.com',
|
||||
invalidPassword: 'wrongpassword'
|
||||
},
|
||||
|
||||
setupNodeEvents(on, config) {
|
||||
cypressSplit(on, config)
|
||||
|
||||
on('task', {
|
||||
log(message) {
|
||||
console.log(message)
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
return config
|
||||
},
|
||||
},
|
||||
})
|
||||
172
cypress/e2e/authentification/login.cy.ts
Normal file
172
cypress/e2e/authentification/login.cy.ts
Normal file
@ -0,0 +1,172 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
Cypress.on('uncaught:exception', (err, _runnable) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Uncaught exception:', err.message)
|
||||
return false
|
||||
})
|
||||
|
||||
describe('Utopia Map Login', () => {
|
||||
const testData = {
|
||||
validUser: {
|
||||
email: Cypress.env('validEmail'),
|
||||
password: Cypress.env('validPassword')
|
||||
},
|
||||
invalidUser: {
|
||||
email: Cypress.env('invalidEmail'),
|
||||
password: Cypress.env('invalidPassword')
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
cy.clearCookies()
|
||||
cy.clearLocalStorage()
|
||||
cy.window().then((win) => {
|
||||
win.sessionStorage.clear()
|
||||
})
|
||||
|
||||
cy.visit('/login')
|
||||
})
|
||||
|
||||
it('should successfully login with valid credentials', () => {
|
||||
cy.intercept('POST', '**/auth/login').as('loginRequest')
|
||||
|
||||
cy.get('input[type="email"]').clear()
|
||||
cy.get('input[type="email"]').type(testData.validUser.email)
|
||||
cy.get('input[type="password"]').clear()
|
||||
cy.get('input[type="password"]').type(testData.validUser.password)
|
||||
cy.get('button:contains("Login")').click()
|
||||
|
||||
cy.wait('@loginRequest').then((interception) => {
|
||||
expect(interception.response?.statusCode).to.eq(200)
|
||||
expect(interception.request.body).to.deep.include({
|
||||
email: testData.validUser.email,
|
||||
password: testData.validUser.password
|
||||
})
|
||||
|
||||
expect(interception.response?.body).to.have.property('data')
|
||||
expect(interception.response?.body.data).to.have.property('access_token')
|
||||
expect(interception.response?.body.data.access_token).to.be.a('string')
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
expect(interception.response?.body.data.access_token).to.not.be.empty
|
||||
})
|
||||
|
||||
cy.get('.Toastify__toast--success', { timeout: 10000 }).should('be.visible')
|
||||
cy.url().should('eq', Cypress.config().baseUrl + '/')
|
||||
})
|
||||
|
||||
it('should show error for missing password', () => {
|
||||
cy.intercept('POST', '**/auth/login').as('loginRequest')
|
||||
|
||||
cy.get('input[type="email"]').type(testData.validUser.email)
|
||||
cy.get('button:contains("Login")').click()
|
||||
|
||||
cy.wait('@loginRequest').then((interception) => {
|
||||
expect(interception.response?.statusCode).to.eq(400)
|
||||
expect(interception.request.body).to.deep.include({
|
||||
email: testData.validUser.email,
|
||||
password: ''
|
||||
})
|
||||
|
||||
expect(interception.response?.body).to.have.property('errors')
|
||||
expect(interception.response?.body.errors).to.be.an('array')
|
||||
expect(interception.response?.body.errors).to.have.length.greaterThan(0)
|
||||
expect(interception.response?.body.errors[0]).to.have.property('message')
|
||||
})
|
||||
|
||||
cy.get('.Toastify__toast--error', { timeout: 10000 }).should('be.visible')
|
||||
cy.url().should('include', '/login')
|
||||
})
|
||||
|
||||
it('should show error for missing email', () => {
|
||||
cy.intercept('POST', '**/auth/login').as('loginRequest')
|
||||
|
||||
cy.get('input[type="password"]').type(testData.validUser.password)
|
||||
cy.get('button:contains("Login")').click()
|
||||
|
||||
cy.wait('@loginRequest').then((interception) => {
|
||||
expect(interception.response?.statusCode).to.eq(400)
|
||||
expect(interception.request.body).to.deep.include({
|
||||
email: '',
|
||||
password: testData.validUser.password
|
||||
})
|
||||
|
||||
expect(interception.response?.body).to.have.property('errors')
|
||||
expect(interception.response?.body.errors).to.be.an('array')
|
||||
expect(interception.response?.body.errors).to.have.length.greaterThan(0)
|
||||
})
|
||||
|
||||
cy.get('.Toastify__toast--error', { timeout: 10000 }).should('be.visible')
|
||||
cy.url().should('include', '/login')
|
||||
})
|
||||
|
||||
it('should show error for missing credentials', () => {
|
||||
cy.intercept('POST', '**/auth/login').as('loginRequest')
|
||||
|
||||
cy.get('button:contains("Login")').click()
|
||||
|
||||
cy.wait('@loginRequest').then((interception) => {
|
||||
expect(interception.response?.statusCode).to.eq(400)
|
||||
expect(interception.request.body).to.deep.include({
|
||||
email: '',
|
||||
password: ''
|
||||
})
|
||||
|
||||
expect(interception.response?.body).to.have.property('errors')
|
||||
expect(interception.response?.body.errors).to.be.an('array')
|
||||
expect(interception.response?.body.errors).to.have.length.greaterThan(0)
|
||||
})
|
||||
|
||||
cy.get('.Toastify__toast--error', { timeout: 10000 }).should('be.visible')
|
||||
cy.url().should('include', '/login')
|
||||
})
|
||||
|
||||
it('should show error for invalid credentials', () => {
|
||||
cy.intercept('POST', '**/auth/login').as('loginRequest')
|
||||
|
||||
cy.get('input[type="email"]').clear()
|
||||
cy.get('input[type="email"]').type(testData.invalidUser.email)
|
||||
cy.get('input[type="password"]').clear()
|
||||
cy.get('input[type="password"]').type(testData.invalidUser.password)
|
||||
cy.get('button:contains("Login")').click()
|
||||
|
||||
cy.wait('@loginRequest').then((interception) => {
|
||||
expect(interception.response?.statusCode).to.eq(401)
|
||||
expect(interception.request.body).to.deep.include({
|
||||
email: testData.invalidUser.email,
|
||||
password: testData.invalidUser.password
|
||||
})
|
||||
|
||||
expect(interception.response?.body).to.have.property('errors')
|
||||
expect(interception.response?.body.errors).to.be.an('array')
|
||||
expect(interception.response?.body.errors[0]).to.have.property('message')
|
||||
expect(interception.response?.body.errors[0].message).to.contain('Invalid user credentials')
|
||||
})
|
||||
|
||||
cy.get('.Toastify__toast--error', { timeout: 10000 }).should('be.visible')
|
||||
cy.url().should('include', '/login')
|
||||
})
|
||||
|
||||
it('should show loading state during login', () => {
|
||||
cy.intercept('POST', '**/auth/login', {
|
||||
delay: 1000,
|
||||
statusCode: 200,
|
||||
body: {
|
||||
data: {
|
||||
access_token: 'test_token_123',
|
||||
expires: 900000,
|
||||
refresh_token: 'refresh_token_123'
|
||||
}
|
||||
}
|
||||
}).as('loginRequest')
|
||||
|
||||
cy.get('input[type="email"]').type(testData.validUser.email)
|
||||
cy.get('input[type="password"]').type(testData.validUser.password)
|
||||
cy.get('button:contains("Login")').click()
|
||||
|
||||
cy.get('.tw\\:loading-spinner', { timeout: 5000 }).should('be.visible')
|
||||
|
||||
cy.wait('@loginRequest')
|
||||
cy.url().should('eq', Cypress.config().baseUrl + '/')
|
||||
})
|
||||
})
|
||||
50
cypress/e2e/authentification/login.form-elements.cy.ts
Normal file
50
cypress/e2e/authentification/login.form-elements.cy.ts
Normal file
@ -0,0 +1,50 @@
|
||||
/// <reference types="cypress" />
|
||||
|
||||
Cypress.on('uncaught:exception', (err, _runnable) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Uncaught exception:', err.message)
|
||||
return false
|
||||
})
|
||||
|
||||
describe('Utopia Map Login Form Elements', () => {
|
||||
// TODO: set this data different
|
||||
const _testData = {
|
||||
validUser: {
|
||||
email: Cypress.env('validEmail'),
|
||||
password: Cypress.env('validPassword')
|
||||
},
|
||||
invalidUser: {
|
||||
email: Cypress.env('invalidEmail'),
|
||||
password: Cypress.env('invalidPassword')
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
cy.clearCookies()
|
||||
cy.clearLocalStorage()
|
||||
cy.window().then((win) => {
|
||||
win.sessionStorage.clear()
|
||||
})
|
||||
|
||||
cy.visit('/login')
|
||||
})
|
||||
|
||||
it('should be displayed correctly', () => {
|
||||
cy.get('h2').should('contain.text', 'Login')
|
||||
cy.get('input[type="email"]')
|
||||
.should('be.visible')
|
||||
.should('have.attr', 'placeholder', 'E-Mail')
|
||||
|
||||
cy.get('input[type="password"]')
|
||||
.should('be.visible')
|
||||
.should('have.attr', 'placeholder', 'Password')
|
||||
|
||||
cy.get('button:contains("Login")')
|
||||
.should('be.visible')
|
||||
.should('not.be.disabled')
|
||||
|
||||
cy.get('a[href="/reset-password"]')
|
||||
.should('be.visible')
|
||||
.should('contain.text', 'Forgot Password?')
|
||||
})
|
||||
})
|
||||
6892
cypress/package-lock.json
generated
Normal file
6892
cypress/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
cypress/package.json
Normal file
30
cypress/package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "utopia-map-e2e-testing",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "Cypress End-to-End Tests for Utopia Map",
|
||||
"scripts": {
|
||||
"test": "cypress run --e2e --browser chromium",
|
||||
"test:open": "cypress open --e2e",
|
||||
"test:split:auto": "SPEC_COUNT=$(find e2e -name '*.cy.ts' | wc -l) && echo \"Running $SPEC_COUNT chunks in parallel\" && for i in $(seq 0 $((SPEC_COUNT-1))); do SPLIT=$SPEC_COUNT SPLIT_INDEX=$i cypress run --e2e --browser chromium & done; wait",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
},
|
||||
"keywords": [
|
||||
"cypress",
|
||||
"cypress-split",
|
||||
"e2e",
|
||||
"testing",
|
||||
"utopia-map"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.36.0",
|
||||
"@types/node": "^24.5.2",
|
||||
"cypress": "^15.3.0",
|
||||
"cypress-split": "^1.24.23",
|
||||
"eslint": "^9.36.0",
|
||||
"eslint-plugin-cypress": "^5.1.1",
|
||||
"typescript": "^5.9.2",
|
||||
"typescript-eslint": "^8.44.1"
|
||||
}
|
||||
}
|
||||
20
cypress/tsconfig.json
Normal file
20
cypress/tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["es5", "dom"],
|
||||
"types": ["cypress", "node"],
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user