hustle / parse-mockdb Goto Github PK
View Code? Open in Web Editor NEWFully Mocked in-memory Parse Database Implementation
License: MIT License
Fully Mocked in-memory Parse Database Implementation
License: MIT License
It looks like ParseMockDB.registerHook
expects a promise, even though regular Cloud Code beforeX handlers are of type function(request,response)
. The contract should be identical to Cloud Code's for fidelity. callbacks are a pain!
EDIT: Okay, instead of function(request,response)
, how about we replace the response
part with promise syntax, but leave the request
as a parameter: i.e. function(request)
.
Check the Parse.Object docs. Most *Request
types are the same as each other and the *Response
types are the same as each other too:
Parse.Cloud.AfterDeleteRequest
Parse.Cloud.AfterSaveRequest
Parse.Cloud.BeforeDeleteRequest
Parse.Cloud.BeforeDeleteResponse
Parse.Cloud.BeforeSaveRequest
Parse.Cloud.BeforeSaveResponse
Note: some assumptions have to be made about the masterKey
.
I'm writing a time-sensitive algorithm that uses createAt
in order to filter away newer records and process only older records.
However when I tried to create test rows that look like they were created in the past, I found I couldn't. I couldn't use .set()
afterwards to mutate that field either.
I configured eslint to check for function ()
and also for missing ;
.
If there's any interest, I can set it up using custom rules, or a standard set like google or airbnb and then conform and get all to pass.
I'd add a dev dependency to eslint, and i'd edit package.json to include a lint sript.
eslint can be configured in package.json.
I simply chose eslint over jshint because the first thing i googled sounded convincing, but have invested little in it, so glad to change to a preferred tool?
I blindly followed the README and ran tests to get:
48) ParseMock when object has beforeSave hook registered rejects the save if there is a problem:
Error: You need to call Parse.initialize before using Parse.
at Context.<anonymous> (test.js:828:13)
Only then did I realise npm_modules
contained 0.0.3 and not the latest 0.1.0.
ugh. I'm trying to npm link
my local parse-mockdb repo, but getting odd error, and I am curious if this is a known issue, or if I can get some help.
npm install parse-mockdb
is the same as the HEAD of my local repo. And npm test
in my project works!npm link ../parse-mockdb
npm test
in my project, I get this error:Failed: Error: You need to call Parse.initialize before using Parse.,Error: You need to call Parse.initialize before using Parse.
Stack:
Error: Failed: Error: You need to call Parse.initialize before using Parse.,Error: You need to call Parse.initialize before using Parse.
at /Users/arthur/code/Epic-Cloud/spec/feedItemSpec.js:73:35
at Array.wrappedRejectedCallback (/Users/arthur/code/Epic-Cloud/node_modules/parse/lib/node/ParsePromise.js:160:25)
at ParsePromise.reject (/Users/arthur/code/Epic-Cloud/node_modules/parse/lib/node/ParsePromise.js:95:35)
at Array.wrappedRejectedCallback (/Users/arthur/code/Epic-Cloud/node_modules/parse/lib/node/ParsePromise.js:181:19)
Any ideas?
Currently, in the request object, the user object is a string, which causes weird errors about either bad atoms or unsaved objects when attempting to use it in a beforeSave hook. This makes it really difficult to test code that depends on the user on the request.
I realize this may not be directly related to parse-mockdb, but I've spent a day on this and narrowed it way down and was wondering if you could give me any insight. It's as if jest is interfering with parse-mockdb's mocking of the REST controller. The jest tests were working until today. I have tried reverting to earlier versions of my repo where they were working, but I still get the errors. (I removed node_modules and reinstalled each time I reverted.)
I've written two very simple tests files, one using mocha and the other jest. There are no special configs for mocha or jest. Both use parse/node. Strangely, if I remove the Parse.initialize call from the mocha test, it still works, but in the jest test I get the usual complaint from Parse.
This is the mocha version, which I simply run with "mocha "
'use strict'
import Parse from 'parse/node'
import ParseMockDB from 'parse-mockdb'
Parse.initialize('test')
describe('parse-mockdb testing', () => {
it('should save correctly', () => {
ParseMockDB.mockDB(); // Mock the Parse RESTController
let
TheObj = Parse.Object.extend('TheParseObj'),
obj = new TheObj()
obj.save({message:'hello'})
.then(obj => {
assert.equal(obj.get('message'), 'hello');
ParseMockDB.cleanUp(); // Clear the Database
ParseMockDB.unMockDB(); // Un-mock the Parse RESTController
})
}
)
})
The output for the mocha test:
parse-mockdb testing
✓ should save correctly
1 passing (21ms)
This is the jest version, which I simply run with "jest "
'use strict'
import Parse from 'parse/node'
import ParseMockDB from 'parse-mockdb'
Parse.initialize('test')
describe('parse-mockdb testing', () => {
test('should save correctly', () => {
expect.assertions(1)
ParseMockDB.mockDB(); // Mock the Parse RESTController
let
TheObj = Parse.Object.extend('TheParseObj'),
obj = new TheObj()
return obj.save({message:'hello'})
.then(obj => {
expect(obj.get('message')).toBeDefined()
ParseMockDB.cleanUp(); // Clear the Database
ParseMockDB.unMockDB(); // Un-mock the Parse RESTController
})
})
})
The output for the jest test (after a 5-second wait):
parse-mockdb testing
✕ should save correctly (4593ms)
● parse-mockdb testing › should save correctly
Error
Failed: XMLHttpRequest failed: "Unable to connect to the Parse API"
● parse-mockdb testing › should save correctly
expect.assertions(1)
Expected one assertion to be called but received zero assertion calls.
at extractExpectedAssertionsErrors (node_modules/expect/build/extract_expected_assertions_errors.js:46:19)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 5.476s
I debugged both files in Webstorm, adding breakpoints in the MockRESTController and mockDB functions in node_modules/parse-mockdb/src/parse-mockdb.js (see screenshot below). When I ran the debugger, it stopped at both breakpoints in the mocha version, but only at the mockDb breakpoint in the jest version.
I noticed the lack of transpiler dependencies etc. Would you advise to use the latest Node (version 4.2.2?)
when use
const qService = new Parse.Query('Service');
qService
.get(id)
.then((service) => {
const qMember = service.relation('member').query();
return qMember.find()
});
Error Message
Type Error: Cannot read property 'object' of undefined
at node_modules/parse-mockdb/src/parse-mockdb.js:501:64
console.log(qMember);
ParseQuery {
classNmae: 'Member',
where: {'$relatedTo': {object: [Object], key: 'member'}
_include: [],
_limit: -1,
_skip: 0,
_extraOptions: {}
}
parse-mockdb is a nice repository 💯
would be useful to get recent changes.
The afterSave
hook in Parse MockDB behaves differently to a real Parse Server (v4.4.0 at time of writing).
In a real server, the afterSave
hook will provide the original object from before the save as request.original
, as well as the saved object in request.object
as expected. In other words, it should provide the same objects on the request
object as you would see in beforeSave
.
Thus, any cloud code which relies on using this information to perform certain actions when particular data has changed isn't able to be unit tested via Parse MockDB.
main.js
test_context.js
The cloud code just logs out the request.original
and request.object
in the beforeSave
hook and the afterSave
hook.
The test script just creates an object and then updates it.
Run the test Parse Server via Docker as below:
$ docker run --rm --name test-mongo -d mongo && \
> docker run --rm --name test-parse-server -p 1337:1337 -e VERBOSE=0 \
> -v $(pwd):/parse-server/cloud --link test-mongo parseplatform/parse-server \
> --appId test-app --masterKey "M@stErK3y" \
> --databaseURI "mongodb://test-mongo/test" --cloud /parse-server/cloud/main.js
...
[1] parse-server running on http://localhost:1337/parse
...
After running the test script in a separate terminal:
$ node test_context.js
Created { foo: 'bar',
createdAt: '2020-11-09T07:42:11.956Z',
updatedAt: '2020-11-09T07:42:11.956Z',
objectId: 'zwZdxCML9F' }
Updated { foo: 'baaaah',
createdAt: '2020-11-09T07:42:11.956Z',
updatedAt: '2020-11-09T07:42:12.043Z',
objectId: 'zwZdxCML9F' }
You will see this in the server logs (split into two chunks: (1) create then (2) update):
Create
BEFORE: undefined -> { foo: 'bar' }
info: beforeSave triggered for Thing for user undefined:
Input: {"foo":"bar"}
Result: {"object":{"foo":"bar"}} {"className":"Thing","triggerType":"beforeSave"}
AFTER: undefined -> {
foo: 'bar',
createdAt: '2020-11-09T07:42:11.956Z',
updatedAt: '2020-11-09T07:42:11.956Z',
objectId: 'zwZdxCML9F'
}
info: afterSave triggered for Thing for user undefined:
Input: {"foo":"bar","createdAt":"2020-11-09T07:42:11.956Z","updatedAt":"2020-11-09T07:42:11.956Z","objectId":"zwZdxCML9F"} {"className":"Thing","triggerType":"afterSave"}
info: afterSave triggered for Thing for user undefined:
Input: {"foo":"bar","createdAt":"2020-11-09T07:42:11.956Z","updatedAt":"2020-11-09T07:42:11.956Z","objectId":"zwZdxCML9F"}
Result: undefined {"className":"Thing","triggerType":"afterSave"}
Update
BEFORE: {
foo: 'bar',
createdAt: '2020-11-09T07:42:11.956Z',
updatedAt: '2020-11-09T07:42:11.956Z',
objectId: 'zwZdxCML9F'
} -> {
foo: 'baaaah',
createdAt: '2020-11-09T07:42:11.956Z',
updatedAt: '2020-11-09T07:42:11.956Z',
objectId: 'zwZdxCML9F'
}
info: beforeSave triggered for Thing for user undefined:
Input: {"foo":"baaaah","createdAt":"2020-11-09T07:42:11.956Z","updatedAt":"2020-11-09T07:42:11.956Z","objectId":"zwZdxCML9F"}
Result: {"object":{"foo":"baaaah"}} {"className":"Thing","triggerType":"beforeSave"}
AFTER: {
foo: 'bar',
createdAt: '2020-11-09T07:42:11.956Z',
updatedAt: '2020-11-09T07:42:11.956Z',
objectId: 'zwZdxCML9F'
} -> {
foo: 'baaaah',
createdAt: '2020-11-09T07:42:11.956Z',
updatedAt: '2020-11-09T07:42:12.043Z',
objectId: 'zwZdxCML9F'
}
info: afterSave triggered for Thing for user undefined:
Input: {"foo":"baaaah","createdAt":"2020-11-09T07:42:11.956Z","updatedAt":"2020-11-09T07:42:12.043Z","objectId":"zwZdxCML9F"} {"className":"Thing","triggerType":"afterSave"}
info: afterSave triggered for Thing for user undefined:
Input: {"foo":"baaaah","createdAt":"2020-11-09T07:42:11.956Z","updatedAt":"2020-11-09T07:42:12.043Z","objectId":"zwZdxCML9F"}
Result: undefined {"className":"Thing","triggerType":"afterSave"}
As you can see in the final part of the logs above, the original object and the saved object are sent through to afterSave
.
When saving an object with nested objects that are already fetched, exactly those nested objects should still be fetched after the save. Check out the following unit test that asserts this:
it('should keep fetched nested objects fetched after the save', function() {
return new Item().save({
price: 45
}).then(function(item0) {
return new Item().save({
price: 50
}).then(function(item2) {
return new Item({
price: 55
}).save().then(function(item3) {
const brand = new Brand();
const item1 = new Item();
item1.id = item0.id; // create pointer to item0
brand.set("items", [item1, item2, item3]);
return brand.save();
});
});
}).then(function(brand) {
assert.equal(brand.get("items")[0].get("price"), undefined);
assert.equal(brand.get("items")[1].get("price"), 50);
assert.equal(brand.get("items")[2].get("price"), 55);
brand.get("items")[0].set("price", 30);
brand.set("name", "foo");
return brand.save();
}).then(function(sbrand) {
assert.equal(sbrand.get("items")[0].get("price"), undefined);
assert.equal(sbrand.get("items")[1].get("price"), 50);
assert.equal(sbrand.get("items")[2].get("price"), 30);
});
});
Hi @TylerBrock,
i'm continuing to investigate #27, and i have a pr coming up real soon, but wanted to get your feedback on a question.
As part of digging into my most recent change and why it broke my tests, I was wondering why the tests didn't fail on parse-mockdb. I then added a test that should have failed, but it didn't, ok. That's when I noticed that the test wasn't using done(). Ok. Fixed that, but then I see that when an assertion in a promise fails, it doesn't get caught by the test runner.
I created a branch to show what I mean. acinader@292fa00
In any event, it seems to me that Parse.Promise and mocha don't play well together. Have you noticed what I am talking about?
I'm game to give it some thought, but before I waste our time, I figured I'd ask if this is in any way on your radar screen?
It's really useful if a test is able to perform verifications on the state of the database after the 'afterSave' hook completes. Usually I use afterSave
to trigger updates on other classes' fields and it's important for that behaviour to be verified.
see parse-community/Parse-SDK-JS#89
but is still failing.
it looks busted....
https://github.com/HustleInc/parse-mockdb/blob/master/src/parse-mockdb.js#L699
the first if does something, but doesn't return anything....
maybe its doing something to the passed in ref? in any event, a unit test couldn't hurt....
@TylerBrock can we please release a new version to npm containing #29 and #26
Just tried upgrading — but tests fail because the following methods were removed
_.all
_.any
... and after that, 5 test are broken.
Given a model MyModel
with a column tags
containing an array of pointers to a Tag
model:
Parse Server:
var q = new Parse.Query(MyModel);
q.equalTo('tags', [tag])
q.find().fail(err => console.log(err))
results in this error:
ParseError {
code: 107,
message: 'You cannot use [object Object] as a query parameter.' }
MockDB finds and returns the matching objects.
Does ParseMockDB remove the need to initialize this?
When retrieving a relation objects via relation.query
, the resulting output have the className
of the parent object, even though they have been correctly created, which causes issues downstream.
beforeSave
hooks often decide what to do based on whether a specific field had changed. It's important to test for no-ops sometimes, for performance reasons, especially when triggers are limited to 3 seconds of wall-clock execution time only.
https://parse.com/docs/js/api/classes/Parse.Object.html#methods_dirty
It's clear that dirty()
and dirtyKeys()
of the request.object
returns undefined.
I didn't really find a way to call cloud jobs using this lib:
(node:9393) UnhandledPromiseRejectionWarning: TypeError: Parse.Cloud.job is not a function
This is my temporary solution by just adding this file mock.CloudJob.js
somewhere:
module.exports = function(Parse){
Parse.Cloud = {
jobs:{},
define: function(){},
job: function(k,f){
Parse.Cloud.jobs[k] = f
},
startJob: function(k,v){
return Parse.Cloud.jobs[k](v)
}
}
}
Now in your code you can do require('mock.CloudJob')(Parse)
and register & start Cloud-jobs as usual.
NOTE: I know this hack doesn't really follow the narrative of this lib, therefore I just figured to post this here (instead of doing a PR which doesn't really fit this lib). It might be useful to someone, or could start a brainstorm for Cloud-jobs in parse-mockdb.
Hello,
I'm running into a problem when I register both beforeSave
and afterSave
hooks; my afterSave
hook relies on the class to be saved. This isn't a problem when I test the hooks separately but I need to be able to run both hooks in other tests. I've got a simple reproduction that might help.
const Parse = require('parse-shim');
const ParseMockDB = require('parse-mockdb');
class Target extends Parse.Object {
constructor(attributes, options) {
super('Target', attributes, options);
}
}
Parse.Object.registerSubclass('Target', Target);
ParseMockDB.mockDB();
ParseMockDB.registerHook('Target', 'afterSave', (request) => {
console.warn(`calling afterSave, isNew() => ${request.object.isNew()}`);
return Parse.Promise.as(request.object);
});
ParseMockDB.registerHook('Target', 'beforeSave', (request) => {
console.warn(`calling beforeSave, isNew() => ${request.object.isNew()}`);
return Parse.Promise.as(request.object);
});
const target = new Target({
title: 'Hello, world',
});
target.save()
.then(() => {
console.warn(`after hooks, isNew() => ${target.isNew()}`)
})
.then(() => {
ParseMockDB.cleanUp();
ParseMockDB.unMockDB();
});
When I run this code, I get this output:
calling beforeSave, isNew() => true
calling afterSave, isNew() => true
after hooks, isNew() => false
However, when I remove the beforeSave
handler, I get:
calling afterSave, isNew() => false
after hooks, isNew() => false
The expected behaviour is that with the beforeSave
handler, the log should be:
calling beforeSave, isNew() => true
calling afterSave, isNew() => false
after hooks, isNew() => false
Let me know if you need any further details or if I can be of assistance.
This is a combo question / feature request.
I just want to confirm that Parse.File.save() doesn't work on marse-mockdb.
When I do:
const parseFile = new Parse.File('test.json', { base64: "{}".toString('base64') });
await parseFile.save();
I get no error, but when I try to save the object the file is set on, I get "Tried to encode an unsaved file."
Is there a workaround for mocking parse files? And if not, has anyone looked into what it'll take to mock it. I can look into it, but want to be sure no one else is doing it (or has decided that it's not possible / worth the effort).
It appears the latest version published to NPM is 0.2.1. I need to use the changes from the latest package release but since it's unpublished, it is unavailable.
Parse.User
doesn't seem well supported right now because if you perform a save
operation, Parse.User
returns an undefined className
. This doesn't play well with the way that Parse mockDB resolves its paths. The underlying request path looks like users
rather than classes/ClassName/1
.
Furthermore, you're allowed to subclass Parse.User
with the Parse JS SDK:https://www.parse.com/questions/extending-the-default-parse-user. Subclasses are also not supported.
@fatuhoku has three outstanding pr's from December. The only thing outstanding is to squash, which hasn't happened in six months and is preventing the mainline from being as useful as it could be. I think that there are a few options:
I am going to mege his pr's into my master and change my npm to pull my master. if i then make any changes (like adding a mock response to the before save) they wont be able to be merged in to this repo
:(.
should
'$exists': function(value) {
return !!this === value;
},
When an object is 'saved' for the first time, its ACL should be set to Public Read/Write.
This is necessary to test that the beforeSave
sets ACL's as appropriate.
I am seeing an issue where saving a custom class that extends Parse.Object results in the
You need to call Parse.initialize before using Parse.
error message when the _CoreManager
tries to get the APPLICATION_ID
.
class CoolClass extends Parse.Object {
constructor(attributes) {
// Pass the ClassName to the Parse.Object constructor
super('CoolClass');
// All other initialization
this.coolness = 'awesome';
}
}
let coolClass = new CoolClass();
coolClass.save() <<<<<<<<<<<<<<<<< Problem occurs here
The following code however works as expected.
let coolClass = new Parse.Object("CoolClass");
coolClass.save();
Am I missing something or custom classes not supported?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.