From 0f80f82d95c3ef389819240b0c795c8fd14d030a Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 12:27:24 +0200 Subject: [PATCH 01/11] Fix invalidDidUrl error string. --- .../suites/did-url-dereferencing/did-url-dereferencing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index 2f241257..ef0a1672 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -123,7 +123,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { expect(dereferencingMetadata['error']).not.toMatch('\\s'); }); } - if (expectedOutcome === 'invalidDidErrorUrlOutcome') { + if (expectedOutcome === 'invalidDidUrlErrorOutcome') { it('invalidDidUrl - The DID URL supplied to the DID URL dereferencing function does not conform to valid syntax.', async () => { expect(dereferencingMetadata['error']).toBe('invalidDidUrl'); // TODO: Check if the input didUrl is really invalid. From 269e96975c979643db4828110b70b5d5716f9a3d Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 12:46:50 +0200 Subject: [PATCH 02/11] Use toBeValidDid() and toBeValidDidUrl() matchers. --- .../suites/did-resolution/did-resolution.js | 10 +++++----- .../suites/did-resolution/utils.js | 14 -------------- .../did-url-dereferencing/did-url-dereferencing.js | 5 ++--- .../suites/did-url-dereferencing/utils.js | 14 -------------- 4 files changed, 7 insertions(+), 36 deletions(-) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index 747d469b..41f9623d 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -5,7 +5,6 @@ const consumeRepresentation = require('./utils').consumeRepresentation; const expectAsciiString = require('./utils').expectAsciiString; const expectXmlDateTimeNormalizedToUtcWithoutPrecision = require('./utils').expectXmlDateTimeNormalizedToUtcWithoutPrecision; const expectMediaType = require('./utils').expectMediaType; -const expectConformantDid = require('./utils').expectConformantDid; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; @@ -20,7 +19,7 @@ const didResolutionTests = (execution, expectedOutcome) => { it('This input is REQUIRED and the value MUST be a conformant DID as defined in § 3.1 DID Syntax.', async () => { expect(did).not.toBeFalsy(); if (! didResolutionMetadata.hasOwnProperty('error') || didResolutionMetadata['error'] !== 'invalidDid') { - expectConformantDid(did); + expect(did).toBeValidDid(); } }); }); @@ -168,7 +167,7 @@ const didResolutionTests = (execution, expectedOutcome) => { if (expectedOutcome === 'invalidDidErrorOutcome') { it('invalidDid - The DID supplied to the DID resolution function does not conform to valid syntax.', async () => { expect(didResolutionMetadata['error']).toBe('invalidDid'); - expectConformantDid(did, true); + expect(did).not.toBeValidDid(); expect(didDocument).toBeFalsy(); }); } @@ -263,7 +262,7 @@ const didResolutionTests = (execution, expectedOutcome) => { expect(typeof didDocumentMetadata['equivalentId']).toBe('array'); didDocumentMetadata['equivalentId'].forEach((i) => { const equivalentid = didDocumentMetadata['equivalentId'][i]; - expectConformantDid(equivalentid); + expect(equivalentid).toBeValidDid(); }) }); it('Each equivalentId DID value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { @@ -283,7 +282,8 @@ const didResolutionTests = (execution, expectedOutcome) => { // TODO: According to the spec, 'canonicalId' is currently not optional, even though that's definitely what the WG intended - see https://github.com/w3c/did-core/issues/717. if (didDocumentMetadata.hasOwnProperty('canonicalId')) { it('The value of canonicalId MUST be a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { - expectConformantDid(didDocumentMetadata['canonicalId']); + const canonicalId = didDocumentMetadata['canonicalId'][i]; + expect(didDocumentMetadata['canonicalId']).toBeValidDid(); }); it('A canonicalId value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { // TODO: This will currently only work if the 'resolve' function is called, not 'resolveRepresentation'. diff --git a/packages/did-core-test-server/suites/did-resolution/utils.js b/packages/did-core-test-server/suites/did-resolution/utils.js index bf117a31..8e640312 100644 --- a/packages/did-core-test-server/suites/did-resolution/utils.js +++ b/packages/did-core-test-server/suites/did-resolution/utils.js @@ -42,18 +42,6 @@ const expectMediaType = (mediaType, not) => { .toMatch(/^\w+\/[-+.\w]+/); }; -const expectConformantDid = ((did, not) => { - // TODO: properly test if this is a conformant DID, try to re-use other test code - (not ? expect(did).not : expect(did)) - .toMatch(/^did:(.+):(.+)$/); -}); - -const expectConformantDidUrl = ((didUrl, not) => { - // TODO: properly test if this is a conformant DID URL, try to re-use other test code - (not ? expect(didUrl).not : expect(didUrl)) - .toMatch(/^did:(.+):(.+)$/); -}); - const expectConformantDidDocument = ((didDocument, not) => { // TODO: properly test if this is a conformant DID document (abstract data model) (not ? expect(Object.keys(didDocument)).not : expect(Object.keys(didDocument))) @@ -93,8 +81,6 @@ module.exports = { expectAsciiString, expectXmlDateTimeNormalizedToUtcWithoutPrecision, expectMediaType, - expectConformantDid, - expectConformantDidUrl, expectConformantDidDocument, expectConformantMetadataStructure, expectKnownConformantMediaType, diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index ef0a1672..e569cf11 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -3,7 +3,6 @@ const parseDidMethod = require('./utils').parseDidMethod; const expectAsciiString = require('./utils').expectAsciiString; const expectXmlDateTimeNormalizedToUtcWithoutPrecision = require('./utils').expectXmlDateTimeNormalizedToUtcWithoutPrecision; const expectMediaType = require('./utils').expectMediaType; -const expectConformantDidUrl = require('./utils').expectConformantDidUrl; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; @@ -24,7 +23,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { it.todo('3.2.2 Relative DID URLs - When resolving a relative DID URL reference, the algorithm specified in RFC3986 Section 5: Reference Resolution MUST be used.'); it('A conformant DID URL as a single string.', async() => { if (! dereferencingMetadata.hasOwnProperty('error') || dereferencingMetadata['error'] !== 'invalidDidUrl') { - expectConformantDidUrl(didUrl); + expect(didUrl).toBeValidDidUrl(); } }); @@ -126,7 +125,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { if (expectedOutcome === 'invalidDidUrlErrorOutcome') { it('invalidDidUrl - The DID URL supplied to the DID URL dereferencing function does not conform to valid syntax.', async () => { expect(dereferencingMetadata['error']).toBe('invalidDidUrl'); - // TODO: Check if the input didUrl is really invalid. + expect(didUrl).not.toBeValidDidUrl(); }); } if (expectedOutcome === 'notFoundErrorOutcome') { diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js index 6b76c3ce..71498f9f 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js @@ -42,18 +42,6 @@ const expectMediaType = (mediaType, not) => { .toMatch(/^\w+\/[-+.\w]+/); }; -const expectConformantDid = ((did, not) => { - // TODO: properly test if this is a conformant DID, try to re-use other test code - (not ? expect(did).not : expect(did)) - .toMatch(/^did:(.+):(.+)$/); -}); - -const expectConformantDidUrl = ((didUrl, not) => { - // TODO: properly test if this is a conformant DID URL, try to re-use other test code - (not ? expect(didUrl).not : expect(didUrl)) - .toMatch(/^did:(.+):(.+)$/); -}); - const expectConformantDidDocument = ((didDocument, not) => { // TODO: properly test if this is a conformant DID document (abstract data model) (not ? expect(Object.keys(didDocument)).not : expect(Object.keys(didDocument))) @@ -93,8 +81,6 @@ module.exports = { expectAsciiString, expectXmlDateTimeNormalizedToUtcWithoutPrecision, expectMediaType, - expectConformantDid, - expectConformantDidUrl, expectConformantDidDocument, expectConformantMetadataStructure, expectKnownConformantMediaType, From cabfd14312642764b69279945ccce8c36d9ceac7 Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 12:56:18 +0200 Subject: [PATCH 03/11] Use toBeAsciiString() matcher. --- .../suites/did-resolution/did-resolution.js | 11 +++++------ .../suites/did-resolution/utils.js | 6 ------ .../did-url-dereferencing/did-url-dereferencing.js | 7 +++---- .../suites/did-url-dereferencing/utils.js | 6 ------ 4 files changed, 8 insertions(+), 22 deletions(-) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index 41f9623d..30d2b529 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -2,7 +2,6 @@ const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; const parseDidMethod = require('./utils').parseDidMethod; const produceRepresentation = require('./utils').produceRepresentation; const consumeRepresentation = require('./utils').consumeRepresentation; -const expectAsciiString = require('./utils').expectAsciiString; const expectXmlDateTimeNormalizedToUtcWithoutPrecision = require('./utils').expectXmlDateTimeNormalizedToUtcWithoutPrecision; const expectMediaType = require('./utils').expectMediaType; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; @@ -119,7 +118,7 @@ const didResolutionTests = (execution, expectedOutcome) => { expectMediaType(resolutionOptions['accept']); }); it('The Media Type MUST be expressed as an ASCII string.', async () => { - expectAsciiString(resolutionOptions['accept']); + expect(resolutionOptions['accept']).toBeAsciiString(); }); } it('This property is OPTIONAL for the resolveRepresentation function and MUST NOT be used with the resolve function.', async () => { @@ -143,7 +142,7 @@ const didResolutionTests = (execution, expectedOutcome) => { }); if (didResolutionMetadata.hasOwnProperty('contentType')) { it('The value of this property MUST be an ASCII string that is the Media Type of the conformant representations.', async () => { - expectAsciiString(didResolutionMetadata['contentType']); + expect(didResolutionMetadata['contentType']).toBeAsciiString(); expectMediaType(didResolutionMetadata['contentType']); expectKnownConformantMediaType(didResolutionMetadata['contentType']); }); @@ -160,7 +159,7 @@ const didResolutionTests = (execution, expectedOutcome) => { }); if (didResolutionMetadata.hasOwnProperty('error')) { it('The value of this property MUST be a single keyword ASCII string.', async () => { - expectAsciiString(didResolutionMetadata['error']); + expect(didResolutionMetadata['error']).toBeAsciiString(); expect(didResolutionMetadata['error']).not.toMatch('\\s'); }); } @@ -239,14 +238,14 @@ const didResolutionTests = (execution, expectedOutcome) => { describe('versionId', () => { if (didDocumentMetadata.hasOwnProperty('versionId')) { it('The value of the property MUST be an ASCII string.', async () => { - expectAsciiString(didDocumentMetadata['versionId']); + expect(didDocumentMetadata['versionId']).toBeAsciiString(); }); } }); describe('nextVersionId', () => { if (didDocumentMetadata.hasOwnProperty('nextVersionId')) { it('The value of the property MUST be an ASCII string.', async () => { - expectAsciiString(didDocumentMetadata['nextVersionId']); + expect(didDocumentMetadata['nextVersionId']).toBeAsciiString(); }); if (didDocumentMetadata.hasOwnProperty('versionId')) { it('nextVersionId is different from versionId.', async () => { diff --git a/packages/did-core-test-server/suites/did-resolution/utils.js b/packages/did-core-test-server/suites/did-resolution/utils.js index 8e640312..a83bba23 100644 --- a/packages/did-core-test-server/suites/did-resolution/utils.js +++ b/packages/did-core-test-server/suites/did-resolution/utils.js @@ -27,11 +27,6 @@ const consumeRepresentation = (representation) => { return JSON.parse(representation); }; -const expectAsciiString = (string, not) => { - (not ? expect(string).not : expect(string)) - .toMatch(/^[\x00-\x7F]*$/); -}; - const expectXmlDateTimeNormalizedToUtcWithoutPrecision = (xmlDateTime, not) => { (not ? expect(xmlDateTime).not : expect(xmlDateTime)) .toMatch(/^([0-9]{4})-([0-1][0-9])-([0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](Z))$/); @@ -78,7 +73,6 @@ module.exports = { parseDidMethod, produceRepresentation, consumeRepresentation, - expectAsciiString, expectXmlDateTimeNormalizedToUtcWithoutPrecision, expectMediaType, expectConformantDidDocument, diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index e569cf11..781c6a1b 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -1,6 +1,5 @@ const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; const parseDidMethod = require('./utils').parseDidMethod; -const expectAsciiString = require('./utils').expectAsciiString; const expectXmlDateTimeNormalizedToUtcWithoutPrecision = require('./utils').expectXmlDateTimeNormalizedToUtcWithoutPrecision; const expectMediaType = require('./utils').expectMediaType; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; @@ -96,7 +95,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { expectMediaType(dereferenceOptions['accept']); }); it('The Media Type MUST be expressed as an ASCII string.', async () => { - expectAsciiString(dereferenceOptions['accept']); + expect(dereferenceOptions['accept']).toBeAsciiString(); }); } }); @@ -106,7 +105,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { if (dereferencingMetadata.hasOwnProperty('contentType')) { it('The Media Type value MUST be expressed as an ASCII string.', async () => { expectMediaType(dereferencingMetadata['contentType']); - expectAsciiString(dereferencingMetadata['contentType']); + expect(dereferencingMetadata['contentType']).toBeAsciiString(); }); } }); @@ -118,7 +117,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { }); if (dereferencingMetadata.hasOwnProperty('error')) { it('The value of this property MUST be a single keyword ASCII string.', async () => { - expectAsciiString(dereferencingMetadata['error']); + expect(dereferencingMetadata['error']).toBeAsciiString(); expect(dereferencingMetadata['error']).not.toMatch('\\s'); }); } diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js index 71498f9f..73553bd2 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js @@ -27,11 +27,6 @@ const consumeRepresentation = (representation) => { return JSON.parse(representation); }; -const expectAsciiString = (string, not) => { - (not ? expect(string).not : expect(string)) - .toMatch(/^[\x00-\x7F]*$/); -}; - const expectXmlDateTimeNormalizedToUtcWithoutPrecision = (xmlDateTime, not) => { (not ? expect(xmlDateTime).not : expect(xmlDateTime)) .toMatch(/^([0-9]{4})-([0-1][0-9])-([0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](Z))$/); @@ -78,7 +73,6 @@ module.exports = { parseDidMethod, produceRepresentation, consumeRepresentation, - expectAsciiString, expectXmlDateTimeNormalizedToUtcWithoutPrecision, expectMediaType, expectConformantDidDocument, From d1b24a09a1f7ce928af132cc241d3164b2edc723 Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 13:09:10 +0200 Subject: [PATCH 04/11] Use toBeDidCoreDatetime() matcher. --- .../suites/did-resolution/did-resolution.js | 7 +++---- .../did-core-test-server/suites/did-resolution/utils.js | 6 ------ .../suites/did-url-dereferencing/did-url-dereferencing.js | 1 - .../suites/did-url-dereferencing/utils.js | 6 ------ 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index 30d2b529..f70c8336 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -2,7 +2,6 @@ const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; const parseDidMethod = require('./utils').parseDidMethod; const produceRepresentation = require('./utils').produceRepresentation; const consumeRepresentation = require('./utils').consumeRepresentation; -const expectXmlDateTimeNormalizedToUtcWithoutPrecision = require('./utils').expectXmlDateTimeNormalizedToUtcWithoutPrecision; const expectMediaType = require('./utils').expectMediaType; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; @@ -187,14 +186,14 @@ const didResolutionTests = (execution, expectedOutcome) => { describe('created', () => { if (didDocumentMetadata.hasOwnProperty('created')) { it('The value of the property MUST be a string formatted as an XML Datetime normalized to UTC 00:00:00 and without sub-second decimal precision.', async () => { - expectXmlDateTimeNormalizedToUtcWithoutPrecision(didDocumentMetadata['created']); + expect(didDocumentMetadata['created']).toBeDidCoreDatetime(); }); } }); describe('updated', () => { if (didDocumentMetadata.hasOwnProperty('updated')) { it('The value of the property MUST follow the same formatting rules as the created property.', async () => { - expectXmlDateTimeNormalizedToUtcWithoutPrecision(didDocumentMetadata['updated']); + expect(didDocumentMetadata['updated']).toBeDidCoreDatetime(); }); if (didDocumentMetadata.hasOwnProperty('created')) { it('updated is later or equal than created.', async () => { @@ -221,7 +220,7 @@ const didResolutionTests = (execution, expectedOutcome) => { describe('nextUpdate', () => { if (didDocumentMetadata.hasOwnProperty('nextUpdate')) { it('The value of the property MUST follow the same formatting rules as the created property.', async () => { - expectXmlDateTimeNormalizedToUtcWithoutPrecision(didDocumentMetadata['nextUpdate']); + expect(didDocumentMetadata['nextUpdate']).toBeDidCoreDatetime(); }); if (didDocumentMetadata.hasOwnProperty('created')) { it('nextUpdate is later than created.', async () => { diff --git a/packages/did-core-test-server/suites/did-resolution/utils.js b/packages/did-core-test-server/suites/did-resolution/utils.js index a83bba23..011d22e5 100644 --- a/packages/did-core-test-server/suites/did-resolution/utils.js +++ b/packages/did-core-test-server/suites/did-resolution/utils.js @@ -27,11 +27,6 @@ const consumeRepresentation = (representation) => { return JSON.parse(representation); }; -const expectXmlDateTimeNormalizedToUtcWithoutPrecision = (xmlDateTime, not) => { - (not ? expect(xmlDateTime).not : expect(xmlDateTime)) - .toMatch(/^([0-9]{4})-([0-1][0-9])-([0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](Z))$/); -} - const expectMediaType = (mediaType, not) => { (not ? expect(mediaType).not : expect(mediaType)) .toMatch(/^\w+\/[-+.\w]+/); @@ -73,7 +68,6 @@ module.exports = { parseDidMethod, produceRepresentation, consumeRepresentation, - expectXmlDateTimeNormalizedToUtcWithoutPrecision, expectMediaType, expectConformantDidDocument, expectConformantMetadataStructure, diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index 781c6a1b..014521b1 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -1,6 +1,5 @@ const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; const parseDidMethod = require('./utils').parseDidMethod; -const expectXmlDateTimeNormalizedToUtcWithoutPrecision = require('./utils').expectXmlDateTimeNormalizedToUtcWithoutPrecision; const expectMediaType = require('./utils').expectMediaType; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js index 73553bd2..1ce39cc2 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js @@ -27,11 +27,6 @@ const consumeRepresentation = (representation) => { return JSON.parse(representation); }; -const expectXmlDateTimeNormalizedToUtcWithoutPrecision = (xmlDateTime, not) => { - (not ? expect(xmlDateTime).not : expect(xmlDateTime)) - .toMatch(/^([0-9]{4})-([0-1][0-9])-([0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](Z))$/); -} - const expectMediaType = (mediaType, not) => { (not ? expect(mediaType).not : expect(mediaType)) .toMatch(/^\w+\/[-+.\w]+/); @@ -73,7 +68,6 @@ module.exports = { parseDidMethod, produceRepresentation, consumeRepresentation, - expectXmlDateTimeNormalizedToUtcWithoutPrecision, expectMediaType, expectConformantDidDocument, expectConformantMetadataStructure, From e02864f27f9e1bc2be3efc49b0fea8230cd1fd81 Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 13:16:19 +0200 Subject: [PATCH 05/11] Use toBeMediaType() matcher. --- .../suites/did-resolution/did-resolution.js | 9 +++--- .../suites/did-resolution/utils.js | 6 ---- .../did-url-dereferencing.js | 5 ++- .../suites/did-url-dereferencing/utils.js | 6 ---- .../src/matchers/toBeMediaType/index.js | 31 +++++++++++++++++++ .../src/matchers/toBeMediaType/index.test.js | 30 ++++++++++++++++++ .../src/matchers/toBeMediaType/predicate.js | 5 +++ 7 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 packages/jest-did-matcher/src/matchers/toBeMediaType/index.js create mode 100644 packages/jest-did-matcher/src/matchers/toBeMediaType/index.test.js create mode 100644 packages/jest-did-matcher/src/matchers/toBeMediaType/predicate.js diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index f70c8336..124343ef 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -2,7 +2,6 @@ const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; const parseDidMethod = require('./utils').parseDidMethod; const produceRepresentation = require('./utils').produceRepresentation; const consumeRepresentation = require('./utils').consumeRepresentation; -const expectMediaType = require('./utils').expectMediaType; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; @@ -42,7 +41,7 @@ const didResolutionTests = (execution, expectedOutcome) => { it('If resolveRepresentation was called, this structure MUST contain a contentType property containing the Media Type of the representation found in the didDocumentStream.', async () => { if (execution.function === 'resolveRepresentation') { expect(Object.keys(didResolutionMetadata)).toContain('contentType'); - expectMediaType(didResolutionMetadata['contentType']); + expect(didResolutionMetadata['contentType']).toBeMediaType(); expectKnownConformantMediaType(didResolutionMetadata['contentType']); expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); } @@ -85,7 +84,7 @@ const didResolutionTests = (execution, expectedOutcome) => { it('If the resolution is successful, and if the resolveRepresentation function was called, this MUST be a byte stream of the resolved DID document in one of the conformant representations.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { expect(didDocumentStream).not.toBeFalsy(); - expectMediaType(didResolutionMetadata['contentType']); + expect(didResolutionMetadata['contentType']).toBeMediaType(); expectKnownConformantMediaType(didResolutionMetadata['contentType']); expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); } @@ -114,7 +113,7 @@ const didResolutionTests = (execution, expectedOutcome) => { describe('accept', () => { if (resolutionOptions.hasOwnProperty('accept')) { it('The Media Type of the caller\'s preferred representation of the DID document.', async () => { - expectMediaType(resolutionOptions['accept']); + expect(resolutionOptions['accept']).toBeMediaType(); }); it('The Media Type MUST be expressed as an ASCII string.', async () => { expect(resolutionOptions['accept']).toBeAsciiString(); @@ -142,7 +141,7 @@ const didResolutionTests = (execution, expectedOutcome) => { if (didResolutionMetadata.hasOwnProperty('contentType')) { it('The value of this property MUST be an ASCII string that is the Media Type of the conformant representations.', async () => { expect(didResolutionMetadata['contentType']).toBeAsciiString(); - expectMediaType(didResolutionMetadata['contentType']); + expect(didResolutionMetadata['contentType']).toBeMediaType(); expectKnownConformantMediaType(didResolutionMetadata['contentType']); }); } diff --git a/packages/did-core-test-server/suites/did-resolution/utils.js b/packages/did-core-test-server/suites/did-resolution/utils.js index 011d22e5..01868eca 100644 --- a/packages/did-core-test-server/suites/did-resolution/utils.js +++ b/packages/did-core-test-server/suites/did-resolution/utils.js @@ -27,11 +27,6 @@ const consumeRepresentation = (representation) => { return JSON.parse(representation); }; -const expectMediaType = (mediaType, not) => { - (not ? expect(mediaType).not : expect(mediaType)) - .toMatch(/^\w+\/[-+.\w]+/); -}; - const expectConformantDidDocument = ((didDocument, not) => { // TODO: properly test if this is a conformant DID document (abstract data model) (not ? expect(Object.keys(didDocument)).not : expect(Object.keys(didDocument))) @@ -68,7 +63,6 @@ module.exports = { parseDidMethod, produceRepresentation, consumeRepresentation, - expectMediaType, expectConformantDidDocument, expectConformantMetadataStructure, expectKnownConformantMediaType, diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index 014521b1..d5297c97 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -1,6 +1,5 @@ const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; const parseDidMethod = require('./utils').parseDidMethod; -const expectMediaType = require('./utils').expectMediaType; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; @@ -91,7 +90,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { describe('accept', () => { if (dereferenceOptions.hasOwnProperty('accept')) { it('The Media Type that the caller prefers for contentStream.', async () => { - expectMediaType(dereferenceOptions['accept']); + expect(dereferenceOptions['accept']).toBeMediaType(); }); it('The Media Type MUST be expressed as an ASCII string.', async () => { expect(dereferenceOptions['accept']).toBeAsciiString(); @@ -103,7 +102,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { describe('contentType', () => { if (dereferencingMetadata.hasOwnProperty('contentType')) { it('The Media Type value MUST be expressed as an ASCII string.', async () => { - expectMediaType(dereferencingMetadata['contentType']); + expect(dereferencingMetadata['contentType']).toBeMediaType(); expect(dereferencingMetadata['contentType']).toBeAsciiString(); }); } diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js index 1ce39cc2..0f892bbd 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js @@ -27,11 +27,6 @@ const consumeRepresentation = (representation) => { return JSON.parse(representation); }; -const expectMediaType = (mediaType, not) => { - (not ? expect(mediaType).not : expect(mediaType)) - .toMatch(/^\w+\/[-+.\w]+/); -}; - const expectConformantDidDocument = ((didDocument, not) => { // TODO: properly test if this is a conformant DID document (abstract data model) (not ? expect(Object.keys(didDocument)).not : expect(Object.keys(didDocument))) @@ -68,7 +63,6 @@ module.exports = { parseDidMethod, produceRepresentation, consumeRepresentation, - expectMediaType, expectConformantDidDocument, expectConformantMetadataStructure, expectKnownConformantMediaType, diff --git a/packages/jest-did-matcher/src/matchers/toBeMediaType/index.js b/packages/jest-did-matcher/src/matchers/toBeMediaType/index.js new file mode 100644 index 00000000..875532bb --- /dev/null +++ b/packages/jest-did-matcher/src/matchers/toBeMediaType/index.js @@ -0,0 +1,31 @@ +import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils'; +import predicate from './predicate'; + +const passMessage = received => () => + matcherHint('.not.toBeMediaType', 'received', '') + + '\n\n' + + 'Expected value to not be of a valid Media Type received:\n' + + ` ${printReceived(received)}`; + +const failMessage = received => () => + matcherHint('.toBeMediaType', 'received', '') + + '\n\n' + + 'Expected value to be of a valid Media Type:\n' + + ` ${printExpected('a valid Media Type')}` + + 'Received:\n' + + ` ${printReceived(received)}`; + +export default { + toBeMediaType: expected => { + const pass = predicate(expected); + if (pass) { + return { pass: true, message: passMessage(expected) }; + } + + return { pass: false, message: failMessage(expected) }; + }, + + isMediaType: obj => { + return predicate(obj); + } +}; diff --git a/packages/jest-did-matcher/src/matchers/toBeMediaType/index.test.js b/packages/jest-did-matcher/src/matchers/toBeMediaType/index.test.js new file mode 100644 index 00000000..8cc546c5 --- /dev/null +++ b/packages/jest-did-matcher/src/matchers/toBeMediaType/index.test.js @@ -0,0 +1,30 @@ +import each from 'jest-each'; + +import matcher from './'; + +expect.extend(matcher); + +describe('.toBeMediaType', () => { + each([ + ["application/did+json"], + ["application/did+ld+json"] + ]).test('passes when given the item is valid Media Type: %s', given => { + expect(given).toBeMediaType(); + }); +}); + +describe('.not.toBeMediaType', () => { + each([ + [""], + [false], + [0], + [{}], + [[]], + [() => {}], + [null], + [undefined], + [NaN] + ]).test('passes when the item is not a valid Media Type: %s', given => { + expect(given).not.toBeMediaType(); + }); +}); diff --git a/packages/jest-did-matcher/src/matchers/toBeMediaType/predicate.js b/packages/jest-did-matcher/src/matchers/toBeMediaType/predicate.js new file mode 100644 index 00000000..6e380425 --- /dev/null +++ b/packages/jest-did-matcher/src/matchers/toBeMediaType/predicate.js @@ -0,0 +1,5 @@ +export default expected => { + const regex = /^\w+\/[-+.\w]+/ + return regex.test(expected) +}; + From 8897f639580bd70f53bfffb72dd4fa62508915cb Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 14:00:48 +0200 Subject: [PATCH 06/11] Implement test for "To dereference a DID fragment, the complete DID URL including the DID fragment MUST be used." --- .../suites/did-resolution/did-resolution.js | 2 +- .../suites/did-resolution/did-resolution.spec.js | 2 +- .../suites/did-resolution/utils.js | 8 ++++++++ .../did-url-dereferencing.js | 16 ++++++++++++---- .../did-url-dereferencing.spec.js | 10 +++++----- .../suites/did-url-dereferencing/utils.js | 12 ++++++++++++ .../dereferencer-example-didwg.json | 6 +++--- 7 files changed, 42 insertions(+), 14 deletions(-) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index 124343ef..6cceffa9 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -7,7 +7,7 @@ const expectConformantMetadataStructure = require('./utils').expectConformantMet const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; const expectConformantRepresentation = require('./utils').expectConformantRepresentation; -const didResolutionTests = (execution, expectedOutcome) => { +const didResolutionTests = (execution, expectedOutcome, implementation) => { const { did, resolutionOptions } = execution.input; const { didResolutionMetadata, didDocument, didDocumentStream, didDocumentMetadata } = execution.output; describe(did + ' (expected outcome: ' + expectedOutcome + ')', () => { diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js index 26a1628f..3e6a6fe8 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js @@ -11,7 +11,7 @@ describe('7.1.x DID Resolution', () => { let i = 0; implementation.executions.forEach((execution) => { const expectedOutcome = utils.findExpectedOutcome(implementation.expectedOutcomes, i++); - require('./did-resolution').didResolutionTests(execution, expectedOutcome); + require('./did-resolution').didResolutionTests(execution, expectedOutcome, implementation); }); }); }); diff --git a/packages/did-core-test-server/suites/did-resolution/utils.js b/packages/did-core-test-server/suites/did-resolution/utils.js index 01868eca..a92a710a 100644 --- a/packages/did-core-test-server/suites/did-resolution/utils.js +++ b/packages/did-core-test-server/suites/did-resolution/utils.js @@ -8,6 +8,14 @@ const findExpectedOutcome = ((expectedOutcomes, i) => { return expectedOutcomesArray[i]; }); +const findExecutionByDid = ((implementation, did) => { + implementation.executions.forEach((execution) => { + if (execution.input.did == did) { + return execution; + } + }); +}); + const isErrorExpectedOutcome = ((expectedOutcome) => { return expectedOutcome.endsWith('ErrorOutcome'); }); diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index d5297c97..066f44e6 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -1,3 +1,4 @@ +const findExecutionByDidUrl = require('./utils').findExecutionByDidUrl; const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; const parseDidMethod = require('./utils').parseDidMethod; const expectConformantDidDocument = require('./utils').expectConformantDidDocument; @@ -5,7 +6,7 @@ const expectConformantMetadataStructure = require('./utils').expectConformantMet const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; const expectConformantRepresentation = require('./utils').expectConformantRepresentation; -const didUrlDereferencingTests = (execution, expectedOutcome) => { +const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => { const { didUrl, dereferenceOptions } = execution.input; const { dereferencingMetadata, contentStream, contentMetadata } = execution.output; describe(didUrl + ' (expected outcome: ' + expectedOutcome + ')', () => { @@ -23,9 +24,16 @@ const didUrlDereferencingTests = (execution, expectedOutcome) => { expect(didUrl).toBeValidDidUrl(); } }); - - it.todo('To dereference a DID fragment, the complete DID URL including the DID fragment MUST be used.'); - + it('To dereference a DID fragment, the complete DID URL including the DID fragment MUST be used.', async () => { + if(didUrl.includes('#')) { + const didUrlWithoutFragment = didUrl.substring(0, didUrl.indexOf('#')); + const executionWithoutFragment = findExecutionByDidUrl(implementation, didUrlWithoutFragment); + if (executionWithoutFragment !== undefined) { + const contentStreamWithoutFragment = executionWithoutFragment.output.contentStream; + expect(contentStreamWithoutFragment).not.toBe(contentStream); + } + } + }); it('This input is REQUIRED.', async () => { expect(didUrl).not.toBeFalsy(); }); diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js index 2ea28303..dfb1f7db 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js @@ -7,11 +7,11 @@ if (!suiteConfig) { const utils = require('./utils'); describe('7.2.x DID URL Dereferencing', () => { - let i = 0; - suiteConfig.dereferencers.forEach((dereferencer) => { - dereferencer.executions.forEach((execution) => { - const expectedOutcome = utils.findExpectedOutcome(dereferencer.expectedOutcomes, i++); - require('./did-url-dereferencing').didUrlDereferencingTests(execution, expectedOutcome); + suiteConfig.dereferencers.forEach((implementation) => { + let i = 0; + implementation.executions.forEach((execution) => { + const expectedOutcome = utils.findExpectedOutcome(implementation.expectedOutcomes, i++); + require('./did-url-dereferencing').didUrlDereferencingTests(execution, expectedOutcome, implementation); }); }); }); diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js index 0f892bbd..90aa264e 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js @@ -8,6 +8,17 @@ const findExpectedOutcome = ((expectedOutcomes, i) => { return expectedOutcomesArray[i]; }); +const findExecutionByDidUrl = ((implementation, didUrl) => { + var found; + implementation.executions.forEach((execution) => { + if (execution.input.didUrl === didUrl) { + found = execution; + return; + } + }); + return found; +}); + const isErrorExpectedOutcome = ((expectedOutcome) => { return expectedOutcome.endsWith('ErrorOutcome'); }); @@ -59,6 +70,7 @@ const expectConformantRepresentation = ((mediaType, representation) => { module.exports = { findExpectedOutcome, + findExecutionByDidUrl, isErrorExpectedOutcome, parseDidMethod, produceRepresentation, diff --git a/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json b/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json index 6e2933dc..db941462 100644 --- a/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json +++ b/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json @@ -10,7 +10,7 @@ { "function": "dereference", "input": { - "didUrl": "did:example:111", + "didUrl": "did:example:222", "dereferenceOptions": { "accept": "application/did+json" } @@ -19,7 +19,7 @@ "dereferencingMetadata": { "contentType": "application/did+json" }, - "contentStream": "{\"id\",:\"did:example:111\",\"verificationMethod\":[],\"service\":[]}", + "contentStream": "{\"id\": \"did:example:222\",\"verificationMethod\": [{\"id\": \"did:example:222#key-1\",\"controller\": \"did:example:222\",\"publicKeyBase58\": \"F6NxfeuPJ5NhmDM6QT2TeSFxcnnkQBgtv6yfQziS5NPM\"}],\"service\": []}", "contentMetadata": { } } @@ -36,7 +36,7 @@ "dereferencingMetadata": { "contentType": "application/did+json" }, - "contentStream": "{\"id\",:\"did:example:222#key-1\",\"controller\":\"did:example:222\",\"publicKeyBase58\":\"F6NxfeuPJ5NhmDM6QT2TeSFxcnnkQBgtv6yfQziS5NPM\"}", + "contentStream": "{\"id\": \"did:example:222#key-1\",\"controller\": \"did:example:222\",\"publicKeyBase58\": \"F6NxfeuPJ5NhmDM6QT2TeSFxcnnkQBgtv6yfQziS5NPM\"}", "contentMetadata": { "contentType": "application/did+json" } From b6f1716e9b63cc343370be2a2f12c4e38412e830 Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 14:27:13 +0200 Subject: [PATCH 07/11] Implement test for "All conformant DID resolvers MUST implement the DID resolution functions for at least one DID method and MUST be able to return a DID document in at least one conformant representation." --- .../suites/did-resolution/did-resolution.js | 40 ++++----- .../did-resolution/did-resolution.spec.js | 15 +++- .../did-url-dereferencing.js | 24 ++---- .../did-url-dereferencing.spec.js | 8 +- .../suites/did-url-dereferencing/utils.js | 82 ------------------- .../utils.js => resolution-utils.js} | 17 +++- 6 files changed, 57 insertions(+), 129 deletions(-) delete mode 100644 packages/did-core-test-server/suites/did-url-dereferencing/utils.js rename packages/did-core-test-server/suites/{did-resolution/utils.js => resolution-utils.js} (90%) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index 6cceffa9..9fd212ae 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -1,17 +1,9 @@ -const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; -const parseDidMethod = require('./utils').parseDidMethod; -const produceRepresentation = require('./utils').produceRepresentation; -const consumeRepresentation = require('./utils').consumeRepresentation; -const expectConformantDidDocument = require('./utils').expectConformantDidDocument; -const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; -const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; -const expectConformantRepresentation = require('./utils').expectConformantRepresentation; +const utils = require('../resolution-utils'); const didResolutionTests = (execution, expectedOutcome, implementation) => { const { did, resolutionOptions } = execution.input; const { didResolutionMetadata, didDocument, didDocumentStream, didDocumentMetadata } = execution.output; describe(did + ' (expected outcome: ' + expectedOutcome + ')', () => { - it.todo('All conformant DID resolvers MUST implement the DID resolution functions for at least one DID method and MUST be able to return a DID document in at least one conformant representation.'); describe('did', () => { it('This input is REQUIRED and the value MUST be a conformant DID as defined in § 3.1 DID Syntax.', async () => { expect(did).not.toBeFalsy(); @@ -22,7 +14,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); describe('resolutionOptions', () => { it('A metadata structure.', async () => { - expectConformantMetadataStructure(resolutionOptions); + utils.expectConformantMetadataStructure(resolutionOptions); }); it('This input is REQUIRED, but the structure MAY be empty.', async () => { expect(resolutionOptions).not.toBeFalsy(); @@ -30,11 +22,11 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); describe('didResolutionMetadata', () => { it('A metadata structure.', async () => { - expectConformantMetadataStructure(didResolutionMetadata); + utils.expectConformantMetadataStructure(didResolutionMetadata); }); it('This structure is REQUIRED, and in the case of an error in the resolution process, this MUST NOT be empty.', async () => { expect(didResolutionMetadata).not.toBeFalsy(); - if (isErrorExpectedOutcome(expectedOutcome)) { + if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(didResolutionMetadata)).not.toHaveLength(0); } }); @@ -42,12 +34,12 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { if (execution.function === 'resolveRepresentation') { expect(Object.keys(didResolutionMetadata)).toContain('contentType'); expect(didResolutionMetadata['contentType']).toBeMediaType(); - expectKnownConformantMediaType(didResolutionMetadata['contentType']); - expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); + utils.expectKnownConformantMediaType(didResolutionMetadata['contentType']); + utils.expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); } }); it('If the resolution is not successful, this structure MUST contain an error property describing the error.', async () => { - if (isErrorExpectedOutcome(expectedOutcome)) { + if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(didResolutionMetadata)).toContain('error'); expect(didResolutionMetadata['error']).toBeTruthy(); } @@ -59,7 +51,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { it('If the resolution is successful, and if the resolve function was called, this MUST be a DID document abstract data model (a map) as described in § 4. Data Model that is capable of being transformed into a conforming DID Document (representation), using the production rules specified by the representation.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { expect(typeof didDocument).toBe('object'); - expectConformantDidDocument(didDocument); + utils.expectConformantDidDocument(didDocument); } // TODO: Test if the DID document abstract data model is capable of being transformed into a conforming DID Document (representation). // This should re-use code from other tests (production). @@ -85,8 +77,8 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { if (! didResolutionMetadata.hasOwnProperty('error')) { expect(didDocumentStream).not.toBeFalsy(); expect(didResolutionMetadata['contentType']).toBeMediaType(); - expectKnownConformantMediaType(didResolutionMetadata['contentType']); - expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); + utils.expectKnownConformantMediaType(didResolutionMetadata['contentType']); + utils.expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); } }); it('If the resolution is unsuccessful, this value MUST be an empty stream.', async () => { @@ -99,12 +91,12 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { describe('didDocumentMetadata', () => { it('If the resolution is successful, this MUST be a metadata structure.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { - expectConformantMetadataStructure(didDocumentMetadata); + utils.expectConformantMetadataStructure(didDocumentMetadata); } }); it('If the resolution is unsuccessful, this output MUST be an empty metadata structure.', async () => { if (didResolutionMetadata.hasOwnProperty('error')) { - expectConformantMetadataStructure(didDocumentMetadata); + utils.expectConformantMetadataStructure(didDocumentMetadata); expect(Object.keys(didDocumentMetadata)).toHaveLength(0); } }); @@ -142,7 +134,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { it('The value of this property MUST be an ASCII string that is the Media Type of the conformant representations.', async () => { expect(didResolutionMetadata['contentType']).toBeAsciiString(); expect(didResolutionMetadata['contentType']).toBeMediaType(); - expectKnownConformantMediaType(didResolutionMetadata['contentType']); + utils.expectKnownConformantMediaType(didResolutionMetadata['contentType']); }); } it('The caller of the resolveRepresentation function MUST use this value when determining how to parse and process the didDocumentStream returned by this function into the data model.', async() => { @@ -151,7 +143,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); describe('error', () => { it('This property is REQUIRED when there is an error in the resolution process.', async () => { - if (isErrorExpectedOutcome(expectedOutcome)) { + if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(didResolutionMetadata)).toContain('error'); } }); @@ -266,7 +258,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { didDocumentMetadata['equivalentId'].forEach((i) => { const equivalentid = didDocumentMetadata['equivalentId'][i]; // TODO: This will currently only work if the 'resolve' function is called, not 'resolveRepresentation'. - expect(parseDidMethod(equivalentid)).toBe(parseDidMethod(didDocument['id'])); + expect(utils.parseDidMethod(equivalentid)).toBe(utils.parseDidMethod(didDocument['id'])); }) }); // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) @@ -284,7 +276,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); it('A canonicalId value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { // TODO: This will currently only work if the 'resolve' function is called, not 'resolveRepresentation'. - expect(parseDidMethod(didDocumentMetadata['canonicalId'])).toBe(parseDidMethod(didDocument['id'])); + expect(utils.parseDidMethod(didDocumentMetadata['canonicalId'])).toBe(utils.parseDidMethod(didDocument['id'])); }); // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) it.skip('A conforming DID Method specification MUST guarantee that the canonicalId value is logically equivalent to the id property value.'); diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js index 3e6a6fe8..6d107efe 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js @@ -4,10 +4,19 @@ if (!suiteConfig) { suiteConfig = require('./default.js'); } -const utils = require('./utils'); +const utils = require('../resolution-utils'); -describe('7.1.x DID Resolution', () => { - suiteConfig.resolvers.forEach((implementation) => { +suiteConfig.resolvers.forEach((implementation) => { + let implementationName = `7.1.x DID Resolution - ${implementation.implementation} - ${implementation.implementer}`; + + describe(implementationName, () => { + it('All conformant DID resolvers MUST implement the DID resolution functions for at least one DID method and MUST be able to return a DID document in at least one conformant representation.', async () => { + expect(implementation.executions).not.toBeEmpty(); + const execution = implementation.executions.find((execution) => (execution.function === 'resolveRepresentation')); + expect(execution).not.toBeFalsy(); + utils.expectKnownConformantMediaType(execution.output.didResolutionMetadata.contentType); + utils.expectConformantDidDocument(utils.consumeRepresentation(execution.output.didDocumentStream)); + }); let i = 0; implementation.executions.forEach((execution) => { const expectedOutcome = utils.findExpectedOutcome(implementation.expectedOutcomes, i++); diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index 066f44e6..16901f73 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -1,10 +1,4 @@ -const findExecutionByDidUrl = require('./utils').findExecutionByDidUrl; -const isErrorExpectedOutcome = require('./utils').isErrorExpectedOutcome; -const parseDidMethod = require('./utils').parseDidMethod; -const expectConformantDidDocument = require('./utils').expectConformantDidDocument; -const expectConformantMetadataStructure = require('./utils').expectConformantMetadataStructure; -const expectKnownConformantMediaType = require('./utils').expectKnownConformantMediaType; -const expectConformantRepresentation = require('./utils').expectConformantRepresentation; +const utils = require('../resolution-utils'); const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => { const { didUrl, dereferenceOptions } = execution.input; @@ -27,7 +21,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => it('To dereference a DID fragment, the complete DID URL including the DID fragment MUST be used.', async () => { if(didUrl.includes('#')) { const didUrlWithoutFragment = didUrl.substring(0, didUrl.indexOf('#')); - const executionWithoutFragment = findExecutionByDidUrl(implementation, didUrlWithoutFragment); + const executionWithoutFragment = utils.findExecutionByDidUrl(implementation, didUrlWithoutFragment); if (executionWithoutFragment !== undefined) { const contentStreamWithoutFragment = executionWithoutFragment.output.contentStream; expect(contentStreamWithoutFragment).not.toBe(contentStream); @@ -40,7 +34,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => }); describe('dereferenceOptions', () => { it('A metadata structure.', async () => { - expectConformantMetadataStructure(dereferenceOptions); + utils.expectConformantMetadataStructure(dereferenceOptions); }); it('This input is REQUIRED, but the structure MAY be empty.', async () => { expect(dereferenceOptions).not.toBeFalsy(); @@ -48,16 +42,16 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => }); describe('dereferencingMetadata', () => { it('A metadata structure.', async () => { - expectConformantMetadataStructure(dereferencingMetadata); + utils.expectConformantMetadataStructure(dereferencingMetadata); }); it('This structure is REQUIRED, and in the case of an error in the dereferencing process, this MUST NOT be empty.', async () => { expect(dereferencingMetadata).not.toBeFalsy(); - if (isErrorExpectedOutcome(expectedOutcome)) { + if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(dereferencingMetadata)).not.toHaveLength(0); } }); it('If the dereferencing is not successful, this structure MUST contain an error property describing the error.', async () => { - if (isErrorExpectedOutcome(expectedOutcome)) { + if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(dereferencingMetadata)).toContain('error'); expect(dereferencingMetadata['error']).toBeTruthy(); } @@ -81,7 +75,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => describe('contentMetadata', () => { it('If the dereferencing is successful, this MUST be a metadata structure, but the structure MAY be empty.', async () => { if (! dereferencingMetadata.hasOwnProperty('error')) { - expectConformantMetadataStructure(contentMetadata); + utils.expectConformantMetadataStructure(contentMetadata); } }); it('If the contentStream is a DID document, this MUST be a didDocumentMetadata structure as described in DID Resolution.', async () => { @@ -89,7 +83,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => }); it('If the dereferencing is unsuccessful, this output MUST be an empty metadata structure.', async () => { if (dereferencingMetadata.hasOwnProperty('error')) { - expectConformantMetadataStructure(contentMetadata); + utils.expectConformantMetadataStructure(contentMetadata); expect(Object.keys(contentMetadata)).toHaveLength(0); } }); @@ -117,7 +111,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => }); describe('error', () => { it('This property is REQUIRED when there is an error in the dereferencing process.', async () => { - if (isErrorExpectedOutcome(expectedOutcome)) { + if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(dereferencingMetadata)).toContain('error'); } }); diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js index dfb1f7db..84557614 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.spec.js @@ -4,10 +4,12 @@ if (!suiteConfig) { suiteConfig = require('./default'); } -const utils = require('./utils'); +const utils = require('../resolution-utils'); -describe('7.2.x DID URL Dereferencing', () => { - suiteConfig.dereferencers.forEach((implementation) => { +suiteConfig.dereferencers.forEach((implementation) => { + let implementationName = `7.2.x DID URL Dereferencing - ${implementation.implementation} - ${implementation.implementer}`; + + describe(implementationName, () => { let i = 0; implementation.executions.forEach((execution) => { const expectedOutcome = utils.findExpectedOutcome(implementation.expectedOutcomes, i++); diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js b/packages/did-core-test-server/suites/did-url-dereferencing/utils.js deleted file mode 100644 index 90aa264e..00000000 --- a/packages/did-core-test-server/suites/did-url-dereferencing/utils.js +++ /dev/null @@ -1,82 +0,0 @@ -const findExpectedOutcome = ((expectedOutcomes, i) => { - const expectedOutcomesArray = []; - Object.keys(expectedOutcomes).forEach((expectedOutcome) => { - expectedOutcomes[expectedOutcome].forEach((expectedOutcomeIndex) => { - expectedOutcomesArray[expectedOutcomeIndex] = expectedOutcome; - }); - }); - return expectedOutcomesArray[i]; -}); - -const findExecutionByDidUrl = ((implementation, didUrl) => { - var found; - implementation.executions.forEach((execution) => { - if (execution.input.didUrl === didUrl) { - found = execution; - return; - } - }); - return found; -}); - -const isErrorExpectedOutcome = ((expectedOutcome) => { - return expectedOutcome.endsWith('ErrorOutcome'); -}); - -const parseDidMethod = (did) => { - var match = /^did:(.+):(.+)$/.exec(did); - return match[1]; -}; - -const produceRepresentation = (didDocument) => { - // TODO: properly produce, try to re-use other test code - return JSON.stringify(didDocument); -}; - -const consumeRepresentation = (representation) => { - // TODO: properly consume, try to re-use other test code - return JSON.parse(representation); -}; - -const expectConformantDidDocument = ((didDocument, not) => { - // TODO: properly test if this is a conformant DID document (abstract data model) - (not ? expect(Object.keys(didDocument)).not : expect(Object.keys(didDocument))) - .toContain('id'); -}); - -const expectConformantMetadataStructure = ((metaDataStructure, not) => { - // TODO: properly test if this is a conformant metadata structure, try to re-use other test code - (not ? expect(typeof metaDataStructure).not : expect(typeof metaDataStructure)) - .toBe('object'); -}); - -const expectKnownConformantMediaType = ((mediaType) => { - expect(mediaType.startsWith('application/did+ld+json') || - mediaType.startsWith('application/did+json') || - mediaType.startsWith('application/did+cbor')).toBe(true); -}); - -const expectConformantRepresentation = ((mediaType, representation) => { - // TODO: properly test if the representation conforms to the mediaType, try to re-use other test code - if (mediaType.startsWith('application/did+ld+json')) { - expect(() => { JSON.parse(representation); }).not.toThrow(); - expect(Object.keys(JSON.parse(representation))).constructor('@context'); - } else if (mediaType.startsWith('application/did+json')) { - expect(() => { JSON.parse(representation); }).not.toThrow(); - } else if (mediaType.startsWith('application/did+cbor')) { - expect(parseInt('0x' + representation)).not.toBeNaN(); - } -}); - -module.exports = { - findExpectedOutcome, - findExecutionByDidUrl, - isErrorExpectedOutcome, - parseDidMethod, - produceRepresentation, - consumeRepresentation, - expectConformantDidDocument, - expectConformantMetadataStructure, - expectKnownConformantMediaType, - expectConformantRepresentation -}; diff --git a/packages/did-core-test-server/suites/did-resolution/utils.js b/packages/did-core-test-server/suites/resolution-utils.js similarity index 90% rename from packages/did-core-test-server/suites/did-resolution/utils.js rename to packages/did-core-test-server/suites/resolution-utils.js index a92a710a..ba42dd33 100644 --- a/packages/did-core-test-server/suites/did-resolution/utils.js +++ b/packages/did-core-test-server/suites/resolution-utils.js @@ -8,6 +8,10 @@ const findExpectedOutcome = ((expectedOutcomes, i) => { return expectedOutcomesArray[i]; }); +const isErrorExpectedOutcome = ((expectedOutcome) => { + return expectedOutcome.endsWith('ErrorOutcome'); +}); + const findExecutionByDid = ((implementation, did) => { implementation.executions.forEach((execution) => { if (execution.input.did == did) { @@ -16,8 +20,15 @@ const findExecutionByDid = ((implementation, did) => { }); }); -const isErrorExpectedOutcome = ((expectedOutcome) => { - return expectedOutcome.endsWith('ErrorOutcome'); +const findExecutionByDidUrl = ((implementation, didUrl) => { + var found; + implementation.executions.forEach((execution) => { + if (execution.input.didUrl === didUrl) { + found = execution; + return; + } + }); + return found; }); const parseDidMethod = (did) => { @@ -68,6 +79,8 @@ const expectConformantRepresentation = ((mediaType, representation) => { module.exports = { findExpectedOutcome, isErrorExpectedOutcome, + findExecutionByDid, + findExecutionByDidUrl, parseDidMethod, produceRepresentation, consumeRepresentation, From caf59340fdb931c43a924393c2bc08a5c7cd886d Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 15:57:58 +0200 Subject: [PATCH 08/11] Remove unused input file. --- .../defaultSuiteConfig.json | 79 ------------------- 1 file changed, 79 deletions(-) delete mode 100644 packages/did-core-test-server/suites/did-url-dereferencing/defaultSuiteConfig.json diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/defaultSuiteConfig.json b/packages/did-core-test-server/suites/did-url-dereferencing/defaultSuiteConfig.json deleted file mode 100644 index 82f7b71e..00000000 --- a/packages/did-core-test-server/suites/did-url-dereferencing/defaultSuiteConfig.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "name": "did-url-dereferencing", - "expectedOutcomes": { - "defaultOutcome": [ 0, 1 ], - "invalidDidUrlErrorOutcome": [ 2 ], - "notFoundErrorOutcome": [ 3 ] - }, - "executions": [ - { - "function": "dereference", - "input": { - "didUrl": "did:example:111", - "dereferenceOptions": { - "accept": "application/did+json" - } - }, - "output": { - "dereferencingMetadata": { - "contentType": "application/did+json" - }, - "contentStream": "{\"id\",:\"did:example:111\",\"verificationMethod\":[],\"service\":[]}", - "contentMetadata": { - } - } - }, - { - "function": "dereference", - "input": { - "didUrl": "did:example:222#key-1", - "dereferenceOptions": { - "accept": "application/did+json" - } - }, - "output": { - "dereferencingMetadata": { - "contentType": "application/did+json" - }, - "contentStream": "{\"id\",:\"did:example:222#key-1\",\"controller\":\"did:example:222\",\"publicKeyBase58\":\"F6NxfeuPJ5NhmDM6QT2TeSFxcnnkQBgtv6yfQziS5NPM\"}", - "contentMetadata": { - "contentType": "application/did+json" - } - } - }, - { - "function": "dereference", - "input": { - "didUrl": "did:example_333", - "dereferenceOptions": { - "accept": "application/did+json" - } - }, - "output": { - "dereferencingMetadata": { - "error": "invalidDidUrl" - }, - "contentStream": "", - "contentMetadata": { - } - } - }, - { - "function": "dereference", - "input": { - "didUrl": "did:example:444", - "dereferenceOptions": { - "accept": "application/did+ld+json" - } - }, - "output": { - "dereferencingMetadata": { - "error": "notFound" - }, - "contentStream": "", - "contentMetadata": { - } - } - } - ] -} From 241315a8979770a2c5e9a85ce396d382c78fbd20 Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 15:57:45 +0200 Subject: [PATCH 09/11] Implement remaining DID Resolution tests. --- .../suites/did-resolution/did-resolution.js | 227 +++++++++--------- .../did-resolution/did-resolution.spec.js | 3 +- .../did-url-dereferencing.js | 11 +- .../dereferencer-example-didwg.json | 1 - .../resolver-example-didwg.json | 3 +- .../suites/resolution-utils.js | 69 +++--- 6 files changed, 165 insertions(+), 149 deletions(-) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index 9fd212ae..ddc20806 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -34,8 +34,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { if (execution.function === 'resolveRepresentation') { expect(Object.keys(didResolutionMetadata)).toContain('contentType'); expect(didResolutionMetadata['contentType']).toBeMediaType(); - utils.expectKnownConformantMediaType(didResolutionMetadata['contentType']); - utils.expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); + utils.expectConformantDidDocumentRepresentation(didDocumentStream, didResolutionMetadata['contentType']); } }); it('If the resolution is not successful, this structure MUST contain an error property describing the error.', async () => { @@ -50,11 +49,10 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { describe('didDocument', () => { it('If the resolution is successful, and if the resolve function was called, this MUST be a DID document abstract data model (a map) as described in § 4. Data Model that is capable of being transformed into a conforming DID Document (representation), using the production rules specified by the representation.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { - expect(typeof didDocument).toBe('object'); utils.expectConformantDidDocument(didDocument); + const didDocumentStream = utils.produceRepresentation(didDocument, 'application/did+json'); + utils.expectConformantDidDocumentRepresentation(didDocumentStream, 'application/did+json'); } - // TODO: Test if the DID document abstract data model is capable of being transformed into a conforming DID Document (representation). - // This should re-use code from other tests (production). }); it('The value of id in the resolved DID document MUST match the DID that was resolved.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { @@ -77,8 +75,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { if (! didResolutionMetadata.hasOwnProperty('error')) { expect(didDocumentStream).not.toBeFalsy(); expect(didResolutionMetadata['contentType']).toBeMediaType(); - utils.expectKnownConformantMediaType(didResolutionMetadata['contentType']); - utils.expectConformantRepresentation(didResolutionMetadata['contentType'], didDocumentStream); + utils.expectConformantDidDocumentRepresentation(didDocumentStream, didResolutionMetadata['contentType']); } }); it('If the resolution is unsuccessful, this value MUST be an empty stream.', async () => { @@ -121,12 +118,12 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { describe('DID Resolution Metadata', () => { describe('contentType', () => { it('This property is REQUIRED if resolution is successful and if the resolveRepresentation function was called.', async() => { - if (! didResolutionMetadata.hasOwnProperty('error') && execution.input.function === 'resolveRepresentation') { + if (! didResolutionMetadata.hasOwnProperty('error') && execution.function === 'resolveRepresentation') { expect(Object.keys(didResolutionMetadata)).toContain('contentType'); } }); it('This property MUST NOT be present if the resolve function was called.', async () => { - if (execution.input.function === 'resolve') { + if (execution.function === 'resolve') { expect(Object.keys(didResolutionMetadata)).not.toContain('contentType'); } }); @@ -134,11 +131,15 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { it('The value of this property MUST be an ASCII string that is the Media Type of the conformant representations.', async () => { expect(didResolutionMetadata['contentType']).toBeAsciiString(); expect(didResolutionMetadata['contentType']).toBeMediaType(); - utils.expectKnownConformantMediaType(didResolutionMetadata['contentType']); + utils.expectConformantDidDocumentRepresentation(didDocumentStream, didResolutionMetadata['contentType']); }); } it('The caller of the resolveRepresentation function MUST use this value when determining how to parse and process the didDocumentStream returned by this function into the data model.', async() => { - // TODO: This should re-use code from other tests (consumption). + if (didResolutionMetadata.hasOwnProperty('contentType')) { + expect(didDocumentStream).not.toBeFalsy(); + expect(utils.consumeRepresentation(didDocumentStream, didResolutionMetadata['contentType'])).not.toBeFalsy(); + expect(utils.consumeRepresentation(didDocumentStream, 'image/jpeg')).toBeFalsy(); + } }); }); describe('error', () => { @@ -174,116 +175,122 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); }); describe('DID Document Metadata', () => { - describe('created', () => { - if (didDocumentMetadata.hasOwnProperty('created')) { - it('The value of the property MUST be a string formatted as an XML Datetime normalized to UTC 00:00:00 and without sub-second decimal precision.', async () => { - expect(didDocumentMetadata['created']).toBeDidCoreDatetime(); - }); - } + testDidDocumentMetadata(didDocumentMetadata, didDocument, expectedOutcome); + }); + }); +}; + +const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutcome) => { + describe('created', () => { + if (didDocumentMetadata.hasOwnProperty('created')) { + it('The value of the property MUST be a string formatted as an XML Datetime normalized to UTC 00:00:00 and without sub-second decimal precision.', async () => { + expect(didDocumentMetadata['created']).toBeDidCoreDatetime(); }); - describe('updated', () => { - if (didDocumentMetadata.hasOwnProperty('updated')) { - it('The value of the property MUST follow the same formatting rules as the created property.', async () => { - expect(didDocumentMetadata['updated']).toBeDidCoreDatetime(); - }); - if (didDocumentMetadata.hasOwnProperty('created')) { - it('updated is later or equal than created.', async () => { - expect((new Date(didDocumentMetadata['updated'])).getTime()).toBeGreaterThanOrEqual((new Date(didDocumentMetadata['created'])).getTime()) - }); - } - } + } + }); + describe('updated', () => { + if (didDocumentMetadata.hasOwnProperty('updated')) { + it('The value of the property MUST follow the same formatting rules as the created property.', async () => { + expect(didDocumentMetadata['updated']).toBeDidCoreDatetime(); }); - describe('deactivated', () => { - if (expectedOutcome === 'deactivatedOutcome') { - it('If a DID has been deactivated, DID document metadata MUST include this property with the boolean value true.', async () => { - expect(Object.keys(didDocumentMetadata)).toContain('deactivated'); - expect(didDocumentMetadata['deactivated']).toBe(true); - }); - } - if (expectedOutcome !== 'deactivatedOutcome') { - if (didDocumentMetadata.hasOwnProperty('deactivated')) { - it('If a DID has not been deactivated, this property is OPTIONAL, but if included, MUST have the boolean value false.', async () => { - expect(didDocumentMetadata['deactivated']).toBe(false); - }); - } - } + if (didDocumentMetadata.hasOwnProperty('created')) { + it('updated is later or equal than created.', async () => { + expect((new Date(didDocumentMetadata['updated'])).getTime()).toBeGreaterThanOrEqual((new Date(didDocumentMetadata['created'])).getTime()) + }); + } + } + }); + describe('deactivated', () => { + if (expectedOutcome && (expectedOutcome === 'deactivatedOutcome')) { + it('If a DID has been deactivated, DID document metadata MUST include this property with the boolean value true.', async () => { + expect(Object.keys(didDocumentMetadata)).toContain('deactivated'); + expect(didDocumentMetadata['deactivated']).toBe(true); }); - describe('nextUpdate', () => { - if (didDocumentMetadata.hasOwnProperty('nextUpdate')) { - it('The value of the property MUST follow the same formatting rules as the created property.', async () => { - expect(didDocumentMetadata['nextUpdate']).toBeDidCoreDatetime(); - }); - if (didDocumentMetadata.hasOwnProperty('created')) { - it('nextUpdate is later than created.', async () => { - expect((new Date(didDocumentMetadata['nextUpdate'])).getTime()).toBeGreaterThan((new Date(didDocumentMetadata['created'])).getTime()) - }); - } - if (didDocumentMetadata.hasOwnProperty('updated')) { - it('nextUpdate is later than updated.', async () => { - expect((new Date(didDocumentMetadata['nextUpdate'])).getTime()).toBeGreaterThan((new Date(didDocumentMetadata['updated'])).getTime()) - }); - } - } + } + if (expectedOutcome && (expectedOutcome !== 'deactivatedOutcome')) { + if (didDocumentMetadata.hasOwnProperty('deactivated')) { + it('If a DID has not been deactivated, this property is OPTIONAL, but if included, MUST have the boolean value false.', async () => { + expect(didDocumentMetadata['deactivated']).toBe(false); + }); + } + } + }); + describe('nextUpdate', () => { + if (didDocumentMetadata.hasOwnProperty('nextUpdate')) { + it('The value of the property MUST follow the same formatting rules as the created property.', async () => { + expect(didDocumentMetadata['nextUpdate']).toBeDidCoreDatetime(); }); - describe('versionId', () => { - if (didDocumentMetadata.hasOwnProperty('versionId')) { - it('The value of the property MUST be an ASCII string.', async () => { - expect(didDocumentMetadata['versionId']).toBeAsciiString(); - }); - } + if (didDocumentMetadata.hasOwnProperty('created')) { + it('nextUpdate is later than created.', async () => { + expect((new Date(didDocumentMetadata['nextUpdate'])).getTime()).toBeGreaterThan((new Date(didDocumentMetadata['created'])).getTime()) + }); + } + if (didDocumentMetadata.hasOwnProperty('updated')) { + it('nextUpdate is later than updated.', async () => { + expect((new Date(didDocumentMetadata['nextUpdate'])).getTime()).toBeGreaterThan((new Date(didDocumentMetadata['updated'])).getTime()) + }); + } + } + }); + describe('versionId', () => { + if (didDocumentMetadata.hasOwnProperty('versionId')) { + it('The value of the property MUST be an ASCII string.', async () => { + expect(didDocumentMetadata['versionId']).toBeAsciiString(); }); - describe('nextVersionId', () => { - if (didDocumentMetadata.hasOwnProperty('nextVersionId')) { - it('The value of the property MUST be an ASCII string.', async () => { - expect(didDocumentMetadata['nextVersionId']).toBeAsciiString(); - }); - if (didDocumentMetadata.hasOwnProperty('versionId')) { - it('nextVersionId is different from versionId.', async () => { - expect(didDocumentMetadata['nextVersionId']).not.toBe(didDocumentMetadata['versionId']); - }); - } - } + } + }); + describe('nextVersionId', () => { + if (didDocumentMetadata.hasOwnProperty('nextVersionId')) { + it('The value of the property MUST be an ASCII string.', async () => { + expect(didDocumentMetadata['nextVersionId']).toBeAsciiString(); }); - describe('equivalentId', () => { - // TODO: According to the spec, 'equivalentId' is currently not optional, even though that's definitely what the WG intended - see https://github.com/w3c/did-core/issues/717. - if (didDocumentMetadata.hasOwnProperty('equivalentId')) { - it('The value of equivalentId MUST be a set where each item in the list is a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { - expect(typeof didDocumentMetadata['equivalentId']).toBe('array'); - didDocumentMetadata['equivalentId'].forEach((i) => { - const equivalentid = didDocumentMetadata['equivalentId'][i]; - expect(equivalentid).toBeValidDid(); - }) - }); - it('Each equivalentId DID value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { - didDocumentMetadata['equivalentId'].forEach((i) => { - const equivalentid = didDocumentMetadata['equivalentId'][i]; - // TODO: This will currently only work if the 'resolve' function is called, not 'resolveRepresentation'. - expect(utils.parseDidMethod(equivalentid)).toBe(utils.parseDidMethod(didDocument['id'])); - }) + if (didDocumentMetadata.hasOwnProperty('versionId')) { + it('nextVersionId is different from versionId.', async () => { + expect(didDocumentMetadata['nextVersionId']).not.toBe(didDocumentMetadata['versionId']); + }); + } + } + }); + describe('equivalentId', () => { + if (didDocumentMetadata.hasOwnProperty('equivalentId')) { + it('The value of equivalentId MUST be a set where each item in the list is a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { + expect(Array.isArray(didDocumentMetadata['equivalentId'])).toBe(true); + didDocumentMetadata['equivalentId'].forEach((equivalentId) => { + expect(equivalentId).toBeValidDid(); + }) + }); + it('Each equivalentId DID value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { + if (didDocument) { + didDocumentMetadata['equivalentId'].forEach((equivalentId) => { + expect(utils.parseDidMethod(equivalentId)).toBe(utils.parseDidMethod(didDocument['id'])); }); - // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) - it.skip('A conforming DID Method specification MUST guarantee that each equivalentId value is logically equivalent to the id property value.'); - // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) - it.skip('equivalentId is a much stronger form of equivalence than alsoKnownAs because the equivalence MUST be guaranteed by the governing DID method.'); } }); - describe('canonicalId', () => { - // TODO: According to the spec, 'canonicalId' is currently not optional, even though that's definitely what the WG intended - see https://github.com/w3c/did-core/issues/717. - if (didDocumentMetadata.hasOwnProperty('canonicalId')) { - it('The value of canonicalId MUST be a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { - const canonicalId = didDocumentMetadata['canonicalId'][i]; - expect(didDocumentMetadata['canonicalId']).toBeValidDid(); - }); - it('A canonicalId value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { - // TODO: This will currently only work if the 'resolve' function is called, not 'resolveRepresentation'. - expect(utils.parseDidMethod(didDocumentMetadata['canonicalId'])).toBe(utils.parseDidMethod(didDocument['id'])); - }); - // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) - it.skip('A conforming DID Method specification MUST guarantee that the canonicalId value is logically equivalent to the id property value.'); + // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) + it.skip('A conforming DID Method specification MUST guarantee that each equivalentId value is logically equivalent to the id property value.', () => { + }); + // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) + it.skip('equivalentId is a much stronger form of equivalence than alsoKnownAs because the equivalence MUST be guaranteed by the governing DID method.', () => { + }); + } + }); + describe('canonicalId', () => { + if (didDocumentMetadata.hasOwnProperty('canonicalId')) { + it('The value of canonicalId MUST be a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { + const canonicalId = didDocumentMetadata['canonicalId']; + expect(canonicalId).toBeValidDid(); + }); + it('A canonicalId value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { + if (didDocument) { + const canonicalId = didDocumentMetadata['canonicalId']; + expect(utils.parseDidMethod(canonicalId)).toBe(utils.parseDidMethod(didDocument['id'])); } }); - }); + // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) + it.skip('A conforming DID Method specification MUST guarantee that the canonicalId value is logically equivalent to the id property value.', () => { + }); + } }); }; -module.exports = { didResolutionTests }; +module.exports = { didResolutionTests, testDidDocumentMetadata }; diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js index 6d107efe..ae4d8e23 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.spec.js @@ -14,8 +14,7 @@ suiteConfig.resolvers.forEach((implementation) => { expect(implementation.executions).not.toBeEmpty(); const execution = implementation.executions.find((execution) => (execution.function === 'resolveRepresentation')); expect(execution).not.toBeFalsy(); - utils.expectKnownConformantMediaType(execution.output.didResolutionMetadata.contentType); - utils.expectConformantDidDocument(utils.consumeRepresentation(execution.output.didDocumentStream)); + utils.expectConformantDidDocumentRepresentation(execution.output.didDocumentStream, execution.output.didResolutionMetadata.contentType); }); let i = 0; implementation.executions.forEach((execution) => { diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index 16901f73..04d3cdc1 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -1,4 +1,5 @@ const utils = require('../resolution-utils'); +const resolution = require('../did-resolution/did-resolution.js'); const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => { const { didUrl, dereferenceOptions } = execution.input; @@ -78,8 +79,14 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => utils.expectConformantMetadataStructure(contentMetadata); } }); - it('If the contentStream is a DID document, this MUST be a didDocumentMetadata structure as described in DID Resolution.', async () => { - // TODO + describe('If the contentStream is a DID document, this MUST be a didDocumentMetadata structure as described in DID Resolution.', () => { + if (! dereferencingMetadata.hasOwnProperty('error')) { + const didDocument = utils.consumeRepresentation(contentStream, dereferencingMetadata['contentType']); + if (didDocument) { + utils.expectConformantMetadataStructure(contentMetadata); + resolution.testDidDocumentMetadata(contentMetadata, didDocument, execution); + } + } }); it('If the dereferencing is unsuccessful, this output MUST be an empty metadata structure.', async () => { if (dereferencingMetadata.hasOwnProperty('error')) { diff --git a/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json b/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json index db941462..6f018bb2 100644 --- a/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json +++ b/packages/did-core-test-server/suites/implementations/dereferencer-example-didwg.json @@ -38,7 +38,6 @@ }, "contentStream": "{\"id\": \"did:example:222#key-1\",\"controller\": \"did:example:222\",\"publicKeyBase58\": \"F6NxfeuPJ5NhmDM6QT2TeSFxcnnkQBgtv6yfQziS5NPM\"}", "contentMetadata": { - "contentType": "application/did+json" } } }, diff --git a/packages/did-core-test-server/suites/implementations/resolver-example-didwg.json b/packages/did-core-test-server/suites/implementations/resolver-example-didwg.json index db0cfbae..8f9fd8bf 100644 --- a/packages/did-core-test-server/suites/implementations/resolver-example-didwg.json +++ b/packages/did-core-test-server/suites/implementations/resolver-example-didwg.json @@ -25,6 +25,8 @@ "service": [] }, "didDocumentMetadata": { + "canonicalId": "did:example:oneoneone", + "equivalentId": ["did:example:one1one", "did:example:1one1"] } } }, @@ -69,7 +71,6 @@ }, "output": { "didResolutionMetadata": { - "contentType": "application/did+json" }, "didDocument": { "id": "did:example:444", diff --git a/packages/did-core-test-server/suites/resolution-utils.js b/packages/did-core-test-server/suites/resolution-utils.js index ba42dd33..63c161b2 100644 --- a/packages/did-core-test-server/suites/resolution-utils.js +++ b/packages/did-core-test-server/suites/resolution-utils.js @@ -36,44 +36,48 @@ const parseDidMethod = (did) => { return match[1]; }; -const produceRepresentation = (didDocument) => { - // TODO: properly produce, try to re-use other test code - return JSON.stringify(didDocument); +const produceRepresentation = (didDocument, contentType) => { + // TODO: improve this by re-using other test code + if (contentType.startsWith('application/did+json') || + contentType.startsWith('application/did+ld+json')) { + return JSON.stringify(didDocument); + } else if (contentType.startsWith('application/did+cbor')) { + return '00'; + } }; -const consumeRepresentation = (representation) => { - // TODO: properly consume, try to re-use other test code - return JSON.parse(representation); +const consumeRepresentation = (representation, contentType) => { + // TODO: improve this by re-using other test code + if (contentType.startsWith('application/did+ld+json')) { + let didDocument = JSON.parse(representation); + expect(Object.keys(didDocument)).toContain('@context'); + return didDocument; + } else if (contentType.startsWith('application/did+json')) { + let didDocument = JSON.parse(representation); + return didDocument; + } else if (contentType.startsWith('application/did+cbor')) { + expect(parseInt('0x' + representation)).not.toBeNaN(); + let didDocument = { 'id': 'did:ex:123' }; + return didDocument; + } }; -const expectConformantDidDocument = ((didDocument, not) => { - // TODO: properly test if this is a conformant DID document (abstract data model) - (not ? expect(Object.keys(didDocument)).not : expect(Object.keys(didDocument))) - .toContain('id'); +const expectConformantDidDocument = ((didDocument) => { + // TODO: improve this by re-using other test code + expect(didDocument).toBeInfraMap(); + expect(Object.keys(didDocument)).toContain('id'); }); -const expectConformantMetadataStructure = ((metaDataStructure, not) => { - // TODO: properly test if this is a conformant metadata structure, try to re-use other test code - (not ? expect(typeof metaDataStructure).not : expect(typeof metaDataStructure)) - .toBe('object'); +const expectConformantDidDocumentRepresentation = ((didDocumentStream, contentType) => { + // TODO: improve this by re-using other test code + const didDocument = consumeRepresentation(didDocumentStream, contentType); + expect(didDocument).not.toBeFalsy(); + expectConformantDidDocument(didDocument); }); -const expectKnownConformantMediaType = ((mediaType) => { - expect(mediaType.startsWith('application/did+ld+json') || - mediaType.startsWith('application/did+json') || - mediaType.startsWith('application/did+cbor')).toBe(true); -}); - -const expectConformantRepresentation = ((mediaType, representation) => { - // TODO: properly test if the representation conforms to the mediaType, try to re-use other test code - if (mediaType.startsWith('application/did+ld+json')) { - expect(() => { JSON.parse(representation); }).not.toThrow(); - expect(Object.keys(JSON.parse(representation))).constructor('@context'); - } else if (mediaType.startsWith('application/did+json')) { - expect(() => { JSON.parse(representation); }).not.toThrow(); - } else if (mediaType.startsWith('application/did+cbor')) { - expect(parseInt('0x' + representation)).not.toBeNaN(); - } +const expectConformantMetadataStructure = ((metaDataStructure) => { + // TODO: improve this by re-using other test code + expect(metaDataStructure).toBeInfraMap(); }); module.exports = { @@ -85,7 +89,6 @@ module.exports = { produceRepresentation, consumeRepresentation, expectConformantDidDocument, - expectConformantMetadataStructure, - expectKnownConformantMediaType, - expectConformantRepresentation + expectConformantDidDocumentRepresentation, + expectConformantMetadataStructure }; From 0322e4c104c7258c38450b01f69b4bb98e0ec62a Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 18:00:40 +0200 Subject: [PATCH 10/11] Remove skipped tests (but keep comments). Suggested by @msporny in https://github.com/w3c/did-test-suite/pull/86#discussion_r625178855. --- .../suites/did-resolution/did-resolution.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index ddc20806..b64e23ca 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -267,11 +267,9 @@ const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutco } }); // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) - it.skip('A conforming DID Method specification MUST guarantee that each equivalentId value is logically equivalent to the id property value.', () => { - }); + // 'A conforming DID Method specification MUST guarantee that each equivalentId value is logically equivalent to the id property value.' // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) - it.skip('equivalentId is a much stronger form of equivalence than alsoKnownAs because the equivalence MUST be guaranteed by the governing DID method.', () => { - }); + // 'equivalentId is a much stronger form of equivalence than alsoKnownAs because the equivalence MUST be guaranteed by the governing DID method.' } }); describe('canonicalId', () => { @@ -287,8 +285,7 @@ const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutco } }); // As discussed on the 2021-04-13 DID WG topic call, the following test can be skipped (see https://www.w3.org/2019/did-wg/Meetings/Minutes/2021-04-13-did-topic) - it.skip('A conforming DID Method specification MUST guarantee that the canonicalId value is logically equivalent to the id property value.', () => { - }); + // 'A conforming DID Method specification MUST guarantee that the canonicalId value is logically equivalent to the id property value.' } }); }; From 582511ad461c009fa62c96200525abd8f961c7cb Mon Sep 17 00:00:00 2001 From: Markus Sabadello Date: Mon, 3 May 2021 18:21:13 +0200 Subject: [PATCH 11/11] Add section numbers. Suggested by @msporny in https://github.com/w3c/did-test-suite/pull/86#discussion_r625181025. --- .../suites/did-resolution/did-resolution.js | 82 +++++++++---------- .../did-url-dereferencing.js | 40 ++++----- 2 files changed, 61 insertions(+), 61 deletions(-) diff --git a/packages/did-core-test-server/suites/did-resolution/did-resolution.js b/packages/did-core-test-server/suites/did-resolution/did-resolution.js index b64e23ca..27abecb2 100644 --- a/packages/did-core-test-server/suites/did-resolution/did-resolution.js +++ b/packages/did-core-test-server/suites/did-resolution/did-resolution.js @@ -5,7 +5,7 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { const { didResolutionMetadata, didDocument, didDocumentStream, didDocumentMetadata } = execution.output; describe(did + ' (expected outcome: ' + expectedOutcome + ')', () => { describe('did', () => { - it('This input is REQUIRED and the value MUST be a conformant DID as defined in § 3.1 DID Syntax.', async () => { + it('7.1 DID Resolution - This input is REQUIRED and the value MUST be a conformant DID as defined in § 3.1 DID Syntax.', async () => { expect(did).not.toBeFalsy(); if (! didResolutionMetadata.hasOwnProperty('error') || didResolutionMetadata['error'] !== 'invalidDid') { expect(did).toBeValidDid(); @@ -13,31 +13,31 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); }); describe('resolutionOptions', () => { - it('A metadata structure.', async () => { + it('7.1 DID Resolution - A metadata structure.', async () => { utils.expectConformantMetadataStructure(resolutionOptions); }); - it('This input is REQUIRED, but the structure MAY be empty.', async () => { + it('7.1 DID Resolution - This input is REQUIRED, but the structure MAY be empty.', async () => { expect(resolutionOptions).not.toBeFalsy(); }); }); describe('didResolutionMetadata', () => { - it('A metadata structure.', async () => { + it('7.1 DID Resolution - A metadata structure.', async () => { utils.expectConformantMetadataStructure(didResolutionMetadata); }); - it('This structure is REQUIRED, and in the case of an error in the resolution process, this MUST NOT be empty.', async () => { + it('7.1 DID Resolution - This structure is REQUIRED, and in the case of an error in the resolution process, this MUST NOT be empty.', async () => { expect(didResolutionMetadata).not.toBeFalsy(); if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(didResolutionMetadata)).not.toHaveLength(0); } }); - it('If resolveRepresentation was called, this structure MUST contain a contentType property containing the Media Type of the representation found in the didDocumentStream.', async () => { + it('7.1 DID Resolution - If resolveRepresentation was called, this structure MUST contain a contentType property containing the Media Type of the representation found in the didDocumentStream.', async () => { if (execution.function === 'resolveRepresentation') { expect(Object.keys(didResolutionMetadata)).toContain('contentType'); expect(didResolutionMetadata['contentType']).toBeMediaType(); utils.expectConformantDidDocumentRepresentation(didDocumentStream, didResolutionMetadata['contentType']); } }); - it('If the resolution is not successful, this structure MUST contain an error property describing the error.', async () => { + it('7.1 DID Resolution - If the resolution is not successful, this structure MUST contain an error property describing the error.', async () => { if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(didResolutionMetadata)).toContain('error'); expect(didResolutionMetadata['error']).toBeTruthy(); @@ -47,21 +47,21 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { // Only test 'didDocument' if 'resolve' was called, and if resolution was successful. if (execution.function === 'resolve') { describe('didDocument', () => { - it('If the resolution is successful, and if the resolve function was called, this MUST be a DID document abstract data model (a map) as described in § 4. Data Model that is capable of being transformed into a conforming DID Document (representation), using the production rules specified by the representation.', async () => { + it('7.1 DID Resolution - If the resolution is successful, and if the resolve function was called, this MUST be a DID document abstract data model (a map) as described in § 4. Data Model that is capable of being transformed into a conforming DID Document (representation), using the production rules specified by the representation.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { utils.expectConformantDidDocument(didDocument); const didDocumentStream = utils.produceRepresentation(didDocument, 'application/did+json'); utils.expectConformantDidDocumentRepresentation(didDocumentStream, 'application/did+json'); } }); - it('The value of id in the resolved DID document MUST match the DID that was resolved.', async () => { + it('7.1 DID Resolution - The value of id in the resolved DID document MUST match the DID that was resolved.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { // remove any query string in the DID uri const expectedId = did.split('?')[0] expect(didDocument['id']).toBe(expectedId); } }); - it('If the resolution is unsuccessful, this value MUST be empty.', async () => { + it('7.1 DID Resolution - If the resolution is unsuccessful, this value MUST be empty.', async () => { if (didResolutionMetadata.hasOwnProperty('error')) { expect(didDocument).toBeFalsy(); } @@ -71,14 +71,14 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { // Only test 'didDocumentStream' if 'resolveRepresentation' was called. if (execution.function === 'resolveRepresentation') { describe('didDocumentStream', () => { - it('If the resolution is successful, and if the resolveRepresentation function was called, this MUST be a byte stream of the resolved DID document in one of the conformant representations.', async () => { + it('7.1 DID Resolution - If the resolution is successful, and if the resolveRepresentation function was called, this MUST be a byte stream of the resolved DID document in one of the conformant representations.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { expect(didDocumentStream).not.toBeFalsy(); expect(didResolutionMetadata['contentType']).toBeMediaType(); utils.expectConformantDidDocumentRepresentation(didDocumentStream, didResolutionMetadata['contentType']); } }); - it('If the resolution is unsuccessful, this value MUST be an empty stream.', async () => { + it('7.1 DID Resolution - If the resolution is unsuccessful, this value MUST be an empty stream.', async () => { if (didResolutionMetadata.hasOwnProperty('error')) { expect(didDocumentStream).toBe(''); } @@ -86,12 +86,12 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); } describe('didDocumentMetadata', () => { - it('If the resolution is successful, this MUST be a metadata structure.', async () => { + it('7.1 DID Resolution - If the resolution is successful, this MUST be a metadata structure.', async () => { if (! didResolutionMetadata.hasOwnProperty('error')) { utils.expectConformantMetadataStructure(didDocumentMetadata); } }); - it('If the resolution is unsuccessful, this output MUST be an empty metadata structure.', async () => { + it('7.1 DID Resolution - If the resolution is unsuccessful, this output MUST be an empty metadata structure.', async () => { if (didResolutionMetadata.hasOwnProperty('error')) { utils.expectConformantMetadataStructure(didDocumentMetadata); expect(Object.keys(didDocumentMetadata)).toHaveLength(0); @@ -101,14 +101,14 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { describe('DID Resolution Options', () => { describe('accept', () => { if (resolutionOptions.hasOwnProperty('accept')) { - it('The Media Type of the caller\'s preferred representation of the DID document.', async () => { + it('7.1.1 DID Resolution Options - The Media Type of the caller\'s preferred representation of the DID document.', async () => { expect(resolutionOptions['accept']).toBeMediaType(); }); - it('The Media Type MUST be expressed as an ASCII string.', async () => { + it('7.1.1 DID Resolution Options - The Media Type MUST be expressed as an ASCII string.', async () => { expect(resolutionOptions['accept']).toBeAsciiString(); }); } - it('This property is OPTIONAL for the resolveRepresentation function and MUST NOT be used with the resolve function.', async () => { + it('7.1.1 DID Resolution Options - This property is OPTIONAL for the resolveRepresentation function and MUST NOT be used with the resolve function.', async () => { if (execution.function === 'resolve') { expect(Object.keys(resolutionOptions)).not.toContain('accept'); } @@ -117,24 +117,24 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); describe('DID Resolution Metadata', () => { describe('contentType', () => { - it('This property is REQUIRED if resolution is successful and if the resolveRepresentation function was called.', async() => { + it('7.1.2 DID Resolution Metadata - This property is REQUIRED if resolution is successful and if the resolveRepresentation function was called.', async() => { if (! didResolutionMetadata.hasOwnProperty('error') && execution.function === 'resolveRepresentation') { expect(Object.keys(didResolutionMetadata)).toContain('contentType'); } }); - it('This property MUST NOT be present if the resolve function was called.', async () => { + it('7.1.2 DID Resolution Metadata - This property MUST NOT be present if the resolve function was called.', async () => { if (execution.function === 'resolve') { expect(Object.keys(didResolutionMetadata)).not.toContain('contentType'); } }); if (didResolutionMetadata.hasOwnProperty('contentType')) { - it('The value of this property MUST be an ASCII string that is the Media Type of the conformant representations.', async () => { + it('7.1.2 DID Resolution Metadata - The value of this property MUST be an ASCII string that is the Media Type of the conformant representations.', async () => { expect(didResolutionMetadata['contentType']).toBeAsciiString(); expect(didResolutionMetadata['contentType']).toBeMediaType(); utils.expectConformantDidDocumentRepresentation(didDocumentStream, didResolutionMetadata['contentType']); }); } - it('The caller of the resolveRepresentation function MUST use this value when determining how to parse and process the didDocumentStream returned by this function into the data model.', async() => { + it('7.1.2 DID Resolution Metadata - The caller of the resolveRepresentation function MUST use this value when determining how to parse and process the didDocumentStream returned by this function into the data model.', async() => { if (didResolutionMetadata.hasOwnProperty('contentType')) { expect(didDocumentStream).not.toBeFalsy(); expect(utils.consumeRepresentation(didDocumentStream, didResolutionMetadata['contentType'])).not.toBeFalsy(); @@ -143,32 +143,32 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { }); }); describe('error', () => { - it('This property is REQUIRED when there is an error in the resolution process.', async () => { + it('7.1.2 DID Resolution Metadata - This property is REQUIRED when there is an error in the resolution process.', async () => { if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(didResolutionMetadata)).toContain('error'); } }); if (didResolutionMetadata.hasOwnProperty('error')) { - it('The value of this property MUST be a single keyword ASCII string.', async () => { + it('7.1.2 DID Resolution Metadata - The value of this property MUST be a single keyword ASCII string.', async () => { expect(didResolutionMetadata['error']).toBeAsciiString(); expect(didResolutionMetadata['error']).not.toMatch('\\s'); }); } if (expectedOutcome === 'invalidDidErrorOutcome') { - it('invalidDid - The DID supplied to the DID resolution function does not conform to valid syntax.', async () => { + it('7.1.2 DID Resolution Metadata - invalidDid - The DID supplied to the DID resolution function does not conform to valid syntax.', async () => { expect(didResolutionMetadata['error']).toBe('invalidDid'); expect(did).not.toBeValidDid(); expect(didDocument).toBeFalsy(); }); } if (expectedOutcome === 'notFoundErrorOutcome') { - it('notFound - The DID resolver was unable to find the DID document resulting from this resolution request.', async() => { + it('7.1.2 DID Resolution Metadata - notFound - The DID resolver was unable to find the DID document resulting from this resolution request.', async() => { expect(didResolutionMetadata['error']).toBe('notFound'); expect(didDocument).toBeFalsy(); }); } if (expectedOutcome === 'representationNotSupportedErrorOutcome') { - it('representationNotSupported - This error code is returned if the representation requested via the accept input metadata property is not supported by the DID method and/or DID resolver implementation.', async() => { + it('7.1.2 DID Resolution Metadata - representationNotSupported - This error code is returned if the representation requested via the accept input metadata property is not supported by the DID method and/or DID resolver implementation.', async() => { expect(didResolutionMetadata['error']).toBe('representationNotSupported'); }); } @@ -183,18 +183,18 @@ const didResolutionTests = (execution, expectedOutcome, implementation) => { const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutcome) => { describe('created', () => { if (didDocumentMetadata.hasOwnProperty('created')) { - it('The value of the property MUST be a string formatted as an XML Datetime normalized to UTC 00:00:00 and without sub-second decimal precision.', async () => { + it('7.1.3 DID Document Metadata - The value of the property MUST be a string formatted as an XML Datetime normalized to UTC 00:00:00 and without sub-second decimal precision.', async () => { expect(didDocumentMetadata['created']).toBeDidCoreDatetime(); }); } }); describe('updated', () => { if (didDocumentMetadata.hasOwnProperty('updated')) { - it('The value of the property MUST follow the same formatting rules as the created property.', async () => { + it('7.1.3 DID Document Metadata - The value of the property MUST follow the same formatting rules as the created property.', async () => { expect(didDocumentMetadata['updated']).toBeDidCoreDatetime(); }); if (didDocumentMetadata.hasOwnProperty('created')) { - it('updated is later or equal than created.', async () => { + it('7.1.3 DID Document Metadata - updated is later or equal than created.', async () => { expect((new Date(didDocumentMetadata['updated'])).getTime()).toBeGreaterThanOrEqual((new Date(didDocumentMetadata['created'])).getTime()) }); } @@ -202,14 +202,14 @@ const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutco }); describe('deactivated', () => { if (expectedOutcome && (expectedOutcome === 'deactivatedOutcome')) { - it('If a DID has been deactivated, DID document metadata MUST include this property with the boolean value true.', async () => { + it('7.1.3 DID Document Metadata - If a DID has been deactivated, DID document metadata MUST include this property with the boolean value true.', async () => { expect(Object.keys(didDocumentMetadata)).toContain('deactivated'); expect(didDocumentMetadata['deactivated']).toBe(true); }); } if (expectedOutcome && (expectedOutcome !== 'deactivatedOutcome')) { if (didDocumentMetadata.hasOwnProperty('deactivated')) { - it('If a DID has not been deactivated, this property is OPTIONAL, but if included, MUST have the boolean value false.', async () => { + it('7.1.3 DID Document Metadata - If a DID has not been deactivated, this property is OPTIONAL, but if included, MUST have the boolean value false.', async () => { expect(didDocumentMetadata['deactivated']).toBe(false); }); } @@ -217,16 +217,16 @@ const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutco }); describe('nextUpdate', () => { if (didDocumentMetadata.hasOwnProperty('nextUpdate')) { - it('The value of the property MUST follow the same formatting rules as the created property.', async () => { + it('7.1.3 DID Document Metadata - The value of the property MUST follow the same formatting rules as the created property.', async () => { expect(didDocumentMetadata['nextUpdate']).toBeDidCoreDatetime(); }); if (didDocumentMetadata.hasOwnProperty('created')) { - it('nextUpdate is later than created.', async () => { + it('7.1.3 DID Document Metadata - nextUpdate is later than created.', async () => { expect((new Date(didDocumentMetadata['nextUpdate'])).getTime()).toBeGreaterThan((new Date(didDocumentMetadata['created'])).getTime()) }); } if (didDocumentMetadata.hasOwnProperty('updated')) { - it('nextUpdate is later than updated.', async () => { + it('7.1.3 DID Document Metadata - nextUpdate is later than updated.', async () => { expect((new Date(didDocumentMetadata['nextUpdate'])).getTime()).toBeGreaterThan((new Date(didDocumentMetadata['updated'])).getTime()) }); } @@ -234,18 +234,18 @@ const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutco }); describe('versionId', () => { if (didDocumentMetadata.hasOwnProperty('versionId')) { - it('The value of the property MUST be an ASCII string.', async () => { + it('7.1.3 DID Document Metadata - The value of the property MUST be an ASCII string.', async () => { expect(didDocumentMetadata['versionId']).toBeAsciiString(); }); } }); describe('nextVersionId', () => { if (didDocumentMetadata.hasOwnProperty('nextVersionId')) { - it('The value of the property MUST be an ASCII string.', async () => { + it('7.1.3 DID Document Metadata - The value of the property MUST be an ASCII string.', async () => { expect(didDocumentMetadata['nextVersionId']).toBeAsciiString(); }); if (didDocumentMetadata.hasOwnProperty('versionId')) { - it('nextVersionId is different from versionId.', async () => { + it('7.1.3 DID Document Metadata - nextVersionId is different from versionId.', async () => { expect(didDocumentMetadata['nextVersionId']).not.toBe(didDocumentMetadata['versionId']); }); } @@ -253,13 +253,13 @@ const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutco }); describe('equivalentId', () => { if (didDocumentMetadata.hasOwnProperty('equivalentId')) { - it('The value of equivalentId MUST be a set where each item in the list is a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { + it('7.1.3 DID Document Metadata - The value of equivalentId MUST be a set where each item in the list is a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { expect(Array.isArray(didDocumentMetadata['equivalentId'])).toBe(true); didDocumentMetadata['equivalentId'].forEach((equivalentId) => { expect(equivalentId).toBeValidDid(); }) }); - it('Each equivalentId DID value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { + it('7.1.3 DID Document Metadata - Each equivalentId DID value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { if (didDocument) { didDocumentMetadata['equivalentId'].forEach((equivalentId) => { expect(utils.parseDidMethod(equivalentId)).toBe(utils.parseDidMethod(didDocument['id'])); @@ -274,11 +274,11 @@ const testDidDocumentMetadata = (didDocumentMetadata, didDocument, expectedOutco }); describe('canonicalId', () => { if (didDocumentMetadata.hasOwnProperty('canonicalId')) { - it('The value of canonicalId MUST be a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { + it('7.1.3 DID Document Metadata - The value of canonicalId MUST be a string that conforms to the rules in Section § 3.1 DID Syntax.', async () => { const canonicalId = didDocumentMetadata['canonicalId']; expect(canonicalId).toBeValidDid(); }); - it('A canonicalId value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { + it('7.1.3 DID Document Metadata - A canonicalId value MUST be produced by, and a form of, the same DID Method as the id property value.', async () => { if (didDocument) { const canonicalId = didDocumentMetadata['canonicalId']; expect(utils.parseDidMethod(canonicalId)).toBe(utils.parseDidMethod(didDocument['id'])); diff --git a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js index 04d3cdc1..7841cf28 100644 --- a/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js +++ b/packages/did-core-test-server/suites/did-url-dereferencing/did-url-dereferencing.js @@ -14,12 +14,12 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => }); it.todo('3.2.2 Relative DID URLs - When resolving a relative DID URL reference, the algorithm specified in RFC3986 Section 5: Reference Resolution MUST be used.'); - it('A conformant DID URL as a single string.', async() => { + it('7.2 DID URL Dereferencing - A conformant DID URL as a single string.', async() => { if (! dereferencingMetadata.hasOwnProperty('error') || dereferencingMetadata['error'] !== 'invalidDidUrl') { expect(didUrl).toBeValidDidUrl(); } }); - it('To dereference a DID fragment, the complete DID URL including the DID fragment MUST be used.', async () => { + it('7.2 DID URL Dereferencing - To dereference a DID fragment, the complete DID URL including the DID fragment MUST be used.', async () => { if(didUrl.includes('#')) { const didUrlWithoutFragment = didUrl.substring(0, didUrl.indexOf('#')); const executionWithoutFragment = utils.findExecutionByDidUrl(implementation, didUrlWithoutFragment); @@ -29,29 +29,29 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => } } }); - it('This input is REQUIRED.', async () => { + it('7.2 DID URL Dereferencing - This input is REQUIRED.', async () => { expect(didUrl).not.toBeFalsy(); }); }); - describe('dereferenceOptions', () => { - it('A metadata structure.', async () => { + describe('dereferencingOptions', () => { + it('7.2 DID URL Dereferencing - A metadata structure.', async () => { utils.expectConformantMetadataStructure(dereferenceOptions); }); - it('This input is REQUIRED, but the structure MAY be empty.', async () => { + it('7.2 DID URL Dereferencing - This input is REQUIRED, but the structure MAY be empty.', async () => { expect(dereferenceOptions).not.toBeFalsy(); }); }); describe('dereferencingMetadata', () => { - it('A metadata structure.', async () => { + it('7.2 DID URL Dereferencing - A metadata structure.', async () => { utils.expectConformantMetadataStructure(dereferencingMetadata); }); - it('This structure is REQUIRED, and in the case of an error in the dereferencing process, this MUST NOT be empty.', async () => { + it('7.2 DID URL Dereferencing - This structure is REQUIRED, and in the case of an error in the dereferencing process, this MUST NOT be empty.', async () => { expect(dereferencingMetadata).not.toBeFalsy(); if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(dereferencingMetadata)).not.toHaveLength(0); } }); - it('If the dereferencing is not successful, this structure MUST contain an error property describing the error.', async () => { + it('7.2 DID URL Dereferencing - If the dereferencing is not successful, this structure MUST contain an error property describing the error.', async () => { if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(dereferencingMetadata)).toContain('error'); expect(dereferencingMetadata['error']).toBeTruthy(); @@ -61,12 +61,12 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => // Only test 'contentStream' if 'dereference' was called. if (execution.function === 'dereference') { describe('contentStream', () => { - it('If the dereferencing function was called and successful, this MUST contain a resource corresponding to the DID URL.', async () => { + it('7.2 DID URL Dereferencing - If the dereferencing function was called and successful, this MUST contain a resource corresponding to the DID URL.', async () => { if (! dereferencingMetadata.hasOwnProperty('error')) { expect(contentStream).not.toBeFalsy(); } }); - it('If the dereferencing is unsuccessful, this value MUST be empty.', async () => { + it('7.2 DID URL Dereferencing - If the dereferencing is unsuccessful, this value MUST be empty.', async () => { if (dereferencingMetadata.hasOwnProperty('error')) { expect(contentStream).toBe(''); } @@ -74,7 +74,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => }); } describe('contentMetadata', () => { - it('If the dereferencing is successful, this MUST be a metadata structure, but the structure MAY be empty.', async () => { + it('7.2 DID URL Dereferencing - If the dereferencing is successful, this MUST be a metadata structure, but the structure MAY be empty.', async () => { if (! dereferencingMetadata.hasOwnProperty('error')) { utils.expectConformantMetadataStructure(contentMetadata); } @@ -88,7 +88,7 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => } } }); - it('If the dereferencing is unsuccessful, this output MUST be an empty metadata structure.', async () => { + it('7.2 DID URL Dereferencing - If the dereferencing is unsuccessful, this output MUST be an empty metadata structure.', async () => { if (dereferencingMetadata.hasOwnProperty('error')) { utils.expectConformantMetadataStructure(contentMetadata); expect(Object.keys(contentMetadata)).toHaveLength(0); @@ -98,10 +98,10 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => describe('DID URL Dereferencing Options', () => { describe('accept', () => { if (dereferenceOptions.hasOwnProperty('accept')) { - it('The Media Type that the caller prefers for contentStream.', async () => { + it('7.2.1 DID URL Dereferencing Options - The Media Type that the caller prefers for contentStream.', async () => { expect(dereferenceOptions['accept']).toBeMediaType(); }); - it('The Media Type MUST be expressed as an ASCII string.', async () => { + it('7.2.1 DID URL Dereferencing Options - The Media Type MUST be expressed as an ASCII string.', async () => { expect(dereferenceOptions['accept']).toBeAsciiString(); }); } @@ -110,32 +110,32 @@ const didUrlDereferencingTests = (execution, expectedOutcome, implementation) => describe('DID URL Dereferencing Metadata', () => { describe('contentType', () => { if (dereferencingMetadata.hasOwnProperty('contentType')) { - it('The Media Type value MUST be expressed as an ASCII string.', async () => { + it('7.2.2 DID URL Dereferencing Metadata - The Media Type value MUST be expressed as an ASCII string.', async () => { expect(dereferencingMetadata['contentType']).toBeMediaType(); expect(dereferencingMetadata['contentType']).toBeAsciiString(); }); } }); describe('error', () => { - it('This property is REQUIRED when there is an error in the dereferencing process.', async () => { + it('7.2.2 DID URL Dereferencing Metadata - This property is REQUIRED when there is an error in the dereferencing process.', async () => { if (utils.isErrorExpectedOutcome(expectedOutcome)) { expect(Object.keys(dereferencingMetadata)).toContain('error'); } }); if (dereferencingMetadata.hasOwnProperty('error')) { - it('The value of this property MUST be a single keyword ASCII string.', async () => { + it('7.2.2 DID URL Dereferencing Metadata - The value of this property MUST be a single keyword ASCII string.', async () => { expect(dereferencingMetadata['error']).toBeAsciiString(); expect(dereferencingMetadata['error']).not.toMatch('\\s'); }); } if (expectedOutcome === 'invalidDidUrlErrorOutcome') { - it('invalidDidUrl - The DID URL supplied to the DID URL dereferencing function does not conform to valid syntax.', async () => { + it('7.2.2 DID URL Dereferencing Metadata - invalidDidUrl - The DID URL supplied to the DID URL dereferencing function does not conform to valid syntax.', async () => { expect(dereferencingMetadata['error']).toBe('invalidDidUrl'); expect(didUrl).not.toBeValidDidUrl(); }); } if (expectedOutcome === 'notFoundErrorOutcome') { - it('notFound - The DID URL dereferencer was unable to find the contentStream resulting from this dereferencing request.', async() => { + it('7.2.2 DID URL Dereferencing Metadata - notFound - The DID URL dereferencer was unable to find the contentStream resulting from this dereferencing request.', async() => { expect(dereferencingMetadata['error']).toBe('notFound'); }); }