Skip to content

Commit b6b4e2f

Browse files
authored
Add testing module (#514)
* Adding testing module * Typescript it * [AUTOMATED]: Prettier Code Styling * [AUTOMATED]: License Headers * Do not register testing module with firebase * [AUTOMATED]: Prettier Code Styling * Feedback * Add owners
1 parent 2e147ff commit b6b4e2f

File tree

9 files changed

+837
-14
lines changed

9 files changed

+837
-14
lines changed

.github/CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ integration/messaging @gauntface @pinarx
2626
# Auth Code
2727
packages/auth @bojeil-google @wti806 @tmsch
2828
packages/auth-types @bojeil-google @wti806 @tmsch
29+
30+
# Testing Code
31+
packages/testing @tonymeng @ryanpbrewster

packages/testing/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# @firebase/testing
2+
3+
This is the testing component for the Firebase JS SDK.

packages/testing/gulpfile.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
const gulp = require('gulp');
18+
const tools = require('../../tools/build');
19+
20+
const buildModule = gulp.parallel([
21+
tools.buildCjs(__dirname),
22+
tools.buildEsm(__dirname)
23+
]);
24+
25+
const setupWatcher = () => {
26+
gulp.watch(['index.ts', 'src/**/*'], buildModule);
27+
};
28+
29+
gulp.task('build', buildModule);
30+
31+
gulp.task('dev', gulp.parallel([setupWatcher]));

packages/testing/index.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/*
18+
* The testing module does not need to be registered since it should not ever
19+
* come by default. The only way to use the testing module is by explicitly
20+
* creating a dependency on @firebase/testing.
21+
*/
22+
23+
export {
24+
apps,
25+
assertFails,
26+
assertSucceeds,
27+
initializeAdminApp,
28+
initializeTestApp,
29+
loadDatabaseRules
30+
} from './src/api';

packages/testing/package.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "@firebase/testing",
3+
"version": "0.1.0",
4+
"private": true,
5+
"description": "",
6+
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
7+
"main": "dist/cjs/index.js",
8+
"browser": "dist/cjs/index.js",
9+
"module": "dist/esm/index.js",
10+
"scripts": {
11+
"dev": "gulp dev",
12+
"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",
13+
"prepare": "gulp build"
14+
},
15+
"license": "Apache-2.0",
16+
"dependencies": {
17+
"firebase-admin": "5.8.0",
18+
"request-promise": "^4.2.2"
19+
},
20+
"devDependencies": {
21+
"chai": "^4.1.1",
22+
"gulp": "gulpjs/gulp#4.0",
23+
"mocha": "^4.0.1",
24+
"nyc": "^11.2.1"
25+
},
26+
"peerDependencies": {
27+
"@firebase/app": "^0.1.0",
28+
"@firebase/app-types": "^0.1.0"
29+
},
30+
"repository": {
31+
"type": "git",
32+
"url": "https://github.com/firebase/firebase-js-sdk/tree/master/packages/testing"
33+
},
34+
"typings": "dist/esm/index.d.ts",
35+
"bugs": {
36+
"url": "https://github.com/firebase/firebase-js-sdk/issues"
37+
}
38+
}

