Skip to content

Commit 8d4101d

Browse files
committed
handle code and e2e testing
1 parent ef5a8dc commit 8d4101d

8 files changed

Lines changed: 161 additions & 11 deletions

File tree

.github/workflows/e2e-tests.yml

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,29 +71,47 @@ jobs:
7171
- name: Pull Docker Images from GCR
7272
run: |
7373
echo "Pulling latest images from GCR..."
74-
# Try to pull with commit SHA first (from recent build)
74+
75+
BACKEND_MISSING=false
76+
FRONTEND_MISSING=false
77+
78+
# Pull backend image
7579
if docker pull gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_IMAGE }}:${{ github.sha }}; then
80+
echo "✅ Found backend image with SHA: ${{ github.sha }}"
7681
docker tag gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_IMAGE }}:${{ github.sha }} \
7782
gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_IMAGE }}:test
78-
else
79-
echo "⚠️ Image with SHA not found, using latest"
80-
docker pull gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_IMAGE }}:latest
83+
elif docker pull gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_IMAGE }}:latest; then
84+
echo "⚠️ SHA image not found, using latest"
8185
docker tag gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_IMAGE }}:latest \
8286
gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_IMAGE }}:test
87+
else
88+
echo "❌ No backend image found in GCR"
89+
BACKEND_MISSING=true
8390
fi
8491
92+
# Pull frontend image
8593
if docker pull gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_IMAGE }}:${{ github.sha }}; then
94+
echo "✅ Found frontend image with SHA: ${{ github.sha }}"
8695
docker tag gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_IMAGE }}:${{ github.sha }} \
8796
gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_IMAGE }}:test
88-
else
89-
echo "⚠️ Image with SHA not found, using latest"
90-
docker pull gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_IMAGE }}:latest
97+
elif docker pull gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_IMAGE }}:latest; then
98+
echo "⚠️ SHA image not found, using latest"
9199
docker tag gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_IMAGE }}:latest \
92100
gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_IMAGE }}:test
101+
else
102+
echo "❌ No frontend image found in GCR"
103+
FRONTEND_MISSING=true
93104
fi
94105
106+
# Pull MySQL
95107
docker pull mysql:8.0
96108
109+
# Check if any images are missing
110+
if [ "$BACKEND_MISSING" = "true" ] || [ "$FRONTEND_MISSING" = "true" ]; then
111+
echo "❌ Required images not found. Please run build workflow first."
112+
exit 1
113+
fi
114+
97115
echo "✅ All images pulled successfully"
98116
99117
# 7. Install Cypress dependencies
@@ -135,7 +153,7 @@ jobs:
135153
docker compose -f docker-compose.test.yml logs backend
136154
137155
echo "Waiting for Backend to be ready..."
138-
timeout 120s bash -c 'until curl -f http://localhost:8080/health 2>/dev/null; do echo "Waiting for Backend..."; sleep 5; done' || {
156+
timeout 120s bash -c 'until curl -f http://localhost:8080/api/health 2>/dev/null; do echo "Waiting for Backend..."; sleep 5; done' || {
139157
echo "❌ Backend failed to start. Showing logs:"
140158
docker compose -f docker-compose.test.yml logs backend
141159
exit 1

docker-compose.test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ services:
4949
ports:
5050
- "8080:8080"
5151
healthcheck:
52-
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
52+
test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
5353
interval: 10s
5454
timeout: 5s
5555
retries: 15

frontend/src/pages/admin/dashboard/page.jsx

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,13 @@ function AdminDashboard() {
321321
type='number'
322322
value={newFloorData.floorNumber}
323323
onChange={(e) => setNewFloorData(prev => ({ ...prev, floorNumber: e.target.value }))}
324+
onKeyPress={(e) => {
325+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
326+
e.preventDefault();
327+
}
328+
}}
329+
min='1'
330+
step='1'
324331
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
325332
placeholder='Enter floor number'
326333
/>
@@ -359,9 +366,16 @@ function AdminDashboard() {
359366
Room Number <span className='text-red-500'>*</span>
360367
</label>
361368
<input
362-
type='text'
369+
type='number'
363370
value={room.roomNumber}
364371
onChange={(e) => updateFloorRoom(index, 'roomNumber', e.target.value)}
372+
onKeyPress={(e) => {
373+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
374+
e.preventDefault();
375+
}
376+
}}
377+
min='1'
378+
step='1'
365379
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
366380
placeholder='e.g., 101'
367381
/>
@@ -387,8 +401,14 @@ function AdminDashboard() {
387401
<input
388402
type='number'
389403
step='0.01'
404+
min='0'
390405
value={room.size}
391406
onChange={(e) => updateFloorRoom(index, 'size', e.target.value)}
407+
onKeyPress={(e) => {
408+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
409+
e.preventDefault();
410+
}
411+
}}
392412
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
393413
placeholder='e.g., 25.5'
394414
/>
@@ -400,8 +420,15 @@ function AdminDashboard() {
400420
</label>
401421
<input
402422
type='number'
423+
min='0'
424+
step='0.01'
403425
value={room.rentAmount}
404426
onChange={(e) => updateFloorRoom(index, 'rentAmount', e.target.value)}
427+
onKeyPress={(e) => {
428+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
429+
e.preventDefault();
430+
}
431+
}}
405432
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
406433
placeholder='e.g., 5000'
407434
/>
@@ -451,6 +478,13 @@ function AdminDashboard() {
451478
type='number'
452479
value={newRoomData.floor}
453480
onChange={(e) => setNewRoomData(prev => ({ ...prev, floor: e.target.value }))}
481+
onKeyPress={(e) => {
482+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
483+
e.preventDefault();
484+
}
485+
}}
486+
min='1'
487+
step='1'
454488
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
455489
placeholder='Enter floor number'
456490
/>
@@ -461,9 +495,16 @@ function AdminDashboard() {
461495
Room Number <span className='text-red-500'>*</span>
462496
</label>
463497
<input
464-
type='text'
498+
type='number'
465499
value={newRoomData.roomNumber}
466500
onChange={(e) => setNewRoomData(prev => ({ ...prev, roomNumber: e.target.value }))}
501+
onKeyPress={(e) => {
502+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
503+
e.preventDefault();
504+
}
505+
}}
506+
min='1'
507+
step='1'
467508
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
468509
placeholder='e.g., 101'
469510
/>
@@ -489,8 +530,14 @@ function AdminDashboard() {
489530
<input
490531
type='number'
491532
step='0.01'
533+
min='0'
492534
value={newRoomData.size}
493535
onChange={(e) => setNewRoomData(prev => ({ ...prev, size: e.target.value }))}
536+
onKeyPress={(e) => {
537+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
538+
e.preventDefault();
539+
}
540+
}}
494541
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
495542
placeholder='e.g., 25.5'
496543
/>
@@ -502,8 +549,15 @@ function AdminDashboard() {
502549
</label>
503550
<input
504551
type='number'
552+
min='0'
553+
step='0.01'
505554
value={newRoomData.rentAmount}
506555
onChange={(e) => setNewRoomData(prev => ({ ...prev, rentAmount: e.target.value }))}
556+
onKeyPress={(e) => {
557+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
558+
e.preventDefault();
559+
}
560+
}}
507561
className='w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
508562
placeholder='e.g., 5000'
509563
/>

frontend/src/pages/admin/maintenance-requests/page.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,8 +830,14 @@ function MaintenanceRequestsPage() {
830830
<input
831831
type='number'
832832
min='1'
833+
step='1'
833834
value={itemQuantity}
834835
onChange={(e) => setItemQuantity(parseInt(e.target.value) || 1)}
836+
onKeyPress={(e) => {
837+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
838+
e.preventDefault();
839+
}
840+
}}
835841
className='w-full border border-gray-300 rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500'
836842
/>
837843
</div>

frontend/src/pages/admin/maintenance/page.jsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,14 @@ function MaintenancePage() {
558558
type='number'
559559
value={formData.recurrenceInterval}
560560
onChange={(e) => handleFormChange('recurrenceInterval', parseInt(e.target.value))}
561+
onKeyPress={(e) => {
562+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
563+
e.preventDefault();
564+
}
565+
}}
561566
className='w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500'
562567
min='1'
568+
step='1'
563569
/>
564570
</div>
565571
)}
@@ -574,9 +580,15 @@ function MaintenancePage() {
574580
type='number'
575581
value={formData.recurrenceDayOfWeek || ''}
576582
onChange={(e) => handleFormChange('recurrenceDayOfWeek', e.target.value ? parseInt(e.target.value) : null)}
583+
onKeyPress={(e) => {
584+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
585+
e.preventDefault();
586+
}
587+
}}
577588
className='w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500'
578589
min='0'
579590
max='6'
591+
step='1'
580592
placeholder='0-6'
581593
/>
582594
</div>
@@ -591,9 +603,15 @@ function MaintenancePage() {
591603
type='number'
592604
value={formData.recurrenceDayOfMonth || ''}
593605
onChange={(e) => handleFormChange('recurrenceDayOfMonth', e.target.value ? parseInt(e.target.value) : null)}
606+
onKeyPress={(e) => {
607+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
608+
e.preventDefault();
609+
}
610+
}}
594611
className='w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500'
595612
min='1'
596613
max='31'
614+
step='1'
597615
placeholder='1-31'
598616
/>
599617
</div>
@@ -700,9 +718,15 @@ function MaintenancePage() {
700718
type='number'
701719
value={formData.notifyDaysBefore}
702720
onChange={(e) => handleFormChange('notifyDaysBefore', parseInt(e.target.value))}
721+
onKeyPress={(e) => {
722+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
723+
e.preventDefault();
724+
}
725+
}}
703726
className='w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500'
704727
min='0'
705728
max='30'
729+
step='1'
706730
/>
707731
<p className='text-xs text-gray-500 mt-1'>
708732
Tenants will be notified this many days before maintenance.

