mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'release-1.5.2' into release-1.6
This commit is contained in:
@@ -45,6 +45,11 @@
|
||||
* The `meteor-promise` package has been upgraded to version 0.8.5,
|
||||
and the `promise` polyfill package has been upgraded to 8.0.1.
|
||||
|
||||
* `Accounts.config` no longer mistakenly allows tokens to expire when
|
||||
the `loginExpirationInDays` option is set to `null`.
|
||||
[Issue #5121](https://github.com/meteor/meteor/issues/5121)
|
||||
[PR #8917](https://github.com/meteor/meteor/pull/8917)
|
||||
|
||||
## v1.5.1, 2017-07-12
|
||||
|
||||
* Node has been upgraded to version 4.8.4.
|
||||
|
||||
@@ -213,8 +213,14 @@ export class AccountsCommon {
|
||||
}
|
||||
}
|
||||
|
||||
_getTokenLifetimeMs() {
|
||||
return (this._options.loginExpirationInDays ||
|
||||
// The options argument is only used by tests.
|
||||
_getTokenLifetimeMs(options) {
|
||||
options = options || this._options;
|
||||
if (options.loginExpirationInDays === null) {
|
||||
// We disable login expiration by returning Infinity
|
||||
return Infinity;
|
||||
}
|
||||
return (options.loginExpirationInDays ||
|
||||
DEFAULT_LOGIN_EXPIRATION_DAYS) * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,24 @@ Tinytest.add('accounts - config validates keys', function (test) {
|
||||
});
|
||||
});
|
||||
|
||||
// test the loginExpirationInDays config
|
||||
|
||||
Tinytest.add( 'accounts - config - token limetime', function (test) {
|
||||
var config = { loginExpirationInDays: 2 };
|
||||
test.equal(Accounts._getTokenLifetimeMs(config), 2 * 24 * 60 * 60 * 1000);
|
||||
});
|
||||
|
||||
Tinytest.add( 'accounts - config - unexpiring tokens', function (test) {
|
||||
var config = { loginExpirationInDays: null };
|
||||
test.equal(Accounts._getTokenLifetimeMs(config), Infinity);
|
||||
});
|
||||
|
||||
Tinytest.add( 'accounts - config - default token limetime', function(test) {
|
||||
var DEFAULT_LOGIN_EXPIRATION_DAYS = 90; // copied from accounts_common.js
|
||||
var config1 = {};
|
||||
var config2 = { loginExpirationInDays: DEFAULT_LOGIN_EXPIRATION_DAYS };
|
||||
test.equal(Accounts._getTokenLifetimeMs(config1), Accounts._getTokenLifetimeMs(config2));
|
||||
});
|
||||
|
||||
var idsInValidateNewUser = {};
|
||||
Accounts.validateNewUser(function (user) {
|
||||
|
||||
@@ -546,17 +546,17 @@ Meteor.methods({forgotPassword: function (options) {
|
||||
Accounts.sendResetPasswordEmail(user._id, caseSensitiveEmail);
|
||||
}});
|
||||
|
||||
// send the user an email with a link that when opened allows the user
|
||||
// to set a new password, without the old password.
|
||||
|
||||
/**
|
||||
* @summary Send an email with a link the user can use to reset their password.
|
||||
* @summary Generates a reset token and saves it into the database.
|
||||
* @locus Server
|
||||
* @param {String} userId The id of the user to send email to.
|
||||
* @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list.
|
||||
* @param {String} userId The id of the user to generate the reset token for.
|
||||
* @param {String} email Which address of the user to generate the reset token for. This address must be in the user's `emails` list. If `null`, defaults to the first email in the list.
|
||||
* @param {String} reason `resetPassword` or `enrollAccount`.
|
||||
* @param {Object} [extraTokenData] Optional additional data to be added into the token record.
|
||||
* @returns {Object} Object with {email, user, token} values.
|
||||
* @importFromPackage accounts-base
|
||||
*/
|
||||
Accounts.sendResetPasswordEmail = function (userId, email) {
|
||||
Accounts.generateResetToken = function (userId, email, reason, extraTokenData) {
|
||||
// Make sure the user exists, and email is one of their addresses.
|
||||
var user = Meteor.users.findOne(userId);
|
||||
if (!user) {
|
||||
@@ -574,44 +574,146 @@ Accounts.sendResetPasswordEmail = function (userId, email) {
|
||||
}
|
||||
|
||||
var token = Random.secret();
|
||||
var when = new Date();
|
||||
var tokenRecord = {
|
||||
token: token,
|
||||
email: email,
|
||||
when: when,
|
||||
reason: 'reset'
|
||||
when: new Date()
|
||||
};
|
||||
Meteor.users.update(userId, {$set: {
|
||||
"services.password.reset": tokenRecord
|
||||
|
||||
if (reason === 'resetPassword') {
|
||||
tokenRecord.reason = 'reset';
|
||||
} else if (reason === 'enrollAccount') {
|
||||
tokenRecord.reason = 'enroll';
|
||||
} else if (reason) {
|
||||
// fallback so that this function can be used for unknown reasons as well
|
||||
tokenRecord.reason = reason;
|
||||
}
|
||||
|
||||
if (extraTokenData) {
|
||||
_.extend(tokenRecord, extraTokenData);
|
||||
}
|
||||
|
||||
Meteor.users.update({_id: user._id}, {$set: {
|
||||
'services.password.reset': tokenRecord
|
||||
}});
|
||||
|
||||
// before passing to template, update user object with new token
|
||||
Meteor._ensure(user, 'services', 'password').reset = tokenRecord;
|
||||
|
||||
var resetPasswordUrl = Accounts.urls.resetPassword(token);
|
||||
return {email, user, token};
|
||||
};
|
||||
|
||||
var options = {
|
||||
to: email,
|
||||
from: Accounts.emailTemplates.resetPassword.from
|
||||
? Accounts.emailTemplates.resetPassword.from(user)
|
||||
: Accounts.emailTemplates.from,
|
||||
subject: Accounts.emailTemplates.resetPassword.subject(user)
|
||||
};
|
||||
|
||||
if (typeof Accounts.emailTemplates.resetPassword.text === 'function') {
|
||||
options.text =
|
||||
Accounts.emailTemplates.resetPassword.text(user, resetPasswordUrl);
|
||||
/**
|
||||
* @summary Generates an e-mail verification token and saves it into the database.
|
||||
* @locus Server
|
||||
* @param {String} userId The id of the user to generate the e-mail verification token for.
|
||||
* @param {String} email Which address of the user to generate the e-mail verification token for. This address must be in the user's `emails` list. If `null`, defaults to the first unverified email in the list.
|
||||
* @param {Object} [extraTokenData] Optional additional data to be added into the token record.
|
||||
* @returns {Object} Object with {email, user, token} values.
|
||||
* @importFromPackage accounts-base
|
||||
*/
|
||||
Accounts.generateVerificationToken = function (userId, email, extraTokenData) {
|
||||
// Make sure the user exists, and email is one of their addresses.
|
||||
var user = Meteor.users.findOne(userId);
|
||||
if (!user) {
|
||||
handleError("Can't find user");
|
||||
}
|
||||
|
||||
if (typeof Accounts.emailTemplates.resetPassword.html === 'function') {
|
||||
options.html =
|
||||
Accounts.emailTemplates.resetPassword.html(user, resetPasswordUrl);
|
||||
// pick the first unverified email if we weren't passed an email.
|
||||
if (!email) {
|
||||
var emailRecord = _.find(user.emails || [], function (e) { return !e.verified; });
|
||||
email = (emailRecord || {}).address;
|
||||
|
||||
if (!email) {
|
||||
handleError("That user has no unverified email addresses.");
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we have a valid email
|
||||
if (!email || !_.contains(_.pluck(user.emails || [], 'address'), email)) {
|
||||
handleError("No such email for user.");
|
||||
}
|
||||
|
||||
var token = Random.secret();
|
||||
var tokenRecord = {
|
||||
token: token,
|
||||
// TODO: This should probably be renamed to "email" to match reset token record.
|
||||
address: email,
|
||||
when: new Date()
|
||||
};
|
||||
|
||||
if (extraTokenData) {
|
||||
_.extend(tokenRecord, extraTokenData);
|
||||
}
|
||||
|
||||
Meteor.users.update({_id: user._id}, {$push: {
|
||||
'services.email.verificationTokens': tokenRecord
|
||||
}});
|
||||
|
||||
// before passing to template, update user object with new token
|
||||
Meteor._ensure(user, 'services', 'email');
|
||||
if (!user.services.email.verificationTokens) {
|
||||
user.services.email.verificationTokens = [];
|
||||
}
|
||||
user.services.email.verificationTokens.push(tokenRecord);
|
||||
|
||||
return {email, user, token};
|
||||
};
|
||||
|
||||
/**
|
||||
* @summary Creates options for email sending for reset password and enroll account emails.
|
||||
* You can use this function when customizing a reset password or enroll account email sending.
|
||||
* @locus Server
|
||||
* @param {Object} email Which address of the user's to send the email to.
|
||||
* @param {Object} user The user object to generate options for.
|
||||
* @param {String} url URL to which user is directed to confirm the email.
|
||||
* @param {String} reason `resetPassword` or `enrollAccount`.
|
||||
* @returns {Object} Options which can be passed to `Email.send`.
|
||||
* @importFromPackage accounts-base
|
||||
*/
|
||||
Accounts.generateOptionsForEmail = function (email, user, url, reason) {
|
||||
var options = {
|
||||
to: email,
|
||||
from: Accounts.emailTemplates[reason].from
|
||||
? Accounts.emailTemplates[reason].from(user)
|
||||
: Accounts.emailTemplates.from,
|
||||
subject: Accounts.emailTemplates[reason].subject(user)
|
||||
};
|
||||
|
||||
if (typeof Accounts.emailTemplates[reason].text === 'function') {
|
||||
options.text = Accounts.emailTemplates[reason].text(user, url);
|
||||
}
|
||||
|
||||
if (typeof Accounts.emailTemplates[reason].html === 'function') {
|
||||
options.html = Accounts.emailTemplates[reason].html(user, url);
|
||||
}
|
||||
|
||||
if (typeof Accounts.emailTemplates.headers === 'object') {
|
||||
options.headers = Accounts.emailTemplates.headers;
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
// send the user an email with a link that when opened allows the user
|
||||
// to set a new password, without the old password.
|
||||
|
||||
/**
|
||||
* @summary Send an email with a link the user can use to reset their password.
|
||||
* @locus Server
|
||||
* @param {String} userId The id of the user to send email to.
|
||||
* @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list.
|
||||
* @param {Object} [extraTokenData] Optional additional data to be added into the token record.
|
||||
* @returns {Object} Object with {email, user, token, url, options} values.
|
||||
* @importFromPackage accounts-base
|
||||
*/
|
||||
Accounts.sendResetPasswordEmail = function (userId, email, extraTokenData) {
|
||||
const {email: realEmail, user, token} =
|
||||
Accounts.generateResetToken(userId, email, 'resetPassword', extraTokenData);
|
||||
const url = Accounts.urls.resetPassword(token);
|
||||
const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'resetPassword');
|
||||
Email.send(options);
|
||||
return {email: realEmail, user, token, url, options};
|
||||
};
|
||||
|
||||
// send the user an email informing them that their account was created, with
|
||||
@@ -627,65 +729,17 @@ Accounts.sendResetPasswordEmail = function (userId, email) {
|
||||
* @locus Server
|
||||
* @param {String} userId The id of the user to send email to.
|
||||
* @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first email in the list.
|
||||
* @param {Object} [extraTokenData] Optional additional data to be added into the token record.
|
||||
* @returns {Object} Object with {email, user, token, url, options} values.
|
||||
* @importFromPackage accounts-base
|
||||
*/
|
||||
Accounts.sendEnrollmentEmail = function (userId, email) {
|
||||
// XXX refactor! This is basically identical to sendResetPasswordEmail.
|
||||
|
||||
// Make sure the user exists, and email is in their addresses.
|
||||
var user = Meteor.users.findOne(userId);
|
||||
if (!user) {
|
||||
throw new Error("Can't find user");
|
||||
}
|
||||
// pick the first email if we weren't passed an email.
|
||||
if (!email && user.emails && user.emails[0]) {
|
||||
email = user.emails[0].address;
|
||||
}
|
||||
// make sure we have a valid email
|
||||
if (!email || !_.contains(_.pluck(user.emails || [], 'address'), email)) {
|
||||
throw new Error("No such email for user.");
|
||||
}
|
||||
|
||||
var token = Random.secret();
|
||||
var when = new Date();
|
||||
var tokenRecord = {
|
||||
token: token,
|
||||
email: email,
|
||||
when: when,
|
||||
reason: 'enroll'
|
||||
};
|
||||
Meteor.users.update(userId, {$set: {
|
||||
"services.password.reset": tokenRecord
|
||||
}});
|
||||
|
||||
// before passing to template, update user object with new token
|
||||
Meteor._ensure(user, 'services', 'password').reset = tokenRecord;
|
||||
|
||||
var enrollAccountUrl = Accounts.urls.enrollAccount(token);
|
||||
|
||||
var options = {
|
||||
to: email,
|
||||
from: Accounts.emailTemplates.enrollAccount.from
|
||||
? Accounts.emailTemplates.enrollAccount.from(user)
|
||||
: Accounts.emailTemplates.from,
|
||||
subject: Accounts.emailTemplates.enrollAccount.subject(user)
|
||||
};
|
||||
|
||||
if (typeof Accounts.emailTemplates.enrollAccount.text === 'function') {
|
||||
options.text =
|
||||
Accounts.emailTemplates.enrollAccount.text(user, enrollAccountUrl);
|
||||
}
|
||||
|
||||
if (typeof Accounts.emailTemplates.enrollAccount.html === 'function') {
|
||||
options.html =
|
||||
Accounts.emailTemplates.enrollAccount.html(user, enrollAccountUrl);
|
||||
}
|
||||
|
||||
if (typeof Accounts.emailTemplates.headers === 'object') {
|
||||
options.headers = Accounts.emailTemplates.headers;
|
||||
}
|
||||
|
||||
Accounts.sendEnrollmentEmail = function (userId, email, extraTokenData) {
|
||||
const {email: realEmail, user, token} =
|
||||
Accounts.generateResetToken(userId, email, 'enrollAccount', extraTokenData);
|
||||
const url = Accounts.urls.enrollAccount(token);
|
||||
const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'enrollAccount');
|
||||
Email.send(options);
|
||||
return {email: realEmail, user, token, url, options};
|
||||
};
|
||||
|
||||
|
||||
@@ -782,71 +836,21 @@ Meteor.methods({resetPassword: function (token, newPassword) {
|
||||
* @locus Server
|
||||
* @param {String} userId The id of the user to send email to.
|
||||
* @param {String} [email] Optional. Which address of the user's to send the email to. This address must be in the user's `emails` list. Defaults to the first unverified email in the list.
|
||||
* @param {Object} [extraTokenData] Optional additional data to be added into the token record.
|
||||
* @returns {Object} Object with {email, user, token, url, options} values.
|
||||
* @importFromPackage accounts-base
|
||||
*/
|
||||
Accounts.sendVerificationEmail = function (userId, address) {
|
||||
Accounts.sendVerificationEmail = function (userId, email, extraTokenData) {
|
||||
// XXX Also generate a link using which someone can delete this
|
||||
// account if they own said address but weren't those who created
|
||||
// this account.
|
||||
|
||||
// Make sure the user exists, and address is one of their addresses.
|
||||
var user = Meteor.users.findOne(userId);
|
||||
if (!user)
|
||||
throw new Error("Can't find user");
|
||||
// pick the first unverified address if we weren't passed an address.
|
||||
if (!address) {
|
||||
var email = _.find(user.emails || [],
|
||||
function (e) { return !e.verified; });
|
||||
address = (email || {}).address;
|
||||
|
||||
if (!address) {
|
||||
throw new Error("That user has no unverified email addresses.");
|
||||
}
|
||||
}
|
||||
// make sure we have a valid address
|
||||
if (!address || !_.contains(_.pluck(user.emails || [], 'address'), address))
|
||||
throw new Error("No such email address for user.");
|
||||
|
||||
|
||||
var tokenRecord = {
|
||||
token: Random.secret(),
|
||||
address: address,
|
||||
when: new Date()};
|
||||
Meteor.users.update(
|
||||
{_id: userId},
|
||||
{$push: {'services.email.verificationTokens': tokenRecord}});
|
||||
|
||||
// before passing to template, update user object with new token
|
||||
Meteor._ensure(user, 'services', 'email');
|
||||
if (!user.services.email.verificationTokens) {
|
||||
user.services.email.verificationTokens = [];
|
||||
}
|
||||
user.services.email.verificationTokens.push(tokenRecord);
|
||||
|
||||
var verifyEmailUrl = Accounts.urls.verifyEmail(tokenRecord.token);
|
||||
|
||||
var options = {
|
||||
to: address,
|
||||
from: Accounts.emailTemplates.verifyEmail.from
|
||||
? Accounts.emailTemplates.verifyEmail.from(user)
|
||||
: Accounts.emailTemplates.from,
|
||||
subject: Accounts.emailTemplates.verifyEmail.subject(user)
|
||||
};
|
||||
|
||||
if (typeof Accounts.emailTemplates.verifyEmail.text === 'function') {
|
||||
options.text =
|
||||
Accounts.emailTemplates.verifyEmail.text(user, verifyEmailUrl);
|
||||
}
|
||||
|
||||
if (typeof Accounts.emailTemplates.verifyEmail.html === 'function')
|
||||
options.html =
|
||||
Accounts.emailTemplates.verifyEmail.html(user, verifyEmailUrl);
|
||||
|
||||
if (typeof Accounts.emailTemplates.headers === 'object') {
|
||||
options.headers = Accounts.emailTemplates.headers;
|
||||
}
|
||||
|
||||
const {email: realEmail, user, token} =
|
||||
Accounts.generateVerificationToken(userId, email, extraTokenData);
|
||||
const url = Accounts.urls.verifyEmail(token);
|
||||
const options = Accounts.generateOptionsForEmail(realEmail, user, url, 'verifyEmail');
|
||||
Email.send(options);
|
||||
return {email: realEmail, user, token, url, options};
|
||||
};
|
||||
|
||||
// Take token from sendVerificationEmail, mark the email as verified,
|
||||
|
||||
@@ -6,5 +6,5 @@ instead of the System WebView on Android",
|
||||
});
|
||||
|
||||
Cordova.depends({
|
||||
'cordova-plugin-crosswalk-webview': '2.2.0'
|
||||
'cordova-plugin-crosswalk-webview': '2.3.0'
|
||||
});
|
||||
|
||||
@@ -94,6 +94,21 @@ var builtinConverters = [
|
||||
return new Date(obj.$date);
|
||||
}
|
||||
},
|
||||
{ // RegExp
|
||||
matchJSONValue: function (obj) {
|
||||
return _.has(obj, '$regexp') && _.has(obj, '$flags') && _.size(obj) === 2;
|
||||
},
|
||||
matchObject: function (obj) {
|
||||
return obj instanceof RegExp;
|
||||
},
|
||||
toJSONValue: function (regexp) {
|
||||
return { $regexp: regexp.source, $flags: regexp.flags };
|
||||
},
|
||||
fromJSONValue: function (obj) {
|
||||
//replaces duplicate / invalid flags
|
||||
return new RegExp(obj.$regexp, obj.$flags.replace(/[^gimuy]/g,'').replace(/(.)(?=.*\1)/g, ''));
|
||||
}
|
||||
},
|
||||
{ // NaN, Inf, -Inf. (These are the only objects with typeof !== 'object'
|
||||
// which we match.)
|
||||
matchJSONValue: function (obj) {
|
||||
|
||||
@@ -185,6 +185,16 @@ Tinytest.add("ejson - parse", function (test) {
|
||||
);
|
||||
});
|
||||
|
||||
Tinytest.add("ejson - regexp", function (test) {
|
||||
test.equal(EJSON.stringify(/foo/gi), "{\"$regexp\":\"foo\",\"$flags\":\"gi\"}");
|
||||
var d = new RegExp("foo", "gi");
|
||||
var obj = { $regexp: "foo", $flags: "gi" };
|
||||
|
||||
var eObj = EJSON.toJSONValue(obj);
|
||||
var roundTrip = EJSON.fromJSONValue(eObj);
|
||||
test.equal(obj, roundTrip);
|
||||
});
|
||||
|
||||
Tinytest.add("ejson - custom types", function (test) {
|
||||
var testSameConstructors = function (obj, compareWith) {
|
||||
test.equal(obj.constructor, compareWith.constructor);
|
||||
|
||||
@@ -10,7 +10,7 @@ Package.describe({
|
||||
});
|
||||
|
||||
Cordova.depends({
|
||||
'cordova-plugin-splashscreen': '4.0.1'
|
||||
'cordova-plugin-splashscreen': '4.0.3'
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
|
||||
@@ -12,7 +12,7 @@ Npm.strip({
|
||||
});
|
||||
|
||||
Cordova.depends({
|
||||
'cordova-plugin-console': '1.0.5'
|
||||
'cordova-plugin-console': '1.0.7'
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
|
||||
@@ -775,8 +775,7 @@ ELEMENT_OPERATORS = {
|
||||
var regexp;
|
||||
if (valueSelector.$options !== undefined) {
|
||||
// Options passed in $options (even the empty string) always overrides
|
||||
// options in the RegExp object itself. (See also
|
||||
// Mongo.Collection._rewriteSelector.)
|
||||
// options in the RegExp object itself.
|
||||
|
||||
// Be clear that we only support the JS-supported options, not extended
|
||||
// ones (eg, Mongo supports x and s). Ideally we would implement x and s
|
||||
|
||||
@@ -4,5 +4,5 @@ Package.describe({
|
||||
});
|
||||
|
||||
Cordova.depends({
|
||||
'cordova-plugin-statusbar': '2.2.1'
|
||||
'cordova-plugin-statusbar': '2.2.3'
|
||||
});
|
||||
|
||||
@@ -362,8 +362,7 @@ Mongo.Collection._publishCursor = function (cursor, sub, collection) {
|
||||
|
||||
// protect against dangerous selectors. falsey and {_id: falsey} are both
|
||||
// likely programmer error, and not what you want, particularly for destructive
|
||||
// operations. JS regexps don't serialize over DDP but can be trivially
|
||||
// replaced by $regex. If a falsey _id is sent in, a new string _id will be
|
||||
// operations. If a falsey _id is sent in, a new string _id will be
|
||||
// generated and returned; if a fallbackId is provided, it will be returned
|
||||
// instead.
|
||||
Mongo.Collection._rewriteSelector = (selector, { fallbackId } = {}) => {
|
||||
@@ -382,48 +381,8 @@ Mongo.Collection._rewriteSelector = (selector, { fallbackId } = {}) => {
|
||||
return { _id: fallbackId || Random.id() };
|
||||
}
|
||||
|
||||
var ret = {};
|
||||
Object.keys(selector).forEach((key) => {
|
||||
const value = selector[key];
|
||||
// Mongo supports both {field: /foo/} and {field: {$regex: /foo/}}
|
||||
if (value instanceof RegExp) {
|
||||
ret[key] = convertRegexpToMongoSelector(value);
|
||||
} else if (value && value.$regex instanceof RegExp) {
|
||||
ret[key] = convertRegexpToMongoSelector(value.$regex);
|
||||
// if value is {$regex: /foo/, $options: ...} then $options
|
||||
// override the ones set on $regex.
|
||||
if (value.$options !== undefined)
|
||||
ret[key].$options = value.$options;
|
||||
} else if (_.contains(['$or','$and','$nor'], key)) {
|
||||
// Translate lower levels of $and/$or/$nor
|
||||
ret[key] = _.map(value, function (v) {
|
||||
return Mongo.Collection._rewriteSelector(v);
|
||||
});
|
||||
} else {
|
||||
ret[key] = value;
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
// convert a JS RegExp object to a Mongo {$regex: ..., $options: ...}
|
||||
// selector
|
||||
function convertRegexpToMongoSelector(regexp) {
|
||||
check(regexp, RegExp); // safety belt
|
||||
|
||||
var selector = {$regex: regexp.source};
|
||||
var regexOptions = '';
|
||||
// JS RegExp objects support 'i', 'm', and 'g'. Mongo regex $options
|
||||
// support 'i', 'm', 'x', and 's'. So we support 'i' and 'm' here.
|
||||
if (regexp.ignoreCase)
|
||||
regexOptions += 'i';
|
||||
if (regexp.multiline)
|
||||
regexOptions += 'm';
|
||||
if (regexOptions)
|
||||
selector.$options = regexOptions;
|
||||
|
||||
return selector;
|
||||
}
|
||||
};
|
||||
|
||||
// 'insert' immediately returns the inserted document's new _id.
|
||||
// The others return values immediately if you are in a stub, an in-memory
|
||||
|
||||
@@ -1183,7 +1183,7 @@ MongoConnection.prototype._observeChanges = function (
|
||||
throw Error("You may not observe a cursor with {fields: {_id: 0}}");
|
||||
}
|
||||
|
||||
var observeKey = JSON.stringify(
|
||||
var observeKey = EJSON.stringify(
|
||||
_.extend({ordered: ordered}, cursorDescription));
|
||||
|
||||
var multiplexer, observeDriver;
|
||||
|
||||
@@ -2152,88 +2152,15 @@ _.each(Meteor.isServer ? [true, false] : [true], function (minimongo) {
|
||||
}); // end idGeneration parametrization
|
||||
|
||||
Tinytest.add('mongo-livedata - rewrite selector', function (test) {
|
||||
test.equal(Mongo.Collection._rewriteSelector({x: /^o+B/im}),
|
||||
{x: {$regex: '^o+B', $options: 'im'}});
|
||||
test.equal(Mongo.Collection._rewriteSelector({x: {$regex: /^o+B/im}}),
|
||||
{x: {$regex: '^o+B', $options: 'im'}});
|
||||
test.equal(Mongo.Collection._rewriteSelector({x: /^o+B/}),
|
||||
{x: {$regex: '^o+B'}});
|
||||
test.equal(Mongo.Collection._rewriteSelector({x: {$regex: /^o+B/}}),
|
||||
{x: {$regex: '^o+B'}});
|
||||
|
||||
test.equal(Mongo.Collection._rewriteSelector('foo'),
|
||||
{_id: 'foo'});
|
||||
|
||||
test.equal(
|
||||
Mongo.Collection._rewriteSelector(
|
||||
{'$or': [
|
||||
{x: /^o/},
|
||||
{y: /^p/},
|
||||
{z: 'q'},
|
||||
{w: {$regex: /^r/}}
|
||||
]}
|
||||
),
|
||||
{'$or': [
|
||||
{x: {$regex: '^o'}},
|
||||
{y: {$regex: '^p'}},
|
||||
{z: 'q'},
|
||||
{w: {$regex: '^r'}}
|
||||
]}
|
||||
);
|
||||
|
||||
test.equal(
|
||||
Mongo.Collection._rewriteSelector(
|
||||
{'$or': [
|
||||
{'$and': [
|
||||
{x: /^a/i},
|
||||
{y: /^b/},
|
||||
{z: {$regex: /^c/i}},
|
||||
{w: {$regex: '^[abc]', $options: 'i'}}, // make sure we don't break vanilla selectors
|
||||
{v: {$regex: /O/, $options: 'i'}}, // $options should override the ones on the RegExp object
|
||||
{u: {$regex: /O/m, $options: 'i'}} // $options should override the ones on the RegExp object
|
||||
]},
|
||||
{'$nor': [
|
||||
{s: /^d/},
|
||||
{t: /^e/i},
|
||||
{u: {$regex: /^f/i}},
|
||||
// even empty string overrides built-in flags
|
||||
{v: {$regex: /^g/i, $options: ''}}
|
||||
]}
|
||||
]}
|
||||
),
|
||||
{'$or': [
|
||||
{'$and': [
|
||||
{x: {$regex: '^a', $options: 'i'}},
|
||||
{y: {$regex: '^b'}},
|
||||
{z: {$regex: '^c', $options: 'i'}},
|
||||
{w: {$regex: '^[abc]', $options: 'i'}},
|
||||
{v: {$regex: 'O', $options: 'i'}},
|
||||
{u: {$regex: 'O', $options: 'i'}}
|
||||
]},
|
||||
{'$nor': [
|
||||
{s: {$regex: '^d'}},
|
||||
{t: {$regex: '^e', $options: 'i'}},
|
||||
{u: {$regex: '^f', $options: 'i'}},
|
||||
{v: {$regex: '^g', $options: ''}}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
|
||||
var oid = new Mongo.ObjectID();
|
||||
test.equal(Mongo.Collection._rewriteSelector(oid),
|
||||
{_id: oid});
|
||||
|
||||
// Make sure selectors with "length" properties are handled properly
|
||||
// (verifies issue #8329 has been resolved).
|
||||
const SomeSelector = function (length) {
|
||||
this.length = length;
|
||||
};
|
||||
const length = 2;
|
||||
const testSelector = new SomeSelector(length);
|
||||
test.equal(
|
||||
Mongo.Collection._rewriteSelector(testSelector),
|
||||
{ length }
|
||||
);
|
||||
|
||||
test.matches(
|
||||
Mongo.Collection._rewriteSelector({ _id: null })._id,
|
||||
/^\S+$/,
|
||||
|
||||
@@ -21,7 +21,7 @@ Npm.strip({
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
api.use('npm-mongo@2.2.24', 'server');
|
||||
api.use('npm-mongo', 'server');
|
||||
api.use('allow-deny');
|
||||
|
||||
api.use([
|
||||
|
||||
35
packages/npm-mongo/.npm/package/npm-shrinkwrap.json
generated
35
packages/npm-mongo/.npm/package/npm-shrinkwrap.json
generated
@@ -32,14 +32,14 @@
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"mongodb": {
|
||||
"version": "2.2.24",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.24.tgz",
|
||||
"integrity": "sha1-gPQNbsW97A3ezw+c4BROeUxGRJo="
|
||||
"version": "2.2.30",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.30.tgz",
|
||||
"integrity": "sha1-jM2AH2dsgXIEDC8rR+lgKg1WNKs="
|
||||
},
|
||||
"mongodb-core": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.8.tgz",
|
||||
"integrity": "sha1-sz4DcNClnZe2yx7GEFJ76elcosA="
|
||||
"version": "2.1.14",
|
||||
"resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.14.tgz",
|
||||
"integrity": "sha1-E8uidkImtb49GJkq8Mljzl6g8P0="
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "1.0.7",
|
||||
@@ -47,29 +47,34 @@
|
||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz",
|
||||
"integrity": "sha1-ZvqLcg4UOLNkaB8q0aY8YYRIydA="
|
||||
"version": "2.2.7",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz",
|
||||
"integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE="
|
||||
},
|
||||
"require_optional": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.0.tgz",
|
||||
"integrity": "sha1-UqhhN6hJco62ClVTNhf4+RT1mr8="
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
|
||||
"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g=="
|
||||
},
|
||||
"resolve-from": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
|
||||
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ=="
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
Package.describe({
|
||||
summary: "Wrapper around the mongo npm package",
|
||||
version: '2.2.24',
|
||||
version: '2.2.30',
|
||||
documentation: null
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
mongodb: "2.2.24"
|
||||
mongodb: "2.2.30"
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
|
||||
@@ -57,5 +57,5 @@ Package.onTest(function (api) {
|
||||
});
|
||||
|
||||
Cordova.depends({
|
||||
'cordova-plugin-inappbrowser': '1.6.1'
|
||||
'cordova-plugin-inappbrowser': '1.7.1'
|
||||
});
|
||||
|
||||
@@ -14,9 +14,9 @@ Npm.strip({
|
||||
});
|
||||
|
||||
Cordova.depends({
|
||||
'cordova-plugin-whitelist': '1.3.1',
|
||||
'cordova-plugin-wkwebview-engine': '1.1.1',
|
||||
'cordova-plugin-meteor-webapp': '1.4.1'
|
||||
'cordova-plugin-whitelist': '1.3.2',
|
||||
'cordova-plugin-wkwebview-engine': '1.1.3',
|
||||
'cordova-plugin-meteor-webapp': '1.4.2'
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
|
||||
@@ -52,7 +52,7 @@ var packageJson = {
|
||||
pathwatcher: "7.1.0",
|
||||
optimism: "0.3.3",
|
||||
'lru-cache': '4.0.1',
|
||||
'cordova-lib': "6.4.0",
|
||||
'cordova-lib': "7.0.1",
|
||||
longjohn: '0.2.11'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1579,8 +1579,31 @@ function doTestCommand(options) {
|
||||
// cleaned up on process exit. Using a temporary app dir means that we can
|
||||
// run multiple "test-packages" commands in parallel without them stomping
|
||||
// on each other.
|
||||
var testRunnerAppDir =
|
||||
options['test-app-path'] || files.mkdtemp('meteor-test-run');
|
||||
let testRunnerAppDir;
|
||||
const testAppPath = options['test-app-path'];
|
||||
if (testAppPath) {
|
||||
try {
|
||||
if (files.mkdir_p(testAppPath, 0o700)) {
|
||||
testRunnerAppDir = testAppPath;
|
||||
} else {
|
||||
Console.error(
|
||||
'The specified --test-app-path directory could not be used, as ' +
|
||||
`"${testAppPath}" already exists and it is not a directory.`
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
} catch (error) {
|
||||
Console.error(
|
||||
'Unable to create the specified --test-app-path directory of ' +
|
||||
`"${testAppPath}".`
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!testRunnerAppDir) {
|
||||
testRunnerAppDir = files.mkdtemp('meteor-test-run');
|
||||
}
|
||||
|
||||
// Download packages for our architecture, and for the deploy server's
|
||||
// architecture if we're deploying.
|
||||
@@ -1611,7 +1634,19 @@ function doTestCommand(options) {
|
||||
projectContextOptions.projectDir = testRunnerAppDir;
|
||||
projectContextOptions.projectDirForLocalPackages = options.appDir;
|
||||
|
||||
require("./default-npm-deps.js").install(testRunnerAppDir);
|
||||
try {
|
||||
require("./default-npm-deps.js").install(testRunnerAppDir);
|
||||
} catch (error) {
|
||||
if (error.code === 'EACCES' && options['test-app-path']) {
|
||||
Console.error(
|
||||
'The specified --test-app-path directory of ' +
|
||||
`"${testRunnerAppDir}" exists, but the current user does not have ` +
|
||||
`read/write permission in it.`
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (buildmessage.jobHasMessages()) {
|
||||
return;
|
||||
}
|
||||
|
||||
4
tools/cordova/index.js
vendored
4
tools/cordova/index.js
vendored
@@ -11,8 +11,8 @@ export const CORDOVA_ARCH = "web.cordova";
|
||||
export const CORDOVA_PLATFORMS = ['ios', 'android'];
|
||||
|
||||
export const CORDOVA_PLATFORM_VERSIONS = {
|
||||
'android': '6.1.1',
|
||||
'ios': '4.3.0'
|
||||
'android': '6.2.3',
|
||||
'ios': '4.4.0'
|
||||
};
|
||||
|
||||
const PLATFORM_TO_DISPLAY_NAME_MAP = {
|
||||
|
||||
44
tools/cordova/project.js
vendored
44
tools/cordova/project.js
vendored
@@ -51,29 +51,29 @@ const pinnedPlatformVersions = CORDOVA_PLATFORM_VERSIONS;
|
||||
// Versions are taken from cordova-lib's package.json and should be updated
|
||||
// when we update to a newer version of cordova-lib.
|
||||
const pinnedPluginVersions = {
|
||||
"cordova-plugin-battery-status": "1.2.2",
|
||||
"cordova-plugin-camera": "2.3.1",
|
||||
"cordova-plugin-console": "1.0.5",
|
||||
"cordova-plugin-contacts": "2.2.1",
|
||||
"cordova-plugin-device": "1.1.4",
|
||||
"cordova-plugin-device-motion": "1.2.3",
|
||||
"cordova-plugin-device-orientation": "1.0.5",
|
||||
"cordova-plugin-dialogs": "1.3.1",
|
||||
"cordova-plugin-file": "4.3.1",
|
||||
"cordova-plugin-file-transfer": "1.6.1",
|
||||
"cordova-plugin-geolocation": "2.4.1",
|
||||
"cordova-plugin-globalization": "1.0.5",
|
||||
"cordova-plugin-inappbrowser": "1.6.1",
|
||||
"cordova-plugin-battery-status": "1.2.4",
|
||||
"cordova-plugin-camera": "2.4.1",
|
||||
"cordova-plugin-console": "1.0.7",
|
||||
"cordova-plugin-contacts": "2.3.1",
|
||||
"cordova-plugin-device": "1.1.6",
|
||||
"cordova-plugin-device-motion": "1.2.5",
|
||||
"cordova-plugin-device-orientation": "1.0.7",
|
||||
"cordova-plugin-dialogs": "1.3.3",
|
||||
"cordova-plugin-file": "4.3.3",
|
||||
"cordova-plugin-file-transfer": "1.6.3",
|
||||
"cordova-plugin-geolocation": "2.4.3",
|
||||
"cordova-plugin-globalization": "1.0.7",
|
||||
"cordova-plugin-inappbrowser": "1.7.1",
|
||||
"cordova-plugin-legacy-whitelist": "1.1.2",
|
||||
"cordova-plugin-media": "2.4.1",
|
||||
"cordova-plugin-media-capture": "1.4.1",
|
||||
"cordova-plugin-network-information": "1.3.1",
|
||||
"cordova-plugin-splashscreen": "4.0.1",
|
||||
"cordova-plugin-statusbar": "2.2.1",
|
||||
"cordova-plugin-test-framework": "1.1.4",
|
||||
"cordova-plugin-vibration": "2.1.3",
|
||||
"cordova-plugin-whitelist": "1.3.1",
|
||||
"cordova-plugin-wkwebview-engine": "1.1.1"
|
||||
"cordova-plugin-media": "3.0.1",
|
||||
"cordova-plugin-media-capture": "1.4.3",
|
||||
"cordova-plugin-network-information": "1.3.3",
|
||||
"cordova-plugin-splashscreen": "4.0.3",
|
||||
"cordova-plugin-statusbar": "2.2.3",
|
||||
"cordova-plugin-test-framework": "1.1.5",
|
||||
"cordova-plugin-vibration": "2.1.5",
|
||||
"cordova-plugin-whitelist": "1.3.2",
|
||||
"cordova-plugin-wkwebview-engine": "1.1.3"
|
||||
}
|
||||
|
||||
export class CordovaProject {
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
|
||||
meteor-base@1.1.0 # Packages every Meteor app needs to have
|
||||
mobile-experience@1.0.4 # Packages for a great mobile UX
|
||||
mongo@1.1.18 # The database Meteor supports right now
|
||||
mongo@1.1.19 # The database Meteor supports right now
|
||||
blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
|
||||
reactive-var@1.0.11 # Reactive variable for tracker
|
||||
jquery@1.11.10 # Helpful client-side library
|
||||
tracker@1.1.3 # Meteor's client-side reactive programming library
|
||||
|
||||
standard-minifier-css@1.3.4 # CSS minifier run for production mode
|
||||
standard-minifier-js@2.1.0 # JS minifier run for production mode
|
||||
standard-minifier-js@2.1.1 # JS minifier run for production mode
|
||||
es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers.
|
||||
ecmascript@0.8.0 # Enable ECMAScript2015+ syntax in app code
|
||||
shell-server@0.2.3 # Server-side component of the `meteor shell` command
|
||||
ecmascript@0.8.2 # Enable ECMAScript2015+ syntax in app code
|
||||
shell-server@0.2.4 # Server-side component of the `meteor shell` command
|
||||
|
||||
autopublish@1.0.7 # Publish all data to the clients (for prototyping)
|
||||
insecure@1.0.7 # Allow all DB writes from clients (for prototyping)
|
||||
dynamic-import
|
||||
dynamic-import@0.1.1
|
||||
dispatch:mocha-phantomjs
|
||||
dispatch:mocha-browser
|
||||
lazy-test-package
|
||||
|
||||
@@ -1 +1 @@
|
||||
METEOR@1.5
|
||||
METEOR@1.5.1
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
|
||||
meteor-base@1.1.0 # Packages every Meteor app needs to have
|
||||
mobile-experience@1.0.4 # Packages for a great mobile UX
|
||||
mongo@1.1.18 # The database Meteor supports right now
|
||||
mongo@1.1.19 # The database Meteor supports right now
|
||||
blaze-html-templates # Compile .html files into Meteor Blaze views
|
||||
session@1.1.7 # Client-side reactive dictionary for your app
|
||||
jquery@1.11.10 # Helpful client-side library
|
||||
tracker@1.1.3 # Meteor's client-side reactive programming library
|
||||
|
||||
es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers.
|
||||
ecmascript@0.8.0 # Enable ECMAScript2015+ syntax in app code
|
||||
ecmascript@0.8.2 # Enable ECMAScript2015+ syntax in app code
|
||||
|
||||
coffeescript
|
||||
modules-test-package
|
||||
dispatch:mocha-phantomjs
|
||||
dispatch:mocha-browser
|
||||
standard-minifier-css@1.3.4
|
||||
standard-minifier-js@2.1.0
|
||||
standard-minifier-js@2.1.1
|
||||
client-only-ecmascript
|
||||
modules-test-plugin
|
||||
shell-server@0.2.3
|
||||
dynamic-import
|
||||
shell-server@0.2.4
|
||||
dynamic-import@0.1.1
|
||||
|
||||
@@ -1 +1 @@
|
||||
METEOR@1.5
|
||||
METEOR@1.5.1
|
||||
|
||||
@@ -74,8 +74,7 @@ if (process.platform !== "win32") {
|
||||
});
|
||||
|
||||
var run = s.run("add", packageName);
|
||||
run.waitSecs(60);
|
||||
run.matchErr("colons");
|
||||
run.matchErrBeforeExit("colons");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -596,3 +596,75 @@ selftest.define("old cli tests (converted)", function () {
|
||||
run.expectExit(0);
|
||||
files.unlink(files.pathJoin(s.cwd, 'settings.js'));
|
||||
});
|
||||
|
||||
// Added to address https://github.com/meteor/meteor/issues/8897.
|
||||
selftest.define(
|
||||
'meteor test-packages --test-app-path directory',
|
||||
function () {
|
||||
var s = new Sandbox();
|
||||
var run;
|
||||
|
||||
// If test-app-path doesn't exist, it should be created.
|
||||
var testAppPath = '/tmp/meteor_test_app_path';
|
||||
files.rm_recursive(testAppPath);
|
||||
selftest.expectFalse(files.exists(testAppPath));
|
||||
s.createApp('test-app-path-app', 'package-tests', {
|
||||
dontPrepareApp: true
|
||||
});
|
||||
s.cd('test-app-path-app/packages/say-something', function () {
|
||||
run = s.run(
|
||||
'test-packages',
|
||||
'--once',
|
||||
{ 'test-app-path': testAppPath },
|
||||
'./'
|
||||
);
|
||||
run.match('Started');
|
||||
selftest.expectTrue(files.exists(testAppPath));
|
||||
run.stop();
|
||||
files.rm_recursive(testAppPath);
|
||||
});
|
||||
|
||||
// If test-app-path already exists, make sure that directory is used.
|
||||
var testAppPath = '/tmp/meteor_test_app_path';
|
||||
files.rm_recursive(testAppPath);
|
||||
files.mkdir_p(testAppPath);
|
||||
selftest.expectTrue(files.exists(testAppPath));
|
||||
selftest.expectFalse(files.exists(testAppPath + '/.meteor'));
|
||||
s.createApp('test-app-path-app', 'package-tests', {
|
||||
dontPrepareApp: true
|
||||
});
|
||||
s.cd('test-app-path-app/packages/say-something', function () {
|
||||
run = s.run(
|
||||
'test-packages',
|
||||
'--once',
|
||||
{ 'test-app-path': testAppPath },
|
||||
'./'
|
||||
);
|
||||
run.match('Started');
|
||||
selftest.expectTrue(files.exists(testAppPath + '/.meteor'));
|
||||
run.stop();
|
||||
files.rm_recursive(testAppPath);
|
||||
});
|
||||
|
||||
// If test-app-path already exists but is a file instead of a directory,
|
||||
// show a console error message explaining this, and exit.
|
||||
var testAppPath = '/tmp/meteor_test_app_path';
|
||||
files.rm_recursive(testAppPath);
|
||||
files.writeFile(testAppPath, '<3 meteor');
|
||||
selftest.expectTrue(files.exists(testAppPath));
|
||||
s.createApp('test-app-path-app', 'package-tests', {
|
||||
dontPrepareApp: true
|
||||
});
|
||||
s.cd('test-app-path-app/packages/say-something', function () {
|
||||
run = s.run(
|
||||
'test-packages',
|
||||
'--once',
|
||||
{ 'test-app-path': testAppPath },
|
||||
'./'
|
||||
);
|
||||
run.matchErr('is not a directory');
|
||||
run.expectExit(1);
|
||||
files.rm_recursive(testAppPath);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -109,6 +109,7 @@ selftest.define("change packages during hot code push", [], function () {
|
||||
run.waitSecs(5);
|
||||
run.match("myapp");
|
||||
run.match("proxy");
|
||||
run.waitSecs(5);
|
||||
run.match("MongoDB");
|
||||
run.waitSecs(5);
|
||||
run.match("your app");
|
||||
|
||||
Reference in New Issue
Block a user