Is it possible to stub meteor methods and publications in cypress tests? - meteor

Is it possible to stub meteor methods and publications in cypress tests?
In the docs (https://docs.cypress.io/guides/getting-started/testing-your-app#Stubbing-the-server) it says:
This means that instead of resetting the database, or seeding it with
the state we want, you can force the server to respond with whatever
you want it to. (...) and even test all of the edge cases, without needing a server.
But I do not find more details about that. All I can find is, that when not using the virtual user in the tests to fill the database, it is possible to call API calls on the app, like so:
cy.request('POST', '/test/seed/user', { username: 'jane.lane' })
.its('body')
.as('currentUser')
In my opinion that is not a "stub". It is a method to "seed" the database.
Is it possible to tell cypress to answer a meteor method in the client code like
Meteor.call('getUser', { username: 'jane.lane' }, callbackFunction);
with some data, it would give back in production?

I can only show an example using sinon to stub Meteor method calls:
const stub = sinon.stub(Meteor, 'call')
stub.callsFake(function (name, obj, callback) {
if (name === 'getUser' && obj.username === 'jane.lane') {
setTimeout(function () {
callback(/* your fake data here */)
})
}
})
That would be of corse a client-side stub. You could also simply override your Meteor method for this one test.

Related

Secure client side env variables in Next JS

I am worried that my Keys for various functions are exposed to the client. I have this function
onRunOCR = async (event) => {
const client = new SomeAPI({
credentials: {
accessKeyId: 'ffg23f23f23f32f23',
secretAccessKey: 'GZMIKGDoISDGpsgjMIPSGMDIPG',
},
})
}
This is basically an on click function in my class component. This is fully exposed to anyone right?
How can I secure it. Would NEXT_PUBLIC_ACCESS_KEY work or is that the same just stores it as a variable?
Thanks
Yes, keys are exposed in your example.
Anyone can access private keys that are exposed to the browser. The most common way to prevent key leakage is only to use them server-side.
You can create an API route or a custom endpoint like an AWS Lambda function that you call in your onClick handler.
Using env variables in your server-side function is okay as they are never rendered to the browser.
.env file
API_KEY_ID=123456
API_ACCESS_KEY=ABCDEF
API route
export default function handler(_, res) {
const data = new SomeAPI({
credentials: {
accessKeyId: process.env.API_KEY_ID,
secretAccessKey: process.env.API_ACCESS_KEY,
},
})
res.status(200).json(data)
}
Other default Next.js server-side features/functions it's okay to place keys are getServerSideProps, getStaticProps, getStaticPaths, and middleware.

How to access custom response values from a page script?

This might sound like a silly question but I have really tried everything I could to figure it out. I am creating a variable and adding it to my response object in custom Express server file like so:
server.get('*', (req, res) => {
res.locals.user = req.user || null;
handle(req, res);
});
Now I want to access this res.locals.user object from all of my pages, i.e. index.js, about.js, etc., in order to keep a tab on the active session's user credentials. It's got to be possible some way, right?
P.S.: Reading some thread on the NextJS Github page, I tried accessing it from my props object as this.props.user but it keeps returning null even when a server-side console.log shows non-null values.
The res object is available on the server as a parameter to getInitialProps. So, with the server code you have above, you can do
static async getInitialProps({res}) {
return { user: res.locals.user }
}
to make it available as this.props.user.

Meteor 1.0 - Custom Authentication Rules

I've a meteor app which uses Neo4j as a database with neo4jreactivity driver. Since I'm not using Mongo, Meteor.loginWithPassword(email, password, function(err) {...}) doesn't work. My question is:
How do I define custom authentication rule to login to the app?
kind of like:
customLogin(email, password, function() {...});
You can use the Accounts.registerLoginHandler method to accomplish this. This function allows developers to add custom authentication methods. Check out https://meteorhacks.com/extending-meteor-accounts.html for a great article with more details.
You likely want to continue to use loginWithPassword, and register a loginHandler similar to the one in Meteor's accounts-password package (see
Meteor's implementation ), with the call to Meteor.users.findOne(selector) replaced with a database lookup in Neo4j.
If you want to use a custom login method, your code might look something like the code from here (modified for the purposes of this question). Note that this code is not complete, nor is it a secure means of authenticating:
// client-side
// This function can be called to log in your users, and will
// trigger the following
Meteor.loginWithNeo4j = function(email, password, callback) {
//create a login request with the email and password passed in
var loginRequest = {email: email, password: password};
//send the login request
Accounts.callLoginMethod({
methodArguments: [loginRequest],
userCallback: callback
});
};
// server-side
Accounts.registerLoginHandler(function(loginRequest) {
// loginRequest is a JS object that will have properties
// "email" and "password as passed in the client code
// -- here you can write code to fetch the user's ID from the database
// take a look at https://github.com/meteor/meteor/blob/devel/packages/accounts-password/password_server.js#L61
// to see how meteor handles password checking
return {
userId: userId
}
});
The accounts package in general has a lot of dependencies on MongoDB, but you should be able to piece together various methods from the package to get auth to work.
To fetch user's object use:
Meteor.neo4j.query('MATCH (a:Player {_id: "kE3ypH4Um"}) RETURN a').get().a[0]
/* or by email */
Meteor.neo4j.query('MATCH (a:Player {email: "name#domain.com"}) RETURN a').get().a[0]
Also see updated driver API

Are there 'private' server methods in Meteor?

Is there a way to stop a Client calling a Server Method from the browser console?
I gather from the Unofficial Meteor FAQ that there isn't. I just wanted to check if that's definitely the case - the FAQ isn't really specific. I mean are there no 'private' methods?
In meteor the 'methods' described by Meteor.methods can all be called from the client. In this sense there aren't private methods because the purpose of the RPC call is for the client to make the call.
If you want a 'private' method you could use an ordinary JavaScript method. If you define the method with var, it would only be accessible within the file, and cannot be called from the client.
var yourmethod = function() {
...
}
which is equivalent to:
function yourmethod() {
...
}
Or you can define it so any of your server script can use it:
yourmethod = function() {
....
}
If you mean you want a RPC method call that is accessible only from the javascript code, but not from the javascript console in chrome this isn't possible. This is because the idea behind meteor is all RPCs from the client are not trusted & there is no way to distinguish whether it came from the console or not. You can use meteor user authentication or Collection.allow or Collection.deny methods to prevent any unauthorized changes this way.
I made a private method by checking this.connection to be null.
Ref: http://docs.meteor.com/#/full/method_connection
Ex.
Meteor.methods({
'serverCallOnlyFunc': function() {
if (this.connection === null) {
//do something
} else {
throw(new Meteor.Error(500, 'Permission denied!'));
}
}
});

Using tinytest to test Meteor client while the server is running

Is it possible to test the Meteor client while the server is running using tinytest? Here's my example testing the client only:
Tinytest.add("Add object to a collection", function(test) {
var people = new Meteor.Collection("people");
people.insert({"name": "Andrew"}, function(error, id) {
test.isNull(error);
});
});
For a fraction of a second this passes, but then it goes into the state of "waiting". I'm also positive that error is not null.
Meteor.Error {error: 404, reason: "Method not found", details: undefined}
I know this is happening because their is no server for the client to communicate with. When I try to run this test on the server and client, I continue to get the same issue with the client. Is there a way to test the client while the server is running?
Thanks, Andrew
Use new Meteor.Collection with no argument to create a stub collection that doesn't require the server. See the docs on Collections:
If you pass null as the name, then you're creating a local collection. It's not synchronized anywhere; it's just a local scratchpad that supports Mongo-style find, insert, update, and remove operations.
This is an async test, so you'll have to use addAsync.
Tinytest.addAsync("Add object to a collection", function(test, next) {
var people = new Meteor.Collection("people");
people.insert({"name": "Andrew"}, function(error, id) {
test.isNull(error);
next();
});
});
Note the next argument which signals that you are done in the callback.

Resources