frontend/src/pages/admin/stock/page.jsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,8 +400,14 @@ function StockManagementPage() {
400400
type='number'
401401
value={formData.quantity}
402402
onChange={(e) => setFormData({...formData, quantity: parseInt(e.target.value) || 0})}
403+
onKeyPress={(e) => {
404+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
405+
e.preventDefault();
406+
}
407+
}}
403408
className='w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
404409
min='0'
410+
step='1'
405411
/>
406412
</div>
407413

@@ -412,6 +418,11 @@ function StockManagementPage() {
412418
step='0.01'
413419
value={formData.unitPrice}
414420
onChange={(e) => setFormData({...formData, unitPrice: parseFloat(e.target.value) || 0})}
421+
onKeyPress={(e) => {
422+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
423+
e.preventDefault();
424+
}
425+
}}
415426
className='w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
416427
min='0'
417428
/>
@@ -471,8 +482,14 @@ function StockManagementPage() {
471482
type='number'
472483
value={transactionData.quantity}
473484
onChange={(e) => setTransactionData({...transactionData, quantity: parseInt(e.target.value) || 0})}
485+
onKeyPress={(e) => {
486+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
487+
e.preventDefault();
488+
}
489+
}}
474490
className='w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500'
475491
min='1'
492+
step='1'
476493
max={transactionType === 'use' ? selectedItem.quantity : undefined}
477494
/>
478495
</div>

