Meteor 1.3 server testing - meteor

I'm trying to understand http://guide.meteor.com/testing.html testing guide but honestly I have no idea how to run server side test on mocha driver. Everything is run as Client test and I have 0 tests on "Server tests".
If I place test file under server/ (server/users.test.js) it will be loaded and executed (ie. console.log('foo') ) but function inside describe .. will not.
EDIT:
if(Meteor.isServer) {
describe('todos', function () {
describe('mutators', function () {
console.log(1)
it('builds correctly from factory', function () {
console.log(2);
});
});
});
}
inside imports/api/user/users.test.js printed "1" but not "2"

Related

Getting TestCafe to recognize dotenv variables

I might be mixing up concepts, but I'd read that it's possible to get TestCafe to recognize variables of the form process.env.MY_COOL_VARIABLE. Also for my Vue.js frontend (built using Vue-CLI, which uses dotenv under the hood), I found I could make a file in .env.test for test values like so:
VUE_APP_MY_COOL_VARIABLE
which I would then access in my test code like so:
test('my fixture', async (t) => {
...
await t
.click(mySelector.find('.div').withText(process.env.VUE_APP_MY_COOL_VARIABLE));
...
}
However, I get the following error:
"text" argument is expected to be a string or a regular expression, but it was undefined.
Seems like my environment variables aren't getting picked up. I build my code like so: vue-cli-service build --mode test.
TestCafe doesn't provide support for .env files out of the box. You can create a test file that will require the dotenv module and load your configuration file:
// enable-dotenv.test.js
require('dotenv').config({ path: '.my.env' });
testcafe chrome enable-dotenv.test.js tests/
Here's how I solved my issue. When debugging, I did a console.log of process.env and noticed that the variable that vue recognizes wasn't visible during testcafe's run. From our package.json:
"test:ui:run": "VUE_APP_MY_COOL_VARIABLE=ui-test yarn build:test && testcafe -a ../ui-test-server.sh chrome",
Also this bit of javascript is run by both the test and mainline code, so I had to use a conditional.
import * as dotenv from 'dotenv';
if (process.env.npm_package_scripts_test_ui_run) { // are we running a testcafe script
dotenv.config({ path: '.env.test' });
}
Have you tried process.env[VUE_APP_MY_COOL_VARIABLE]? It's worth noting that everything in dotenv comes back as a string so you may need to do the casting yourself. For example:
function getEnvVariableValue(envVariable: string) {
// Cast to boolean
if (envVariableValue.toUpperCase() === "TRUE") {
return true;
} else if (envVariableValue.toUpperCase() === "FALSE") {
return false;
// Cast to number
} else if (!isNaN(Number(envVariableValue))) {
return Number(envVariableValue);
} else {
return envVariableValue;
}
}
You can also try creating a .env file in the root folder to see if it picks it that way. I use dotenv in my project directly by including it in the package.json as a dependency and it works this way.

Disable web security in Cypress just for one test

After reading the Cypress documentation on web security and when to disable it, I've decided I indeed need to do it. Is there a way to disable this just for one particular test/test suite? I'm using version 3.4.1 and this config is being set in cypress.json - therefore it's global for all tests.
Is there a way to disable web security just for one test? Thanks!
Original answer:
Does this work for you?
describe("test the config json", function () {
it("use web security false here", function () {
Cypress.config('chromeWebSecurity',false);
cy.visit("https://www.google.com");
console.log(Cypress.config('chromeWebSecurity'));
});
it("use web security true here", function () {
Cypress.config('chromeWebSecurity',true);
cy.visit("https://www.google.com");
console.log(Cypress.config('chromeWebSecurity'));
});
});
The config is changed as you can see from the console log.
See document here https://docs.cypress.io/guides/references/configuration.html#Cypress-config
Updates:
After I saw DurkoMatKo's comment I managed to find an URL to test this 'chromeWebSecurity' option. It did not work as expected.
I think changing this config might not work during running the same browser as this is more like a browser feature which will determine when start.
In this case what I can think of is only to run Cypress with different configurations.
The cypress doc here shows clear steps to do this.
hope this helps.
In my case it worked as follows.
the first thing was to set chromeWebSecurity to false
//cypress.json
{
"chromeWebSecurity": false
}
Then what I do is with a before assign it to true with Cypress.config
//cypress/integration/testing.spec.js
context('DEMO-01', () => {
beforeEach(function () {
Cypress.config('chromeWebSecurity', true);
});
describe('CP001 - start dasboard', () => {
it('P01: open dashboard', () => {
cy.visit(URL);
});
});
});

Meteor - file download with meteor-files package ( ostrio:files)

I would need some help with meteor-files package
I'm following the simplest-download DEMO here https://github.com/VeliovGroup/Meteor-Files/tree/master/demo-simplest-download-button and getting on a few bumpers. First here is the code:
this.Books = new Meteor.Files({
debug: true,
collectionName: 'Books'
});
// To have sample file in DB we will upload it on server startup:
if (Meteor.isServer) {
Books.denyClient();
Books.collection.attachSchema(Books.schema);
Meteor.startup(function () {
if (true) {
Books.load('http://localhost:3000/file.pdf', {
fileName: 'file.pdf',
meta: {}
});
}
});
Meteor.publish('Books', function () {
return Books.find().cursor;
});
} else {
Meteor.subscribe('Books');
}
Problem - When I c/p the code from the git then there is this condition if
(!Images.find().count())
which meteor just doesn't recognize as a function and breaks there. I fixed that with just replacing it with TRUE as you can see in code
Problem is that now everything runs and my file is successfuly imported but I can see in the server log that he is not able to find the file resulting in:
[FilesCollection] [load] Received: http://localhost:3000/file.pdf
I20160806-14:00:27.190(2)? [FilesCollection] [load] [insert] file.pdf -> Books
I20160806-14:00:29.360(2)? [FilesCollection] [find(undefined)]
I20160806-14:00:33.045(2)? [FilesCollection] [find(undefined)]
The package was out of date and needed a meteor update from my side. If someone will need

Meteor/Iron-Router: how to define routes using data from settings.json

For the URL to which a route applies I have a part defined in settings.json, like this
baseUrl: '/private'
My settings are published and accessible through the collections 'Settings' (on the client). So I tried the following:
Meteor.subscribe('settings');
Deps.autorun(function () {
var settings = Settings.findOne():
if (settings) {
Router.map(function () {
this.route('project', {
path: settings.baseUrl + '/:projectId,
controller: 'ProjectController'
});
});
}
});
The problem is that during initialisation the data is not yet on the client available, so I have to wait until the data is present. So far this approach doesn't work (yet). But before spending many hours I was wondering if someone has done this before or can tell me if this is the right approach ?
Updated answer:
I published solution in repository : https://github.com/parhelium/meteor-so-inject-data-to-html
. Test it by opening url : localhost:3000/test
In this case FastRender package is useless as it injects collection data in the end of head tag -> line 63.
Inject-Initial package injects data in the beginning of head tag -> line 106.
Needed packages:
mrt add iron-router
mrt add inject-initial
Source code:
Settings = new Meteor.Collection("settings");
if (Meteor.isClient) {
var settings = Injected.obj('settings');
console.log(settings);
Router.map(function () {
this.route('postShow', {
path: '/'+settings.path,
action: function () {
console.log("dynamic route !");
}
});
});
}
if (Meteor.isServer){
if(Settings.find().count() == 0){
Settings.insert({path:"test",data:"null"});
}
Inject.obj('settings', Settings.findOne());
}
Read about security in the bottom of the page : https://github.com/gadicc/meteor-inject-initial/
OLD ANSWER :
Below solution won't work in this specific case as FastRender injects data in the end of head tag. Because of that Routes are being initialized before injected data is present.
It will work when data from Settings collection will be sent together with html.
You can do that using package FastRender.
Create file server/router.js :
FastRender.onAllRoutes(function(path) {
// don't subscribe if client is downloading resources
if(/(css|js|html|map)/.test(path)) {
return;
}
this.subscribe('settings');
});
Create also publish function:
Meteor.publish('settings', function () {
return Settings.find({});
});
The above code means that if user open any url of your app then client will subscribe to "settings" publication and data will be injected on the server into html and available for client immediately.
I use this approach to be able to connect many different domains to meteor app and accordingly sent proper data.

How can I implement a call to a package that doesn't use fibers from with Meteor?

I am trying to use twit in Meteor in order to communicate to the Twitter REST api.
It works fine in say a server.js file in the /server/ directory if I call it by itself. If I wrap or call it from within say an observe or even call a function that calls twit's functions from an observe I get errors.
For example this works perfectly fine within a /server/server.js.
T.post('statuses/update', { status: 'hello world!' }, function(err, reply) {
console.log('error: ' + JSON.stringify(err,0,4));
console.log('reply: ' + JSON.stringify(reply,0,4));
});
But, suppose I want to say call Twitter every time a record is inserted.
var query = Posts.find({}, {fields: {}});
var handle = query.observe({
added: function(post, before_index){
if(post.twitter_id_str === undefined || post.twitter_id_str === '' ||
post.twitter_id_str === null) {
T.post('statuses/update', { status: 'hello world!' }, function(err, reply) {
console.log('error: ' + JSON.stringify(err,0,4));
console.log('reply: ' + JSON.stringify(reply,0,4));
if(reply){
// TODO update record with twitter id_str
// BREAKS here - crash, restart
console.log('incoming twitter string: ' + reply.id_str);
Posts.update(
{_id: post._id},
{$set:{twitter_id_str:reply.id_str}}
);
}
});
} else {
console.log('remove me we have it: ' + post.twitter_id_str);
}
}
});
Which throws this error, server crashes and restarts but no code logic is run where I have commented the Break.
app/packages/mongo-livedata/collection.js:215
throw e;
^
Error: Meteor code must always run within a Fiber
at [object Object].get (app/packages/meteor/dynamics_nodejs.js:14:15)
at [object Object]._maybeBeginWrite (app/packages/mongo-livedata/mongo_driver.js:68:41)
at [object Object].update (app/packages/mongo-livedata/mongo_driver.js:191:20)
at [object Object].update (app/packages/mongo-livedata/collection.js:203:32)
at app/server/server.js:39:13
at /usr/lib/meteor/lib/node_modules/twit/lib/oarequest.js:85:16
at passBackControl (/usr/lib/meteor/lib/node_modules/twit/node_modules/oauth/lib/oauth.js:359:11)
at IncomingMessage.<anonymous> (/usr/lib/meteor/lib/node_modules/twit/node_modules/oauth/lib/oauth.js:378:9)
at IncomingMessage.emit (events.js:88:20)
at HTTPParser.onMessageComplete (http.js:137:23)
Exited with code: 1
In summary, the Twitter code runs fine on it's own but not when within the Meteor fibers stuff. I tried putting it in another function and calling that from within the observe etc... no avail.
Any recommendations or ideas?
You'll need to do the twit post API call in a fiber:
Fiber(function() { ... your twit API call ... }).run()
Have a look at this related question: "Meteor code must always run within a Fiber" when calling Collection.insert on server

Resources