Skip to content

Commit

Permalink
fixed unit test errors
Browse files Browse the repository at this point in the history
  • Loading branch information
pragatimodi committed Oct 14, 2023
1 parent c9b6a41 commit 7cb9087
Show file tree
Hide file tree
Showing 6 changed files with 286 additions and 34 deletions.
4 changes: 2 additions & 2 deletions etc/firebase-admin.auth.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,11 +367,11 @@ export class PasskeyConfig {
export class PasskeyConfigManager {
constructor(app: App);
// (undocumented)
createPasskeyConfig(rpId: string, passkeyConfigRequest: PasskeyConfigRequest, tenantId?: string): Promise<PasskeyConfigRequest>;
createPasskeyConfig(rpId: string, passkeyConfigRequest: PasskeyConfigRequest, tenantId?: string): Promise<PasskeyConfig>;
// (undocumented)
getPasskeyConfig(tenantId?: string): Promise<PasskeyConfig>;
// (undocumented)
updatePasskeyConfig(passkeyConfigRequest: PasskeyConfigRequest, tenantId?: string): Promise<PasskeyConfigRequest>;
updatePasskeyConfig(passkeyConfigRequest: PasskeyConfigRequest, tenantId?: string): Promise<PasskeyConfig>;
}

// @public (undocumented)
Expand Down
8 changes: 4 additions & 4 deletions src/auth/passkey-config-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { App } from '../app';
import {
AuthRequestHandler,
} from './auth-api-request';
import {PasskeyConfig, PasskeyConfigClientRequest, PasskeyConfigRequest, PasskeyConfigServerResponse} from './passkey-config';
import { PasskeyConfig, PasskeyConfigClientRequest, PasskeyConfigRequest, PasskeyConfigServerResponse } from './passkey-config';

Check failure on line 20 in src/auth/passkey-config-manager.ts

View workflow job for this annotation

GitHub Actions / build (14.x)

This line has a length of 128. Maximum allowed is 120


export class PasskeyConfigManager {
Expand All @@ -28,7 +28,7 @@ export class PasskeyConfigManager {
}

public getPasskeyConfig(tenantId?: string): Promise<PasskeyConfig> {
return this.authRequestHandler.getPasskeyConfig()
return this.authRequestHandler.getPasskeyConfig(tenantId)
.then((response: PasskeyConfigServerResponse) => {
return new PasskeyConfig(response);
});
Expand All @@ -38,13 +38,13 @@ export class PasskeyConfigManager {
return this.authRequestHandler.updatePasskeyConfig(true, tenantId, passkeyConfigRequest, rpId)
.then((response: PasskeyConfigClientRequest) => {
return new PasskeyConfig(response);
})
});
}

public updatePasskeyConfig(passkeyConfigRequest: PasskeyConfigRequest, tenantId?: string): Promise<PasskeyConfig> {
return this.authRequestHandler.updatePasskeyConfig(false, tenantId, passkeyConfigRequest)
.then((response: PasskeyConfigClientRequest) => {
return new PasskeyConfig(response);
})
});
}
}
22 changes: 11 additions & 11 deletions src/auth/passkey-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,20 @@ export class PasskeyConfig {
);
}
}
if(!validator.isNonEmptyArray(passkeyConfigRequest.expectedOrigins) || !validator.isNonNullObject(passkeyConfigRequest.expectedOrigins)) {
if(!validator.isNonEmptyArray(passkeyConfigRequest.expectedOrigins)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'passkeyConfigRequest.expectedOrigins' must be a valid non-empty array of strings.'`,
);
}
for(const origin in passkeyConfigRequest.expectedOrigins) {
if(!validator.isString(origin)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'passkeyConfigRequest.expectedOrigins' must be a valid non-empty array of strings.'`,
);
}
}
for (const origin of passkeyConfigRequest.expectedOrigins) {
if (!validator.isNonEmptyString(origin)) {
throw new FirebaseAuthError(
AuthClientErrorCode.INVALID_ARGUMENT,
`'passkeyConfigRequest.expectedOrigins' must be a valid non-empty array of strings.'`,
);
}
}
};

