Skip to content

Commit

Permalink
test: separate request creation from execution for easier testing
Browse files Browse the repository at this point in the history
  • Loading branch information
romeodemeteriojr committed Jul 11, 2024
1 parent ab1788b commit 5672642
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 81 deletions.
149 changes: 85 additions & 64 deletions packages/zcli-core/src/lib/request.test.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,112 @@
import { expect, test } from '@oclif/test'
import { requestAPI } from './request'
import { createRequestConfig, requestAPI } from './request'
import { HttpStatusCode } from 'axios'
import * as requestUtils from './requestUtils'
import Auth from './auth'
import { Profile } from '../types'

describe('requestAPI', () => {
describe('createRequestConfig', () => {
test
.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456',
ZENDESK_OAUTH_TOKEN: 'good_token'
})
.stub(Auth, 'getLoggedInProfile', () => ({ subdomain: 'z3ntest2', domain: 'example.com' }))
.nock('https://z3ntest.zendesk.com', api => {
api
.get('/api/v2/me')
.reply(function () {
expect(this.req.headers.authorization).to.equal('Bearer good_token')
return [200]
})
.stub(requestUtils, 'getSubdomain', () => 'fake')
.stub(requestUtils, 'getDomain', () => 'fake.com')
.it('should create a request with an OAuth token', async () => {
const req = await createRequestConfig('api/v2/me')
expect(req.headers.Authorization).to.equal('Bearer good_token')
})
.do(async () => {
await requestAPI('api/v2/me', { method: 'GET' })

test
.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_OAUTH_TOKEN: 'good_token'
})
.stub(requestUtils, 'getSubdomain', () => 'fake')
.stub(requestUtils, 'getDomain', () => 'fake.com')
.it('should be able to attach extra headers to request', async () => {
const req = await createRequestConfig('api/v2/me', {
headers: { foo: 'bar' },
method: 'GET'
})
expect(req.headers.Authorization).to.equal('Bearer good_token')
expect(req.headers.foo).to.equal('bar')
})
.it('should make a request with Auth token')

test
.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_DOMAIN: 'expected.com',
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456'
})
.stub(Auth, 'getLoggedInProfile', () => ({ subdomain: 'z3ntest2', domain: 'example.com' }))
.nock('https://z3ntest.zendesk.com', api => {
api
.get('/api/v2/me')
.reply(function () {
expect(this.req.headers.authorization).to.equal('Basic dGVzdEB6ZW5kZXNrLmNvbS90b2tlbjoxMjM0NTY=')
expect(this.req.headers.foo).to.equal('bar')
return [200]
})
.stub(requestUtils, 'getSubdomain', () => 'fake')
.stub(requestUtils, 'getDomain', () => 'fake.com')
.it('should be able to create a request with a Basic auth token', async () => {
const req = await createRequestConfig('api/v2/me', {})
expect(req.headers.Authorization).to.equal('Basic dGVzdEB6ZW5kZXNrLmNvbS90b2tlbjoxMjM0NTY=')
})
.do(async () => {
await requestAPI('api/v2/me', {
headers: { foo: 'bar' },
method: 'GET'
})

test
.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_DOMAIN: 'expected.com',
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456'
})
.stub(requestUtils, 'getSubdomain', () => 'fake')
.stub(requestUtils, 'getDomain', () => 'fake.com')
.it('should create a request with the correct domain', async () => {
const req = await createRequestConfig('api/v2/me')
expect(req.baseURL).to.equal('https://z3ntest.expected.com')
})
.it('should be able to attach extra headers to request')

test.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_DOMAIN: 'example.com',
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456'
})
.stub(Auth, 'getLoggedInProfile', () => ({ subdomain: 'z3ntest2', domain: 'example.com' }))
.nock('https://z3ntest.example.com', api => {
api
.get('/api/v2/me')
.reply(function () {
expect(this.req.headers.authorization).to.equal('Basic dGVzdEB6ZW5kZXNrLmNvbS90b2tlbjoxMjM0NTY=')
return [200]
})
}).do(async () => {
await requestAPI('api/v2/me', {
method: 'GET'
})
test
.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456'
})
.stub(requestUtils, 'getSubdomain', () => 'fake')
.stub(requestUtils, 'getDomain', () => 'fake.com')
.it('should use the default domain if ZENDESK_SUBDOMAIN is provided and ZENDESK_DOMAIN is not provided, not the profile domain', async () => {
const req = await createRequestConfig('api/v2/me')
expect(req.baseURL).to.equal('https://z3ntest.zendesk.com')
})

test
.env({
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456'
})
.stub(requestUtils, 'getSubdomain', () => 'ping')
.stub(requestUtils, 'getDomain', () => 'me.com')
.stub(Auth, 'getLoggedInProfile', () : Profile => ({ subdomain: 'ping', domain: 'me.com' }))
.it('should be able to create auth using profile subdomain and domain', async () => {
const req = await createRequestConfig('api/v2/me', {})
expect(req.baseURL).to.equal('https://ping.me.com')
expect(req.headers.Authorization).to.equal('Basic dGVzdEB6ZW5kZXNrLmNvbS90b2tlbjoxMjM0NTY=')
})
.it('should make a request to the correct domain')
})

