From 4e40fde446c4356891c2bf307f940c40082f695d Mon Sep 17 00:00:00 2001 From: Jaap Rood Date: Tue, 2 Jun 2020 14:48:04 +0200 Subject: [PATCH 1/6] Implement methods on TestingService to fetch capture, coverage report, undocumented endpoints and the spec --- .../ui/src/services/testing/TestingService.ts | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/workspaces/ui/src/services/testing/TestingService.ts b/workspaces/ui/src/services/testing/TestingService.ts index 698fcc73a5..ff35686535 100644 --- a/workspaces/ui/src/services/testing/TestingService.ts +++ b/workspaces/ui/src/services/testing/TestingService.ts @@ -1,4 +1,14 @@ -import { ITestingService, Result, Capture, ok } from '.'; +import { + ITestingService, + Capture, + CoverageReport, + Result, + ok, + err, + NotFoundError, + RfcEventStream, + UndocumentedEndpoint, +} from '.'; import UrlJoin from 'url-join'; // TODO: implement ITestingService @@ -74,4 +84,79 @@ export class TestingService { return ok(payload.captures); } + + async loadCapture(captureId): Promise> { + const response = await this.callApi(`/captures/${captureId}`); + + if (!response.ok) { + if (response.status === 404) { + return err(new NotFoundError()); + } else { + throw new Error('Capture could not be fetched'); + } + } + + const payload = await response.json(); + + return ok(payload); + } + + async loadReport(captureId): Promise> { + const response = await this.callApi( + `/captures/${captureId}/reports/coverage` + ); + + if (!response.ok) { + if (response.status === 404) { + return err(new NotFoundError()); + } else { + throw new Error('CoverageReport for capture could not be fetched'); + } + } + + const payload = await response.json(); + + return ok(payload); + } + + async loadUndocumentedEndpoints( + captureId + ): Promise> { + const response = await this.callApi( + `/captures/${captureId}/reports/undocumented-urls` + ); + + if (!response.ok) { + if (response.status === 404) { + return err(new NotFoundError()); + } else { + throw new Error( + 'Undocumented endpoints for capture could not be fetched' + ); + } + } + + const payload = await response.json(); + return ok(payload); + } + + async loadSpecEvents( + captureId + ): Promise> { + const response = await this.callApi(`/captures/${captureId}/spec`, { + redirect: 'follow', + }); + + if (!response.ok) { + if (response.status === 404) { + return err(new NotFoundError()); + } else { + throw new Error('Spec for capture could not be fetched'); + } + } + + const payload = await response.json(); + + return ok(payload); + } } From d6e2c3fccf5b450ced5059d3ebffc0b946b6b4de Mon Sep 17 00:00:00 2001 From: Jaap Rood Date: Tue, 2 Jun 2020 18:49:08 +0200 Subject: [PATCH 2/6] Follow redirects with the cli-server proxy of the testing service, to prevent CORS issues with S3 signed urls --- workspaces/cli-server/src/server.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/workspaces/cli-server/src/server.ts b/workspaces/cli-server/src/server.ts index 1c5b76497c..e3931445d7 100644 --- a/workspaces/cli-server/src/server.ts +++ b/workspaces/cli-server/src/server.ts @@ -165,6 +165,7 @@ class CliServer { '/api/testing', createProxyMiddleware({ changeOrigin: true, + followRedirects: true, target: this.config.cloudApiBaseUrl, pathRewrite(input, req) { return input.substring(req.baseUrl.length); From 54e5e8115674a35346559f615f96bcaed5e886b4 Mon Sep 17 00:00:00 2001 From: Jaap Rood Date: Tue, 2 Jun 2020 18:49:38 +0200 Subject: [PATCH 3/6] Fix TestingService.loadSpecEvents not following redirects --- workspaces/ui/src/services/testing/TestingService.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/workspaces/ui/src/services/testing/TestingService.ts b/workspaces/ui/src/services/testing/TestingService.ts index ff35686535..1ca6643652 100644 --- a/workspaces/ui/src/services/testing/TestingService.ts +++ b/workspaces/ui/src/services/testing/TestingService.ts @@ -39,6 +39,7 @@ export class TestingService { headers.set('Authorization', `Bearer ${this.authToken}`); const response = await fetch(url, { + ...options, headers, }); @@ -143,9 +144,7 @@ export class TestingService { async loadSpecEvents( captureId ): Promise> { - const response = await this.callApi(`/captures/${captureId}/spec`, { - redirect: 'follow', - }); + const response = await this.callApi(`/captures/${captureId}/spec`); if (!response.ok) { if (response.status === 404) { From 90b5c887513ba0f310a32fa5bfeed83a1e994493 Mon Sep 17 00:00:00 2001 From: Jaap Rood Date: Wed, 3 Jun 2020 10:25:52 +0200 Subject: [PATCH 4/6] Fix returning of CoverageReport with loadReport of TestingService --- workspaces/ui/src/services/testing/TestingService.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/workspaces/ui/src/services/testing/TestingService.ts b/workspaces/ui/src/services/testing/TestingService.ts index 1ca6643652..c2831e9b98 100644 --- a/workspaces/ui/src/services/testing/TestingService.ts +++ b/workspaces/ui/src/services/testing/TestingService.ts @@ -10,6 +10,8 @@ import { UndocumentedEndpoint, } from '.'; import UrlJoin from 'url-join'; +import { StableHasher } from '../../utilities/CoverageUtilities'; +import { opticEngine } from '@useoptic/domain'; // TODO: implement ITestingService export class TestingService { @@ -116,8 +118,14 @@ export class TestingService { } const payload = await response.json(); - - return ok(payload); + const deserialized = opticEngine.CoverageReportJsonDeserializer.fromJs( + payload + ); + const converter = new opticEngine.com.useoptic.CoverageReportConverter( + StableHasher + ); + const serializedReport = converter.toJs(deserialized); + return ok(serializedReport); } async loadUndocumentedEndpoints( From 0ef3ff59ab9f093445cca002b122a1524924d740 Mon Sep 17 00:00:00 2001 From: Jaap Rood Date: Wed, 3 Jun 2020 10:38:45 +0200 Subject: [PATCH 5/6] Allow TestingService to implement ITestingService, but making the last method optional --- workspaces/ui/src/services/testing/TestingService.ts | 2 +- workspaces/ui/src/services/testing/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workspaces/ui/src/services/testing/TestingService.ts b/workspaces/ui/src/services/testing/TestingService.ts index c2831e9b98..4efebc76a8 100644 --- a/workspaces/ui/src/services/testing/TestingService.ts +++ b/workspaces/ui/src/services/testing/TestingService.ts @@ -14,7 +14,7 @@ import { StableHasher } from '../../utilities/CoverageUtilities'; import { opticEngine } from '@useoptic/domain'; // TODO: implement ITestingService -export class TestingService { +export class TestingService implements ITestingService { private authToken: string; private refreshing?: Promise; diff --git a/workspaces/ui/src/services/testing/index.ts b/workspaces/ui/src/services/testing/index.ts index b520a12410..c6f709dda1 100644 --- a/workspaces/ui/src/services/testing/index.ts +++ b/workspaces/ui/src/services/testing/index.ts @@ -9,7 +9,7 @@ export interface ITestingService { captureId: CaptureId ): Promise>; - loadEndpointDiffs( + loadEndpointDiffs?( captureId: CaptureId, pathId: PathId, httpMethod: HttpMethod From 6bbfd64a0586560f7dd714618346d0e13cc400d0 Mon Sep 17 00:00:00 2001 From: Jaap Rood Date: Wed, 3 Jun 2020 12:12:59 +0200 Subject: [PATCH 6/6] Render the correct amount of undocumented endpoints detected in a capture --- workspaces/ui/src/components/testing/ReportSummary.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/workspaces/ui/src/components/testing/ReportSummary.js b/workspaces/ui/src/components/testing/ReportSummary.js index 31603378a7..4917c658b5 100644 --- a/workspaces/ui/src/components/testing/ReportSummary.js +++ b/workspaces/ui/src/components/testing/ReportSummary.js @@ -103,7 +103,7 @@ export default function ReportSummary(props) {

from capturing interactions for build {summary.buildId}{' '} @@ -248,14 +248,18 @@ export default function ReportSummary(props) { } ReportSummary.displayName = 'Testing/ReportSummary'; -function SummaryStats({ totalInteractions, totalDiffs, totalUnmatchedPaths }) { +function SummaryStats({ + totalInteractions, + totalDiffs, + totalUndocumentedEndpoints, +}) { const classes = useStyles(); return ( Optic observed , yielding in and{' '} - . + . ); }