[SOLVED] ValidatedMethod crashes while testing

All I have to do is import my ValidatedMethod into the test, and it crashes with:

Error: A method named ‘walks.writeInitialRecord’ is already defined

import { Meteor } from 'meteor/meteor';
import { Walks } from './collections';

import SimpleSchema from 'simpl-schema';
import { ValidatedMethod } from 'meteor/mdg:validated-method';

export const writeInitialRecordMethod = new ValidatedMethod({
    name: 'walks.writeInitialRecord',
    mixins: [simpleSchemaMixin],
    validate: Walks.simpleSchema().validator(),
    run({ walkName }) {
        return Walks.insert({walkName: walkName});
    }
});

Meteor.methods({
    [writeInitialRecordMethod.name]: function(args){
        writeInitialRecordMethod.validate.call(this, args);
        writeInitialRecordMethod.run.call(this, args);
    }
});


Here is the test code in a file called first.app-test.js (as you can see there is no code - because all I have to do is import the method, and everything crashes):

import chai from 'chai';
import { writeInitialRecordMethod }  from '../methods';

I have searched for the string ‘walks.writeInitialRecord’ in all of my code and can confirm that this string is only found in one place - in my ValidatedMethod.

Here is the Collections and SimpleSchema stuff:

import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';


export let Walks = new Mongo.Collection('walks');
Walks.attachBehaviour('timestampable');

export let Schemas = {};

Schemas.Walks = new SimpleSchema({
    walkName:    {type: String},
});

Walks.attachSchema(Schemas.Walks);

If I write my own code, without ValidatedMethod, it works. Here is my working code:

export const writeInitialRecordMethod = {
    name: 'walks.writeInitialRecord',
    validate(args) {
        new SimpleSchema({
            walkName:    {type: String},
        }).validate(args)
    },
    run({ walkName }) {
        return Walks.insert({walkName: walkName});
    }
};

Here is the full error:

W20170810-12:31:11.545(2)? (STDERR) Error: A method named ‘walks.writeInitialRecord’ is already defined
W20170810-12:31:11.545(2)? (STDERR) at packages/ddp-server/livedata_server.js:1592:15
W20170810-12:31:11.546(2)? (STDERR) at Function..each..forEach (packages/underscore.js:147:22)
W20170810-12:31:11.546(2)? (STDERR) at [object Object]..extend.methods (packages/ddp-server/livedata_server.js:1588:7)
W20170810-12:31:11.547(2)? (STDERR) at meteorInstall.imports.server.methods.js (imports/server/methods.js:44:8)
W20170810-12:31:11.547(2)? (STDERR) at fileEvaluate (packages/modules-runtime.js:333:9)
W20170810-12:31:11.548(2)? (STDERR) at require (packages/modules-runtime.js:228:16)
W20170810-12:31:11.548(2)? (STDERR) at meteorInstall.imports.server.test.first.app-test.js (imports/server/test/first.app-test.js:1:105)
W20170810-12:31:11.549(2)? (STDERR) at fileEvaluate (packages/modules-runtime.js:333:9)
W20170810-12:31:11.549(2)? (STDERR) at require (packages/modules-runtime.js:228:16)
W20170810-12:31:11.550(2)? (STDERR) at /private/var/folders/3n/2yry_ys510q6dx0frpznpc4c0000z
/T/meteor-test-runnvkqdp/.meteor/local/build/programs/server/app/app.js:764:1

Why are you doing that? Read the ValidatedMethod docs to see how you’re supposed to use it. In your code, ValidatedMethod will create a Meteor Method for you called "walks.writeInitialRecord", then you immediately try to create a new Meteor Method with the same name.

Error: A method named ‘walks.writeInitialRecord’ is already defined

The error message tells you what’s happening, you’re creating another Meteor Method with the same name.

Read the docs is always good advice, but I’ve come here as a last resort after three days looking at the problem and after reading the docs many, many times.

I have read the error message more times than I can count.

You say that I immediately try to create a new Meteor Method with the same name.
Would you mind pointing out where this happens - on which line?
That would solve my problem. I can’t see it myself.

Thanks.

export const writeInitialRecordMethod = new ValidatedMethod({
    name: 'walks.writeInitialRecord',
    mixins: [simpleSchemaMixin],
    validate: Walks.simpleSchema().validator(),
    run({ walkName }) {
        return Walks.insert({walkName: walkName});
    }
});

This above actually goes and creates a Meteor Method for you in the background.

Then you immediately try to create another Meteor Method with the same name in this bit below

Meteor.methods({
    [writeInitialRecordMethod.name]: function(args){
        writeInitialRecordMethod.validate.call(this, args);
        writeInitialRecordMethod.run.call(this, args);
    }
});

That code is nowhere in the docs so idk where you got the idea to do that. Just remove that entirely, it’s redundant, the new ValidatedMethod() already did that for you in the background. Then when you want to call the ValidatedMethod you import it and call it like they show you in the docs:

import { writeInitialRecordMethod } from './some-file';

...
writeInitialRecordMethod.call(args, callback);

That code does not create another Meteor Method: it creates a single Meteor method, which calls the ValidatedMethod.

That code is from the Meteor guide to Methods. https://guide.meteor.com/methods.html#advanced-boilerplate
Look at the last four lines of code there.

Advanced boilerplate is designed to facilitate testing, among other things.

No, the snippet you’re looking at is an example of the boilerplate you would have to write if you didn’t use the validated-method package. Read the next section of that same page:

To alleviate some of the boilerplate that’s involved in correct Method definitions, we’ve published a wrapper package called mdg:validated-method that does most of this for you.

Then look at the code example below that which is how to use validated-method, which does that boilerplate for you

If you read a little further down it says:

You call it the same way you call the advanced Method above, but the Method definition is significantly simpler.

It has to be called from inside a Meteor.methods block, otherwise it isn’t a Meteor method.
If I’m honest I’d be grateful if you’d give someone else a chance to answer, I’m not sure you’ve worked on this stuff much.

I’ve been working with Meteor and enterprise software in general for years, and I’ve given you the correct answer a few times already. I even told you the exact lines of code to remove to get it working, instead of arguing against my advice just remove those lines of code and you’ll see that I’m right. It seems like you’re confused by that page in the Meteor Guide, so I would advise you to ignore it and you just read the README for the validated-method and follow the example exactly as it’s displayed.

Perhaps looking at the source code for the validated-method package would help you understand that it does actually create a Meteor Method for you.

You’re right ! It works !
The guide confused me.

I can see in the todos app, which uses ValidatedMethods, that the Meteor.methods block has disappeared.

Thanks for continuing to answer despite my total scepticism.
I am always amazed and grateful that people take the time to answer some of my questions.
Thanks again.

1 Like