packages/testing/src/api/index.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* Copyright 2018 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as admin from 'firebase-admin';
18+
import * as request from 'request-promise';
19+
import * as fs from 'fs';
20+
21+
const DBURL = 'http://localhost:9000';
22+
23+
class FakeCredentials {
24+
getAccessToken() {
25+
return Promise.resolve({
26+
expires_in: 1000000,
27+
access_token: 'owner'
28+
});
29+
}
30+
getCertificate() {
31+
return null;
32+
}
33+
}
34+
35+
export function apps(): (admin.app.App | null)[] {
36+
return admin.apps;
37+
}
38+
39+
export function initializeAdminApp(options: any): admin.app.App {
40+
if (!('databaseName' in options)) {
41+
throw new Error('databaseName not specified');
42+
}
43+
return admin.initializeApp(
44+
{
45+
credential: new FakeCredentials(),
46+
databaseURL: DBURL + '?ns=' + options.databaseName
47+
},
48+
'app-' + (new Date().getTime() + Math.random())
49+
);
50+
}
51+
52+
export function initializeTestApp(options: any): admin.app.App {
53+
if (!('databaseName' in options)) {
54+
throw new Error('databaseName not specified');
55+
}
56+
// if options.auth is not present, we will construct an app with auth == null
57+
return admin.initializeApp(
58+
{
59+
credential: new FakeCredentials(),
60+
databaseURL: DBURL + '?ns=' + options.databaseName,
61+
databaseAuthVariableOverride: options.auth || null
62+
},
63+
'app-' + (new Date().getTime() + Math.random())
64+
);
65+
}
66+
67+
export function loadDatabaseRules(options: any): void {
68+
if (!('databaseName' in options)) {
69+
throw new Error('databaseName not specified');
70+
}
71+
if (!('rulesPath' in options)) {
72+
throw new Error('rulesPath not specified');
73+
}
74+
if (!fs.existsSync(options.rulesPath)) {
75+
throw new Error('Could not find file: ' + options.rulesPath);
76+
}
77+
fs
78+
.createReadStream(options.rulesPath)
79+
.pipe(
80+
request({
81+
uri: DBURL + '/.settings/rules.json?ns=' + options.databaseName,
82+
method: 'PUT',
83+
headers: { Authorization: 'Bearer owner' }
84+
})
85+
)
86+
.catch(function(err) {
87+
throw new Error('could not load rules: ' + err);
88+
});
89+
}
90+
91+
export function assertFails(pr: Promise<any>): any {
92+
return pr.then(
93+
v =>
94+
Promise.reject(new Error('Expected request to fail, but it succeeded.')),
95+
err => err
96+
);
97+
}
98+
99+
export function assertSucceeds(pr: Promise<any>): any {
100+
return pr;
101+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* Copyright 2017 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { expect } from 'chai';
18+
import * as firebase from '../src/api';
19+
20+
describe('Testing Module Tests', function() {
21+
it('assertSucceeds() iff success', async function() {
22+
const success = Promise.resolve('success');
23+
const failure = Promise.reject('failure');
24+
await firebase.assertSucceeds(success).catch(() => {
25+
throw new Error('Expected success to succeed.');
26+
});
27+
await firebase
28+
.assertSucceeds(failure)
29+
.then(() => {
30+
throw new Error('Expected failure to fail.');
31+
})
32+
.catch(() => {});
33+
});
34+
35+
it('assertFails() iff failure', async function() {
36+
const success = Promise.resolve('success');
37+
const failure = Promise.reject('failure');
38+
await firebase
39+
.assertFails(success)
40+
.then(() => {
41+
throw new Error('Expected success to fail.');
42+
})
43+
.catch(() => {});
44+
await firebase.assertFails(failure).catch(() => {
45+
throw new Error('Expected failure to succeed.');
46+
});
47+
});
48+
49+
it('initializeAdminApp() throws if no databaseName', function() {
50+
expect(firebase.initializeAdminApp.bind(null, {})).to.throw(
51+
/databaseName not specified/
52+
);
53+
expect(
54+
firebase.initializeAdminApp.bind(null, { databaseName: 'foo' })
55+
).to.not.throw();
56+
});
57+
58+
it('initializeAdminApp() provides admin', function() {
59+
const app = firebase.initializeAdminApp({ databaseName: 'foo' });
60+
expect(app.options).to.not.have.any.keys('databaseAuthVariableOverride');
61+
});
62+
63+
it('initializeTestApp() throws if no databaseName', function() {
64+
expect(firebase.initializeTestApp.bind(null, {})).to.throw(
65+
/databaseName not specified/
66+
);
67+
expect(
68+
firebase.initializeTestApp.bind(null, { databaseName: 'foo' })
69+
).to.not.throw();
70+
});
71+
72+
it('initializeTestApp() uses specified auth.', function() {
73+
let app = firebase.initializeTestApp({ databaseName: 'foo' });
74+
expect(app.options).to.have.any.keys('databaseAuthVariableOverride');
75+
76+
app = firebase.initializeTestApp({
77+
databaseName: 'foo',
78+
auth: { uid: 'alice' }
79+
});
80+
expect(app.options).to.have.any.keys('databaseAuthVariableOverride');
81+
expect(app.options.databaseAuthVariableOverride).to.have.all.keys('uid');
82+
expect(app.options.databaseAuthVariableOverride['uid']).to.be.equal(
83+
'alice'
84+
);
85+
});
86+
87+
it('loadDatabaseRules() throws if no databaseName or rulesPath', async function() {
88+
expect(firebase.loadDatabaseRules.bind(null, {})).to.throw(
89+
/databaseName not specified/
90+
);
91+
expect(
92+
firebase.loadDatabaseRules.bind(null, { databaseName: 'foo' })
93+
).to.throw(/rulesPath not specified/);
94+
expect(
95+
firebase.loadDatabaseRules.bind(null, {
96+
rulesPath: '/path/does/not/exist/file.json'
97+
})
98+
).to.throw(/databaseName not specified/);
99+
expect(
100+
firebase.loadDatabaseRules.bind(null, {
101+
databaseName: 'foo',
102+
rulesPath: '/path/does/not/exist/file.json'
103+
})
104+
).to.throw(/Could not find file/);
105+
});
106+
107+
it('loadDatabaseRules() throws on file not found', function() {
108+
const options = {
109+
databaseName: 'foo',
110+
rulesPath: '/path/does/not/exist/file.json'
111+
};
112+
expect(firebase.loadDatabaseRules.bind(null, options)).to.throw(
113+
/Could not find file/
114+
);
115+
});
116+
117+
it('apps() returns all created apps', async function() {
118+
const numApps = firebase.apps().length;
119+
await firebase.initializeAdminApp({ databaseName: 'foo' });
120+
expect(firebase.apps().length).to.equal(numApps + 1);
121+
await firebase.initializeAdminApp({ databaseName: 'foo' });
122+
expect(firebase.apps().length).to.equal(numApps + 2);
123+
await firebase.initializeTestApp({ databaseName: 'foo' });
124+
expect(firebase.apps().length).to.equal(numApps + 3);
125+
});
126+
});

packages/testing/tsconfig.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"extends": "../../config/tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "dist"
5+
},
6+
"exclude": [
7+
"dist/**/*"
8+
]
9+
}

0 commit comments

Comments
 (0)