Skip to content

Commit 67f0f03

Browse files
committed
update integration with tests to cover credential preload, getAuth, and logout
1 parent ba8c5bc commit 67f0f03

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

test/api-client.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as sinon from 'sinon'
88
import {stderr} from 'stdout-stderr'
99

1010
import {Command as CommandBase} from '../src/command.js'
11+
import {setCredentialManagerProvider} from '../src/credential-manager.js'
1112
import {RequestId, requestIdHeader} from '../src/request-id.js'
1213
import {restoreCredentialManagerStub, stubCredentialManager} from './helpers/credential-manager-stub.js'
1314

@@ -28,6 +29,7 @@ const test = fancy
2829

2930
describe('api_client', () => {
3031
beforeEach(function () {
32+
nock.cleanAll()
3133
process.env = {}
3234
debug.disable()
3335
api = nock('https://api.heroku.com')
@@ -40,6 +42,56 @@ describe('api_client', () => {
4042
restoreCredentialManagerStub()
4143
})
4244

45+
describe('getAuth', () => {
46+
test
47+
.it('returns token from credential manager', async ctx => {
48+
stubCredentialManager('token-from-store')
49+
const cmd = new Command([], ctx.config)
50+
cmd.config = ctx.config
51+
expect(await cmd.heroku.getAuth()).to.equal('token-from-store')
52+
})
53+
54+
test
55+
.it('returns cached auth when _auth is already set', async ctx => {
56+
stubCredentialManager('ignored-after-cache')
57+
const cmd = new Command([], ctx.config)
58+
cmd.config = ctx.config
59+
cmd.heroku.auth = 'cached-only'
60+
expect(await cmd.heroku.getAuth()).to.equal('cached-only')
61+
})
62+
})
63+
64+
describe('logout', () => {
65+
const removeAuthCalls: {account: string | undefined; hosts: string[]}[] = []
66+
67+
beforeEach(() => {
68+
removeAuthCalls.length = 0
69+
setCredentialManagerProvider({
70+
async getAuth() {
71+
return 'logout-test-token'
72+
},
73+
async removeAuth(account: string | undefined, hosts: string[]) {
74+
removeAuthCalls.push({account, hosts})
75+
},
76+
async saveAuth() {},
77+
})
78+
api.delete('/oauth/sessions/~').reply(200, {})
79+
api.get('/oauth/authorizations').reply(200, [])
80+
api.get('/oauth/authorizations/~').reply(200, {})
81+
})
82+
83+
test
84+
.it('calls removeAuth with api and git hosts after revoking session', async ctx => {
85+
const cmd = new Command([], ctx.config)
86+
cmd.config = ctx.config
87+
await cmd.heroku.logout()
88+
expect(removeAuthCalls).to.have.length(1)
89+
expect(removeAuthCalls[0].account).to.be.undefined
90+
expect(removeAuthCalls[0].hosts).to.deep.equal(['api.heroku.com', 'git.heroku.com'])
91+
expect(cmd.heroku.auth).to.be.undefined
92+
})
93+
})
94+
4395
test
4496
.it('makes an HTTP request', async ctx => {
4597
api = nock('https://api.heroku.com', {

test/command.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ const __dirname = dirname(__filename)
88

99
import {Command} from '../src/command.js'
1010
import * as flags from '../src/flags/index.js'
11+
import {restoreCredentialManagerStub, stubCredentialManager, stubCredentialManagerWithNoCredentials} from './helpers/credential-manager-stub.js'
12+
13+
const {env: processEnv} = process
1114

1215
const test = fancy
1316
.add('config', () => {
@@ -37,6 +40,45 @@ class CommandWithoutPromptInBaseFlags extends TestableCommand {
3740
}
3841

3942
describe('command', () => {
43+
describe('credential preload in init', () => {
44+
beforeEach(() => {
45+
process.env = {}
46+
stubCredentialManager('mypass')
47+
})
48+
49+
afterEach(() => {
50+
process.env = processEnv
51+
restoreCredentialManagerStub()
52+
})
53+
54+
test
55+
.it('populates this.heroku.auth after init so sync checks see the token', async (ctx: any) => {
56+
const cmd = new MyCommand([], ctx.config)
57+
cmd.config = ctx.config
58+
await cmd.init()
59+
expect(cmd.heroku.auth).to.equal('mypass')
60+
})
61+
62+
test
63+
.it('uses HEROKU_API_KEY over credential store in init', async (ctx: any) => {
64+
process.env.HEROKU_API_KEY = 'env-token'
65+
const cmd = new MyCommand([], ctx.config)
66+
cmd.config = ctx.config
67+
await cmd.init()
68+
expect(cmd.heroku.auth).to.equal('env-token')
69+
})
70+
71+
test
72+
.it('leaves this.heroku.auth undefined after init when no credentials exist', async (ctx: any) => {
73+
restoreCredentialManagerStub()
74+
stubCredentialManagerWithNoCredentials()
75+
const cmd = new MyCommand([], ctx.config)
76+
cmd.config = ctx.config
77+
await cmd.init()
78+
expect(cmd.heroku.auth).to.be.undefined
79+
})
80+
})
81+
4082
it('sets app', () => class AppCommand extends Command {
4183
static flags = {
4284
app: flags.app(),

test/helpers/credential-manager-stub.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ export function stubCredentialManager(token = DEFAULT_TOKEN) {
1414
})
1515
}
1616

17+
/** Simulates credential-manager when no token is stored (getAuth throws; APIClient.getAuth returns undefined). */
18+
export function stubCredentialManagerWithNoCredentials() {
19+
setCredentialManagerProvider({
20+
async getAuth() {
21+
throw new Error('No credentials found. Please log in.')
22+
},
23+
async removeAuth() {},
24+
async saveAuth() {},
25+
})
26+
}
27+
1728
export function restoreCredentialManagerStub() {
1829
setCredentialManagerProvider({
1930
getAuth: real.getAuth,

0 commit comments

Comments
 (0)