diff --git a/packages/vc/src/is-credential.test.ts b/packages/vc/src/is-credential.test.ts new file mode 100644 index 0000000..e40843e --- /dev/null +++ b/packages/vc/src/is-credential.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, it } from "vitest" + +import { isCredential } from "./is-credential" + +// A minimal valid W3C credential +const validCredential = { + "@context": ["https://www.w3.org/2018/credentials/v1"], + type: ["VerifiableCredential"], + issuer: { id: "did:web:issuer.example.com" }, + issuanceDate: "2025-01-01T00:00:00.000Z", + credentialSubject: { id: "did:web:subject.example.com" }, +} + +describe("isCredential", () => { + it("returns true for a valid credential", () => { + expect(isCredential(validCredential)).toBe(true) + }) + + it("accepts issuer as a plain string", () => { + expect( + isCredential({ + ...validCredential, + issuer: "did:web:issuer.example.com", + }), + ).toBe(true) + }) + + it("accepts credentials with optional fields", () => { + expect( + isCredential({ + ...validCredential, + id: "urn:uuid:123", + expirationDate: "2030-01-01T00:00:00.000Z", + credentialStatus: { + id: "https://status.example.com/1", + type: "BitstringStatusListEntry", + }, + proof: { type: "JwtProof2020" }, + }), + ).toBe(true) + }) + + it("rejects null", () => { + expect(isCredential(null)).toBe(false) + }) + + it("rejects undefined", () => { + expect(isCredential(undefined)).toBe(false) + }) + + it("rejects a plain string", () => { + expect(isCredential("not a credential")).toBe(false) + }) + + it("rejects an empty object", () => { + expect(isCredential({})).toBe(false) + }) + + it("rejects when @context is missing", () => { + const { "@context": _, ...noContext } = validCredential + expect(isCredential(noContext)).toBe(false) + }) + + it("rejects when type is missing", () => { + const { type: _, ...noType } = validCredential + expect(isCredential(noType)).toBe(false) + }) + + it("rejects when issuer is missing", () => { + const { issuer: _, ...noIssuer } = validCredential + expect(isCredential(noIssuer)).toBe(false) + }) + + it("rejects when issuanceDate is missing", () => { + const { issuanceDate: _, ...noDate } = validCredential + expect(isCredential(noDate)).toBe(false) + }) + + it("rejects when credentialSubject is missing", () => { + const { credentialSubject: _, ...noSubject } = validCredential + expect(isCredential(noSubject)).toBe(false) + }) +}) diff --git a/packages/vc/src/revocation/is-status-list-credential.test.ts b/packages/vc/src/revocation/is-status-list-credential.test.ts new file mode 100644 index 0000000..db598d3 --- /dev/null +++ b/packages/vc/src/revocation/is-status-list-credential.test.ts @@ -0,0 +1,87 @@ +import { describe, expect, it } from "vitest" + +import { isStatusListCredential } from "./is-status-list-credential" + +const baseCredential = { + "@context": ["https://www.w3.org/2018/credentials/v1"], + type: ["VerifiableCredential", "BitstringStatusListCredential"], + issuer: { id: "did:web:issuer.example.com" }, + issuanceDate: "2025-01-01T00:00:00.000Z", +} + +const validStatusListCredential = { + ...baseCredential, + credentialSubject: { + id: "https://status.example.com/list/1", + type: "BitstringStatusList", + statusPurpose: "revocation", + encodedList: "H4sIAAAAAAAA...", + }, +} + +describe("isStatusListCredential", () => { + it("returns true for a valid status list credential", () => { + expect(isStatusListCredential(validStatusListCredential)).toBe(true) + }) + + it("returns false when credentialSubject has wrong type", () => { + expect( + isStatusListCredential({ + ...baseCredential, + credentialSubject: { + id: "https://status.example.com/list/1", + type: "SomethingElse", + statusPurpose: "revocation", + encodedList: "H4sIAAAAAAAA...", + }, + }), + ).toBe(false) + }) + + it("returns false when credentialSubject is missing encodedList", () => { + expect( + isStatusListCredential({ + ...baseCredential, + credentialSubject: { + id: "https://status.example.com/list/1", + type: "BitstringStatusList", + statusPurpose: "revocation", + }, + }), + ).toBe(false) + }) + + it("returns false when credentialSubject is missing statusPurpose", () => { + expect( + isStatusListCredential({ + ...baseCredential, + credentialSubject: { + id: "https://status.example.com/list/1", + type: "BitstringStatusList", + encodedList: "H4sIAAAAAAAA...", + }, + }), + ).toBe(false) + }) + + it("returns false for a regular credential without status list subject", () => { + expect( + isStatusListCredential({ + ...baseCredential, + credentialSubject: { id: "did:web:subject.example.com" }, + }), + ).toBe(false) + }) + + it("rejects null", () => { + expect(isStatusListCredential(null)).toBe(false) + }) + + it("rejects an empty object", () => { + expect(isStatusListCredential({})).toBe(false) + }) + + it("rejects a plain string", () => { + expect(isStatusListCredential("not a credential")).toBe(false) + }) +})