Skip to content

Add testing module #514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 16, 2018
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
3 changes: 3 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ integration/messaging @gauntface @pinarx
# Auth Code
packages/auth @bojeil-google @wti806 @tmsch
packages/auth-types @bojeil-google @wti806 @tmsch

# Testing Code
packages/testing @tonymeng @ryanpbrewster
3 changes: 3 additions & 0 deletions packages/testing/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @firebase/testing

This is the testing component for the Firebase JS SDK.
31 changes: 31 additions & 0 deletions packages/testing/gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright 2017 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.
*/

const gulp = require('gulp');
const tools = require('../../tools/build');

const buildModule = gulp.parallel([
tools.buildCjs(__dirname),
tools.buildEsm(__dirname)
]);

const setupWatcher = () => {
gulp.watch(['index.ts', 'src/**/*'], buildModule);
};

gulp.task('build', buildModule);

gulp.task('dev', gulp.parallel([setupWatcher]));
30 changes: 30 additions & 0 deletions packages/testing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright 2017 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.
*/

/*
* The testing module does not need to be registered since it should not ever
* come by default. The only way to use the testing module is by explicitly
* creating a dependency on @firebase/testing.
*/

export {
apps,
assertFails,
assertSucceeds,
initializeAdminApp,
initializeTestApp,
loadDatabaseRules
} from './src/api';
38 changes: 38 additions & 0 deletions packages/testing/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@firebase/testing",
"version": "0.1.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets make sure we have the private value set to true for this module. I don't think we want to publish this quite yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

"private": true,
"description": "",
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
"main": "dist/cjs/index.js",
"browser": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"scripts": {
"dev": "gulp dev",
"test": "TS_NODE_CACHE=NO nyc --reporter lcovonly -- mocha 'test/{,!(browser)/**/}*.test.ts' --compilers ts:ts-node/register/type-check --retries 5 --timeout 5000 --exit",
"prepare": "gulp build"
},
"license": "Apache-2.0",
"dependencies": {
"firebase-admin": "5.8.0",
"request-promise": "^4.2.2"
},
"devDependencies": {
"chai": "^4.1.1",
"gulp": "gulpjs/gulp#4.0",
"mocha": "^4.0.1",
"nyc": "^11.2.1"
},
"peerDependencies": {
"@firebase/app": "^0.1.0",
"@firebase/app-types": "^0.1.0"
},
"repository": {
"type": "git",
"url": "https://github.com/firebase/firebase-js-sdk/tree/master/packages/testing"
},
"typings": "dist/esm/index.d.ts",
"bugs": {
"url": "https://github.com/firebase/firebase-js-sdk/issues"
}
}
101 changes: 101 additions & 0 deletions packages/testing/src/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* Copyright 2018 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.
*/

import * as admin from 'firebase-admin';
import * as request from 'request-promise';
import * as fs from 'fs';

const DBURL = 'http://localhost:9000';

class FakeCredentials {
getAccessToken() {
return Promise.resolve({
expires_in: 1000000,
access_token: 'owner'
});
}
getCertificate() {
return null;
}
}

export function apps(): (admin.app.App | null)[] {
return admin.apps;
}

export function initializeAdminApp(options: any): admin.app.App {
if (!('databaseName' in options)) {
throw new Error('databaseName not specified');
}
return admin.initializeApp(
{
credential: new FakeCredentials(),
databaseURL: DBURL + '?ns=' + options.databaseName
},
'app-' + (new Date().getTime() + Math.random())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this Math.random() is actually increasing the chance of a name collision. Can we just use the timestamp or an autoincrement id?

);
}

export function initializeTestApp(options: any): admin.app.App {
if (!('databaseName' in options)) {
throw new Error('databaseName not specified');
}
// if options.auth is not present, we will construct an app with auth == null
return admin.initializeApp(
{
credential: new FakeCredentials(),
databaseURL: DBURL + '?ns=' + options.databaseName,
databaseAuthVariableOverride: options.auth || null
},
'app-' + (new Date().getTime() + Math.random())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe call this admin-app-{}?

);
}

export function loadDatabaseRules(options: any): void {
if (!('databaseName' in options)) {
throw new Error('databaseName not specified');
}
if (!('rulesPath' in options)) {
throw new Error('rulesPath not specified');
}
if (!fs.existsSync(options.rulesPath)) {
throw new Error('Could not find file: ' + options.rulesPath);
}
fs
.createReadStream(options.rulesPath)
.pipe(
request({
uri: DBURL + '/.settings/rules.json?ns=' + options.databaseName,
method: 'PUT',
headers: { Authorization: 'Bearer owner' }
})
)
.catch(function(err) {
throw new Error('could not load rules: ' + err);
});
}

