async function testAuth(serviceClass, authMethod, dummyResponse, options = {}) {
  if (!(serviceClass.prototype instanceof BaseService)) {
    throw new TypeError(
      'Invalid serviceClass: Must be an instance of BaseService.',
    )
  }

  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,
  } = options
  if (contentType && typeof contentType !== 'string') {
    throw new TypeError('Invalid contentType: Must be a String.')
  }
  const header = contentType ? { 'Content-Type': contentType } : 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 (!authOrigins) {
    throw new TypeError(`Missing authorizedOrigins for ${serviceClass.name}.`)
  }
  const jwtToken = authMethod === 'JwtAuth' ? fakeJwtToken() : undefined

  const scopeArr = []
  authOrigins.forEach(authOrigin => {
    const scope = nock(authOrigin)
    scopeArr.push(scope)
    switch (authMethod) {
      case 'BasicAuth':
        scope
          .get(/.*/)
          .basicAuth({ user: fakeUser, pass: fakeSecret })
          .reply(200, dummyResponse, header)
        break
      case 'ApiKeyHeader':
        scope
          .get(/.*/)
          .matchHeader(apiHeaderKey, fakeSecret)
          .reply(200, dummyResponse, header)
        break
      case 'BearerAuthHeader':
        scope
          .get(/.*/)
          .matchHeader('Authorization', `${bearerHeaderKey} ${fakeSecret}`)
          .reply(200, dummyResponse, header)
        break
      case 'QueryStringAuth':
        if (!queryPassKey || typeof queryPassKey !== 'string') {
          throw new TypeError('Invalid queryPassKey: Must be a String.')
        }
        scope
          .get(/.*/)
          .query(queryObject => {
            if (queryObject[queryPassKey] !== fakeSecret) {
              return false
            }
            if (queryUserKey) {
              if (typeof queryUserKey !== 'string') {
                throw new TypeError('Invalid queryUserKey: Must be a String.')
              }
              if (queryObject[queryUserKey] !== fakeUser) {
                return false
              }
            }
            return true
          })
          .reply(200, dummyResponse, header)
        break
      case 'JwtAuth': {
        if (!jwtLoginEndpoint || typeof jwtLoginEndpoint !== 'string') {
          throw new TypeError('Invalid jwtLoginEndpoint: Must be a String.')
        }
        if (jwtLoginEndpoint.startsWith(authOrigin)) {
          scope
            .post(/.*/, { username: fakeUser, password: fakeSecret })
            .reply(200, { token: jwtToken })
        } else {
          scope
            .get(/.*/)
            .matchHeader('Authorization', `Bearer ${jwtToken}`)
            .reply(200, dummyResponse, header)
        }
        break
      }

      default:
        throw new TypeError(`Unkown auth method for ${serviceClass.name}.`)
    }
  })

  expect(
    await serviceClass.invoke(defaultContext, config, exampleInvokeParams),
  ).to.not.have.property('isError')

  // if we get 'Mocks not yet satisfied' we have redundent authOrigins or we are missing a critical request
  scopeArr.forEach(scope => scope.done())
}
Test authentication of a badge for it's first OpenAPI example using a provided dummyResponse and authentication method.

@param {BaseService} serviceClass The service class tested.
@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.
@throws {TypeError} - Throws a TypeError if the input `serviceClass` is not an instance of BaseService,
  or if `serviceClass` is missing authorizedOrigins.

@example
// Example usage:
testAuth(StackExchangeReputation, QueryStringAuth, { items: [{ reputation: 8 }] })