Skip to content

Commit

Permalink
test: Add credential API tests [DEV-3238] (#442)
Browse files Browse the repository at this point in the history
* feat: Add jsonld tests

* Debug

* use did list

* Use existing did in json

* assert responses

* Update format in payload

* Minor fix

* Add assertionMethod

* Add verify credential tests

* Add revocation tests

* Run tests with one worker

* fix minor issue

* Match complete responses

* Update package-lock.json

* MAke the same style for tests

---------

Co-authored-by: Ankur Banerjee <ankurdotb@users.noreply.github.com>
Co-authored-by: Andrew Nikitin <andrew.nikitin@cheqd.io>
  • Loading branch information
3 people committed Dec 22, 2023
1 parent 8a6fceb commit 0c84d9b
Show file tree
Hide file tree
Showing 31 changed files with 5,231 additions and 86 deletions.
1,459 changes: 1,459 additions & 0 deletions current_db.sql

Large diffs are not rendered by default.

962 changes: 962 additions & 0 deletions current_prod_db.sql

Large diffs are not rendered by default.

127 changes: 127 additions & 0 deletions encrypted.credentials

Large diffs are not rendered by default.

2,303 changes: 2,303 additions & 0 deletions new_staging_db.sql

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default defineConfig({
// Github Actions runners have 2 logical CPU cores
// Defaults to half of the logical CPU cores available
// Docs: https://playwright.dev/docs/api/class-testconfig#test-config-workers
workers: process.env.CI ? 2 : undefined,
workers: process.env.CI ? 1 : undefined,

// Limit the numbers of failures to set a fail-fast strategy on CI
// Docs: https://playwright.dev/docs/api/class-testconfig#test-config-max-failures
Expand Down
2 changes: 1 addition & 1 deletion src/static/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1495,7 +1495,7 @@
"type": "string",
"enum": [
"jwt",
"lds"
"jsonld"
],
"example": "jwt"
},
Expand Down
2 changes: 1 addition & 1 deletion src/types/swagger-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
* type: string
* enum:
* - jwt
* - lds
* - jsonld
* example: jwt
* credentialStatus:
* description: Optional `credentialStatus` properties for VC revocation or suspension. Takes `statusListName` and `statusListPurpose` as inputs.
Expand Down
3 changes: 2 additions & 1 deletion tests/e2e/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export enum PAYLOADS_PATH {
CREDENTIAL = `${PAYLOAD_BASE_PATH}/credential`,
CREDENTIAL_STATUS = `${PAYLOAD_BASE_PATH}/credential-status`,
PRESENTATION = `${PAYLOAD_BASE_PATH}/presentation`,

}

const GENERATED_BASE_PATH = './tests/e2e/generated';
Expand All @@ -19,6 +19,7 @@ export enum GENERATED_PATH {
export enum CONTENT_TYPE {
APPLICATION_JSON = 'application/json',
APPLICATION_DID_LD_JSON = 'application/did+ld+json',
APPLICATION_X_WWW_FORM_URLENCODED = 'application/x-www-form-urlencoded',
}

export const DID_METHOD = 'cheqd';
Expand Down
File renamed without changes.
101 changes: 101 additions & 0 deletions tests/e2e/credential/issue-verify-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import type { VerifiableCredential } from '@veramo/core';

import { test, expect } from '@playwright/test';
import { StatusCodes } from 'http-status-codes';
import * as fs from 'fs';
import { CONTENT_TYPE } from '../constants';

test.use({ storageState: 'playwright/.auth/user.json' });

const PAYLOADS_BASE_PATH = './tests/payloads/credential';

let jwtCredential: VerifiableCredential, jsonldCredential: VerifiableCredential;

test(' Issue a jwt credential', async ({ request }) => {
const credentialData = JSON.parse(fs.readFileSync(`${PAYLOADS_BASE_PATH}/credential-issue-jwt.json`, 'utf-8'));
const response = await request.post(`/credential/issue`, {
data: JSON.stringify(credentialData),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
jwtCredential = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(jwtCredential.proof.type).toBe('JwtProof2020');
expect(jwtCredential.proof).toHaveProperty('jwt');
expect(typeof jwtCredential.issuer === 'string' ? jwtCredential.issuer : jwtCredential.issuer.id).toBe(
credentialData.issuerDid
);
expect(jwtCredential.type).toContain('VerifiableCredential');
expect(jwtCredential.credentialSubject).toMatchObject({
...credentialData.attributes,
id: credentialData.subjectDid,
});
});

test(' Verify a jwt credential', async ({ request }) => {
const response = await request.post(`/credential/verify`, {
data: JSON.stringify({
credential: jwtCredential.proof.jwt,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const result = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(result.verified).toBe(true);
});

test(' Issue a jwt credential with a deactivated DID', async ({ request }) => {
const credentialData = JSON.parse(fs.readFileSync(`${PAYLOADS_BASE_PATH}/credential-issue-jwt.json`, 'utf-8'));
credentialData.issuerDid = 'did:cheqd:testnet:edce6dfb-b59c-493b-a4b8-1d16a6184349';
const response = await request.post(`/credential/issue`, {
data: JSON.stringify(credentialData),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
expect(response.status()).toBe(StatusCodes.BAD_REQUEST);
});

test(' Issue a jsonLD credential', async ({ request }) => {
const credentialData = JSON.parse(fs.readFileSync(`${PAYLOADS_BASE_PATH}/credential-issue-jsonld.json`, 'utf-8'));
const response = await request.post(`/credential/issue`, {
data: JSON.stringify(credentialData),
headers: {
'Content-Type': 'application/json',
},
});
jsonldCredential = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(jsonldCredential.proof.type).toBe('Ed25519Signature2018');
expect(jsonldCredential.proof).toHaveProperty('jws');
expect(typeof jwtCredential.issuer === 'string' ? jwtCredential.issuer : jwtCredential.issuer.id).toBe(
credentialData.issuerDid
);
expect(jwtCredential.type).toContain('VerifiableCredential');
expect(jwtCredential.credentialSubject).toMatchObject({
...credentialData.attributes,
id: credentialData.subjectDid,
});
});

test(' Verify a jsonld credential', async ({ request }) => {
const response = await request.post(`/credential/verify`, {
data: JSON.stringify({
credential: jsonldCredential,
fetchRemoteContexts: true,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const result = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);

Check failure on line 99 in tests/e2e/credential/issue-verify-flow.spec.ts

View workflow job for this annotation

GitHub Actions / Build & Test / Build Node.js

[Logged In User Tests] › credential/issue-verify-flow.spec.ts:87:1 › Verify a jsonld credential

1) [Logged In User Tests] › credential/issue-verify-flow.spec.ts:87:1 › Verify a jsonld credential Error: expect(received).toBe(expected) // Object.is equality Expected: 200 Received: 400 97 | const result = await response.json(); 98 | expect(response).toBeOK(); > 99 | expect(response.status()).toBe(StatusCodes.OK); | ^ 100 | expect(result.verified).toBe(true); 101 | }); 102 | at /home/runner/work/credential-service/credential-service/tests/e2e/credential/issue-verify-flow.spec.ts:99:28

Check failure on line 99 in tests/e2e/credential/issue-verify-flow.spec.ts

View workflow job for this annotation

GitHub Actions / Build & Test / Build Node.js

[Logged In User Tests] › credential/issue-verify-flow.spec.ts:87:1 › Verify a jsonld credential

1) [Logged In User Tests] › credential/issue-verify-flow.spec.ts:87:1 › Verify a jsonld credential Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: 200 Received: 400 97 | const result = await response.json(); 98 | expect(response).toBeOK(); > 99 | expect(response.status()).toBe(StatusCodes.OK); | ^ 100 | expect(result.verified).toBe(true); 101 | }); 102 | at /home/runner/work/credential-service/credential-service/tests/e2e/credential/issue-verify-flow.spec.ts:99:28

Check failure on line 99 in tests/e2e/credential/issue-verify-flow.spec.ts

View workflow job for this annotation

GitHub Actions / Build & Test / Build Node.js

[Logged In User Tests] › credential/issue-verify-flow.spec.ts:87:1 › Verify a jsonld credential

1) [Logged In User Tests] › credential/issue-verify-flow.spec.ts:87:1 › Verify a jsonld credential Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: 200 Received: 400 97 | const result = await response.json(); 98 | expect(response).toBeOK(); > 99 | expect(response.status()).toBe(StatusCodes.OK); | ^ 100 | expect(result.verified).toBe(true); 101 | }); 102 | at /home/runner/work/credential-service/credential-service/tests/e2e/credential/issue-verify-flow.spec.ts:99:28
expect(result.verified).toBe(true);
});
File renamed without changes.
89 changes: 89 additions & 0 deletions tests/e2e/credential/revocation-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import type { VerifiableCredential } from '@veramo/core';

import { test, expect } from '@playwright/test';
import { StatusCodes } from 'http-status-codes';
import * as fs from 'fs';
import { CONTENT_TYPE } from '../constants';

test.use({ storageState: 'playwright/.auth/user.json' });

const PAYLOADS_BASE_PATH = './tests/payloads/credential';

let jwtCredential: VerifiableCredential;

test(' Issue a jwt credential with revocation statuslist', async ({ request }) => {
const credentialData = JSON.parse(
fs.readFileSync(`${PAYLOADS_BASE_PATH}/credential-issue-jwt-revocation.json`, 'utf-8')
);
const response = await request.post(`/credential/issue`, {
data: JSON.stringify(credentialData),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
jwtCredential = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(jwtCredential.proof.type).toBe('JwtProof2020');
expect(jwtCredential.proof).toHaveProperty('jwt');
expect(typeof jwtCredential.issuer === 'string' ? jwtCredential.issuer : jwtCredential.issuer.id).toBe(
credentialData.issuerDid
);
expect(jwtCredential.type).toContain('VerifiableCredential');
expect(jwtCredential.credentialSubject).toMatchObject({
...credentialData.attributes,
id: credentialData.subjectDid,
});
expect(jwtCredential.credentialStatus).toMatchObject({
type: 'StatusList2021Entry',
statusPurpose: 'revocation',
});
expect(jwtCredential.credentialStatus).toHaveProperty('statusListIndex');
expect(jwtCredential.credentialStatus).toHaveProperty('id');
});

test(" Verify a credential's revocation status", async ({ request }) => {
const response = await request.post(`/credential/verify?verifyStatus=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const result = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(result.verified).toBe(true);
expect(result.revoked).toBe(false);
});

test(' Verify a credential status after revocation', async ({ request }) => {
const response = await request.post(`/credential/revoke?publish=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const result = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(result.revoked).toBe(true);
expect(result.published).toBe(true);

const verificationResponse = await request.post(`/credential/verify?verifyStatus=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const verificationResult = await verificationResponse.json();
expect(verificationResponse).toBeOK();
expect(verificationResponse.status()).toBe(StatusCodes.OK);
expect(verificationResult.verified).toBe(true);
expect(verificationResult.revoked).toBe(true);
});
File renamed without changes.
File renamed without changes.
119 changes: 119 additions & 0 deletions tests/e2e/credential/suspension-flow.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import type { VerifiableCredential } from '@veramo/core';

import { test, expect } from '@playwright/test';
import { StatusCodes } from 'http-status-codes';
import * as fs from 'fs';
import { CONTENT_TYPE } from '../constants';

test.use({ storageState: 'playwright/.auth/user.json' });

const PAYLOADS_BASE_PATH = './tests/payloads/credential';

let jwtCredential: VerifiableCredential;

test(' Issue a jwt credential with suspension statuslist', async ({ request }) => {
const credentialData = JSON.parse(
fs.readFileSync(`${PAYLOADS_BASE_PATH}/credential-issue-jwt-revocation.json`, 'utf-8')
);
credentialData.credentialStatus.statusPurpose = 'suspension';
const response = await request.post(`/credential/issue`, {
data: JSON.stringify(credentialData),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
jwtCredential = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(jwtCredential.proof.type).toBe('JwtProof2020');
expect(jwtCredential.proof).toHaveProperty('jwt');
expect(typeof jwtCredential.issuer === 'string' ? jwtCredential.issuer : jwtCredential.issuer.id).toBe(
credentialData.issuerDid
);
expect(jwtCredential.type).toContain('VerifiableCredential');
expect(jwtCredential.credentialSubject).toMatchObject({
...credentialData.attributes,
id: credentialData.subjectDid,
});
expect(jwtCredential.credentialStatus).toMatchObject({
type: 'StatusList2021Entry',
statusPurpose: 'suspension',
});
expect(jwtCredential.credentialStatus).toHaveProperty('statusListIndex');
expect(jwtCredential.credentialStatus).toHaveProperty('id');
});

test(" Verify a credential's suspension status", async ({ request }) => {
const response = await request.post(`/credential/verify?verifyStatus=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const result = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(result.verified).toBe(true);
expect(result.suspended).toBe(false);
});

test(' Verify a credential status after suspension', async ({ request }) => {
const response = await request.post(`/credential/suspend?publish=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const result = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);
expect(result.suspended).toBe(true);
expect(result.published).toBe(true);

const verificationResponse = await request.post(`/credential/verify?verifyStatus=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const verificationResult = await verificationResponse.json();
expect(verificationResponse).toBeOK();
expect(verificationResponse.status()).toBe(StatusCodes.OK);
expect(verificationResult.verified).toBe(true);
expect(verificationResult.suspended).toBe(true);
});

test(' Verify a credential status after reinstating', async ({ request }) => {
const response = await request.post(`/credential/reinstate?publish=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const result = await response.json();
expect(response).toBeOK();
expect(response.status()).toBe(StatusCodes.OK);

Check failure on line 103 in tests/e2e/credential/suspension-flow.spec.ts

View workflow job for this annotation

GitHub Actions / Build & Test / Build Node.js

[Logged In User Tests] › credential/suspension-flow.spec.ts:92:1 › Verify a credential status after reinstating

2) [Logged In User Tests] › credential/suspension-flow.spec.ts:92:1 › Verify a credential status after reinstating Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(received).toBe(expected) // Object.is equality Expected: 200 Received: 500 101 | const result = await response.json(); 102 | expect(response).toBeOK(); > 103 | expect(response.status()).toBe(StatusCodes.OK); | ^ 104 | expect(result.unsuspended).toBe(true); 105 | 106 | const verificationResponse = await request.post(`/credential/verify?verifyStatus=true`, { at /home/runner/work/credential-service/credential-service/tests/e2e/credential/suspension-flow.spec.ts:103:28
expect(result.unsuspended).toBe(true);

Check failure on line 104 in tests/e2e/credential/suspension-flow.spec.ts

View workflow job for this annotation

GitHub Actions / Build & Test / Build Node.js

[Logged In User Tests] › credential/suspension-flow.spec.ts:92:1 › Verify a credential status after reinstating

2) [Logged In User Tests] › credential/suspension-flow.spec.ts:92:1 › Verify a credential status after reinstating Error: expect(received).toBe(expected) // Object.is equality Expected: true Received: false 102 | expect(response).toBeOK(); 103 | expect(response.status()).toBe(StatusCodes.OK); > 104 | expect(result.unsuspended).toBe(true); | ^ 105 | 106 | const verificationResponse = await request.post(`/credential/verify?verifyStatus=true`, { 107 | data: JSON.stringify({ at /home/runner/work/credential-service/credential-service/tests/e2e/credential/suspension-flow.spec.ts:104:29

const verificationResponse = await request.post(`/credential/verify?verifyStatus=true`, {
data: JSON.stringify({
credential: jwtCredential,
}),
headers: {
'Content-Type': CONTENT_TYPE.APPLICATION_JSON,
},
});
const verificationResult = await verificationResponse.json();
expect(verificationResponse).toBeOK();
expect(verificationResponse.status()).toBe(StatusCodes.OK);
expect(verificationResult.verified).toBe(true);
expect(verificationResult.suspended).toBe(false);
});
File renamed without changes.
Loading

0 comments on commit 0c84d9b

Please sign in to comment.