Skip to content

Commit 9b41aa0

Browse files
committed
chore: Cypress test for user login and workflow for E2E testing
1 parent c60a078 commit 9b41aa0

File tree

5 files changed

+208
-9
lines changed

5 files changed

+208
-9
lines changed

.github/workflows/cypress.yml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build-and-test:
11+
runs-on: ubuntu-latest
12+
services:
13+
db:
14+
image: postgres:17-alpine
15+
ports:
16+
- 5432:5432
17+
env:
18+
POSTGRES_USER: libredesk
19+
POSTGRES_PASSWORD: libredesk
20+
POSTGRES_DB: libredesk
21+
options: >-
22+
--health-cmd="pg_isready -U libredesk"
23+
--health-interval=10s
24+
--health-timeout=5s
25+
--health-retries=5
26+
redis:
27+
image: redis
28+
ports:
29+
- 6379:6379
30+
31+
steps:
32+
- uses: actions/checkout@v3
33+
34+
- name: Set up Go
35+
uses: actions/setup-go@v3
36+
with:
37+
go-version: "1.22.3"
38+
39+
- name: Set up Node.js
40+
uses: actions/setup-node@v3
41+
with:
42+
node-version: "20"
43+
44+
- name: Install pnpm
45+
run: npm install -g pnpm
46+
47+
- name: Install cypress deps
48+
run: sudo apt-get update && sudo apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb
49+
50+
- name: Build binary and frontend
51+
run: make build
52+
53+
- name: Configure app
54+
run: |
55+
cp config.sample.toml config.toml
56+
57+
- name: Install db schema and run tests
58+
env:
59+
LIBREDESK_SYSTEM_USER_PASSWORD: "StrongPass!123"
60+
run: |
61+
./libredesk --install --idempotent-install --yes --config ./config.toml
62+
./libredesk --upgrade --yes --config ./config.toml
63+
./libredesk --config ./config.toml &
64+
sleep 10
65+
cd frontend
66+
pnpm run test:e2e:ci

frontend/cypress.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { defineConfig } from 'cypress'
33
export default defineConfig({
44
e2e: {
55
specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
6-
baseUrl: 'http://localhost:4173'
6+
baseUrl: 'http://localhost:9000'
77
},
88
component: {
99
specPattern: 'src/**/__tests__/*.{cy,spec}.{js,ts,jsx,tsx}',

frontend/cypress/e2e/example.cy.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

frontend/cypress/e2e/testLogin.cy.js

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// cypress/e2e/login.cy.js
2+
3+
describe('Login Component', () => {
4+
beforeEach(() => {
5+
// Visit the login page
6+
cy.visit('/')
7+
8+
// Mock the API response for OIDC providers
9+
cy.intercept('GET', '**/api/v1/oidc/enabled', {
10+
statusCode: 200,
11+
body: {
12+
data: [
13+
{
14+
id: 1,
15+
name: 'Google',
16+
logo_url: 'https://example.com/google-logo.png',
17+
disabled: false
18+
}
19+
]
20+
}
21+
}).as('getOIDCProviders')
22+
})
23+
24+
it('should display login form', () => {
25+
cy.contains('h3', 'Libredesk').should('be.visible')
26+
cy.contains('p', 'Sign in to your account').should('be.visible')
27+
cy.get('#email').should('be.visible')
28+
cy.get('#password').should('be.visible')
29+
cy.contains('a', 'Forgot password?').should('be.visible')
30+
cy.contains('button', 'Sign in').should('be.visible')
31+
})
32+
33+
it('should display OIDC providers when loaded', () => {
34+
cy.wait('@getOIDCProviders')
35+
cy.contains('button', 'Google').should('be.visible')
36+
cy.contains('div', 'Or continue with').should('be.visible')
37+
})
38+
39+
it('should show error for invalid login attempt', () => {
40+
// Mock failed login API call
41+
cy.intercept('POST', '**/api/v1/login', {
42+
statusCode: 401,
43+
body: {
44+
message: 'Invalid credentials'
45+
}
46+
}).as('loginFailure')
47+
48+
// Enter System username and wrong password
49+
cy.get('#email').type('System')
50+
cy.get('#password').type('WrongPassword')
51+
52+
// Submit form
53+
cy.contains('button', 'Sign in').click()
54+
55+
// Wait for API call
56+
cy.wait('@loginFailure')
57+
58+
// Verify error message appears
59+
cy.contains('Invalid credentials').should('be.visible')
60+
})
61+
62+
it('should login successfully with correct credentials', () => {
63+
// Mock successful login API call
64+
cy.intercept('POST', '**/api/v1/login', {
65+
statusCode: 200,
66+
body: {
67+
data: {
68+
id: 1,
69+
email: 'System',
70+
name: 'System User'
71+
}
72+
}
73+
}).as('loginSuccess')
74+
75+
// Enter System username and correct password
76+
cy.get('#email').type('System')
77+
cy.get('#password').type('StrongPass!123')
78+
79+
// Submit form
80+
cy.contains('button', 'Sign in').click()
81+
82+
// Wait for API call
83+
cy.wait('@loginSuccess')
84+
85+
// Verify redirection to inboxes page
86+
cy.url().should('include', '/inboxes/assigned')
87+
})
88+
89+
it('should validate email format', () => {
90+
// Enter invalid email and a password
91+
cy.get('#email').type('invalid-email')
92+
cy.get('#password').type('password')
93+
94+
// Submit form
95+
cy.contains('button', 'Sign in').click()
96+
97+
// Check for validation error (matching the error message with a trailing period)
98+
cy.contains('Invalid email address.').should('be.visible')
99+
})
100+
101+
it('should validate empty password', () => {
102+
// Enter email but no password
103+
cy.get('#email').type('[email protected]')
104+
105+
// Submit form
106+
cy.contains('button', 'Sign in').click()
107+
108+
// Check for validation error (matching the error message with a trailing period)
109+
cy.contains('Password cannot be empty.').should('be.visible')
110+
})
111+
112+
it('should show loading state during login', () => {
113+
// Mock slow API response
114+
cy.intercept('POST', '**/api/v1/login', {
115+
statusCode: 200,
116+
body: {
117+
data: {
118+
id: 1,
119+
email: 'System',
120+
name: 'System User'
121+
}
122+
},
123+
delay: 1000
124+
}).as('slowLogin')
125+
126+
// Enter credentials
127+
cy.get('#email').type('System')
128+
cy.get('#password').type('StrongPass!123')
129+
130+
// Submit form
131+
cy.contains('button', 'Sign in').click()
132+
133+
// Check if loading state is shown
134+
cy.contains('Logging in...').should('be.visible')
135+
cy.get('svg.animate-spin').should('be.visible')
136+
137+
// Wait for API call to finish
138+
cy.wait('@slowLogin')
139+
})
140+
})

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"build": "vite build",
99
"preview": "vite preview",
1010
"test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'",
11+
"test:e2e:ci": "cypress run --e2e --headless",
1112
"test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'",
1213
"test:unit": "cypress run --component",
1314
"test:unit:dev": "cypress open --component",

0 commit comments

Comments
 (0)