From 4f6a2804c4db86803be736e1f1be4b3db719fc70 Mon Sep 17 00:00:00 2001
From: ak68a
Date: Wed, 25 Mar 2026 16:52:44 -0500
Subject: [PATCH 1/2] test(vc): add tests for isCredential and
isStatusListCredential type guards
Cover both type guard functions that previously had zero tests:
isCredential: valid credentials, string issuer, optional fields,
rejection of null/undefined/string/empty objects, and each required
field missing individually.
isStatusListCredential: valid status list credential, wrong subject
type, missing encodedList, missing statusPurpose, regular credential
without status list subject, and non-credential inputs.
---
packages/vc/src/is-credential.test.ts | 83 +++++++++++++++++++
.../is-status-list-credential.test.ts | 81 ++++++++++++++++++
2 files changed, 164 insertions(+)
create mode 100644 packages/vc/src/is-credential.test.ts
create mode 100644 packages/vc/src/revocation/is-status-list-credential.test.ts
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..354d22f
--- /dev/null
+++ b/packages/vc/src/revocation/is-status-list-credential.test.ts
@@ -0,0 +1,81 @@
+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("returns false when the outer shape is not a valid credential", () => {
+ expect(isStatusListCredential(null)).toBe(false)
+ expect(isStatusListCredential({})).toBe(false)
+ expect(isStatusListCredential("not a credential")).toBe(false)
+ })
+})
From 03af4141ea8ab879ff61466841fb5149dc84ccc2 Mon Sep 17 00:00:00 2001
From: ak68a
Date: Wed, 25 Mar 2026 16:55:22 -0500
Subject: [PATCH 2/2] test(vc): split bundled assertions into individual test
cases
---
.../vc/src/revocation/is-status-list-credential.test.ts | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/packages/vc/src/revocation/is-status-list-credential.test.ts b/packages/vc/src/revocation/is-status-list-credential.test.ts
index 354d22f..db598d3 100644
--- a/packages/vc/src/revocation/is-status-list-credential.test.ts
+++ b/packages/vc/src/revocation/is-status-list-credential.test.ts
@@ -73,9 +73,15 @@ describe("isStatusListCredential", () => {
).toBe(false)
})
- it("returns false when the outer shape is not a valid credential", () => {
+ 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)
})
})