diff --git a/examples/doc-scan/src/controllers/index.controller.js b/examples/doc-scan/src/controllers/index.controller.js index fc5a803b..28ae3b50 100644 --- a/examples/doc-scan/src/controllers/index.controller.js +++ b/examples/doc-scan/src/controllers/index.controller.js @@ -12,6 +12,7 @@ const { OrthogonalRestrictionsFilterBuilder, RequestedIdDocumentComparisonCheckBuilder, RequestedThirdPartyIdentityCheckBuilder, + RequestedWatchlistScreeningCheckBuilder, RequiredSupplementaryDocumentBuilder, ProofOfAddressObjectiveBuilder, RequestedSupplementaryDocTextExtractionTaskBuilder, @@ -53,6 +54,12 @@ async function createSession() { new RequestedThirdPartyIdentityCheckBuilder() .build() ) + .withRequestedCheck( + new RequestedWatchlistScreeningCheckBuilder() + .withAdverseMediaCategory() + .withSanctionsCategory() + .build() + ) .withRequestedTask( new RequestedTextExtractionTaskBuilder() .withManualCheckAlways() diff --git a/examples/doc-scan/views/pages/partials/check.ejs b/examples/doc-scan/views/pages/partials/check.ejs index 2f7f968d..951adce7 100644 --- a/examples/doc-scan/views/pages/partials/check.ejs +++ b/examples/doc-scan/views/pages/partials/check.ejs @@ -1,3 +1,5 @@ +<% displayGeneratedProfile = typeof hasGeneratedProfile === 'undefined' ? false : hasGeneratedProfile %> +<% displayWatchlistSummary = typeof hasWatchlistSummary === 'undefined' ? false : hasWatchlistSummary %> @@ -91,6 +93,71 @@ <% } %> + <% if (displayWatchlistSummary && check.getReport().getWatchlistSummary()) { %> + + + + + <% } %> + <% } %> <% if (check.getGeneratedMedia().length > 0) { %> @@ -115,5 +182,25 @@ <% } %> + <% if (displayGeneratedProfile && check.getGeneratedProfile()) { %> + + + + + <% } %> + -
Watchlist Summary + + + + + + + <% if (check.getReport().getWatchlistSummary().getAssociatedCountryCodes().length > 0) { %> + + + + + <% } %> + <% if (check.getReport().getWatchlistSummary().getRawResults() && check.getReport().getWatchlistSummary().getRawResults().getMedia()) { %> + + + + + <% } %> + <% if (check.getReport().getWatchlistSummary().getSearchConfig() && check.getReport().getWatchlistSummary().getSearchConfig().getCategories().length > 0) { %> + + + + + <% } %> + +
Total hits<%= check.getReport().getWatchlistSummary().getTotalHits(); %>
Associated country codes<%= check.getReport().getWatchlistSummary().getAssociatedCountryCodes().join(', '); %>
Raw results + + + + + + + +
Media + + + + + + + + + + + +
ID<%= check.getReport().getWatchlistSummary().getRawResults().getMedia().id; %>
Type<%= check.getReport().getWatchlistSummary().getRawResults().getMedia().type; %>
+
+
Search config + + + + + + + +
Categories<%= check.getReport().getWatchlistSummary().getSearchConfig().getCategories().join(', '); %>
+
+
Generated Profile + + + + + + + + + + + +
ID<%= check.getGeneratedProfile().media.id; %>
Type<%= check.getGeneratedProfile().media.type; %>
+
\ No newline at end of file + diff --git a/examples/doc-scan/views/pages/success.ejs b/examples/doc-scan/views/pages/success.ejs index 368a80fd..a23593db 100644 --- a/examples/doc-scan/views/pages/success.ejs +++ b/examples/doc-scan/views/pages/success.ejs @@ -184,7 +184,29 @@
<% sessionResult.getThirdPartyIdentityChecks().forEach(function(check){ %> - <%- include('partials/check', { check }); %> + <%- include('partials/check', { check, hasGeneratedProfile: true }); %> + <% }); %> +
+
+ + <% } %> + + <% if (sessionResult.getWatchlistScreeningChecks().length > 0) { %> +
+
+

+ +

+
+ +
+
+ <% sessionResult.getWatchlistScreeningChecks().forEach(function(check){ %> + <%- include('partials/check', { check, hasGeneratedProfile: true, hasWatchlistSummary: true }); %> <% }); %>
@@ -225,7 +247,7 @@
- <% + <% let docNum = 0; sessionResult.getResources().getIdDocuments().forEach(function(document) { docNum++; diff --git a/index.js b/index.js index 2c6e63b9..defca7a8 100644 --- a/index.js +++ b/index.js @@ -27,6 +27,7 @@ const { RequestedDocumentAuthenticityCheckBuilder, RequestedIdDocumentComparisonCheckBuilder, RequestedThirdPartyIdentityCheckBuilder, + RequestedWatchlistScreeningCheckBuilder, RequestedFaceMatchCheckBuilder, RequestedLivenessCheckBuilder, RequestedTextExtractionTaskBuilder, @@ -66,6 +67,7 @@ module.exports = { RequestedDocumentAuthenticityCheckBuilder, RequestedIdDocumentComparisonCheckBuilder, RequestedThirdPartyIdentityCheckBuilder, + RequestedWatchlistScreeningCheckBuilder, RequestedFaceMatchCheckBuilder, RequestedLivenessCheckBuilder, RequestedTextExtractionTaskBuilder, diff --git a/package-lock.json b/package-lock.json index 96e063c8..f6a17eed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "yoti", - "version": "3.16.0", + "version": "3.17.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index c2e0ccbe..cee17c79 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yoti", - "version": "3.16.0", + "version": "3.17.0", "description": "Yoti NodeJS SDK for back-end integration", "author": "Yoti LTD (https://www.yoti.com/developers)", "license": "MIT", diff --git a/sonar-project.properties b/sonar-project.properties index 31166b7c..306a2661 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.organization = getyoti sonar.projectKey = getyoti:node sonar.projectName = Node SDK -sonar.projectVersion = 3.16.0 +sonar.projectVersion = 3.17.0 sonar.exclusions=tests/**,examples/**,node_modules/**,coverage/** sonar.javascript.lcov.reportPaths=coverage/lcov.info sonar.verbose = true diff --git a/src/doc_scan_service/doc.scan.constants.js b/src/doc_scan_service/doc.scan.constants.js index d4f9b17a..65e3c446 100644 --- a/src/doc_scan_service/doc.scan.constants.js +++ b/src/doc_scan_service/doc.scan.constants.js @@ -13,6 +13,9 @@ module.exports = Object.freeze({ ID_DOCUMENT_FACE_MATCH: 'ID_DOCUMENT_FACE_MATCH', ID_DOCUMENT_COMPARISON: 'ID_DOCUMENT_COMPARISON', THIRD_PARTY_IDENTITY: 'THIRD_PARTY_IDENTITY', + WATCHLIST_SCREENING: 'WATCHLIST_SCREENING', + ADVERSE_MEDIA: 'ADVERSE-MEDIA', + SANCTIONS: 'SANCTIONS', LIVENESS: 'LIVENESS', ZOOM: 'ZOOM', CAMERA: 'CAMERA', diff --git a/src/doc_scan_service/index.js b/src/doc_scan_service/index.js index dcc482fe..a3aff37d 100644 --- a/src/doc_scan_service/index.js +++ b/src/doc_scan_service/index.js @@ -8,6 +8,7 @@ const SdkConfigBuilder = require('./session/create/sdk.config.builder'); const RequestedDocumentAuthenticityCheckBuilder = require('./session/create/check/requested.document.authenticity.check.builder'); const RequestedIdDocumentComparisonCheckBuilder = require('./session/create/check/requested.id.document.comparison.check.builder'); const RequestedThirdPartyIdentityCheckBuilder = require('./session/create/check/requested.third.party.identity.check.builder'); +const RequestedWatchlistScreeningCheckBuilder = require('./session/create/check/requested.watchlist.screening.check.builder'); const RequestedFaceMatchCheckBuilder = require('./session/create/check/requested.face.match.check.builder'); const RequestedLivenessCheckBuilder = require('./session/create/check/requested.liveness.check.builder'); const RequestedTextExtractionTaskBuilder = require('./session/create/task/requested.text.extraction.task.builder'); @@ -28,6 +29,7 @@ module.exports = { RequestedDocumentAuthenticityCheckBuilder, RequestedIdDocumentComparisonCheckBuilder, RequestedThirdPartyIdentityCheckBuilder, + RequestedWatchlistScreeningCheckBuilder, RequestedFaceMatchCheckBuilder, RequestedLivenessCheckBuilder, RequestedTextExtractionTaskBuilder, diff --git a/src/doc_scan_service/session/create/check/requested.watchlist.screening.check.builder.js b/src/doc_scan_service/session/create/check/requested.watchlist.screening.check.builder.js new file mode 100644 index 00000000..acfd6b27 --- /dev/null +++ b/src/doc_scan_service/session/create/check/requested.watchlist.screening.check.builder.js @@ -0,0 +1,57 @@ +'use strict'; + +const RequestedWatchlistScreeningCheck = require('./requested.watchlist.screening.check'); +const RequestedWatchlistScreeningConfig = require('./requested.watchlist.screening.config'); +const DocScanConstants = require('../../../doc.scan.constants'); +const Validation = require('../../../../yoti_common/validation'); + +/** + * Builder to assist the creation of {@link RequestedWatchlistScreeningCheck}. + * + * @class RequestedWatchlistScreeningCheckBuilder + */ +/* eslint class-methods-use-this: ["error", { "exceptMethods": ["build"] }] */ +class RequestedWatchlistScreeningCheckBuilder { + constructor() { + this.categories = []; + } + + /** + * Adds ADVERSE_MEDIA to the list of categories used for watchlist screening + * + * @returns {this} + */ + withAdverseMediaCategory() { + return this.withCategory(DocScanConstants.ADVERSE_MEDIA); + } + + /** + * Adds SANCTIONS to the list of categories used for watchlist screening + * + * @returns {this} + */ + withSanctionsCategory() { + return this.withCategory(DocScanConstants.SANCTIONS); + } + + /** + * Adds a category to the list of categories used for watchlist screening + * + * @param {string} category + * + * @returns {this} + */ + withCategory(category) { + Validation.isString(category, 'category'); + Validation.notNullOrEmpty(category, 'category'); + this.categories.push(category); + return this; + } + + build() { + const config = new RequestedWatchlistScreeningConfig(this.categories); + return new RequestedWatchlistScreeningCheck(config); + } +} + +module.exports = RequestedWatchlistScreeningCheckBuilder; diff --git a/src/doc_scan_service/session/create/check/requested.watchlist.screening.check.js b/src/doc_scan_service/session/create/check/requested.watchlist.screening.check.js new file mode 100644 index 00000000..1cea5d46 --- /dev/null +++ b/src/doc_scan_service/session/create/check/requested.watchlist.screening.check.js @@ -0,0 +1,21 @@ +'use strict'; + +const RequestedCheck = require('./requested.check'); +const DocScanConstants = require('../../../doc.scan.constants'); +const Validation = require('../../../../yoti_common/validation'); +const RequestedWatchlistScreeningConfig = require('./requested.watchlist.screening.config'); + +/** + * @class RequestedWatchlistScreeningCheck + */ +class RequestedWatchlistScreeningCheck extends RequestedCheck { + /** + * @param {RequestedWatchlistScreeningConfig} config + */ + constructor(config) { + Validation.instanceOf(config, RequestedWatchlistScreeningConfig, 'config'); + super(DocScanConstants.WATCHLIST_SCREENING, config); + } +} + +module.exports = RequestedWatchlistScreeningCheck; diff --git a/src/doc_scan_service/session/create/check/requested.watchlist.screening.config.js b/src/doc_scan_service/session/create/check/requested.watchlist.screening.config.js new file mode 100644 index 00000000..e170e416 --- /dev/null +++ b/src/doc_scan_service/session/create/check/requested.watchlist.screening.config.js @@ -0,0 +1,31 @@ +'use strict'; + +const Validation = require('../../../../yoti_common/validation'); +/** + * The configuration applied when creating a RequestedWatchlistScreeningCheck + * + * @class RequestedWatchlistScreeningConfig + */ +class RequestedWatchlistScreeningConfig { + /** + * @param {string[]} categories + * The list of categories corresponding to each watchlist screening conducted + */ + constructor(categories) { + if (categories) { + Validation.isArrayOfStrings(categories, 'categories'); + this.categories = categories.filter((elem, pos) => categories.indexOf(elem) === pos); + } + } + + /** + * @returns {Object} data for JSON.stringify() + */ + toJSON() { + return { + categories: this.categories, + }; + } +} + +module.exports = RequestedWatchlistScreeningConfig; diff --git a/src/doc_scan_service/session/retrieve/generated.profile.response.js b/src/doc_scan_service/session/retrieve/generated.profile.response.js new file mode 100644 index 00000000..e7898484 --- /dev/null +++ b/src/doc_scan_service/session/retrieve/generated.profile.response.js @@ -0,0 +1,20 @@ +'use strict'; + +const MediaResponse = require('./media.response'); + +class GeneratedProfileResponse { + constructor(generatedProfile) { + if (generatedProfile.media) { + this.media = new MediaResponse(generatedProfile.media); + } + } + + /** + * @returns {MediaResponse} + */ + getMedia() { + return this.media; + } +} + +module.exports = GeneratedProfileResponse; diff --git a/src/doc_scan_service/session/retrieve/get.session.result.js b/src/doc_scan_service/session/retrieve/get.session.result.js index 91df2f5c..993cc36c 100644 --- a/src/doc_scan_service/session/retrieve/get.session.result.js +++ b/src/doc_scan_service/session/retrieve/get.session.result.js @@ -10,6 +10,7 @@ const SupplementaryDocumentTextDataCheckResponse = require('./supplementary.docu const LivenessCheckResponse = require('./liveness.check.response'); const IdDocumentComparisonCheckResponse = require('./id.document.comparison.check.response'); const ThirdPartyIdentityCheckResponse = require('./third.party.identity.check.response'); +const WatchlistScreeningCheckResponse = require('./watchlist.screening.check.response'); const DocScanConstants = require('../../doc.scan.constants'); const { YotiDate } = require('../../../data_type/date'); @@ -42,6 +43,8 @@ class GetSessionResult { return new IdDocumentComparisonCheckResponse(check); case DocScanConstants.THIRD_PARTY_IDENTITY: return new ThirdPartyIdentityCheckResponse(check); + case DocScanConstants.WATCHLIST_SCREENING: + return new WatchlistScreeningCheckResponse(check); case DocScanConstants.ID_DOCUMENT_FACE_MATCH: return new FaceMatchCheckResponse(check); case DocScanConstants.ID_DOCUMENT_TEXT_DATA_CHECK: @@ -163,6 +166,13 @@ class GetSessionResult { return this.getChecks().filter((check) => check instanceof ThirdPartyIdentityCheckResponse); } + /** + * @returns {WatchlistScreeningCheckResponse[]} + */ + getWatchlistScreeningChecks() { + return this.getChecks().filter((check) => check instanceof WatchlistScreeningCheckResponse); + } + /** * @returns {ResourceContainer} */ diff --git a/src/doc_scan_service/session/retrieve/profile.check.response.js b/src/doc_scan_service/session/retrieve/profile.check.response.js new file mode 100644 index 00000000..798feebd --- /dev/null +++ b/src/doc_scan_service/session/retrieve/profile.check.response.js @@ -0,0 +1,21 @@ +const CheckResponse = require('./check.response'); +const GeneratedProfileResponse = require('./generated.profile.response'); + +class ProfileCheckResponse extends CheckResponse { + constructor(check) { + super(check); + + if (check.generated_profile) { + this.generatedProfile = new GeneratedProfileResponse(check.generated_profile); + } + } + + /** + * @returns {GeneratedProfileResponse} + */ + getGeneratedProfile() { + return this.generatedProfile; + } +} + +module.exports = ProfileCheckResponse; diff --git a/src/doc_scan_service/session/retrieve/raw.results.response.js b/src/doc_scan_service/session/retrieve/raw.results.response.js new file mode 100644 index 00000000..9a3dca1b --- /dev/null +++ b/src/doc_scan_service/session/retrieve/raw.results.response.js @@ -0,0 +1,20 @@ +'use strict'; + +const MediaResponse = require('./media.response'); + +class RawResultsResponse { + constructor(rawResults) { + if (rawResults.media) { + this.media = new MediaResponse(rawResults.media); + } + } + + /** + * @returns {MediaResponse} + */ + getMedia() { + return this.media; + } +} + +module.exports = RawResultsResponse; diff --git a/src/doc_scan_service/session/retrieve/search.config.response.js b/src/doc_scan_service/session/retrieve/search.config.response.js new file mode 100644 index 00000000..2c43c70f --- /dev/null +++ b/src/doc_scan_service/session/retrieve/search.config.response.js @@ -0,0 +1,23 @@ +'use strict'; + +const Validation = require('../../../yoti_common/validation'); + +class SearchConfigResponse { + constructor(searchConfig) { + if (searchConfig.categories) { + Validation.isArrayOfStrings(searchConfig.categories, 'categories'); + this.categories = searchConfig.categories; + } else { + this.categories = []; + } + } + + /** + * @returns {string[]} + */ + getCategories() { + return this.categories; + } +} + +module.exports = SearchConfigResponse; diff --git a/src/doc_scan_service/session/retrieve/third.party.identity.check.response.js b/src/doc_scan_service/session/retrieve/third.party.identity.check.response.js index 39ec3f8e..74684b4a 100644 --- a/src/doc_scan_service/session/retrieve/third.party.identity.check.response.js +++ b/src/doc_scan_service/session/retrieve/third.party.identity.check.response.js @@ -1,8 +1,8 @@ 'use strict'; -const CheckResponse = require('./check.response'); +const ProfileCheckResponse = require('./profile.check.response'); -class ThirdPartyIdentityCheckResponse extends CheckResponse { +class ThirdPartyIdentityCheckResponse extends ProfileCheckResponse { } module.exports = ThirdPartyIdentityCheckResponse; diff --git a/src/doc_scan_service/session/retrieve/watchlist.check.response.js b/src/doc_scan_service/session/retrieve/watchlist.check.response.js new file mode 100644 index 00000000..46b02c4b --- /dev/null +++ b/src/doc_scan_service/session/retrieve/watchlist.check.response.js @@ -0,0 +1,21 @@ +const ProfileCheckResponse = require('./profile.check.response'); +const WatchlistReportResponse = require('./watchlist.report.response'); + +class WatchlistCheckResponse extends ProfileCheckResponse { + constructor(check) { + super(check); + + if (check.report) { + this.report = new WatchlistReportResponse(check.report); + } + } + + /** + * @returns {WatchlistReportResponse} + */ + getReport() { + return this.report; + } +} + +module.exports = WatchlistCheckResponse; diff --git a/src/doc_scan_service/session/retrieve/watchlist.report.response.js b/src/doc_scan_service/session/retrieve/watchlist.report.response.js new file mode 100644 index 00000000..ec13db2f --- /dev/null +++ b/src/doc_scan_service/session/retrieve/watchlist.report.response.js @@ -0,0 +1,20 @@ +'use strict'; + +const ReportResponse = require('./report.response'); +const WatchlistSummaryResponse = require('./watchlist.summary.response'); + +class WatchlistReportResponse extends ReportResponse { + constructor(report) { + super(report); + + if (report.watchlist_summary) { + this.watchListSummary = new WatchlistSummaryResponse(report.watchlist_summary); + } + } + + getWatchlistSummary() { + return this.watchListSummary; + } +} + +module.exports = WatchlistReportResponse; diff --git a/src/doc_scan_service/session/retrieve/watchlist.screening.check.response.js b/src/doc_scan_service/session/retrieve/watchlist.screening.check.response.js new file mode 100644 index 00000000..2f97121a --- /dev/null +++ b/src/doc_scan_service/session/retrieve/watchlist.screening.check.response.js @@ -0,0 +1,8 @@ +'use strict'; + +const WatchlistCheckResponse = require('./watchlist.check.response'); + +class WatchlistScreeningCheckResponse extends WatchlistCheckResponse { +} + +module.exports = WatchlistScreeningCheckResponse; diff --git a/src/doc_scan_service/session/retrieve/watchlist.summary.response.js b/src/doc_scan_service/session/retrieve/watchlist.summary.response.js new file mode 100644 index 00000000..8b3bbc37 --- /dev/null +++ b/src/doc_scan_service/session/retrieve/watchlist.summary.response.js @@ -0,0 +1,61 @@ +'use strict'; + +const RawResultsResponse = require('./raw.results.response'); +const SearchConfigResponse = require('./search.config.response'); +const Validation = require('../../../yoti_common/validation'); + +class WatchlistSummaryResponse { + constructor(summary) { + if (summary.total_hits) { + Validation.isNumber(summary.total_hits, 'total_hits'); + this.totalHits = summary.total_hits; + } else { + this.totalHits = 0; + } + + if (summary.associated_country_codes) { + Validation.isArrayOfStrings(summary.associated_country_codes, 'associated_country_codes'); + this.associatedCountryCodes = summary.associated_country_codes; + } else { + this.associatedCountryCodes = []; + } + + if (summary.raw_results) { + this.rawResults = new RawResultsResponse(summary.raw_results); + } + + if (summary.search_config) { + this.searchConfig = new SearchConfigResponse(summary.search_config); + } + } + + /** + * @returns {number} + */ + getTotalHits() { + return this.totalHits; + } + + /** + * @returns {string[]} + */ + getAssociatedCountryCodes() { + return this.associatedCountryCodes; + } + + /** + * @returns {RawResultsResponse} + */ + getRawResults() { + return this.rawResults; + } + + /** + * @returns {SearchConfigResponse} + */ + getSearchConfig() { + return this.searchConfig; + } +} + +module.exports = WatchlistSummaryResponse; diff --git a/tests/doc_scan_service/session/create/check/requested.watchlist.screening.check.builder.spec.js b/tests/doc_scan_service/session/create/check/requested.watchlist.screening.check.builder.spec.js new file mode 100644 index 00000000..aa4b9a2e --- /dev/null +++ b/tests/doc_scan_service/session/create/check/requested.watchlist.screening.check.builder.spec.js @@ -0,0 +1,90 @@ +const { RequestedWatchlistScreeningCheckBuilder } = require('../../../../..'); + +describe('RequestedWatchlistScreeningCheckBuilder', () => { + it('should build RequestedWatchlistScreeningCheck (default, without any categories specified)', () => { + const expectedJson = JSON.stringify({ + type: 'WATCHLIST_SCREENING', + config: { + categories: [], + }, + }); + + const check = new RequestedWatchlistScreeningCheckBuilder().build(); + + expect(JSON.stringify(check)).toBe(expectedJson); + }); + + describe('when categories are specified', () => { + const getExpectedSerialisedCheck = (categories = []) => JSON.stringify({ + type: 'WATCHLIST_SCREENING', + config: { + categories, + }, + }); + + describe('using the "withAdverseMediaCategory()" method', () => { + it('should add "ADVERSE-MEDIA" to the categories', () => { + const check = new RequestedWatchlistScreeningCheckBuilder() + .withAdverseMediaCategory() + .build(); + + const serialisedCheck = JSON.stringify(check); + const expectedSerialisedCheck = getExpectedSerialisedCheck(['ADVERSE-MEDIA']); + expect(serialisedCheck).toBe(expectedSerialisedCheck); + }); + }); + describe('using the "withSanctionsCategory()" method', () => { + it('should add "SANCTIONS" to the categories', () => { + const check = new RequestedWatchlistScreeningCheckBuilder() + .withSanctionsCategory() + .build(); + + const serialisedCheck = JSON.stringify(check); + const expectedSerialisedCheck = getExpectedSerialisedCheck(['SANCTIONS']); + expect(serialisedCheck).toBe(expectedSerialisedCheck); + }); + }); + describe('using the generic "withCategory()" method', () => { + it('should add any passed string to the categories', () => { + const check = new RequestedWatchlistScreeningCheckBuilder() + .withCategory('A_NEW_CATEGORY') + .build(); + + const serialisedCheck = JSON.stringify(check); + const expectedSerialisedCheck = getExpectedSerialisedCheck(['A_NEW_CATEGORY']); + expect(serialisedCheck).toBe(expectedSerialisedCheck); + }); + it('should throw an TypeError when the category is not valid string', () => { + expect(() => { + new RequestedWatchlistScreeningCheckBuilder() + .withCategory(false) + .build(); + }).toThrowError(TypeError); + }); + }); + describe('when adding combination of category', () => { + it('should ensure uniqueness of each category', () => { + const check = new RequestedWatchlistScreeningCheckBuilder() + .withAdverseMediaCategory() + .withAdverseMediaCategory() + .withCategory('ADVERSE-MEDIA') + .withCategory('ADVERSE-MEDIA') + .withSanctionsCategory() + .withSanctionsCategory() + .withCategory('SANCTIONS') + .withCategory('SANCTIONS') + .withCategory('BOING') + .withCategory('BOING') + .withCategory('BOING') + .withCategory('BOING') + .withCategory('BOING') + .withCategory('BOING') + .build(); + + const serialisedCheck = JSON.stringify(check); + const expectedSerialisedCheck = getExpectedSerialisedCheck(['ADVERSE-MEDIA', 'SANCTIONS', 'BOING']); + expect(serialisedCheck).toBe(expectedSerialisedCheck); + }); + }); + }); +}); diff --git a/tests/doc_scan_service/session/create/session.specification.builder.test.js b/tests/doc_scan_service/session/create/session.specification.builder.test.js index edc78c31..e8a153b7 100644 --- a/tests/doc_scan_service/session/create/session.specification.builder.test.js +++ b/tests/doc_scan_service/session/create/session.specification.builder.test.js @@ -6,6 +6,7 @@ const { RequestedDocumentAuthenticityCheckBuilder, RequestedIdDocumentComparisonCheckBuilder, RequestedThirdPartyIdentityCheckBuilder, + RequestedWatchlistScreeningCheckBuilder, NotificationConfigBuilder, SdkConfigBuilder, RequiredIdDocumentBuilder, @@ -38,6 +39,10 @@ describe('SessionSpecificationBuilder', () => { const docAuthenticityCheck = new RequestedDocumentAuthenticityCheckBuilder().build(); const idDocumentComparisonCheck = new RequestedIdDocumentComparisonCheckBuilder().build(); const thirdPartyIdentityCheck = new RequestedThirdPartyIdentityCheckBuilder().build(); + const watchListScreeningCheck = new RequestedWatchlistScreeningCheckBuilder() + .withAdverseMediaCategory() + .withSanctionsCategory() + .build(); const documentFilter = new DocumentRestrictionsFilterBuilder() .forWhitelist() @@ -58,6 +63,7 @@ describe('SessionSpecificationBuilder', () => { .withRequestedCheck(docAuthenticityCheck) .withRequestedCheck(idDocumentComparisonCheck) .withRequestedCheck(thirdPartyIdentityCheck) + .withRequestedCheck(watchListScreeningCheck) .withRequestedTask(textExtractionTask) .withRequiredDocument(requiredDocument) .build(); @@ -77,6 +83,7 @@ describe('SessionSpecificationBuilder', () => { docAuthenticityCheck, idDocumentComparisonCheck, thirdPartyIdentityCheck, + watchListScreeningCheck, ], requested_tasks: [ textExtractionTask, diff --git a/tests/doc_scan_service/session/create/session.specification.test.js b/tests/doc_scan_service/session/create/session.specification.test.js index d5cc8b3f..4294f254 100644 --- a/tests/doc_scan_service/session/create/session.specification.test.js +++ b/tests/doc_scan_service/session/create/session.specification.test.js @@ -3,7 +3,7 @@ const SessionSpecification = require('../../../../src/doc_scan_service/session/c const { NotificationConfigBuilder, SdkConfigBuilder, -} = require('../../../../'); +} = require('../../../..'); const SOME_TRACKING_ID = 'some-tracking-id'; diff --git a/tests/doc_scan_service/session/retrieve/generated.profile.response.spec.js b/tests/doc_scan_service/session/retrieve/generated.profile.response.spec.js new file mode 100644 index 00000000..67881761 --- /dev/null +++ b/tests/doc_scan_service/session/retrieve/generated.profile.response.spec.js @@ -0,0 +1,23 @@ +const GeneratedProfileResponse = require('../../../../src/doc_scan_service/session/retrieve/generated.profile.response'); +const MediaResponse = require('../../../../src/doc_scan_service/session/retrieve/media.response'); + +describe('GeneratedProfileResponse', () => { + let generatedProfileResponse; + + beforeEach(() => { + generatedProfileResponse = new GeneratedProfileResponse({ + media: { + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + type: 'JSON', + created: '2021-02-16T17:02:53.519Z', + last_updated: '2021-02-16T17:02:53.519Z', + }, + }); + }); + + describe('#getMedia', () => { + it('should return media', () => { + expect(generatedProfileResponse.getMedia()).toBeInstanceOf(MediaResponse); + }); + }); +}); diff --git a/tests/doc_scan_service/session/retrieve/get.session.result.spec.js b/tests/doc_scan_service/session/retrieve/get.session.result.spec.js index 26a2f2a7..dc1cda77 100644 --- a/tests/doc_scan_service/session/retrieve/get.session.result.spec.js +++ b/tests/doc_scan_service/session/retrieve/get.session.result.spec.js @@ -8,6 +8,7 @@ const LivenessCheckResponse = require('../../../../src/doc_scan_service/session/ const ResourceContainer = require('../../../../src/doc_scan_service/session/retrieve/resource.container'); const IdDocumentComparisonCheckResponse = require('../../../../src/doc_scan_service/session/retrieve/id.document.comparison.check.response'); const ThirdPartyIdentityCheckResponse = require('../../../../src/doc_scan_service/session/retrieve/third.party.identity.check.response'); +const WatchlistScreeningCheckResponse = require('../../../../src/doc_scan_service/session/retrieve/watchlist.screening.check.response'); const { YotiDate } = require('../../../..'); const ID_DOCUMENT_AUTHENTICITY = 'ID_DOCUMENT_AUTHENTICITY'; @@ -17,6 +18,7 @@ const SUPPLEMENTARY_DOCUMENT_TEXT_DATA_CHECK = 'SUPPLEMENTARY_DOCUMENT_TEXT_DATA const LIVENESS = 'LIVENESS'; const ID_DOCUMENT_COMPARISON = 'ID_DOCUMENT_COMPARISON'; const THIRD_PARTY_IDENTITY = 'THIRD_PARTY_IDENTITY'; +const WATCHLIST_SCREENING = 'WATCHLIST_SCREENING'; const SOME_UNKNOWN_CHECK = 'SOME_UNKNOWN_CHECK'; const SOME_DATE_STRING = '2019-12-02T12:00:00.123Z'; @@ -56,6 +58,9 @@ describe('GetSessionResult', () => { { type: THIRD_PARTY_IDENTITY, }, + { + type: WATCHLIST_SCREENING, + }, ], biometric_consent: SOME_DATE_STRING, }); @@ -95,7 +100,7 @@ describe('GetSessionResult', () => { describe('when checks are available', () => { it('should return array of checks', () => { const checks = session.getChecks(); - expect(checks.length).toBe(7); + expect(checks.length).toBe(8); expect(checks[0]).toBeInstanceOf(AuthenticityCheckResponse); expect(checks[1]).toBeInstanceOf(LivenessCheckResponse); expect(checks[2]).toBeInstanceOf(FaceMatchCheckResponse); @@ -103,6 +108,7 @@ describe('GetSessionResult', () => { expect(checks[4]).toBeInstanceOf(IdDocumentComparisonCheckResponse); expect(checks[5]).toBeInstanceOf(SupplementaryDocumentTextDataCheckResponse); expect(checks[6]).toBeInstanceOf(ThirdPartyIdentityCheckResponse); + expect(checks[7]).toBeInstanceOf(WatchlistScreeningCheckResponse); checks.forEach((check) => expect(check).toBeInstanceOf(CheckResponse)); }); }); @@ -179,6 +185,15 @@ describe('GetSessionResult', () => { }); }); + describe('#getWatchlistScreeningChecks', () => { + it('should return array of WatchlistScreeningCheckResponse', () => { + const checks = session.getWatchlistScreeningChecks(); + expect(checks.length).toBe(1); + expect(checks[0]).toBeInstanceOf(WatchlistScreeningCheckResponse); + expect(checks[0].getType()).toBe(WATCHLIST_SCREENING); + }); + }); + describe('#getFaceMatchChecks', () => { it('should return array of FaceMatchCheckResponse', () => { const checks = session.getFaceMatchChecks(); diff --git a/tests/doc_scan_service/session/retrieve/profile.check.response.spec.js b/tests/doc_scan_service/session/retrieve/profile.check.response.spec.js new file mode 100644 index 00000000..79bd5298 --- /dev/null +++ b/tests/doc_scan_service/session/retrieve/profile.check.response.spec.js @@ -0,0 +1,113 @@ +const ProfileCheckResponse = require('../../../../src/doc_scan_service/session/retrieve/profile.check.response'); +const GeneratedMedia = require('../../../../src/doc_scan_service/session/retrieve/generated.media'); +const GeneratedProfileResponse = require('../../../../src/doc_scan_service/session/retrieve/generated.profile.response'); +const ReportResponse = require('../../../../src/doc_scan_service/session/retrieve/report.response'); + +describe('ProfileCheckResponse', () => { + let profileCheckResponse; + + beforeEach(() => { + profileCheckResponse = new ProfileCheckResponse({ + type: 'some-type', + id: 'some-id', + state: 'some-state', + created: '2006-01-02T22:04:05.123Z', + last_updated: '2006-02-02T22:04:05.123Z', + resources_used: [ + 'some-resource', + 'some-other-resource', + ], + generated_media: [ + {}, + {}, + ], + report: {}, + generated_profile: {}, + }); + }); + + describe('#getType', () => { + it('should return type', () => { + expect(profileCheckResponse.getType()).toBe('some-type'); + }); + }); + + describe('#getId', () => { + it('should return ID', () => { + expect(profileCheckResponse.getId()).toBe('some-id'); + }); + }); + + describe('#getState', () => { + it('should return state', () => { + expect(profileCheckResponse.getState()).toBe('some-state'); + }); + }); + + describe('#getCreated', () => { + it('should return created', () => { + expect(profileCheckResponse.getCreated().getMicrosecondTimestamp()) + .toBe('2006-01-02T22:04:05.123000Z'); + }); + }); + + describe('#getLastUpdated', () => { + it('should return last updated', () => { + expect(profileCheckResponse.getLastUpdated().getMicrosecondTimestamp()) + .toBe('2006-02-02T22:04:05.123000Z'); + }); + }); + + describe('#getResourcesUsed', () => { + describe('when resources used are available', () => { + it('should return list of resources', () => { + const resources = profileCheckResponse.getResourcesUsed(); + expect(resources.length).toBe(2); + expect(resources[0]).toBe('some-resource'); + expect(resources[1]).toBe('some-other-resource'); + }); + }); + describe('when resources used are not available', () => { + it('should return empty array', () => { + profileCheckResponse = new ProfileCheckResponse({}); + const resources = profileCheckResponse.getResourcesUsed(); + expect(resources).toBeInstanceOf(Array); + expect(resources.length).toBe(0); + }); + }); + }); + + describe('#getGeneratedMedia', () => { + describe('when generated media is available', () => { + it('should return list of generated media', () => { + const media = profileCheckResponse.getGeneratedMedia(); + expect(media.length).toBe(2); + media.forEach((mediaItem) => { + expect(mediaItem).toBeInstanceOf(GeneratedMedia); + }); + }); + }); + describe('when generated media is not available', () => { + it('should return empty array', () => { + profileCheckResponse = new ProfileCheckResponse({}); + const media = profileCheckResponse.getGeneratedMedia(); + expect(media).toBeInstanceOf(Array); + expect(media.length).toBe(0); + }); + }); + }); + + describe('#getReport', () => { + it('should return report', () => { + const report = profileCheckResponse.getReport(); + expect(report).toBeInstanceOf(ReportResponse); + }); + }); + + describe('#getGeneratedProfile', () => { + it('should return generatedProfile', () => { + const generatedProfile = profileCheckResponse.getGeneratedProfile(); + expect(generatedProfile).toBeInstanceOf(GeneratedProfileResponse); + }); + }); +}); diff --git a/tests/doc_scan_service/session/retrieve/raw.results.response.spec.js b/tests/doc_scan_service/session/retrieve/raw.results.response.spec.js new file mode 100644 index 00000000..d1af2cf3 --- /dev/null +++ b/tests/doc_scan_service/session/retrieve/raw.results.response.spec.js @@ -0,0 +1,23 @@ +const RawResultsResponse = require('../../../../src/doc_scan_service/session/retrieve/raw.results.response'); +const MediaResponse = require('../../../../src/doc_scan_service/session/retrieve/media.response'); + +describe('RawResultsResponse', () => { + let rawResultsResponse; + + beforeEach(() => { + rawResultsResponse = new RawResultsResponse({ + media: { + id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', + type: 'JSON', + created: '2021-02-16T17:02:53.519Z', + last_updated: '2021-02-16T17:02:53.519Z', + }, + }); + }); + + describe('#getMedia', () => { + it('should return media', () => { + expect(rawResultsResponse.getMedia()).toBeInstanceOf(MediaResponse); + }); + }); +}); diff --git a/tests/doc_scan_service/session/retrieve/search.config.response.spec.js b/tests/doc_scan_service/session/retrieve/search.config.response.spec.js new file mode 100644 index 00000000..08aacf4c --- /dev/null +++ b/tests/doc_scan_service/session/retrieve/search.config.response.spec.js @@ -0,0 +1,24 @@ +const SearchConfigResponse = require('../../../../src/doc_scan_service/session/retrieve/search.config.response'); + +describe('SearchConfigResponse', () => { + let searchConfigResponse; + + beforeEach(() => { + searchConfigResponse = new SearchConfigResponse({ + categories: ['NEWS', 'SPORTS', 'HISTORY'], + }); + }); + + describe('#getCategories', () => { + it('should return categories', () => { + expect(searchConfigResponse.getCategories()).toEqual(['NEWS', 'SPORTS', 'HISTORY']); + }); + }); + + describe('#constructor', () => { + it('should set up empty categories if none present', () => { + searchConfigResponse = new SearchConfigResponse({}); + expect(searchConfigResponse.getCategories()).toEqual([]); + }); + }); +}); diff --git a/tests/doc_scan_service/session/retrieve/watchlist.check.response.spec.js b/tests/doc_scan_service/session/retrieve/watchlist.check.response.spec.js new file mode 100644 index 00000000..ffa0ce21 --- /dev/null +++ b/tests/doc_scan_service/session/retrieve/watchlist.check.response.spec.js @@ -0,0 +1,113 @@ +const WatchlistCheckResponse = require('../../../../src/doc_scan_service/session/retrieve/watchlist.check.response'); +const GeneratedMedia = require('../../../../src/doc_scan_service/session/retrieve/generated.media'); +const GeneratedProfileResponse = require('../../../../src/doc_scan_service/session/retrieve/generated.profile.response'); +const WatchlistReportResponse = require('../../../../src/doc_scan_service/session/retrieve/watchlist.report.response'); + +describe('WatchlistCheckResponse', () => { + let watchListCheckResponse; + + beforeEach(() => { + watchListCheckResponse = new WatchlistCheckResponse({ + type: 'some-type', + id: 'some-id', + state: 'some-state', + created: '2006-01-02T22:04:05.123Z', + last_updated: '2006-02-02T22:04:05.123Z', + resources_used: [ + 'some-resource', + 'some-other-resource', + ], + generated_media: [ + {}, + {}, + ], + report: {}, + generated_profile: {}, + }); + }); + + describe('#getType', () => { + it('should return type', () => { + expect(watchListCheckResponse.getType()).toBe('some-type'); + }); + }); + + describe('#getId', () => { + it('should return ID', () => { + expect(watchListCheckResponse.getId()).toBe('some-id'); + }); + }); + + describe('#getState', () => { + it('should return state', () => { + expect(watchListCheckResponse.getState()).toBe('some-state'); + }); + }); + + describe('#getCreated', () => { + it('should return created', () => { + expect(watchListCheckResponse.getCreated().getMicrosecondTimestamp()) + .toBe('2006-01-02T22:04:05.123000Z'); + }); + }); + + describe('#getLastUpdated', () => { + it('should return last updated', () => { + expect(watchListCheckResponse.getLastUpdated().getMicrosecondTimestamp()) + .toBe('2006-02-02T22:04:05.123000Z'); + }); + }); + + describe('#getResourcesUsed', () => { + describe('when resources used are available', () => { + it('should return list of resources', () => { + const resources = watchListCheckResponse.getResourcesUsed(); + expect(resources.length).toBe(2); + expect(resources[0]).toBe('some-resource'); + expect(resources[1]).toBe('some-other-resource'); + }); + }); + describe('when resources used are not available', () => { + it('should return empty array', () => { + watchListCheckResponse = new WatchlistCheckResponse({}); + const resources = watchListCheckResponse.getResourcesUsed(); + expect(resources).toBeInstanceOf(Array); + expect(resources.length).toBe(0); + }); + }); + }); + + describe('#getGeneratedMedia', () => { + describe('when generated media is available', () => { + it('should return list of generated media', () => { + const media = watchListCheckResponse.getGeneratedMedia(); + expect(media.length).toBe(2); + media.forEach((mediaItem) => { + expect(mediaItem).toBeInstanceOf(GeneratedMedia); + }); + }); + }); + describe('when generated media is not available', () => { + it('should return empty array', () => { + watchListCheckResponse = new WatchlistCheckResponse({}); + const media = watchListCheckResponse.getGeneratedMedia(); + expect(media).toBeInstanceOf(Array); + expect(media.length).toBe(0); + }); + }); + }); + + describe('#getReport', () => { + it('should return report as instance of WatchlistReportResponse', () => { + const report = watchListCheckResponse.getReport(); + expect(report).toBeInstanceOf(WatchlistReportResponse); + }); + }); + + describe('#getGeneratedProfile', () => { + it('should return generatedProfile', () => { + const generatedProfile = watchListCheckResponse.getGeneratedProfile(); + expect(generatedProfile).toBeInstanceOf(GeneratedProfileResponse); + }); + }); +}); diff --git a/tests/doc_scan_service/session/retrieve/watchlist.report.response.spec.js b/tests/doc_scan_service/session/retrieve/watchlist.report.response.spec.js new file mode 100644 index 00000000..329793e7 --- /dev/null +++ b/tests/doc_scan_service/session/retrieve/watchlist.report.response.spec.js @@ -0,0 +1,41 @@ +const WatchlistReportResponse = require('../../../../src/doc_scan_service/session/retrieve/watchlist.report.response'); +const RecommendationResponse = require('../../../../src/doc_scan_service/session/retrieve/recommendation.response'); +const BreakdownResponse = require('../../../../src/doc_scan_service/session/retrieve/breakdown.response'); +const WatchlistSummaryResponse = require('../../../../src/doc_scan_service/session/retrieve/watchlist.summary.response'); + +describe('WatchlistReportResponse', () => { + let reportResponse; + + beforeEach(() => { + reportResponse = new WatchlistReportResponse({ + recommendation: {}, + breakdown: [ + {}, + {}, + ], + watchlist_summary: {}, + }); + }); + + describe('#getRecommendation', () => { + it('should return recommendation', () => { + expect(reportResponse.getRecommendation()).toBeInstanceOf(RecommendationResponse); + }); + }); + + describe('#getBreakdown', () => { + it('should return list of breakdown items', () => { + const breakdownItems = reportResponse.getBreakdown(); + expect(breakdownItems.length).toBe(2); + breakdownItems.forEach((breakdownItem) => { + expect(breakdownItem).toBeInstanceOf(BreakdownResponse); + }); + }); + }); + + describe('#getWatchlistSummary', () => { + it('should return watchlistSummary', () => { + expect(reportResponse.getWatchlistSummary()).toBeInstanceOf(WatchlistSummaryResponse); + }); + }); +}); diff --git a/tests/doc_scan_service/session/retrieve/watchlist.summary.response.spec.js b/tests/doc_scan_service/session/retrieve/watchlist.summary.response.spec.js new file mode 100644 index 00000000..fc04c463 --- /dev/null +++ b/tests/doc_scan_service/session/retrieve/watchlist.summary.response.spec.js @@ -0,0 +1,42 @@ +const WatchlistSummaryResponse = require('../../../../src/doc_scan_service/session/retrieve/watchlist.summary.response'); +const RawResultsResponse = require('../../../../src/doc_scan_service/session/retrieve/raw.results.response'); +const SearchConfigResponse = require('../../../../src/doc_scan_service/session/retrieve/search.config.response'); + +describe('WatchlistSummaryResponse', () => { + let watchListSummaryResponse; + + beforeEach(() => { + watchListSummaryResponse = new WatchlistSummaryResponse({ + total_hits: 9, + associated_country_codes: ['USA', 'GBR'], + search_config: {}, + raw_results: { + media: {}, + }, + }); + }); + + describe('#getTotalHits', () => { + it('should return the total hits', () => { + expect(watchListSummaryResponse.getTotalHits()).toBe(9); + }); + }); + + describe('#getAssociatedCountryCodes', () => { + it('should return the list of associated country codes', () => { + expect(watchListSummaryResponse.getAssociatedCountryCodes()).toEqual(['USA', 'GBR']); + }); + }); + + describe('#getRawResults', () => { + it('should return the raw results response', () => { + expect(watchListSummaryResponse.getRawResults()).toBeInstanceOf(RawResultsResponse); + }); + }); + + describe('#getSearchConfig', () => { + it('should return the search config response', () => { + expect(watchListSummaryResponse.getSearchConfig()).toBeInstanceOf(SearchConfigResponse); + }); + }); +});