diff --git a/config/custom-environment-variables.yml b/config/custom-environment-variables.yml
index bbe982eadff33..21b529e373726 100644
--- a/config/custom-environment-variables.yml
+++ b/config/custom-environment-variables.yml
@@ -31,6 +31,8 @@ public:
__format: 'json'
services:
+ bitbucket:
+ authorizedOrigins: 'BITBUCKET_ORIGINS'
bitbucketServer:
authorizedOrigins: 'BITBUCKET_SERVER_ORIGINS'
drone:
diff --git a/config/default.yml b/config/default.yml
index cea2edad7b60d..1edf706af3fea 100644
--- a/config/default.yml
+++ b/config/default.yml
@@ -14,6 +14,8 @@ public:
cors:
allowedOrigin: []
services:
+ bitbucket:
+ authorizedOrigins: 'https://bitbucket.org'
github:
baseUri: 'https://api.github.com'
debug:
diff --git a/core/base-service/base-graphql.js b/core/base-service/base-graphql.js
index 650e6fb549a82..e70a81c0d4c52 100644
--- a/core/base-service/base-graphql.js
+++ b/core/base-service/base-graphql.js
@@ -27,6 +27,8 @@ class BaseGraphqlService extends BaseService {
return parseJson(buffer)
}
+ static headers = { Accept: 'application/json' }
+
/**
* Request data from an upstream GraphQL API,
* parse it and validate against a schema
@@ -76,7 +78,7 @@ class BaseGraphqlService extends BaseService {
transformErrors = defaultTransformErrors,
}) {
const mergedOptions = {
- ...{ headers: { Accept: 'application/json' } },
+ ...{ headers: this.constructor.headers },
...options,
}
mergedOptions.method = 'POST'
diff --git a/core/base-service/base-json.js b/core/base-service/base-json.js
index 281eebe6b4778..c87bafe038b2c 100644
--- a/core/base-service/base-json.js
+++ b/core/base-service/base-json.js
@@ -21,6 +21,8 @@ class BaseJsonService extends BaseService {
return parseJson(buffer)
}
+ static headers = { Accept: 'application/json' }
+
/**
* Request data from an upstream API serving JSON,
* parse it and validate against a schema
@@ -54,7 +56,7 @@ class BaseJsonService extends BaseService {
logErrors = [429],
}) {
const mergedOptions = {
- ...{ headers: { Accept: 'application/json' } },
+ ...{ headers: this.constructor.headers },
...options,
}
const { buffer } = await this._request({
diff --git a/core/base-service/base-svg-scraping.js b/core/base-service/base-svg-scraping.js
index 7eacea6f7dab6..8d992353cb0a4 100644
--- a/core/base-service/base-svg-scraping.js
+++ b/core/base-service/base-svg-scraping.js
@@ -42,6 +42,8 @@ class BaseSvgScrapingService extends BaseService {
}
}
+ static headers = { Accept: 'image/svg+xml' }
+
/**
* Request data from an endpoint serving SVG,
* parse a value from it and validate against a schema
@@ -79,7 +81,7 @@ class BaseSvgScrapingService extends BaseService {
}) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
const mergedOptions = {
- ...{ headers: { Accept: 'image/svg+xml' } },
+ ...{ headers: this.constructor.headers },
...options,
}
const { buffer } = await this._request({
diff --git a/core/base-service/base-toml.js b/core/base-service/base-toml.js
index 435f6bafbefea..883423b37abe8 100644
--- a/core/base-service/base-toml.js
+++ b/core/base-service/base-toml.js
@@ -14,6 +14,14 @@ import trace from './trace.js'
* @abstract
*/
class BaseTomlService extends BaseService {
+ static headers = {
+ Accept:
+ // the official header should be application/toml - see https://toml.io/en/v1.0.0#mime-type
+ // but as this is not registered here https://www.iana.org/assignments/media-types/media-types.xhtml
+ // some apps use other mime-type like application/x-toml, text/plain etc....
+ 'text/x-toml, text/toml, application/x-toml, application/toml, text/plain',
+ }
+
/**
* Request data from an upstream API serving TOML,
* parse it and validate against a schema
@@ -48,15 +56,7 @@ class BaseTomlService extends BaseService {
}) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
const mergedOptions = {
- ...{
- headers: {
- Accept:
- // the official header should be application/toml - see https://toml.io/en/v1.0.0#mime-type
- // but as this is not registered here https://www.iana.org/assignments/media-types/media-types.xhtml
- // some apps use other mime-type like application/x-toml, text/plain etc....
- 'text/x-toml, text/toml, application/x-toml, application/toml, text/plain',
- },
- },
+ ...{ headers: this.constructor.headers },
...options,
}
const { buffer } = await this._request({
diff --git a/core/base-service/base-xml.js b/core/base-service/base-xml.js
index 4424abf608a7f..0afffeb1dc846 100644
--- a/core/base-service/base-xml.js
+++ b/core/base-service/base-xml.js
@@ -15,6 +15,8 @@ import { InvalidResponse } from './errors.js'
* @abstract
*/
class BaseXmlService extends BaseService {
+ static headers = { Accept: 'application/xml, text/xml' }
+
/**
* Request data from an upstream API serving XML,
* parse it and validate against a schema
@@ -53,7 +55,7 @@ class BaseXmlService extends BaseService {
}) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
const mergedOptions = {
- ...{ headers: { Accept: 'application/xml, text/xml' } },
+ ...{ headers: this.constructor.headers },
...options,
}
const { buffer } = await this._request({
diff --git a/core/base-service/base-yaml.js b/core/base-service/base-yaml.js
index 9cb700a18442b..e0d19a42a270b 100644
--- a/core/base-service/base-yaml.js
+++ b/core/base-service/base-yaml.js
@@ -14,6 +14,11 @@ import trace from './trace.js'
* @abstract
*/
class BaseYamlService extends BaseService {
+ static headers = {
+ Accept:
+ 'text/x-yaml, text/yaml, application/x-yaml, application/yaml, text/plain',
+ }
+
/**
* Request data from an upstream API serving YAML,
* parse it and validate against a schema
@@ -50,12 +55,7 @@ class BaseYamlService extends BaseService {
}) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
const mergedOptions = {
- ...{
- headers: {
- Accept:
- 'text/x-yaml, text/yaml, application/x-yaml, application/yaml, text/plain',
- },
- },
+ ...{ headers: this.constructor.headers },
...options,
}
const { buffer } = await this._request({
diff --git a/core/server/server.js b/core/server/server.js
index e50ae7392b8d9..21c0c83a99a99 100644
--- a/core/server/server.js
+++ b/core/server/server.js
@@ -118,6 +118,7 @@ const publicConfigSchema = Joi.object({
allowedOrigin: Joi.array().items(optionalUrl).required(),
},
services: Joi.object({
+ bitbucket: defaultService,
bitbucketServer: defaultService,
drone: defaultService,
github: {
diff --git a/services/azure-devops/azure-devops-coverage.spec.js b/services/azure-devops/azure-devops-coverage.spec.js
new file mode 100644
index 0000000000000..9c05337bd0db0
--- /dev/null
+++ b/services/azure-devops/azure-devops-coverage.spec.js
@@ -0,0 +1,33 @@
+import { testAuth } from '../test-helpers.js'
+import AzureDevOpsCoverage from './azure-devops-coverage.service.js'
+
+describe('AzureDevOpsCoverage', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ AzureDevOpsCoverage,
+ 'BasicAuth',
+ {
+ coverageData: [
+ {
+ coverageStats: [
+ {
+ label: 'Coverage',
+ total: 95,
+ covered: 93,
+ },
+ ],
+ },
+ ],
+ count: 1,
+ value: [
+ {
+ id: 90395,
+ },
+ ],
+ },
+ { multipleRequests: true },
+ )
+ })
+ })
+})
diff --git a/services/azure-devops/azure-devops-tests.spec.js b/services/azure-devops/azure-devops-tests.spec.js
new file mode 100644
index 0000000000000..c139576779584
--- /dev/null
+++ b/services/azure-devops/azure-devops-tests.spec.js
@@ -0,0 +1,32 @@
+import { testAuth } from '../test-helpers.js'
+import AzureDevOpsTests from './azure-devops-tests.service.js'
+
+describe('AzureDevOpsTests', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ AzureDevOpsTests,
+ 'BasicAuth',
+ {
+ aggregatedResultsAnalysis: {
+ totalTests: 95,
+ resultsByOutcome: {
+ Passed: {
+ count: 93,
+ },
+ },
+ },
+ count: 1,
+ value: [
+ {
+ id: 90395,
+ },
+ ],
+ },
+ {
+ multipleRequests: true,
+ },
+ )
+ })
+ })
+})
diff --git a/services/jenkins/jenkins-build.spec.js b/services/jenkins/jenkins-build.spec.js
index 4bba9b389fd68..ad84c3fc912bd 100644
--- a/services/jenkins/jenkins-build.spec.js
+++ b/services/jenkins/jenkins-build.spec.js
@@ -1,10 +1,18 @@
-import { expect } from 'chai'
-import nock from 'nock'
import { test, forCases, given } from 'sazerac'
import { renderBuildStatusBadge } from '../build-status.js'
-import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
+import { testAuth } from '../test-helpers.js'
import JenkinsBuild from './jenkins-build.service.js'
+const authConfigOverride = {
+ public: {
+ services: {
+ jenkins: {
+ authorizedOrigins: ['https://ci.eclipse.org'],
+ },
+ },
+ },
+}
+
describe('JenkinsBuild', function () {
test(JenkinsBuild.prototype.transform, () => {
forCases([
@@ -57,49 +65,13 @@ describe('JenkinsBuild', function () {
})
describe('auth', function () {
- cleanUpNockAfterEach()
-
- const user = 'admin'
- const pass = 'password'
- const config = {
- public: {
- services: {
- jenkins: {
- authorizedOrigins: ['https://jenkins.ubuntu.com'],
- },
- },
- },
- private: {
- jenkins_user: user,
- jenkins_pass: pass,
- },
- }
-
it('sends the auth information as configured', async function () {
- const scope = nock('https://jenkins.ubuntu.com')
- .get('/server/job/curtin-vmtest-daily-x/api/json?tree=color')
- // This ensures that the expected credentials are actually being sent with the HTTP request.
- // Without this the request wouldn't match and the test would fail.
- .basicAuth({ user, pass })
- .reply(200, { color: 'blue' })
-
- expect(
- await JenkinsBuild.invoke(
- defaultContext,
- config,
- {},
- {
- jobUrl:
- 'https://jenkins.ubuntu.com/server/job/curtin-vmtest-daily-x',
- },
- ),
- ).to.deep.equal({
- label: undefined,
- message: 'passing',
- color: 'brightgreen',
- })
-
- scope.done()
+ return testAuth(
+ JenkinsBuild,
+ 'BasicAuth',
+ { color: 'blue' },
+ { configOverride: authConfigOverride },
+ )
})
})
})
diff --git a/services/jenkins/jenkins-coverage.spec.js b/services/jenkins/jenkins-coverage.spec.js
new file mode 100644
index 0000000000000..eb8a11ac57931
--- /dev/null
+++ b/services/jenkins/jenkins-coverage.spec.js
@@ -0,0 +1,25 @@
+import { testAuth } from '../test-helpers.js'
+import JenkinsCoverage from './jenkins-coverage.service.js'
+
+const authConfigOverride = {
+ public: {
+ services: {
+ jenkins: {
+ authorizedOrigins: ['https://ci-maven.apache.org'],
+ },
+ },
+ },
+}
+
+describe('JenkinsCoverage', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ JenkinsCoverage,
+ 'BasicAuth',
+ { instructionCoverage: { percentage: 93 } },
+ { configOverride: authConfigOverride },
+ )
+ })
+ })
+})
diff --git a/services/jenkins/jenkins-tests.spec.js b/services/jenkins/jenkins-tests.spec.js
new file mode 100644
index 0000000000000..14eaa5b90a602
--- /dev/null
+++ b/services/jenkins/jenkins-tests.spec.js
@@ -0,0 +1,27 @@
+import { testAuth } from '../test-helpers.js'
+import JenkinsTests from './jenkins-tests.service.js'
+
+const authConfigOverride = {
+ public: {
+ services: {
+ jenkins: {
+ authorizedOrigins: ['https://jenkins.sqlalchemy.org'],
+ },
+ },
+ },
+}
+
+describe('JenkinsTests', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ JenkinsTests,
+ 'BasicAuth',
+ { actions: [{ totalCount: 3, failCount: 2, skipCount: 1 }] },
+ {
+ configOverride: authConfigOverride,
+ },
+ )
+ })
+ })
+})
diff --git a/services/jira/jira-issue.spec.js b/services/jira/jira-issue.spec.js
index 4d3cbfdd3911f..d70aa6aa1995d 100644
--- a/services/jira/jira-issue.spec.js
+++ b/services/jira/jira-issue.spec.js
@@ -1,35 +1,22 @@
-import { expect } from 'chai'
-import nock from 'nock'
-import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
+import { testAuth } from '../test-helpers.js'
import JiraIssue from './jira-issue.service.js'
-import { user, pass, host, config } from './jira-test-helpers.js'
+import { config } from './jira-test-helpers.js'
describe('JiraIssue', function () {
- cleanUpNockAfterEach()
-
- it('sends the auth information as configured', async function () {
- const scope = nock(`https://${host}`)
- .get(`/rest/api/2/issue/${encodeURIComponent('secure-234')}`)
- // This ensures that the expected credentials are actually being sent with the HTTP request.
- // Without this the request wouldn't match and the test would fail.
- .basicAuth({ user, pass })
- .reply(200, { fields: { status: { name: 'in progress' } } })
-
- expect(
- await JiraIssue.invoke(
- defaultContext,
- config,
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ JiraIssue,
+ 'BasicAuth',
{
- issueKey: 'secure-234',
+ fields: {
+ status: {
+ name: 'in progress',
+ },
+ },
},
- { baseUrl: `https://${host}` },
- ),
- ).to.deep.equal({
- label: 'secure-234',
- message: 'in progress',
- color: 'lightgrey',
+ { configOverride: config },
+ )
})
-
- scope.done()
})
})
diff --git a/services/jira/jira-sprint.spec.js b/services/jira/jira-sprint.spec.js
index 33a647ed7c371..7ec69e9a6154a 100644
--- a/services/jira/jira-sprint.spec.js
+++ b/services/jira/jira-sprint.spec.js
@@ -1,49 +1,22 @@
-import { expect } from 'chai'
-import nock from 'nock'
-import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
+import { testAuth } from '../test-helpers.js'
import JiraSprint from './jira-sprint.service.js'
-import {
- user,
- pass,
- host,
- config,
- sprintId,
- sprintQueryString,
-} from './jira-test-helpers.js'
+import { config } from './jira-test-helpers.js'
describe('JiraSprint', function () {
- cleanUpNockAfterEach()
-
- it('sends the auth information as configured', async function () {
- const scope = nock(`https://${host}`)
- .get('/jira/rest/api/2/search')
- .query(sprintQueryString)
- // This ensures that the expected credentials are actually being sent with the HTTP request.
- // Without this the request wouldn't match and the test would fail.
- .basicAuth({ user, pass })
- .reply(200, {
- total: 2,
- issues: [
- { fields: { resolution: { name: 'done' } } },
- { fields: { resolution: { name: 'Unresolved' } } },
- ],
- })
-
- expect(
- await JiraSprint.invoke(
- defaultContext,
- config,
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ JiraSprint,
+ 'BasicAuth',
{
- sprintId,
+ total: 2,
+ issues: [
+ { fields: { resolution: { name: 'done' } } },
+ { fields: { resolution: { name: 'Unresolved' } } },
+ ],
},
- { baseUrl: `https://${host}/jira` },
- ),
- ).to.deep.equal({
- label: 'completion',
- message: '50%',
- color: 'orange',
+ { configOverride: config },
+ )
})
-
- scope.done()
})
})
diff --git a/services/jira/jira-test-helpers.js b/services/jira/jira-test-helpers.js
index e188179146bc5..6cdcdfff8919f 100644
--- a/services/jira/jira-test-helpers.js
+++ b/services/jira/jira-test-helpers.js
@@ -5,18 +5,14 @@ const sprintQueryString = {
maxResults: 500,
}
-const user = 'admin'
-const pass = 'password'
-const host = 'myprivatejira.test'
const config = {
public: {
services: {
jira: {
- authorizedOrigins: [`https://${host}`],
+ authorizedOrigins: ['https://issues.apache.org'],
},
},
},
- private: { jira_user: user, jira_pass: pass },
}
-export { sprintId, sprintQueryString, user, pass, host, config }
+export { sprintId, sprintQueryString, config }
diff --git a/services/nexus/nexus.spec.js b/services/nexus/nexus.spec.js
index 1f4114bfdc61a..e554a9300ea71 100644
--- a/services/nexus/nexus.spec.js
+++ b/services/nexus/nexus.spec.js
@@ -1,6 +1,5 @@
import { expect } from 'chai'
-import nock from 'nock'
-import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
+import { testAuth } from '../test-helpers.js'
import { InvalidResponse, NotFound } from '../index.js'
import Nexus from './nexus.service.js'
@@ -113,52 +112,27 @@ describe('Nexus', function () {
})
describe('auth', function () {
- cleanUpNockAfterEach()
-
- const user = 'admin'
- const pass = 'password'
const config = {
public: {
services: {
nexus: {
- authorizedOrigins: ['https://repository.jboss.org'],
+ authorizedOrigins: ['https://oss.sonatype.org'],
},
},
},
- private: {
- nexus_user: user,
- nexus_pass: pass,
- },
}
-
it('sends the auth information as configured', async function () {
- const scope = nock('https://repository.jboss.org')
- .get('/nexus/service/local/lucene/search')
- .query({ g: 'jboss', a: 'jboss-client' })
- // This ensures that the expected credentials are actually being sent with the HTTP request.
- // Without this the request wouldn't match and the test would fail.
- .basicAuth({ user, pass })
- .reply(200, { data: [{ latestRelease: '2.3.4' }] })
-
- expect(
- await Nexus.invoke(
- defaultContext,
- config,
- {
- repo: 'r',
- groupId: 'jboss',
- artifactId: 'jboss-client',
+ return testAuth(
+ Nexus,
+ 'BasicAuth',
+ {
+ data: {
+ baseVersion: '9.3.95',
+ version: '9.3.95',
},
- {
- server: 'https://repository.jboss.org/nexus',
- },
- ),
- ).to.deep.equal({
- message: 'v2.3.4',
- color: 'blue',
- })
-
- scope.done()
+ },
+ { configOverride: config },
+ )
})
})
})
diff --git a/services/sonar/sonar-coverage.spec.js b/services/sonar/sonar-coverage.spec.js
new file mode 100644
index 0000000000000..c6c2e1e5086b2
--- /dev/null
+++ b/services/sonar/sonar-coverage.spec.js
@@ -0,0 +1,19 @@
+import { testAuth } from '../test-helpers.js'
+import SonarCoverage from './sonar-coverage.service.js'
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
+
+describe('SonarCoverage', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarCoverage,
+ 'BasicAuth',
+ legacySonarResponse('coverage', 95),
+ { configOverride: testAuthConfigOverride },
+ )
+ })
+ })
+})
diff --git a/services/sonar/sonar-documented-api-density.spec.js b/services/sonar/sonar-documented-api-density.spec.js
index a5ca4fe55267b..d8b01594bb1b6 100644
--- a/services/sonar/sonar-documented-api-density.spec.js
+++ b/services/sonar/sonar-documented-api-density.spec.js
@@ -1,5 +1,10 @@
import { test, given } from 'sazerac'
+import { testAuth } from '../test-helpers.js'
import SonarDocumentedApiDensity from './sonar-documented-api-density.service.js'
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
describe('SonarDocumentedApiDensity', function () {
test(SonarDocumentedApiDensity.render, () => {
@@ -24,4 +29,15 @@ describe('SonarDocumentedApiDensity', function () {
color: 'brightgreen',
})
})
+
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarDocumentedApiDensity,
+ 'BasicAuth',
+ legacySonarResponse('density', 93),
+ { configOverride: testAuthConfigOverride },
+ )
+ })
+ })
})
diff --git a/services/sonar/sonar-fortify-rating.spec.js b/services/sonar/sonar-fortify-rating.spec.js
index 4fa12729598b6..b226d64762015 100644
--- a/services/sonar/sonar-fortify-rating.spec.js
+++ b/services/sonar/sonar-fortify-rating.spec.js
@@ -1,51 +1,19 @@
-import { expect } from 'chai'
-import nock from 'nock'
-import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
+import { testAuth } from '../test-helpers.js'
import SonarFortifyRating from './sonar-fortify-rating.service.js'
-
-const token = 'abc123def456'
-const config = {
- public: {
- services: {
- sonar: { authorizedOrigins: ['http://sonar.petalslink.com'] },
- },
- },
- private: {
- sonarqube_token: token,
- },
-}
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
describe('SonarFortifyRating', function () {
- cleanUpNockAfterEach()
-
- it('sends the auth information as configured', async function () {
- const scope = nock('http://sonar.petalslink.com')
- .get('/api/measures/component')
- .query({
- componentKey: 'org.ow2.petals:petals-se-ase',
- metricKeys: 'fortify-security-rating',
- })
- // This ensures that the expected credentials are actually being sent with the HTTP request.
- // Without this the request wouldn't match and the test would fail.
- .basicAuth({ user: token })
- .reply(200, {
- component: {
- measures: [{ metric: 'fortify-security-rating', value: 4 }],
- },
- })
-
- expect(
- await SonarFortifyRating.invoke(
- defaultContext,
- config,
- { component: 'org.ow2.petals:petals-se-ase' },
- { server: 'http://sonar.petalslink.com' },
- ),
- ).to.deep.equal({
- color: 'green',
- message: '4/5',
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarFortifyRating,
+ 'BasicAuth',
+ legacySonarResponse('fortify-security-rating', 4),
+ { configOverride: testAuthConfigOverride },
+ )
})
-
- scope.done()
})
})
diff --git a/services/sonar/sonar-generic.spec.js b/services/sonar/sonar-generic.spec.js
new file mode 100644
index 0000000000000..d1cf759fef550
--- /dev/null
+++ b/services/sonar/sonar-generic.spec.js
@@ -0,0 +1,29 @@
+import { testAuth } from '../test-helpers.js'
+import SonarGeneric from './sonar-generic.service.js'
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
+
+describe('SonarGeneric', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarGeneric,
+ 'BasicAuth',
+ legacySonarResponse('test', 903),
+ {
+ configOverride: testAuthConfigOverride,
+ exampleOverride: {
+ component: 'test',
+ metricName: 'test',
+ branch: 'home',
+ server:
+ testAuthConfigOverride.public.services.sonar.authorizedOrigins[0],
+ sonarVersion: '4.2',
+ },
+ },
+ )
+ })
+ })
+})
diff --git a/services/sonar/sonar-quality-gate.spec.js b/services/sonar/sonar-quality-gate.spec.js
index aa694ae066ba4..e9bc91fd28afd 100644
--- a/services/sonar/sonar-quality-gate.spec.js
+++ b/services/sonar/sonar-quality-gate.spec.js
@@ -1,5 +1,10 @@
import { test, given } from 'sazerac'
+import { testAuth } from '../test-helpers.js'
import SonarQualityGate from './sonar-quality-gate.service.js'
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
describe('SonarQualityGate', function () {
test(SonarQualityGate.render, () => {
@@ -12,4 +17,15 @@ describe('SonarQualityGate', function () {
color: 'critical',
})
})
+
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarQualityGate,
+ 'BasicAuth',
+ legacySonarResponse('alert_status', 'OK'),
+ { configOverride: testAuthConfigOverride },
+ )
+ })
+ })
})
diff --git a/services/sonar/sonar-spec-helpers.js b/services/sonar/sonar-spec-helpers.js
new file mode 100644
index 0000000000000..1d142f4800576
--- /dev/null
+++ b/services/sonar/sonar-spec-helpers.js
@@ -0,0 +1,36 @@
+import SonarBase from './sonar-base.js'
+import { openApiQueryParams } from './sonar-helpers.js'
+
+const testAuthConfigOverride = {
+ public: {
+ services: {
+ [SonarBase.auth.serviceKey]: {
+ authorizedOrigins: [
+ openApiQueryParams.find(v => v.name === 'server').example,
+ ],
+ },
+ },
+ },
+}
+
+/**
+ * Returns a legacy sonar api response with desired key and value
+ *
+ * @param {string} key Key for the response value
+ * @param {string|number} val Value to assign to response key
+ * @returns {object} Sonar api response
+ */
+function legacySonarResponse(key, val) {
+ return [
+ {
+ msr: [
+ {
+ key,
+ val,
+ },
+ ],
+ },
+ ]
+}
+
+export { testAuthConfigOverride, legacySonarResponse }
diff --git a/services/sonar/sonar-tech-debt.spec.js b/services/sonar/sonar-tech-debt.spec.js
index b6ef2009205bd..a636f8c78facb 100644
--- a/services/sonar/sonar-tech-debt.spec.js
+++ b/services/sonar/sonar-tech-debt.spec.js
@@ -1,5 +1,10 @@
import { test, given } from 'sazerac'
+import { testAuth } from '../test-helpers.js'
import SonarTechDebt from './sonar-tech-debt.service.js'
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
describe('SonarTechDebt', function () {
test(SonarTechDebt.render, () => {
@@ -29,4 +34,15 @@ describe('SonarTechDebt', function () {
color: 'red',
})
})
+
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarTechDebt,
+ 'BasicAuth',
+ legacySonarResponse('sqale_debt_ratio', 95),
+ { configOverride: testAuthConfigOverride },
+ )
+ })
+ })
})
diff --git a/services/sonar/sonar-tests.spec.js b/services/sonar/sonar-tests.spec.js
index 81909602e18d3..9dd7681076bc1 100644
--- a/services/sonar/sonar-tests.spec.js
+++ b/services/sonar/sonar-tests.spec.js
@@ -1,5 +1,10 @@
import { test, given } from 'sazerac'
+import { testAuth } from '../test-helpers.js'
import { SonarTests } from './sonar-tests.service.js'
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
describe('SonarTests', function () {
test(SonarTests.render, () => {
@@ -34,4 +39,15 @@ describe('SonarTests', function () {
color: 'red',
})
})
+
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarTests,
+ 'BasicAuth',
+ legacySonarResponse('tests', 95),
+ { configOverride: testAuthConfigOverride },
+ )
+ })
+ })
})
diff --git a/services/sonar/sonar-violations.spec.js b/services/sonar/sonar-violations.spec.js
index 08aa8279125a9..2c24087279bc2 100644
--- a/services/sonar/sonar-violations.spec.js
+++ b/services/sonar/sonar-violations.spec.js
@@ -1,6 +1,11 @@
import { test, given } from 'sazerac'
import { metric } from '../text-formatters.js'
+import { testAuth } from '../test-helpers.js'
import SonarViolations from './sonar-violations.service.js'
+import {
+ legacySonarResponse,
+ testAuthConfigOverride,
+} from './sonar-spec-helpers.js'
describe('SonarViolations', function () {
test(SonarViolations.render, () => {
@@ -110,4 +115,18 @@ describe('SonarViolations', function () {
color: 'red',
})
})
+
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SonarViolations,
+ 'BasicAuth',
+ legacySonarResponse('violations', 95),
+ {
+ configOverride: testAuthConfigOverride,
+ exampleOverride: { format: 'short' },
+ },
+ )
+ })
+ })
})
diff --git a/services/symfony/symfony-insight-grade.spec.js b/services/symfony/symfony-insight-grade.spec.js
new file mode 100644
index 0000000000000..28bd368c062a6
--- /dev/null
+++ b/services/symfony/symfony-insight-grade.spec.js
@@ -0,0 +1,17 @@
+import { testAuth } from '../test-helpers.js'
+import SymfonyInsightGrade from './symfony-insight-grade.service.js'
+
+describe('SymfonyInsightGrade', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SymfonyInsightGrade,
+ 'BasicAuth',
+ `
+ gold
+ finished
+ `,
+ )
+ })
+ })
+})
diff --git a/services/symfony/symfony-insight-stars.spec.js b/services/symfony/symfony-insight-stars.spec.js
new file mode 100644
index 0000000000000..e1a3deffb7502
--- /dev/null
+++ b/services/symfony/symfony-insight-stars.spec.js
@@ -0,0 +1,17 @@
+import { testAuth } from '../test-helpers.js'
+import SymfonyInsightStars from './symfony-insight-stars.service.js'
+
+describe('SymfonyInsightStars', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SymfonyInsightStars,
+ 'BasicAuth',
+ `
+ gold
+ finished
+ `,
+ )
+ })
+ })
+})
diff --git a/services/symfony/symfony-insight-violations.spec.js b/services/symfony/symfony-insight-violations.spec.js
new file mode 100644
index 0000000000000..0c20a3838a785
--- /dev/null
+++ b/services/symfony/symfony-insight-violations.spec.js
@@ -0,0 +1,16 @@
+import { testAuth } from '../test-helpers.js'
+import SymfonyInsightViolations from './symfony-insight-violations.service.js'
+
+describe('SymfonyInsightViolations', function () {
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ SymfonyInsightViolations,
+ 'BasicAuth',
+ `
+ finished
+ `,
+ )
+ })
+ })
+})
diff --git a/services/teamcity/teamcity-build.spec.js b/services/teamcity/teamcity-build.spec.js
index 1e207bce56370..91ba4c6a85253 100644
--- a/services/teamcity/teamcity-build.spec.js
+++ b/services/teamcity/teamcity-build.spec.js
@@ -1,39 +1,16 @@
-import { expect } from 'chai'
-import nock from 'nock'
-import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
+import { testAuth } from '../test-helpers.js'
import TeamCityBuild from './teamcity-build.service.js'
-import { user, pass, host, config } from './teamcity-test-helpers.js'
+import { config } from './teamcity-test-helpers.js'
describe('TeamCityBuild', function () {
- cleanUpNockAfterEach()
-
- it('sends the auth information as configured', async function () {
- const scope = nock(`https://${host}`)
- .get(`/app/rest/builds/${encodeURIComponent('buildType:(id:bt678)')}`)
- // This ensures that the expected credentials are actually being sent with the HTTP request.
- // Without this the request wouldn't match and the test would fail.
- .basicAuth({ user, pass })
- .reply(200, {
- status: 'FAILURE',
- statusText:
- 'Tests failed: 1 (1 new), passed: 50246, ignored: 1, muted: 12',
- })
-
- expect(
- await TeamCityBuild.invoke(
- defaultContext,
- config,
- {
- verbosity: 'e',
- buildId: 'bt678',
- },
- { server: `https://${host}` },
- ),
- ).to.deep.equal({
- message: 'tests failed: 1 (1 new), passed: 50246, ignored: 1, muted: 12',
- color: 'red',
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ TeamCityBuild,
+ 'BasicAuth',
+ { status: 'SUCCESS', statusText: 'Success' },
+ { configOverride: config },
+ )
})
-
- scope.done()
})
})
diff --git a/services/teamcity/teamcity-coverage.spec.js b/services/teamcity/teamcity-coverage.spec.js
index 0e7bbae64d3da..7bec5ef4c774e 100644
--- a/services/teamcity/teamcity-coverage.spec.js
+++ b/services/teamcity/teamcity-coverage.spec.js
@@ -1,44 +1,21 @@
-import { expect } from 'chai'
-import nock from 'nock'
-import { cleanUpNockAfterEach, defaultContext } from '../test-helpers.js'
+import { testAuth } from '../test-helpers.js'
import TeamCityCoverage from './teamcity-coverage.service.js'
-import { user, pass, host, config } from './teamcity-test-helpers.js'
+import { config } from './teamcity-test-helpers.js'
describe('TeamCityCoverage', function () {
- cleanUpNockAfterEach()
-
- it('sends the auth information as configured', async function () {
- const scope = nock(`https://${host}`)
- .get(
- `/app/rest/builds/${encodeURIComponent(
- 'buildType:(id:bt678)',
- )}/statistics`,
- )
- .query({})
- // This ensures that the expected credentials are actually being sent with the HTTP request.
- // Without this the request wouldn't match and the test would fail.
- .basicAuth({ user, pass })
- .reply(200, {
- property: [
- { name: 'CodeCoverageAbsSCovered', value: '82' },
- { name: 'CodeCoverageAbsSTotal', value: '100' },
- ],
- })
-
- expect(
- await TeamCityCoverage.invoke(
- defaultContext,
- config,
+ describe('auth', function () {
+ it('sends the auth information as configured', async function () {
+ return testAuth(
+ TeamCityCoverage,
+ 'BasicAuth',
{
- buildId: 'bt678',
+ property: [
+ { name: 'CodeCoverageAbsSCovered', value: '93' },
+ { name: 'CodeCoverageAbsSTotal', value: '95' },
+ ],
},
- { server: 'https://mycompany.teamcity.com' },
- ),
- ).to.deep.equal({
- message: '82%',
- color: 'yellowgreen',
+ { configOverride: config },
+ )
})
-
- scope.done()
})
})
diff --git a/services/teamcity/teamcity-test-helpers.js b/services/teamcity/teamcity-test-helpers.js
index 655a16cbd94fb..a3051df624a82 100644
--- a/services/teamcity/teamcity-test-helpers.js
+++ b/services/teamcity/teamcity-test-helpers.js
@@ -1,18 +1,13 @@
-const user = 'admin'
-const pass = 'password'
-const host = 'mycompany.teamcity.com'
+import TeamCityBase from './teamcity-base.js'
+
const config = {
public: {
services: {
- teamcity: {
- authorizedOrigins: [`https://${host}`],
+ [TeamCityBase.auth.serviceKey]: {
+ authorizedOrigins: ['https://teamcity.jetbrains.com'],
},
},
},
- private: {
- teamcity_user: user,
- teamcity_pass: pass,
- },
}
-export { user, pass, host, config }
+export { config }
diff --git a/services/test-helpers.js b/services/test-helpers.js
index b1368389c33c5..de76ac53829ca 100644
--- a/services/test-helpers.js
+++ b/services/test-helpers.js
@@ -1,3 +1,4 @@
+import _ from 'lodash'
import dayjs from 'dayjs'
import { expect } from 'chai'
import nock from 'nock'
@@ -37,6 +38,7 @@ function noToken(serviceClass) {
* Retrieves an example set of parameters for invoking a service class using OpenAPI example of that class.
*
* @param {BaseService} serviceClass The service class containing OpenAPI specifications.
+ * @param {'path'|'query'} paramType The type of params to extract, may be path params or query params.
* @returns {object} An object with call params to use with a service invoke of the first OpenAPI example.
* @throws {TypeError} - Throws a TypeError if the input `serviceClass` is not an instance of BaseService,
* or if it lacks the expected structure.
@@ -48,17 +50,21 @@ function noToken(serviceClass) {
* // Output: { stackexchangesite: 'stackoverflow', query: '123' }
* StackExchangeReputation.invoke(defaultContext, config, example)
*/
-function getBadgeExampleCall(serviceClass) {
+function getBadgeExampleCall(serviceClass, paramType) {
if (!(serviceClass.prototype instanceof BaseService)) {
throw new TypeError(
'Invalid serviceClass: Must be an instance of BaseService.',
)
}
- if (!serviceClass.openApi) {
- throw new TypeError(
- `Missing OpenAPI in service class ${serviceClass.name}.`,
+ if (Object.keys(serviceClass.openApi).length === 0) {
+ console.warn(
+ `Missing OpenAPI in service class ${serviceClass.name}. Make sure to use exampleOverride in testAuth.`,
)
+ return {}
+ }
+ if (!['path', 'query'].includes(paramType)) {
+ throw new TypeError('Invalid paramType: Must be path or query.')
}
const firstOpenapiPath = Object.keys(serviceClass.openApi)[0]
@@ -73,7 +79,13 @@ function getBadgeExampleCall(serviceClass) {
// reformat structure for serviceClass.invoke
const exampleInvokeParams = firstOpenapiExampleParams.reduce((acc, obj) => {
- acc[obj.name] = obj.example
+ if (obj.in === paramType) {
+ let example = obj.example
+ if (obj?.schema?.type === 'boolean') {
+ example = example || ''
+ }
+ acc[obj.name] = example
+ }
return acc
}, {})
@@ -88,6 +100,7 @@ function getBadgeExampleCall(serviceClass) {
* @param {string} fakeKey - The fake key to be used in the configuration.
* @param {string} fakeUser - Optional, The fake user to be used in the configuration.
* @param {string} fakeauthorizedOrigins - authorizedOrigins to add to config.
+ * @param {object} authOverride Return result with overrid params.
* @returns {object} - The configuration object.
* @throws {TypeError} - Throws an error if the input is not a class.
*/
@@ -96,6 +109,7 @@ function generateFakeConfig(
fakeKey,
fakeUser,
fakeauthorizedOrigins,
+ authOverride,
) {
if (
!serviceClass ||
@@ -106,37 +120,38 @@ function generateFakeConfig(
'Invalid serviceClass: Must be an instance of BaseService.',
)
}
- if (!fakeKey || typeof fakeKey !== 'string') {
- throw new TypeError('Invalid fakeKey: Must be a String.')
+ if (!fakeKey && !fakeUser) {
+ throw new TypeError('Must provide at least one: fakeKey or fakeUser.')
}
if (!fakeauthorizedOrigins || !Array.isArray(fakeauthorizedOrigins)) {
throw new TypeError('Invalid fakeauthorizedOrigins: Must be an array.')
}
- if (!serviceClass.auth) {
- throw new Error(`Missing auth for ${serviceClass.name}.`)
+ const auth = { ...serviceClass.auth, ...authOverride }
+ if (Object.keys(auth).length === 0) {
+ throw new Error(`Auth empty for ${serviceClass.name}.`)
}
- if (!serviceClass.auth.passKey) {
+ if (fakeKey && !auth.passKey) {
+ throw new Error(`Missing auth.passKey for ${serviceClass.name}.`)
+ }
+ if (fakeKey && typeof fakeKey !== 'string') {
throw new Error(`Missing auth.passKey for ${serviceClass.name}.`)
}
// Extract the passKey property from auth, or use a default if not present
- const passKeyProperty = serviceClass.auth.passKey
- let passUserProperty = 'placeholder'
- if (fakeUser) {
- if (typeof fakeKey !== 'string') {
- throw new TypeError('Invalid fakeUser: Must be a String.')
- }
- if (!serviceClass.auth.userKey) {
- throw new Error(`Missing auth.userKey for ${serviceClass.name}.`)
- }
- passUserProperty = serviceClass.auth.userKey
+ const passKeyProperty = auth.passKey ? auth.passKey : undefined
+ if (fakeUser && typeof fakeUser !== 'string') {
+ throw new TypeError('Invalid fakeUser: Must be a String.')
+ }
+ if (fakeUser && !auth.userKey) {
+ throw new Error(`Missing auth.userKey for ${serviceClass.name}.`)
}
+ const passUserProperty = auth.userKey ? auth.userKey : undefined
// Build and return the configuration object with the fake key
return {
public: {
services: {
- [serviceClass.auth.serviceKey]: {
+ [auth.serviceKey]: {
authorizedOrigins: fakeauthorizedOrigins,
},
},
@@ -152,6 +167,8 @@ function generateFakeConfig(
* Returns the first auth origin found for a provided service class.
*
* @param {BaseService} serviceClass The service class to find the authorized origins.
+ * @param {object} authOverride Return result with overrid params.
+ * @param {object} configOverride - Override the config.
* @throws {TypeError} - Throws a TypeError if the input `serviceClass` is not an instance of BaseService.
* @returns {string} First auth origin found.
*
@@ -160,7 +177,7 @@ function generateFakeConfig(
* getServiceClassAuthOrigin(Obs)
* // outputs 'https://api.opensuse.org'
*/
-function getServiceClassAuthOrigin(serviceClass) {
+function getServiceClassAuthOrigin(serviceClass, authOverride, configOverride) {
if (
!serviceClass ||
!serviceClass.prototype ||
@@ -170,12 +187,17 @@ function getServiceClassAuthOrigin(serviceClass) {
`Invalid serviceClass ${serviceClass}: Must be an instance of BaseService.`,
)
}
- if (serviceClass.auth.authorizedOrigins) {
+ const auth = { ...serviceClass.auth, ...authOverride }
+ if (auth.authorizedOrigins) {
return serviceClass.auth.authorizedOrigins
} else {
- return [
- config.public.services[serviceClass.auth.serviceKey].authorizedOrigins,
- ]
+ const mergedConfig = _.merge(runnerConfig, configOverride)
+ if (!mergedConfig.public.services[auth.serviceKey]) {
+ throw new TypeError(
+ `Missing service key defenition for ${auth.serviceKey}: Use an override if applicable.`,
+ )
+ }
+ return [mergedConfig.public.services[auth.serviceKey].authorizedOrigins]
}
}
@@ -201,12 +223,15 @@ function fakeJwtToken() {
* @param {'BasicAuth'|'ApiKeyHeader'|'BearerAuthHeader'|'QueryStringAuth'|'JwtAuth'} authMethod The auth method of the tested service class.
* @param {object} dummyResponse An object containing the dummy response by the server.
* @param {object} options - Additional options for non default keys and content-type of the dummy response.
- * @param {'application/xml'|'application/json'} options.contentType - Header for the response, may contain any string.
* @param {string} options.apiHeaderKey - Non default header for ApiKeyHeader auth.
* @param {string} options.bearerHeaderKey - Non default bearer header prefix for BearerAuthHeader.
* @param {string} options.queryUserKey - QueryStringAuth user key.
* @param {string} options.queryPassKey - QueryStringAuth pass key.
* @param {string} options.jwtLoginEndpoint - jwtAuth Login endpoint.
+ * @param {object} options.exampleOverride - Override example params in test.
+ * @param {object} options.authOverride - Override class auth params.
+ * @param {object} options.configOverride - Override the config for this test.
+ * @param {boolean} options.multipleRequests - For classes that require multiple requests to complete the test.
* @throws {TypeError} - Throws a TypeError if the input `serviceClass` is not an instance of BaseService,
* or if `serviceClass` is missing authorizedOrigins.
*
@@ -221,39 +246,72 @@ async function testAuth(serviceClass, authMethod, dummyResponse, options = {}) {
)
}
- cleanUpNockAfterEach()
-
- const fakeUser = serviceClass.auth.userKey ? 'fake-user' : undefined
- const fakeSecret = 'fake-secret'
- const authOrigins = getServiceClassAuthOrigin(serviceClass)
- const config = generateFakeConfig(
- serviceClass,
- fakeSecret,
- fakeUser,
- authOrigins,
- )
- const exampleInvokeParams = getBadgeExampleCall(serviceClass)
- if (options && typeof options !== 'object') {
- throw new TypeError('Invalid options: Must be an object.')
- }
const {
- contentType,
apiHeaderKey = 'x-api-key',
bearerHeaderKey = 'Bearer',
queryUserKey,
queryPassKey,
jwtLoginEndpoint,
+ exampleOverride = {},
+ authOverride,
+ configOverride,
+ multipleRequests = false,
} = options
- if (contentType && typeof contentType !== 'string') {
- throw new TypeError('Invalid contentType: Must be a String.')
- }
- const header = contentType ? { 'Content-Type': contentType } : undefined
+ const header = serviceClass.headers
+ ? { 'Content-Type': serviceClass.headers.Accept.split(', ')[0] }
+ : undefined
if (!apiHeaderKey || typeof apiHeaderKey !== 'string') {
throw new TypeError('Invalid apiHeaderKey: Must be a String.')
}
if (!bearerHeaderKey || typeof bearerHeaderKey !== 'string') {
throw new TypeError('Invalid bearerHeaderKey: Must be a String.')
}
+ if (typeof exampleOverride !== 'object') {
+ throw new TypeError('Invalid exampleOverride: Must be an Object.')
+ }
+ if (authOverride && typeof authOverride !== 'object') {
+ throw new TypeError('Invalid authOverride: Must be an Object.')
+ }
+ if (configOverride && typeof configOverride !== 'object') {
+ throw new TypeError('Invalid configOverride: Must be an Object.')
+ }
+ if (multipleRequests && typeof multipleRequests !== 'boolean') {
+ throw new TypeError('Invalid multipleRequests: Must be an Object.')
+ }
+
+ if (!multipleRequests) {
+ cleanUpNockAfterEach()
+ }
+
+ const auth = { ...serviceClass.auth, ...authOverride }
+ const fakeUser = auth.userKey
+ ? 'fake-user'
+ : auth.defaultToEmptyStringForUser
+ ? ''
+ : undefined
+ const fakeSecret = auth.passKey ? 'fake-secret' : undefined
+ if (!fakeUser && !fakeSecret) {
+ throw new TypeError(
+ `Missing auth pass/user for ${serviceClass.name}. At least one is required.`,
+ )
+ }
+ const authOrigins = getServiceClassAuthOrigin(
+ serviceClass,
+ authOverride,
+ configOverride,
+ )
+ const config = generateFakeConfig(
+ serviceClass,
+ fakeSecret,
+ fakeUser,
+ authOrigins,
+ authOverride,
+ )
+ const exampleInvokePathParams = getBadgeExampleCall(serviceClass, 'path')
+ const exampleInvokeQueryParams = getBadgeExampleCall(serviceClass, 'query')
+ if (options && typeof options !== 'object') {
+ throw new TypeError('Invalid options: Must be an object.')
+ }
if (!authOrigins) {
throw new TypeError(`Missing authorizedOrigins for ${serviceClass.name}.`)
@@ -263,6 +321,9 @@ async function testAuth(serviceClass, authMethod, dummyResponse, options = {}) {
const scopeArr = []
authOrigins.forEach(authOrigin => {
const scope = nock(authOrigin)
+ if (multipleRequests) {
+ scope.persist()
+ }
scopeArr.push(scope)
switch (authMethod) {
case 'BasicAuth':
@@ -328,9 +389,29 @@ async function testAuth(serviceClass, authMethod, dummyResponse, options = {}) {
})
expect(
- await serviceClass.invoke(defaultContext, config, exampleInvokeParams),
+ await serviceClass.invoke(
+ defaultContext,
+ _.merge(config, configOverride),
+ {
+ ...exampleInvokePathParams,
+ ...exampleOverride,
+ },
+ {
+ ...exampleInvokeQueryParams,
+ ...exampleOverride,
+ },
+ ),
).to.not.have.property('isError')
+ // cleapup persistance if we have multiple requests
+ if (multipleRequests) {
+ scopeArr.forEach(scope => scope.persist(false))
+ nock.restore()
+ nock.cleanAll()
+ nock.enableNetConnect()
+ nock.activate()
+ }
+
// if we get 'Mocks not yet satisfied' we have redundent authOrigins or we are missing a critical request
scopeArr.forEach(scope => scope.done())
}