public static buildServerRequest(isCreateRequest: boolean, passkeyConfigRequest?: PasskeyConfigRequest, rpId?: string): PasskeyConfigClientRequest {
Expand All @@ -91,8 +91,8 @@ export class PasskeyConfig {
if(isCreateRequest && typeof rpId !== 'undefined') {
request.rpId = rpId;
}
if(typeof request.expectedOrigins !== 'undefined') {
request.expectedOrigins = passkeyConfigRequest?.expectedOrigins;
if(typeof passkeyConfigRequest?.expectedOrigins !== 'undefined') {
request.expectedOrigins = passkeyConfigRequest.expectedOrigins;
}
return request;
};
Expand Down
12 changes: 3 additions & 9 deletions test/integration/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import {
} from '../../lib/auth/index';
import * as sinon from 'sinon';
import * as sinonChai from 'sinon-chai';
import {PasskeyConfigRequest} from '../../src/auth';

const chalk = require('chalk'); // eslint-disable-line @typescript-eslint/no-var-requires

Expand Down Expand Up @@ -2206,15 +2205,10 @@ describe('admin.auth', () => {
expectedOrigins: ['app1', 'example.com'],
};

// Helper function to reset passkey config to the initial state
async function resetPasskeyConfig() {
const resetRequest = { expectedOrigins: expectedPasskeyConfig.expectedOrigins };
await getAuth().passkeyConfigManager().updatePasskeyConfig(resetRequest);
}

// Before each test, reset the passkey config to the initial state
beforeEach(async () => {
await resetPasskeyConfig();
const resetRequest = { expectedOrigins: expectedPasskeyConfig.expectedOrigins };
await getAuth().passkeyConfigManager().updatePasskeyConfig(resetRequest);
});

it('createPasskeyConfig() should create passkey config with expected passkeyConfig', async () => {
Expand All @@ -2223,7 +2217,7 @@ describe('admin.auth', () => {

const createdPasskeyConfig = await getAuth().passkeyConfigManager().createPasskeyConfig(rpId, createRequest);
const passkeyConfigObj = createdPasskeyConfig.toJSON();

expect(passkeyConfigObj).to.deep.equal(expectedPasskeyConfig);
});

Expand Down
256 changes: 256 additions & 0 deletions test/unit/auth/passkey-config-manager.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/*!
* Copyright 2023 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

import * as _ from 'lodash';
import * as chai from 'chai';
import * as sinon from 'sinon';
import * as sinonChai from 'sinon-chai';
import * as chaiAsPromised from 'chai-as-promised';

import * as mocks from '../../resources/mocks';
import { FirebaseApp } from '../../../src/app/firebase-app';
import { AuthRequestHandler } from '../../../src/auth/auth-api-request';
import { AuthClientErrorCode, FirebaseAuthError } from '../../../src/utils/error';
import { PasskeyConfigManager } from '../../../src/auth/passkey-config-manager';
import {
PasskeyConfig, PasskeyConfigServerResponse, PasskeyConfigRequest,
} from '../../../src/auth/passkey-config';

chai.should();
chai.use(sinonChai);
chai.use(chaiAsPromised);

const expect = chai.expect;

describe('PasskeyConfigManager', () => {
let mockApp: FirebaseApp;
let passkeyConfigManager: PasskeyConfigManager;
let nullAccessTokenPasskeyConfigManager: PasskeyConfigManager;
let malformedAccessTokenPasskeyConfigManager: PasskeyConfigManager;
let rejectedPromiseAccessTokenPasskeyConfigManager: PasskeyConfigManager;
const GET_CONFIG_RESPONSE: PasskeyConfigServerResponse = {
name: `projects/project-id/passkeyConfig`,
rpId: `project-id.firebaseapp.com`,
expectedOrigins: ['app1', 'example.com'],
};

before(() => {
mockApp = mocks.app();
passkeyConfigManager = new PasskeyConfigManager(mockApp);
nullAccessTokenPasskeyConfigManager = new PasskeyConfigManager(
mocks.appReturningNullAccessToken());
malformedAccessTokenPasskeyConfigManager = new PasskeyConfigManager(
mocks.appReturningMalformedAccessToken());
rejectedPromiseAccessTokenPasskeyConfigManager = new PasskeyConfigManager(
mocks.appRejectedWhileFetchingAccessToken());
});

after(() => {
return mockApp.delete();
});

describe('getPasskeyConfig()', () => {
const expectedPasskeyConfig = new PasskeyConfig(GET_CONFIG_RESPONSE);
const expectedError = new FirebaseAuthError(AuthClientErrorCode.INVALID_CONFIG);
// Stubs used to simulate underlying API calls.
let stubs: sinon.SinonStub[] = [];
afterEach(() => {
_.forEach(stubs, (stub) => stub.restore());
stubs = [];
});

it('should be rejected given an app which returns null access tokens', () => {
return nullAccessTokenPasskeyConfigManager.getPasskeyConfig()
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should be rejected given an app which returns invalid access tokens', () => {
return malformedAccessTokenPasskeyConfigManager.getPasskeyConfig()
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should be rejected given an app which fails to generate access tokens', () => {
return rejectedPromiseAccessTokenPasskeyConfigManager.getPasskeyConfig()
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should resolve with a Passkey Config on success', () => {
// Stub getPasskeyConfig to return expected result.
const stub = sinon.stub(AuthRequestHandler.prototype, 'getPasskeyConfig')
.returns(Promise.resolve(GET_CONFIG_RESPONSE));
stubs.push(stub);
return passkeyConfigManager.getPasskeyConfig()
.then((result) => {
// Confirm underlying API called with expected parameters.
expect(stub).to.have.been.calledOnce;
// Confirm expected project config returned.
expect(result).to.deep.equal(expectedPasskeyConfig);
});
});

it('should throw an error when the backend returns an error', () => {
// Stub getConfig to throw a backend error.
const stub = sinon.stub(AuthRequestHandler.prototype, 'getPasskeyConfig')
.returns(Promise.reject(expectedError));
stubs.push(stub);
return passkeyConfigManager.getPasskeyConfig()
.then(() => {
throw new Error('Unexpected success');
}, (error) => {
// Confirm underlying API called with expected parameters.
expect(stub).to.have.been.calledOnce;
// Confirm expected error returned.
expect(error).to.equal(expectedError);
});
});
});

describe('createPasskeyConfig()', () => {
const rpId: string = 'project-id.firebaseapp.com';
const expectedOrigins: string[] = ['app1', 'example.com']
const passkeyConfigRequest: PasskeyConfigRequest = {
expectedOrigins: expectedOrigins ,
};
const expectedPasskeyConfig = new PasskeyConfig(GET_CONFIG_RESPONSE);
const expectedError = new FirebaseAuthError(
AuthClientErrorCode.INTERNAL_ERROR,
'Unable to create the config provided.');
// Stubs used to simulate underlying API calls.
let stubs: sinon.SinonStub[] = [];
afterEach(() => {
sinon.restore();
});

it('should be rejected given no passkeyConfigOptions', () => {
return (passkeyConfigManager as any).createPasskeyConfig(null as unknown as PasskeyConfigRequest)
.should.eventually.be.rejected.and.have.property('code', 'auth/argument-error');
});

it('should be rejected given an app which returns null access tokens', () => {
console.log("TEST===" + JSON.stringify(passkeyConfigRequest));
return nullAccessTokenPasskeyConfigManager.createPasskeyConfig(rpId, passkeyConfigRequest)
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should be rejected given an app which returns invalid access tokens', () => {
return malformedAccessTokenPasskeyConfigManager.createPasskeyConfig(rpId, passkeyConfigRequest)
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should be rejected given an app which fails to generate access tokens', () => {
return rejectedPromiseAccessTokenPasskeyConfigManager.createPasskeyConfig(rpId, passkeyConfigRequest)
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should resolve with a PasskeyConfig on createPasskeyConfig request success', () => {
// Stub createPasskeyConfig to return expected result.
const stub = sinon.stub(AuthRequestHandler.prototype, 'updatePasskeyConfig')
.returns(Promise.resolve(GET_CONFIG_RESPONSE));
stubs.push(stub);
return passkeyConfigManager.createPasskeyConfig(rpId, passkeyConfigRequest)
.then((actualPasskeyConfig) => {
// Confirm underlying API called with expected parameters.
expect(stub).to.have.been.calledOnce.and.calledWith(true, undefined, passkeyConfigRequest, rpId);
// Confirm expected Passkey Config object returned.
expect(actualPasskeyConfig).to.deep.equal(expectedPasskeyConfig);
});
});

it('should throw an error when createPasskeyConfig returns an error', () => {
// Stub createPasskeyConfig to throw a backend error.
const stub = sinon.stub(AuthRequestHandler.prototype, 'updatePasskeyConfig')
.returns(Promise.reject(expectedError));
stubs.push(stub);
return passkeyConfigManager.createPasskeyConfig(rpId, passkeyConfigRequest)
.then(() => {
throw new Error('Unexpected success');
}, (error) => {
// Confirm underlying API called with expected parameters.
expect(stub).to.have.been.calledOnce.and.calledWith(true, undefined, passkeyConfigRequest, rpId);
// Confirm expected error returned.
expect(error).to.equal(expectedError);
});
});
});

describe('updatePasskeyConfig()', () => {
const passkeyConfigOptions: PasskeyConfigRequest = {
expectedOrigins: ['app1', 'example.com', 'app2'],
};
const expectedPasskeyConfig = new PasskeyConfig(GET_CONFIG_RESPONSE);
const expectedError = new FirebaseAuthError(
AuthClientErrorCode.INTERNAL_ERROR,
'Unable to update the config provided.');
// Stubs used to simulate underlying API calls.
let stubs: sinon.SinonStub[] = [];
afterEach(() => {
_.forEach(stubs, (stub) => stub.restore());
stubs = [];
});

it('should be rejected given no passkeyConfigOptions', () => {
return (passkeyConfigManager as any).updatePasskeyConfig(null as unknown as PasskeyConfigRequest)
.should.eventually.be.rejected.and.have.property('code', 'auth/argument-error');
});

it('should be rejected given an app which returns null access tokens', () => {
return nullAccessTokenPasskeyConfigManager.updatePasskeyConfig(passkeyConfigOptions)
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should be rejected given an app which returns invalid access tokens', () => {
return malformedAccessTokenPasskeyConfigManager.updatePasskeyConfig(passkeyConfigOptions)
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should be rejected given an app which fails to generate access tokens', () => {
return rejectedPromiseAccessTokenPasskeyConfigManager.updatePasskeyConfig(passkeyConfigOptions)
.should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

it('should resolve with a PasskeyConfig on updatePasskeyConfig request success', () => {
// Stub updatePasskeyConfig to return expected result.
const updateConfigStub = sinon.stub(AuthRequestHandler.prototype, 'updatePasskeyConfig')
.returns(Promise.resolve(GET_CONFIG_RESPONSE));
stubs.push(updateConfigStub);
return passkeyConfigManager.updatePasskeyConfig(passkeyConfigOptions)
.then((actualPasskeyConfig) => {
// Confirm underlying API called with expected parameters.
expect(updateConfigStub).to.have.been.calledOnce.and.calledWith(false, undefined, passkeyConfigOptions);
// Confirm expected Project Config object returned.
expect(actualPasskeyConfig).to.deep.equal(expectedPasskeyConfig);
});
});

it('should throw an error when updatePasskeyConfig returns an error', () => {
// Stub updatePasskeyConfig to throw a backend error.
const updateConfigStub = sinon.stub(AuthRequestHandler.prototype, 'updatePasskeyConfig')
.returns(Promise.reject(expectedError));
stubs.push(updateConfigStub);
return passkeyConfigManager.updatePasskeyConfig(passkeyConfigOptions)
.then(() => {
throw new Error('Unexpected success');
}, (error) => {
// Confirm underlying API called with expected parameters.
expect(updateConfigStub).to.have.been.calledOnce.and.calledWith(false, undefined, passkeyConfigOptions);
// Confirm expected error returned.
expect(error).to.equal(expectedError);
});
});
});
});
Loading

0 comments on commit 7cb9087

Please sign in to comment.