May 10, 2021 Meteor
We've created a reusable pattern in our reporting of errors, so why not package it for others in the Meteor community to use?
To get started, we need a Meteor developer account. Y ou can apply meteor.com, but chances are you'll get it by the time you sign up for the book. In either case, you should find out what your userna name is, as we'll use it extensively in this chapter.
In this chapter we use the username
tmeasday
of course you can change it to your own.
First we need to create a structure to hold the new package. U
se the
meteor create --package tmeasday:errors
to complete. I
t is important to note that Meteor has created a folder and some files
packages/tmeasday:errors/
Let's
package.js
which tells Meteor what objects or functions to export if you use the package.
Package.describe({
name: "tmeasday:errors",
summary: "A pattern to display application errors to the user",
version: "1.0.0"
});
Package.onUse(function (api, where) {
api.versionsFrom('0.9.0');
api.use(['minimongo', 'mongo-livedata', 'templating'], 'client');
api.addFiles(['errors.js', 'errors_list.html', 'errors_list.js'], 'client');
if (api.export)
api.export('Errors');
});
When developing a real-world package, it's a great
git
URL of your code base (for example, in the
Package.describe
block of https://github.com/tmeasday/meteor-errors.git the git
https://github.com/tmeasday/meteor-errors.git
That way, users can browse the source code, and (assuming you use GitHub) your package's readme appears on Atomsphere.
Let's add 3 files to the package. (We can remove the templates that Meteor automatically adds) We can pull these files from Microscope without much modification, except for some suitable naming and slightly clearer APIs:
Errors = {
// Local (client-only) collection
collection: new Mongo.Collection(null),
throw: function(message) {
Errors.collection.insert({message: message, seen: false})
}
};
<template name="meteorErrors">
<div class="errors">
{{#each errors}}
{{> meteorError}}
{{/each}}
</div>
</template>
<template name="meteorError">
<div class="alert alert-danger" role="alert">
<button type="button" class="close" data-dismiss="alert">×</button>
{{message}}
</div>
</template>
Template.meteorErrors.helpers({
errors: function() {
return Errors.collection.find();
}
});
Template.meteorError.rendered = function() {
var error = this.data;
Meteor.setTimeout(function () {
Errors.collection.remove(error._id);
}, 3000);
};
Now we need to do local testing on Microscope to make sure the code is working correctly. I
n order to link the package to the project, we
meteor add tmeasday:errors
Then, you need to delete existing files that have become redundant:
rm client/helpers/errors.js
rm client/templates/includes/errors.html
rm client/templates/includes/errors.js
Another thing we need to do is do some small updates using the correct API:
{{> header}}
{{> meteorErrors}}
Meteor.call('postInsert', post, function(error, result) {
if (error) {
// display the error to the user
Errors.throw(error.reason);
Posts.update(currentPostId, {$set: postProperties}, function(error) {
if (error) {
// display the error to the user
Errors.throw(error.reason);
Once these modifications are complete, we can resume our pre-subcontracted behavior.
The first step in a development package is to test it in an application, but the next step is to write a test suite that corrects the behavior of the test package. Meteor itself comes with Tinytest ( the built-in package tester) that makes it easy to run the test suite to make sure the package is correct when sharing it with others.
Let's create a test file and use Tinytest to run some tests on the new package:
Tinytest.add("Errors - collection", function(test) {
test.equal(Errors.collection.find({}).count(), 0);
Errors.throw('A new error!');
test.equal(Errors.collection.find({}).count(), 1);
Errors.collection.remove({});
});
Tinytest.addAsync("Errors - template", function(test, done) {
Errors.throw('A new error!');
test.equal(Errors.collection.find({}).count(), 1);
// render the template
UI.insert(UI.render(Template.meteorErrors), document.body);
Meteor.setTimeout(function() {
test.equal(Errors.collection.find({}).count(), 0);
done();
}, 3500);
});
In these tests, we check to see if
Meteor.Errors
functionality works, and to confirm again that
rendered
is still working.
We won't write all the details of the Meteor package test here (and the API hasn't been finalized yet, and it's likely to change), but hopefully it's a way to explain itself to some extent.
Use the following code to tell Meteor how to run .js in the
package.js
Package.onTest(function(api) {
api.use('tmeasday:errors', 'client');
api.use(['tinytest', 'test-helpers'], 'client');
api.addFiles('errors_tests.js', 'client');
});
Then we can run the test:
meteor test-packages tmeasday:errors
Now we're going to release this package, push it to the Meteor package server, and show it in Atmopshere for people all over the world to use.
Fortunately, it's easy.
We're just cd-to-package directories,
meteor publish --create
cd
cd packages/tmeasday:errors
meteor publish --create
Now that the package has been published, we can remove it from the project and add it directly from Atmopshere:
rm -r packages/tmeasday:errors
meteor add tmeasday:errors
Now we should see Meteor download our package for the first time. It's great!
As in the usual appendix sections, make sure to restore your changes before moving on to the next chapter (or consider your changes as you read other chapters of the book). )