Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ee33ebf

Browse files
authoredJul 17, 2020
Add Storage Integration tests (#3414)
1 parent ea699fa commit ee33ebf

File tree

14 files changed

+233
-66
lines changed

14 files changed

+233
-66
lines changed
 

‎.changeset/strange-lions-dress.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@firebase/storage": patch
3+
---
4+
5+
Error messages for backend errors now include the backend's reponse message.

‎packages/storage/karma.conf.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@
1818
const karma = require('karma');
1919
const path = require('path');
2020
const karmaBase = require('../../config/karma.base');
21-
22-
const files = [`test/**/*`];
21+
const { argv } = require('yargs');
2322

2423
module.exports = function (config) {
2524
const karmaConfig = Object.assign({}, karmaBase, {
2625
// files to load into karma
27-
files: files,
26+
files: getTestFiles(argv),
2827
// frameworks to use
2928
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
3029
frameworks: ['mocha']
@@ -33,4 +32,14 @@ module.exports = function (config) {
3332
config.set(karmaConfig);
3433
};
3534

36-
module.exports.files = files;
35+
function getTestFiles(argv) {
36+
if (argv.unit) {
37+
return ['test/unit/*'];
38+
} else if (argv.integration) {
39+
return ['test/integration/*'];
40+
} else {
41+
return ['test/**/*'];
42+
}
43+
}
44+
45+
module.exports.files = getTestFiles(argv);

‎packages/storage/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
"dev": "rollup -c -w",
1616
"test": "run-p test:browser lint",
1717
"test:ci": "node ../../scripts/run_tests_in_ci.js",
18+
"test:browser:unit": "karma start --single-run --unit",
19+
"test:browser:integration": "karma start --single-run --integration",
1820
"test:browser": "karma start --single-run",
1921
"prepare": "yarn build",
2022
"prettier": "prettier --write 'src/**/*.ts' 'test/**/*.ts'"
@@ -31,6 +33,7 @@
3133
"@firebase/app-types": "0.x"
3234
},
3335
"devDependencies": {
36+
"@firebase/auth": "0.x",
3437
"rollup": "2.21.0",
3538
"rollup-plugin-typescript2": "0.27.1",
3639
"typescript": "3.9.6"

‎packages/storage/src/implementation/error.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ export class FirebaseStorageError implements Error {
5454
}
5555

5656
get message(): string {
57-
return this.message_;
57+
if (this.serverResponse_) {
58+
return this.message_ + '\n' + this.serverResponse_;
59+
} else {
60+
return this.message_;
61+
}
5862
}
5963

6064
get serverResponse(): null | string {
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import firebase from '@firebase/app';
19+
import '@firebase/auth';
20+
21+
// See https://github.com/typescript-eslint/typescript-eslint/issues/363
22+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
23+
import * as storage from '@firebase/storage-types';
24+
25+
import { expect } from 'chai';
26+
import '../../index';
27+
28+
// eslint-disable-next-line @typescript-eslint/no-require-imports
29+
const PROJECT_CONFIG = require('../../../../config/project.json');
30+
31+
export const PROJECT_ID = PROJECT_CONFIG.projectId;
32+
export const STORAGE_BUCKET = PROJECT_CONFIG.storageBucket;
33+
export const API_KEY = PROJECT_CONFIG.apiKey;
34+
35+
let appCount = 0;
36+
37+
export async function withTestInstance(
38+
fn: (storage: storage.FirebaseStorage) => void | Promise<void>
39+
): Promise<void> {
40+
const app = firebase.initializeApp(
41+
{ apiKey: API_KEY, projectId: PROJECT_ID, storageBucket: STORAGE_BUCKET },
42+
'test-app-' + appCount++
43+
);
44+
await firebase.auth!(app).signInAnonymously();
45+
const storage = firebase.storage!(app);
46+
return fn(storage);
47+
}
48+
49+
describe('FirebaseStorage', () => {
50+
it('can upload bytes', () => {
51+
return withTestInstance(async storage => {
52+
const ref = storage.ref('public/bytes');
53+
await ref.put(new Uint8Array([0, 1, 3]));
54+
});
55+
});
56+
57+
it('can upload string', () => {
58+
return withTestInstance(async storage => {
59+
const ref = storage.ref('public/string');
60+
await ref.putString('foo');
61+
});
62+
});
63+
64+
it('validates operations on root', () => {
65+
return withTestInstance(async storage => {
66+
const ref = storage.ref('');
67+
try {
68+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
69+
ref.putString('foo');
70+
expect.fail();
71+
} catch (e) {
72+
expect(e.message).to.satisfy((v: string) =>
73+
v.match(
74+
/The operation 'putString' cannot be performed on a root reference/
75+
)
76+
);
77+
}
78+
});
79+
});
80+
81+
it('can delete object ', () => {
82+
return withTestInstance(async storage => {
83+
const ref = storage.ref('public/delete');
84+
await ref.putString('foo');
85+
86+
// getDownloadURL() succeeds for an existing object
87+
await ref.getDownloadURL();
88+
89+
await ref.delete();
90+
try {
91+
// getDownloadURL() fails for a deleted object
92+
await ref.getDownloadURL();
93+
expect.fail();
94+
} catch (e) {
95+
expect(e.message).to.satisfy((v: string) =>
96+
v.match(/Object 'public\/delete' does not exist/)
97+
);
98+
}
99+
});
100+
});
101+
102+
it('can get download URL', () => {
103+
return withTestInstance(async storage => {
104+
const ref = storage.ref('public/downloadurl');
105+
await ref.put(new Uint8Array([0, 1, 3]));
106+
const url = await ref.getDownloadURL();
107+
expect(url).to.satisfy((v: string) =>
108+
v.match(
109+
/https:\/\/firebasestorage\.googleapis\.com\/v0\/b\/.*\/o\/public%2Fdownloadurl/
110+
)
111+
);
112+
});
113+
});
114+
115+
it('can get metadata', () => {
116+
return withTestInstance(async storage => {
117+
const ref = storage.ref('public/getmetadata');
118+
await ref.put(new Uint8Array([0, 1, 3]));
119+
const metadata = await ref.getMetadata();
120+
expect(metadata.name).to.equal('getmetadata');
121+
});
122+
});
123+
124+
it('can update metadata', () => {
125+
return withTestInstance(async storage => {
126+
const ref = storage.ref('public/updatemetadata');
127+
await ref.put(new Uint8Array([0, 1, 3]));
128+
const metadata = await ref.updateMetadata({
129+
customMetadata: { foo: 'bar' }
130+
});
131+
expect(metadata.customMetadata).to.deep.equal({ foo: 'bar' });
132+
});
133+
});
134+
135+
it('can list files', () => {
136+
return withTestInstance(async storage => {
137+
await storage.ref('public/list/a').putString('');
138+
await storage.ref('public/list/b').putString('');
139+
await storage.ref('public/list/c/d').putString('');
140+
const listResult = await storage.ref('public/list').listAll();
141+
expect(listResult.items.map(v => v.name)).to.have.members(['a', 'b']);
142+
expect(listResult.prefixes.map(v => v.name)).to.have.members(['c']);
143+
});
144+
});
145+
});

‎packages/storage/test/blob.test.ts renamed to ‎packages/storage/test/unit/blob.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
import { assert } from 'chai';
1919
import * as sinon from 'sinon';
20-
import { FbsBlob } from '../src/implementation/blob';
21-
import * as type from '../src/implementation/type';
20+
import { FbsBlob } from '../../src/implementation/blob';
21+
import * as type from '../../src/implementation/type';
2222
import * as testShared from './testshared';
2323

2424
describe('Firebase Storage > Blob', () => {

‎packages/storage/test/reference.test.ts renamed to ‎packages/storage/test/unit/reference.test.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,22 @@
1616
*/
1717
import { assert } from 'chai';
1818
import { FirebaseApp } from '@firebase/app-types';
19-
import { AuthWrapper } from '../src/implementation/authwrapper';
20-
import { makeRequest } from '../src/implementation/request';
21-
import { StringFormat } from '../src/implementation/string';
22-
import { Headers } from '../src/implementation/xhrio';
23-
import { Metadata } from '../src/metadata';
24-
import { Reference } from '../src/reference';
25-
import { Service } from '../src/service';
19+
import { AuthWrapper } from '../../src/implementation/authwrapper';
20+
import { makeRequest } from '../../src/implementation/request';
21+
import { StringFormat } from '../../src/implementation/string';
22+
import { Headers } from '../../src/implementation/xhrio';
23+
import { Metadata } from '../../src/metadata';
24+
import { Reference } from '../../src/reference';
25+
import { Service } from '../../src/service';
2626
import * as testShared from './testshared';
2727
import { SendHook, TestingXhrIo } from './xhrio';
28-
import { DEFAULT_HOST } from '../src/implementation/constants';
29-
import { FirebaseAuthInternal } from '@firebase/auth-interop-types';
28+
import { DEFAULT_HOST } from '../../src/implementation/constants';
3029
import { Provider } from '@firebase/component';
3130

3231
/* eslint-disable @typescript-eslint/no-floating-promises */
3332
function makeFakeService(
3433
app: FirebaseApp,
35-
authProvider: Provider<FirebaseAuthInternal>,
34+
authProvider: Provider<'auth-internal'>,
3635
sendHook: SendHook
3736
): Service {
3837
return new Service(app, authProvider, testShared.makePool(sendHook));

‎packages/storage/test/request.test.ts renamed to ‎packages/storage/test/unit/request.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
import { assert } from 'chai';
1818
import * as sinon from 'sinon';
1919
import firebase from '@firebase/app';
20-
import { makeRequest } from '../src/implementation/request';
21-
import { RequestInfo } from '../src/implementation/requestinfo';
22-
import { XhrIo } from '../src/implementation/xhrio';
20+
import { makeRequest } from '../../src/implementation/request';
21+
import { RequestInfo } from '../../src/implementation/requestinfo';
22+
import { XhrIo } from '../../src/implementation/xhrio';
2323
import { makePool } from './testshared';
2424
import { TestingXhrIo } from './xhrio';
2525

‎packages/storage/test/requests.test.ts renamed to ‎packages/storage/test/unit/requests.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@
1515
* limitations under the License.
1616
*/
1717
import { assert } from 'chai';
18-
import { AuthWrapper } from '../src/implementation/authwrapper';
19-
import { FbsBlob } from '../src/implementation/blob';
20-
import { Location } from '../src/implementation/location';
21-
import * as MetadataUtils from '../src/implementation/metadata';
22-
import { makeRequest } from '../src/implementation/request';
23-
import * as requests from '../src/implementation/requests';
24-
import { makeUrl } from '../src/implementation/url';
25-
import * as errors from '../src/implementation/error';
26-
import { RequestInfo } from '../src/implementation/requestinfo';
27-
import { XhrIoPool } from '../src/implementation/xhriopool';
28-
import { Metadata } from '../src/metadata';
29-
import { Reference } from '../src/reference';
30-
import { Service } from '../src/service';
18+
import { AuthWrapper } from '../../src/implementation/authwrapper';
19+
import { FbsBlob } from '../../src/implementation/blob';
20+
import { Location } from '../../src/implementation/location';
21+
import * as MetadataUtils from '../../src/implementation/metadata';
22+
import { makeRequest } from '../../src/implementation/request';
23+
import * as requests from '../../src/implementation/requests';
24+
import { makeUrl } from '../../src/implementation/url';
25+
import * as errors from '../../src/implementation/error';
26+
import { RequestInfo } from '../../src/implementation/requestinfo';
27+
import { XhrIoPool } from '../../src/implementation/xhriopool';
28+
import { Metadata } from '../../src/metadata';
29+
import { Reference } from '../../src/reference';
30+
import { Service } from '../../src/service';
3131
import {
3232
assertObjectIncludes,
3333
fakeXhrIo,
@@ -36,7 +36,7 @@ import {
3636
import {
3737
DEFAULT_HOST,
3838
CONFIG_STORAGE_BUCKET_KEY
39-
} from '../src/implementation/constants';
39+
} from '../../src/implementation/constants';
4040
import { FirebaseApp } from '@firebase/app-types';
4141

4242
describe('Firebase Storage > Requests', () => {

‎packages/storage/test/service.test.ts renamed to ‎packages/storage/test/unit/service.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
* limitations under the License.
1616
*/
1717
import { assert } from 'chai';
18-
import { TaskEvent } from '../src/implementation/taskenums';
19-
import { XhrIoPool } from '../src/implementation/xhriopool';
20-
import { Service } from '../src/service';
18+
import { TaskEvent } from '../../src/implementation/taskenums';
19+
import { XhrIoPool } from '../../src/implementation/xhriopool';
20+
import { Service } from '../../src/service';
2121
import * as testShared from './testshared';
22-
import { DEFAULT_HOST } from '../src/implementation/constants';
23-
import { FirebaseStorageError } from '../src/implementation/error';
22+
import { DEFAULT_HOST } from '../../src/implementation/constants';
23+
import { FirebaseStorageError } from '../../src/implementation/error';
2424

2525
const fakeAppGs = testShared.makeFakeApp('gs://mybucket');
2626
const fakeAppGsEndingSlash = testShared.makeFakeApp('gs://mybucket/');

‎packages/storage/test/string.test.ts renamed to ‎packages/storage/test/unit/string.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717
import { assert } from 'chai';
18-
import { dataFromString, StringFormat } from '../src/implementation/string';
18+
import { dataFromString, StringFormat } from '../../src/implementation/string';
1919
import { assertThrows, assertUint8ArrayEquals } from './testshared';
2020

2121
describe('Firebase Storage > String', () => {

‎packages/storage/test/task.test.ts renamed to ‎packages/storage/test/unit/task.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@
1515
* limitations under the License.
1616
*/
1717
import { assert } from 'chai';
18-
import { AuthWrapper } from '../src/implementation/authwrapper';
19-
import { FbsBlob } from '../src/implementation/blob';
20-
import { Location } from '../src/implementation/location';
21-
import { getMappings } from '../src/implementation/metadata';
22-
import { Unsubscribe } from '../src/implementation/observer';
23-
import { makeRequest } from '../src/implementation/request';
24-
import { TaskEvent, TaskState } from '../src/implementation/taskenums';
25-
import { Headers } from '../src/implementation/xhrio';
26-
import { Reference } from '../src/reference';
27-
import { Service } from '../src/service';
28-
import { UploadTask } from '../src/task';
18+
import { AuthWrapper } from '../../src/implementation/authwrapper';
19+
import { FbsBlob } from '../../src/implementation/blob';
20+
import { Location } from '../../src/implementation/location';
21+
import { getMappings } from '../../src/implementation/metadata';
22+
import { Unsubscribe } from '../../src/implementation/observer';
23+
import { makeRequest } from '../../src/implementation/request';
24+
import { TaskEvent, TaskState } from '../../src/implementation/taskenums';
25+
import { Headers } from '../../src/implementation/xhrio';
26+
import { Reference } from '../../src/reference';
27+
import { Service } from '../../src/service';
28+
import { UploadTask } from '../../src/task';
2929
import {
3030
assertThrows,
3131
bind as fbsBind,

‎packages/storage/test/testshared.ts renamed to ‎packages/storage/test/unit/testshared.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@
1616
*/
1717
import { expect } from 'chai';
1818
import { FirebaseApp } from '@firebase/app-types';
19-
import * as constants from '../src/implementation/constants';
20-
import { Code, FirebaseStorageError } from '../src/implementation/error';
21-
import * as type from '../src/implementation/type';
22-
import { Headers, XhrIo } from '../src/implementation/xhrio';
23-
import { XhrIoPool } from '../src/implementation/xhriopool';
19+
import * as constants from '../../src/implementation/constants';
20+
import { Code, FirebaseStorageError } from '../../src/implementation/error';
21+
import * as type from '../../src/implementation/type';
22+
import { Headers, XhrIo } from '../../src/implementation/xhrio';
23+
import { XhrIoPool } from '../../src/implementation/xhriopool';
2424
import { SendHook, StringHeaders, TestingXhrIo } from './xhrio';
25-
import { FirebaseAuthInternal } from '@firebase/auth-interop-types';
25+
import { FirebaseAuthTokenData } from '@firebase/auth-interop-types';
2626
import {
2727
Provider,
2828
ComponentContainer,
@@ -36,7 +36,7 @@ export const fakeApp = makeFakeApp();
3636
export const fakeAuthProvider = makeFakeAuthProvider({
3737
accessToken: authToken
3838
});
39-
export const emptyAuthProvider = new Provider<FirebaseAuthInternal>(
39+
export const emptyAuthProvider = new Provider<'auth-internal'>(
4040
'auth-internal',
4141
new ComponentContainer('storage-container')
4242
);
@@ -53,23 +53,25 @@ export function makeFakeApp(bucketArg?: string): FirebaseApp {
5353
}
5454

5555
export function makeFakeAuthProvider(
56-
token: {} | null
57-
): Provider<FirebaseAuthInternal> {
56+
token: FirebaseAuthTokenData | null
57+
): Provider<'auth-internal'> {
5858
const provider = new Provider(
5959
'auth-internal',
6060
new ComponentContainer('storage-container')
6161
);
6262
provider.setComponent(
6363
new Component(
6464
'auth-internal',
65-
() => ({
66-
getToken: async () => token
67-
}),
65+
() => {
66+
return {
67+
getToken: () => Promise.resolve(token)
68+
} as any; // eslint-disable-line @typescript-eslint/no-explicit-any
69+
},
6870
ComponentType.PRIVATE
6971
)
7072
);
7173

72-
return provider as Provider<FirebaseAuthInternal>;
74+
return provider as Provider<'auth-internal'>;
7375
}
7476

7577
export function makePool(sendHook: SendHook | null): XhrIoPool {

‎packages/storage/test/xhrio.ts renamed to ‎packages/storage/test/unit/xhrio.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
import * as type from '../src/implementation/type';
18-
import { ErrorCode, Headers, XhrIo } from '../src/implementation/xhrio';
17+
import * as type from '../../src/implementation/type';
18+
import { ErrorCode, Headers, XhrIo } from '../../src/implementation/xhrio';
1919

2020
export type SendHook = (
2121
xhrio: TestingXhrIo,

0 commit comments

Comments
 (0)
Please sign in to comment.