export function assertFails(pr: Promise<any>): any {
return pr.then(
v =>
Promise.reject(new Error('Expected request to fail, but it succeeded.')),
err => err
);
}

export function assertSucceeds(pr: Promise<any>): any {
return pr;
}
126 changes: 126 additions & 0 deletions packages/testing/test/database.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/**
* Copyright 2017 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.
*/

import { expect } from 'chai';
import * as firebase from '../src/api';

describe('Testing Module Tests', function() {
it('assertSucceeds() iff success', async function() {
const success = Promise.resolve('success');
const failure = Promise.reject('failure');
await firebase.assertSucceeds(success).catch(() => {
throw new Error('Expected success to succeed.');
});
await firebase
.assertSucceeds(failure)
.then(() => {
throw new Error('Expected failure to fail.');
})
.catch(() => {});
});

it('assertFails() iff failure', async function() {
const success = Promise.resolve('success');
const failure = Promise.reject('failure');
await firebase
.assertFails(success)
.then(() => {
throw new Error('Expected success to fail.');
})
.catch(() => {});
await firebase.assertFails(failure).catch(() => {
throw new Error('Expected failure to succeed.');
});
});

it('initializeAdminApp() throws if no databaseName', function() {
expect(firebase.initializeAdminApp.bind(null, {})).to.throw(
/databaseName not specified/
);
expect(
firebase.initializeAdminApp.bind(null, { databaseName: 'foo' })
).to.not.throw();
});

it('initializeAdminApp() provides admin', function() {
const app = firebase.initializeAdminApp({ databaseName: 'foo' });
expect(app.options).to.not.have.any.keys('databaseAuthVariableOverride');
});

it('initializeTestApp() throws if no databaseName', function() {
expect(firebase.initializeTestApp.bind(null, {})).to.throw(
/databaseName not specified/
);
expect(
firebase.initializeTestApp.bind(null, { databaseName: 'foo' })
).to.not.throw();
});

it('initializeTestApp() uses specified auth.', function() {
let app = firebase.initializeTestApp({ databaseName: 'foo' });
expect(app.options).to.have.any.keys('databaseAuthVariableOverride');

app = firebase.initializeTestApp({
databaseName: 'foo',
auth: { uid: 'alice' }
});
expect(app.options).to.have.any.keys('databaseAuthVariableOverride');
expect(app.options.databaseAuthVariableOverride).to.have.all.keys('uid');
expect(app.options.databaseAuthVariableOverride['uid']).to.be.equal(
'alice'
);
});

it('loadDatabaseRules() throws if no databaseName or rulesPath', async function() {
expect(firebase.loadDatabaseRules.bind(null, {})).to.throw(
/databaseName not specified/
);
expect(
firebase.loadDatabaseRules.bind(null, { databaseName: 'foo' })
).to.throw(/rulesPath not specified/);
expect(
firebase.loadDatabaseRules.bind(null, {
rulesPath: '/path/does/not/exist/file.json'
})
).to.throw(/databaseName not specified/);
expect(
firebase.loadDatabaseRules.bind(null, {
databaseName: 'foo',
rulesPath: '/path/does/not/exist/file.json'
})
).to.throw(/Could not find file/);
});

it('loadDatabaseRules() throws on file not found', function() {
const options = {
databaseName: 'foo',
rulesPath: '/path/does/not/exist/file.json'
};
expect(firebase.loadDatabaseRules.bind(null, options)).to.throw(
/Could not find file/
);
});

it('apps() returns all created apps', async function() {
const numApps = firebase.apps().length;
await firebase.initializeAdminApp({ databaseName: 'foo' });
expect(firebase.apps().length).to.equal(numApps + 1);
await firebase.initializeAdminApp({ databaseName: 'foo' });
expect(firebase.apps().length).to.equal(numApps + 2);
await firebase.initializeTestApp({ databaseName: 'foo' });
expect(firebase.apps().length).to.equal(numApps + 3);
});
});
9 changes: 9 additions & 0 deletions packages/testing/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../config/tsconfig.base.json",
"compilerOptions": {
"outDir": "dist"
},
"exclude": [
"dist/**/*"
]
}
Loading