frontend/src/pages/admin/unit/edit/page.jsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,14 @@ function EditUnitPage() {
164164
name="floor"
165165
value={formData.floor}
166166
onChange={handleChange}
167+
onKeyPress={(e) => {
168+
if (e.key === '.' || e.key === '-' || e.key === 'e' || e.key === 'E') {
169+
e.preventDefault();
170+
}
171+
}}
167172
required
168173
min="1"
174+
step="1"
169175
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
170176
placeholder="e.g., 1"
171177
/>
@@ -181,6 +187,11 @@ function EditUnitPage() {
181187
name="rentAmount"
182188
value={formData.rentAmount}
183189
onChange={handleChange}
190+
onKeyPress={(e) => {
191+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
192+
e.preventDefault();
193+
}
194+
}}
184195
required
185196
min="0"
186197
step="0.01"
@@ -199,6 +210,11 @@ function EditUnitPage() {
199210
name="sizeSqm"
200211
value={formData.sizeSqm}
201212
onChange={handleChange}
213+
onKeyPress={(e) => {
214+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
215+
e.preventDefault();
216+
}
217+
}}
202218
min="0"
203219
step="0.01"
204220
className="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"

frontend/src/pages/admin/unit/send_invoice/page.jsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,11 @@ function SendInvoicePage() {
465465
step="0.01"
466466
value={electricityUnits}
467467
onChange={(e) => setElectricityUnits(e.target.value)}
468+
onKeyPress={(e) => {
469+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
470+
e.preventDefault();
471+
}
472+
}}
468473
className='w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400'
469474
placeholder='Enter electricity units'
470475
/>
@@ -482,6 +487,11 @@ function SendInvoicePage() {
482487
step="0.01"
483488
value={waterUnits}
484489
onChange={(e) => setWaterUnits(e.target.value)}
490+
onKeyPress={(e) => {
491+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
492+
e.preventDefault();
493+
}
494+
}}
485495
className='w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400'
486496
placeholder='Enter water units'
487497
/>
@@ -506,6 +516,11 @@ function SendInvoicePage() {
506516
step="0.01"
507517
value={customAmount}
508518
onChange={(e) => setCustomAmount(e.target.value)}
519+
onKeyPress={(e) => {
520+
if (e.key === '-' || e.key === 'e' || e.key === 'E') {
521+
e.preventDefault();
522+
}
523+
}}
509524
className='w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-400'
510525
placeholder={invoiceType === 'SECURITY_DEPOSIT' ? unit?.rentAmount || 0 : 'Enter amount'}
511526
/>

0 commit comments

Comments
 (0)