Skip to main content

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​

  1. 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
    });
    });
  2. 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
    });
    });
  3. 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
    });
    });
  4. 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​

  1. 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
    });
    });
  2. 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
    });
    });
  3. 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​

  1. 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
    });
    });
  2. 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​

  1. 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
    });
    });
  2. 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​

  1. 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
    });
    });
  2. 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);
});
});