test.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456'
})
.stub(Auth, 'getLoggedInProfile', () => ({ subdomain: 'z3ntest2', domain: 'example.com' }))
describe('requestAPI', () => {
test
.env({
ZENDESK_SUBDOMAIN: 'z3ntest',
ZENDESK_EMAIL: 'test@zendesk.com',
ZENDESK_API_TOKEN: '123456',
ZENDESK_OAUTH_TOKEN: 'good_token'
})
.stub(requestUtils, 'getSubdomain', () => 'fake')
.stub(requestUtils, 'getDomain', () => 'fake.com')
.nock('https://z3ntest.zendesk.com', api => {
api
.get('/api/v2/me')
.reply(function () {
expect(this.req.headers.authorization).to.equal('Basic dGVzdEB6ZW5kZXNrLmNvbS90b2tlbjoxMjM0NTY=')
return [200]
})
}).do(async () => {
await requestAPI('api/v2/me', {
method: 'GET'
})
.reply(HttpStatusCode.Ok)
})
.it('should call an http endpoint', async () => {
const response = await requestAPI('api/v2/me', { method: 'GET' })
expect(response.status).to.equal(HttpStatusCode.Ok)
})
.it('should not use the domain stored in current in profile if ZENDESK_SUBDOMAIN is provided and ZENDESK_DOMAIN is not provided')
})
35 changes: 18 additions & 17 deletions packages/zcli-core/src/lib/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ import Auth from './auth'
import { CLIError } from '@oclif/core/lib/errors'
import * as chalk from 'chalk'
import { EnvVars, varExists } from './env'
import { getBaseUrl, getDomain as getProfileDomain, getSubdomain as getProfileSubdomain } from './requestUtils'
import { getBaseUrl, getDomain, getSubdomain } from './requestUtils'

const MSG_ENV_OR_LOGIN = 'Set the following environment variables: ZENDESK_SUBDOMAIN, ZENDESK_EMAIL, ZENDESK_API_TOKEN. Or try logging in via `zcli login -i`'
const ERR_NO_AUTH_TOKEN = `No authorization token found. ${MSG_ENV_OR_LOGIN}`
const ERR_AUTH_FAILED = `Authorization failed. ${MSG_ENV_OR_LOGIN}`
const ERR_ENV_SUBDOMAIN_NOT_FOUND = `No subdomain found. ${MSG_ENV_OR_LOGIN}`

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const requestAPI = async (url: string, options: any = {}, json = false) => {
export const createRequestConfig = async (url: string, options: any = {}) => {
let auth
if (
varExists(EnvVars.SUBDOMAIN, EnvVars.OAUTH_TOKEN) ||
Expand All @@ -25,29 +24,31 @@ export const requestAPI = async (url: string, options: any = {}, json = false) =
auth = new Auth({ secureStore })
}
const [authToken, profileSubdomain, profileDomain] =
await Promise.all([auth.getAuthorizationToken(), getProfileSubdomain(auth), getProfileDomain(auth)])
if (!authToken) throw new CLIError(chalk.red(ERR_NO_AUTH_TOKEN))
await Promise.all([auth.getAuthorizationToken(), getSubdomain(auth), getDomain(auth)])
if (!authToken) throw new CLIError(chalk.red(ERR_AUTH_FAILED))
const subdomain = process.env[EnvVars.SUBDOMAIN] || profileSubdomain
if (!subdomain) throw new CLIError(chalk.red(ERR_ENV_SUBDOMAIN_NOT_FOUND))
// If subdomain is set, use domain env even if not set. Otherwise, use profile domain.
const domain = process.env[EnvVars.SUBDOMAIN] ? process.env[EnvVars.DOMAIN] : profileDomain

if (options.headers) {
options.headers = { Authorization: authToken, ...options.headers }
} else {
options.headers = { Authorization: authToken }
}
if (authToken && subdomain) {
const baseURL = getBaseUrl(subdomain, domain)
return axios.request({
baseURL,
url,
validateStatus: function (status) {
return status < 500
},
...options
})
const baseURL = getBaseUrl(subdomain, domain)

return {
baseURL,
url,
validateStatus: function (status: number) {
return status < 500
},
...options
}
}

throw new CLIError(chalk.red(ERR_AUTH_FAILED))
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const requestAPI = async (url: string, options: any = {}, json = false) => {
const requestConfig = await createRequestConfig(url, options)
return axios.request(requestConfig)
}

0 comments on commit 5672642

Please sign in to comment.