Shift System Testing Guide
Overviewβ
This document outlines testing procedures for the shift management system across all platforms (API, Mobile, Desktop).
API Testingβ
Prerequisitesβ
- Test database with sample data
- Valid authentication tokens
- Test user accounts with various roles
Test Casesβ
-
Shift Creation
describe("Shift Creation", () => {
it("should create a new shift", async () => {
// Test basic shift creation
});
it("should validate required fields", async () => {
// Test validation
});
it("should handle duplicate shifts", async () => {
// Test duplicate prevention
});
}); -
Break Management
describe("Break Management", () => {
it("should start a break", async () => {
// Test break start
});
it("should end a break", async () => {
// Test break end
});
it("should prevent multiple active breaks", async () => {
// Test break validation
});
}); -
Time Calculations
describe("Time Calculations", () => {
it("should calculate total time correctly", async () => {
// Test total time
});
it("should calculate break time correctly", async () => {
// Test break time
});
it("should calculate overtime correctly", async () => {
// Test overtime
});
}); -
Shift Completion
describe("Shift Completion", () => {
it("should complete shift with no pending tasks", async () => {
// Test normal completion
});
it("should prevent completion with pending tasks", async () => {
// Test pending task validation
});
it("should calculate final totals correctly", async () => {
// Test final calculations
});
});
Mobile Testingβ
Test Environment Setupβ
- Expo development build
- Mock API responses
- Test user accounts
Test Casesβ
-
UI Components
describe("Timecard Component", () => {
it("should render correctly", () => {
// Test component rendering
});
it("should update time display", () => {
// Test time updates
});
it("should handle state changes", () => {
// Test state management
});
}); -
Offline Support
describe("Offline Functionality", () => {
it("should work offline", () => {
// Test offline operation
});
it("should sync when online", () => {
// Test sync behavior
});
it("should handle conflicts", () => {
// Test conflict resolution
});
}); -
Local Storage
describe("Storage Management", () => {
it("should persist state", () => {
// Test state persistence
});
it("should recover from crashes", () => {
// Test crash recovery
});
it("should clean up old data", () => {
// Test cleanup
});
});
Integration Testingβ
Test Scenariosβ
-
Job Integration
describe("Job Integration", () => {
it("should link shifts to jobs", () => {
// Test job linking
});
it("should track task time", () => {
// Test task timing
});
it("should handle job completion", () => {
// Test completion flow
});
}); -
Payroll Integration
describe("Payroll Integration", () => {
it("should calculate pay correctly", () => {
// Test pay calculation
});
it("should handle rate changes", () => {
// Test rate updates
});
it("should process overtime", () => {
// Test overtime processing
});
});
Performance Testingβ
Test Casesβ
-
Load Testing
describe("Load Testing", () => {
it("should handle multiple concurrent shifts", () => {
// Test concurrent operations
});
it("should maintain performance under load", () => {
// Test performance
});
it("should handle large datasets", () => {
// Test data scaling
});
}); -
Response Times
describe("Response Times", () => {
it("should meet API SLA", () => {
// Test API response times
});
it("should optimize bulk operations", () => {
// Test bulk operations
});
it("should cache effectively", () => {
// Test caching
});
});
Security Testingβ
Test Casesβ
-
Authentication
describe("Authentication", () => {
it("should require valid token", () => {
// Test auth requirements
});
it("should validate permissions", () => {
// Test permissions
});
it("should handle token expiry", () => {
// Test token lifecycle
});
}); -
Data Access
describe("Data Access", () => {
it("should enforce tenant isolation", () => {
// Test multi-tenant security
});
it("should validate data ownership", () => {
// Test ownership rules
});
it("should audit access", () => {
// Test audit logging
});
});
Regression Testingβ
Maintain a suite of regression tests covering:
- Core functionality
- Edge cases
- Known bug fixes
- Performance improvements
Test Dataβ
Maintain test data sets for:
- Various shift scenarios
- Break patterns
- Overtime situations
- Error conditions
Continuous Integrationβ
Configure CI pipeline to:
- Run all tests on PRs
- Check code coverage
- Validate performance
- Check security compliance
Critical Test Scenariosβ
Break Type Validationβ
describe("Break Type Validation", () => {
it("should require valid break type", async () => {
const response = await request(app)
.put("/api/v1/shifts/123/break")
.send({ breakType: "invalid" });
expect(response.status).toBe(400);
expect(response.body.message).toContain("Invalid break type");
});
it('should default to "other" when type not specified', async () => {
const response = await request(app)
.put("/api/v1/shifts/123/break")
.send({ startTime: new Date() });
expect(response.status).toBe(200);
expect(response.body.data.breaks[0].type).toBe("other");
});
it("should prevent multiple active breaks", async () => {
// Start first break
await request(app)
.put("/api/v1/shifts/123/break")
.send({ breakType: "lunch", startTime: new Date() });
// Attempt to start second break
const response = await request(app)
.put("/api/v1/shifts/123/break")
.send({ breakType: "rest", startTime: new Date() });
expect(response.status).toBe(400);
expect(response.body.message).toContain("active break");
});
});
Clock In/Out Edge Casesβ
describe("Clock Operations", () => {
it("should prevent concurrent shifts", async () => {
// Create active shift
await Shift.create({
employee: "emp123",
startTime: new Date(),
status: "in-progress",
});
// Attempt to start another shift
const response = await request(app)
.post("/api/v1/shifts")
.send({ employee: "emp123" });
expect(response.status).toBe(400);
expect(response.body.message).toContain("active shift");
});
it("should handle timezone differences", async () => {
const UTC_start = new Date("2024-01-01T08:00:00Z");
const PST_end = new Date("2024-01-01T17:00:00-08:00");
const shift = await Shift.create({
employee: "emp123",
startTime: UTC_start,
});
const response = await request(app)
.put(`/api/v1/shifts/${shift._id}`)
.send({ endTime: PST_end });
expect(response.status).toBe(200);
expect(new Date(response.body.data.totalTime)).toBe(9 * 60 * 60 * 1000); // 9 hours
});
it("should handle network failures gracefully", async () => {
// Simulate offline storage
const offlineShift = {
startTime: new Date(),
type: "clockIn",
employee: "emp123",
};
await Storage.setItem("pendingClockIn", offlineShift);
// Simulate coming back online
const response = await request(app)
.post("/api/v1/shifts/sync")
.send(offlineShift);
expect(response.status).toBe(200);
expect(response.body.data.startTime).toBe(offlineShift.startTime);
});
});
Time Validationβ
describe("Time Validation", () => {
it("should prevent future start times", async () => {
const futureDate = new Date();
futureDate.setHours(futureDate.getHours() + 1);
const response = await request(app)
.post("/api/v1/shifts")
.send({ startTime: futureDate });
expect(response.status).toBe(400);
expect(response.body.message).toContain("future");
});
it("should prevent invalid end times", async () => {
const shift = await Shift.create({
employee: "emp123",
startTime: new Date(),
});
const pastDate = new Date();
pastDate.setHours(pastDate.getHours() - 1);
const response = await request(app)
.put(`/api/v1/shifts/${shift._id}`)
.send({ endTime: pastDate });
expect(response.status).toBe(400);
expect(response.body.message).toContain("before it starts");
});
it("should validate shift duration", async () => {
const shift = await Shift.create({
employee: "emp123",
startTime: new Date(),
});
const longEndTime = new Date();
longEndTime.setHours(longEndTime.getHours() + 25);
const response = await request(app)
.put(`/api/v1/shifts/${shift._id}`)
.send({ endTime: longEndTime });
expect(response.status).toBe(400);
expect(response.body.message).toContain("24 hours");
});
});
Device Time Syncβ
describe("Time Synchronization", () => {
it("should detect significant time differences", async () => {
// Mock server time
const serverTime = new Date();
jest.spyOn(global, "Date").mockImplementation(
() => new Date(serverTime.getTime() + 6 * 60 * 1000) // 6 minutes ahead
);
const response = await request(app).post("/api/v1/shifts/validate-time");
expect(response.status).toBe(400);
expect(response.body.message).toContain("device time");
});
it("should handle minor time differences", async () => {
// Mock server time
const serverTime = new Date();
jest.spyOn(global, "Date").mockImplementation(
() => new Date(serverTime.getTime() + 2 * 60 * 1000) // 2 minutes ahead
);
const response = await request(app).post("/api/v1/shifts/validate-time");
expect(response.status).toBe(200);
});
});