-
-
Save nfarina/90ba99a5187113900c86289e67586aaa to your computer and use it in GitHub Desktop.
// | |
// Quick & Dirty Google Cloud Storage emulator for tests. Requires | |
// `stream-buffers` from npm. Use it like this: | |
// | |
// `new MockStorage().bucket('my-bucket').file('my_file').createWriteStream()` | |
// | |
class MockStorage { | |
buckets: {[name: string]: MockBucket}; | |
constructor() { | |
this.buckets = {}; | |
} | |
bucket(name: string) { | |
return this.buckets[name] || | |
(this.buckets[name] = new MockBucket(name)); | |
} | |
} | |
class MockBucket { | |
name: string; | |
files: {[path: string]: MockFile}; | |
constructor(name: string) { | |
this.name = name; | |
this.files = {}; | |
} | |
file(path: string) { | |
return this.files[path] || | |
(this.files[path] = new MockFile(path)); | |
} | |
} | |
class MockFile { | |
path: string; | |
contents: Buffer; | |
metadata: Object; | |
constructor(path: string) { | |
this.path = path; | |
this.contents = new Buffer(0); | |
this.metadata = {}; | |
} | |
get() { | |
return [this, this.metadata]; | |
} | |
setMetadata(metadata: Object) { | |
const customMetadata = {...this.metadata.metadata, ...metadata.metadata}; | |
this.metadata = {...this.metadata, ...metadata, metadata: customMetadata}; | |
} | |
createReadStream() { | |
const streamBuffers = require('stream-buffers'); | |
const readable = new streamBuffers.ReadableStreamBuffer(); | |
readable.put(this.contents); | |
readable.stop(); | |
return readable; | |
} | |
createWriteStream({metadata}: Object) { | |
this.setMetadata(metadata); | |
const streamBuffers = require('stream-buffers'); | |
const writable = new streamBuffers.WritableStreamBuffer(); | |
writable.on('finish', () => { | |
this.contents = writable.getContents(); | |
}); | |
return writable; | |
} | |
delete() { | |
return Promise.resolve(); | |
} | |
} |
hey man, you should publish an npm package of this, what you think? If you allow, i do it.
Sure I’m happy to turn this into a proper repo and npm package, if people are finding it useful.
Would be userful for me, please, do it :)
No package yet? 😅
TS Example I've been using from the example above, I wanted to contribute back as it was a big help.
/* eslint-disable @typescript-eslint/no-unused-vars */
//
// Quick & Dirty Google Cloud Storage emulator for tests. Requires
// `stream-buffers` from npm. Use it like this:
//
// `new MockStorage().bucket('my-bucket').file('my_file').createWriteStream()`
//
import type { CreateWriteStreamOptions, GetSignedUrlConfig } from '@google-cloud/storage';
import streamBuffers from 'stream-buffers';
export class MockStorage {
public buckets: object;
public constructor() {
this.buckets = {};
}
public bucket(name: string): MockBucket {
if (this.buckets[name] === undefined) {
this.buckets[name] = new MockBucket(name);
}
return this.buckets[name];
}
}
export class MockBucket {
public name: string;
public files: object;
public constructor(name: string) {
this.name = name;
this.files = {};
}
public upload(name: string, options: any): MockFile[] {
return [this.file(name)];
}
public file(name: string): MockFile {
if (this.files[name] === undefined) {
this.files[name] = new MockFile(name);
}
return this.files[name];
}
}
interface Metadata {
metadata?: object;
}
export class MockFile {
public name: string;
public path?: string;
public contents: Buffer;
public metadata: {
metadata?: object;
};
public constructor(name: string, path?: string) {
this.name = name;
this.path = path;
this.contents = Buffer.alloc(0);
this.metadata = {};
}
public get(): [MockFile, any] {
return [this, this.metadata];
}
public async delete(): Promise<void> {
return Promise.resolve();
}
public exists(): [boolean, any] {
return [true, this.metadata];
}
public setMetadata(metadata: Metadata): void {
const customMetadata = { ...this.metadata.metadata, ...metadata.metadata };
this.metadata = { ...this.metadata, ...metadata, metadata: customMetadata };
}
public async getSignedUrl(options?: GetSignedUrlConfig): Promise<string> {
return Promise.resolve('https://example.com');
}
public createReadStream(): any {
const readable = new streamBuffers.ReadableStreamBuffer();
readable.put(this.contents);
readable.stop();
return readable;
}
public createWriteStream(options?: CreateWriteStreamOptions): any {
const writable = new streamBuffers.WritableStreamBuffer();
writable.on('finish', () => {
this.contents = writable.getContents();
});
return writable;
}
}
Hi, how do you actually inject it into jest
mocking? Thanks!
Hi, how do you actually inject it into
jest
mocking? Thanks!
I personally run all my Firebase calls through a single getFirebaseApp()
sort of function. When running under test mode, it returns a mock App that stubs out the getters for mock Storage, Firestore, etc.
Should be able to use https://jestjs.io/docs/mock-functions#mocking-modules, or https://www.npmjs.com/package/proxyquire. Both should be able to mock out the actual call to '@google-cloud/storage'
I am making some progress with this approach:
function mockedStorage() {
return class MockStorage {
public buckets: MockBucketList;
public constructor() {
this.buckets = {};
}
public bucket(name: string): MockBucket {
if (this.buckets[name] === undefined) {
this.buckets[name] = new MockBucket(name);
}
return this.buckets[name];
}
};
}
jest.mock('@google-cloud/storage', () => ({
Storage: mockedStorage()
}));
Hi everyone! Just wanted to share that I recently published a small package to help mock @google-cloud/storage
written in TypeScript. Check out mock-gcs
: https://github.com/aldipermanaetikaputra/mock-gcs. Hope it helps!
@aldipermanaetikaputra I have a Datastore one if you'd like that as well. I couldn't find this packages repo so I couldn't file issues or contribute back. https://www.npmjs.com/package/datastore-mock?activeTab=readme So I forked it to a script. Would be nice if it could get maintained and updated.
I have a rather-insane Firestore one as well :) actually works...but it only implements the "compat" API
Glad to hear it!