mirror of
https://github.com/bitwarden/browser
synced 2026-02-03 02:03:53 +00:00
Critical: Add comprehensive test coverage for backward compatibility
Add test cases for the primary use case addressed by this PR: validating OrganizationReportSummary objects without the newApplications field. Tests added: - isOrganizationReportSummary accepts objects without newApplications - isOrganizationReportSummary accepts objects with undefined newApplications - validateOrganizationReportSummary accepts objects without newApplications - validateOrganizationReportSummary accepts objects with undefined newApplications - Validation enforces empty string rejection when newApplications is present - Validation enforces array length limits when newApplications is present - Validation enforces string length limits when newApplications is present This prevents regression where legacy encrypted data (which predates the newApplications field) would fail to decrypt. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -247,6 +247,76 @@ describe("Risk Insights Type Guards", () => {
|
||||
/Invalid OrganizationReportSummary/,
|
||||
);
|
||||
});
|
||||
|
||||
// Backward compatibility tests - legacy encrypted data predates newApplications field
|
||||
it("should accept OrganizationReportSummary without newApplications field (backward compatibility)", () => {
|
||||
const validLegacyData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
// newApplications field intentionally omitted - legacy data
|
||||
};
|
||||
|
||||
expect(() => validateOrganizationReportSummary(validLegacyData)).not.toThrow();
|
||||
expect(validateOrganizationReportSummary(validLegacyData)).toEqual(validLegacyData);
|
||||
});
|
||||
|
||||
it("should accept OrganizationReportSummary with undefined newApplications (backward compatibility)", () => {
|
||||
const validData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
newApplications: undefined,
|
||||
};
|
||||
|
||||
expect(() => validateOrganizationReportSummary(validData)).not.toThrow();
|
||||
});
|
||||
|
||||
it("should enforce array length limits on newApplications when present", () => {
|
||||
const invalidData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
newApplications: new Array(50001).fill("app"), // exceeds MAX_ARRAY_LENGTH
|
||||
};
|
||||
|
||||
expect(() => validateOrganizationReportSummary(invalidData)).toThrow(
|
||||
/Invalid OrganizationReportSummary.*newApplications/,
|
||||
);
|
||||
});
|
||||
|
||||
it("should enforce string length limits on newApplications when present", () => {
|
||||
const invalidData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
newApplications: ["app-1", "a".repeat(1001)], // exceeds MAX_STRING_LENGTH
|
||||
};
|
||||
|
||||
expect(() => validateOrganizationReportSummary(invalidData)).toThrow(
|
||||
/Invalid OrganizationReportSummary.*newApplications/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateOrganizationReportApplicationArray", () => {
|
||||
@@ -616,6 +686,82 @@ describe("Risk Insights Type Guards", () => {
|
||||
};
|
||||
expect(isOrganizationReportSummary(invalidData)).toBe(false);
|
||||
});
|
||||
|
||||
// Backward compatibility tests - legacy encrypted data predates newApplications field
|
||||
it("should return true for OrganizationReportSummary without newApplications field (backward compatibility)", () => {
|
||||
const validLegacyData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
// newApplications field intentionally omitted - legacy data
|
||||
};
|
||||
expect(isOrganizationReportSummary(validLegacyData)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for OrganizationReportSummary with undefined newApplications (backward compatibility)", () => {
|
||||
const validData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
newApplications: undefined,
|
||||
};
|
||||
expect(isOrganizationReportSummary(validData)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for empty string in newApplications when present", () => {
|
||||
const invalidData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
newApplications: ["app-1", "", "app-3"], // empty string should be rejected
|
||||
};
|
||||
expect(isOrganizationReportSummary(invalidData)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when newApplications exceeds array length limit", () => {
|
||||
const invalidData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
newApplications: new Array(50001).fill("app"), // exceeds MAX_ARRAY_LENGTH
|
||||
};
|
||||
expect(isOrganizationReportSummary(invalidData)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false when newApplications contains strings exceeding length limit", () => {
|
||||
const invalidData = {
|
||||
totalMemberCount: 10,
|
||||
totalApplicationCount: 5,
|
||||
totalAtRiskMemberCount: 2,
|
||||
totalAtRiskApplicationCount: 1,
|
||||
totalCriticalApplicationCount: 3,
|
||||
totalCriticalMemberCount: 4,
|
||||
totalCriticalAtRiskMemberCount: 1,
|
||||
totalCriticalAtRiskApplicationCount: 1,
|
||||
newApplications: ["app-1", "a".repeat(1001)], // exceeds MAX_STRING_LENGTH
|
||||
};
|
||||
expect(isOrganizationReportSummary(invalidData)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isOrganizationReportApplication", () => {
|
||||
|
||||
Reference in New Issue
Block a user