Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/lib/api/CommercetoolsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,10 @@ export class CommercetoolsApi {
CommercetoolsApi.validateConfig(config)
this.config = config
this.auth = new CommercetoolsAuth(config)
this.endpoints = REGION_URLS[this.config.region]
this.endpoints = {
auth: config.authUrl ?? REGION_URLS[this.config.region].auth,
api: config.apiUrl ?? REGION_URLS[this.config.region].api,
}
this.requestExecutor = getRequestExecutor({
timeoutMs: config.timeoutMs,
httpsAgent: config.httpsAgent,
Expand Down
5 changes: 4 additions & 1 deletion src/lib/auth/CommercetoolsAuthApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ export class CommercetoolsAuthApi {

constructor(config: CommercetoolsAuthApiConfig) {
this.config = config
this.endpoints = REGION_URLS[this.config.region]
this.endpoints = {
auth: config.authUrl ?? REGION_URLS[this.config.region].auth,
api: config.apiUrl ?? REGION_URLS[this.config.region].api,
}
this.requestExecutor = getRequestExecutor({
timeoutMs: config.timeoutMs,
httpsAgent: config.httpsAgent,
Expand Down
16 changes: 16 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ export interface CommercetoolsBaseConfig extends CommercetoolsHooks {
* identify the source of incoming requests.
*/
systemIdentifier?: string

/**
* Optional custom authentication endpoint URL.
* If provided, this will be used instead of the region-based auth URL.
* Useful for pointing to mock servers during integration tests.
* @example 'http://localhost:3000/auth'
*/
authUrl?: string

/**
* Optional custom API endpoint URL.
* If provided, this will be used instead of the region-based API URL.
* Useful for pointing to mock servers during integration tests.
* @example 'http://localhost:3000/api'
*/
apiUrl?: string
}

export interface CommercetoolsHooks {
Expand Down
58 changes: 58 additions & 0 deletions src/test/api/CommercetoolsApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,40 @@ describe('CommercetoolsApi', () => {
it('should bubble up the error if `validateConfig` method throws an error', () => {
expect(() => new CommercetoolsApi({ ...defaultConfig, projectKey: '' })).toThrowError()
})

it('should allow custom API endpoint to be configured', () => {
const api = new CommercetoolsApi({
...defaultConfig,
apiUrl: 'http://localhost:4000/api',
})
expect(api.endpoints.auth).toBe('https://auth.europe-west1.gcp.commercetools.com')
expect(api.endpoints.api).toBe('http://localhost:4000/api')
})

it('should use region-based endpoint when custom apiUrl is not provided', () => {
const api = new CommercetoolsApi(defaultConfig)
expect(api.endpoints.auth).toBe('https://auth.europe-west1.gcp.commercetools.com')
expect(api.endpoints.api).toBe('https://api.europe-west1.gcp.commercetools.com')
})

it('should allow both custom auth and api endpoints to be configured', () => {
const api = new CommercetoolsApi({
...defaultConfig,
authUrl: 'http://localhost:4000/auth',
apiUrl: 'http://localhost:4000/api',
})
expect(api.endpoints.api).toBe('http://localhost:4000/api')
expect(api.endpoints.auth).toBe('http://localhost:4000/auth')
})

it('should pass custom endpoints to auth instance', () => {
const api = new CommercetoolsApi({
...defaultConfig,
authUrl: 'http://localhost:4000/auth',
})
expect(api.auth.config.authUrl).toBe('http://localhost:4000/auth')
expect(api.endpoints.api).toBe('https://api.europe-west1.gcp.commercetools.com')
})
})

describe('extractCommonRequestOptions', () => {
Expand Down Expand Up @@ -159,6 +193,30 @@ describe('CommercetoolsApi', () => {
expect(product).toEqual({ success: true })
})

it('should use custom API endpoint when making requests', async () => {
const customApiUrl = 'http://localhost:4000'
const customAuthUrl = 'http://localhost:4000'
nock(customAuthUrl, {
encodedQueryParams: true,
})
.post('/oauth/token', 'grant_type=client_credentials&scope=defaultClientScope1%3Atest-project-key')
.reply(200, defaultClientGrantResponse)
nock(customApiUrl, {
encodedQueryParams: true,
})
.get('/test-project-key/stores')
.reply(200, { success: true })
const api = new CommercetoolsApi({
...defaultConfig,
apiUrl: customApiUrl,
authUrl: customAuthUrl,
})

const result = await api.queryStores()

expect(result).toEqual({ success: true })
})

it('should make a GET request to the correct endpoint with the passed in parameters in the querystring', async () => {
nock('https://api.europe-west1.gcp.commercetools.com', {
encodedQueryParams: true,
Expand Down
49 changes: 49 additions & 0 deletions src/test/auth/CommercetoolsAuth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@ describe('CommercetoolsAuth', () => {
clientScopes: ['scope3', 'scope4'],
})
})

it('should allow custom auth endpoint to be configured', () => {
const auth = new CommercetoolsAuth({
...defaultConfig,
authUrl: 'http://localhost:4000/auth',
})
expect((auth as any).api.endpoints.auth).toBe('http://localhost:4000/auth')
})

it('should use region-based endpoint when custom authUrl is not provided', () => {
const auth = new CommercetoolsAuth(defaultConfig)
expect((auth as any).api.endpoints.auth).toBe('https://auth.us-east-2.aws.commercetools.com')
})

it('should allow both custom auth and api endpoints to be configured', () => {
const auth = new CommercetoolsAuth({
...defaultConfig,
authUrl: 'http://localhost:4000/auth',
apiUrl: 'http://localhost:4000/api',
})
expect((auth as any).api.endpoints.auth).toBe('http://localhost:4000/auth')
expect((auth as any).api.endpoints.api).toBe('http://localhost:4000/api')
})
})

describe('getClientGrant', () => {
Expand Down Expand Up @@ -157,6 +180,32 @@ describe('CommercetoolsAuth', () => {
clock.uninstall()
})

it('should use custom auth endpoint when making requests', async () => {
const clock = FakeTimers.install({ now: new Date('2020-01-01T09:35:23.000') })
const customAuthUrl = 'http://localhost:4000'
const auth = new CommercetoolsAuth({
...defaultConfig,
authUrl: customAuthUrl,
})
const scope = nock(customAuthUrl, {
encodedQueryParams: true,
})
.post('/oauth/token', 'grant_type=client_credentials&scope=defaultClientScope1%3Atest-project-key')
.reply(200, defaultClientGrantResponse)

const token = await auth.getClientGrant()

scope.isDone()
expect(token).toEqual({
accessToken: 'test-access-token',
scopes: ['scope1', 'scope2', 'scope3'],
expiresIn: 172800,
expiresAt: new Date('2020-01-03T09:35:23.000'),
customerId: '123456',
})
clock.uninstall()
})

it('should wait on a single promise when two requests are made at the same time', async () => {
const clock = FakeTimers.install({ now: new Date('2020-01-01T09:35:23.000') })
const auth = new CommercetoolsAuth(defaultConfig)
Expand Down
52 changes: 52 additions & 0 deletions src/test/auth/CommercetoolsAuthApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,40 @@ describe('CommercetoolsAuthApi', () => {
nock.disableNetConnect()
})

describe('constructor', () => {
it('should use region-based endpoint when custom authUrl is not provided', () => {
const auth = new CommercetoolsAuthApi(defaultConfig)
expect(auth.endpoints.auth).toBe('https://auth.us-east-2.aws.commercetools.com')
})

it('should use custom auth endpoint when provided', () => {
const auth = new CommercetoolsAuthApi({
...defaultConfig,
authUrl: 'http://localhost:4000/auth',
})
expect(auth.endpoints.auth).toBe('http://localhost:4000/auth')
})

it('should use custom auth and api endpoints when both are provided', () => {
const auth = new CommercetoolsAuthApi({
...defaultConfig,
authUrl: 'http://localhost:4000/auth',
apiUrl: 'http://localhost:4000/api',
})
expect(auth.endpoints.auth).toBe('http://localhost:4000/auth')
expect(auth.endpoints.api).toBe('http://localhost:4000/api')
})

it('should fall back to region-based API endpoint when only custom authUrl is provided', () => {
const auth = new CommercetoolsAuthApi({
...defaultConfig,
authUrl: 'http://localhost:4000/auth',
})
expect(auth.endpoints.auth).toBe('http://localhost:4000/auth')
expect(auth.endpoints.api).toBe('https://api.us-east-2.aws.commercetools.com')
})
})

describe('getClientGrant', () => {
it('should call commercetools with the expected request', async () => {
const scope = nock('https://auth.us-east-2.aws.commercetools.com', {
Expand All @@ -49,6 +83,24 @@ describe('CommercetoolsAuthApi', () => {
scope.isDone()
expect(grant).toEqual(defaultResponseToken)
})

it('should use custom auth endpoint when making requests', async () => {
const customAuthUrl = 'http://localhost:4000'
const scope = nock(customAuthUrl, {
encodedQueryParams: true,
})
.post('/oauth/token', 'grant_type=client_credentials&scope=scope1%3Atest-project-key')
.reply(200, defaultResponseToken)
const auth = new CommercetoolsAuthApi({
...defaultConfig,
authUrl: customAuthUrl,
})

const grant = await auth.getClientGrant(['scope1'])

scope.isDone()
expect(grant).toEqual(defaultResponseToken)
})
})

describe('refreshGrant', () => {
Expand Down