diff --git a/.envrc b/.envrc
index a60b67f960..47ab5b6410 100644
--- a/.envrc
+++ b/.envrc
@@ -27,6 +27,10 @@ function @test-self {
@meteor self-test "$@"
}
+function @test-in-console {
+ "$ROOT_DIR/packages/test-in-console/run.sh" "$@"
+}
+
function @check-syntax {
node "$ROOT_DIR/scripts/admin/check-legacy-syntax/check-syntax.js"
}
diff --git a/.github/workflows/meteor-selftest-windows.yml b/.github/workflows/meteor-selftest-windows.yml
index d78f633ec3..2935532c1b 100644
--- a/.github/workflows/meteor-selftest-windows.yml
+++ b/.github/workflows/meteor-selftest-windows.yml
@@ -22,6 +22,9 @@ env:
jobs:
test:
runs-on: windows-2019-meteor
+ concurrency:
+ group: ${{ github.head_ref }}-meteor-selftest-windows
+ cancel-in-progress: true
steps:
- name: Checkout code
diff --git a/.github/workflows/test-deprecated-packages.yml b/.github/workflows/test-deprecated-packages.yml
new file mode 100644
index 0000000000..e4ed12fe92
--- /dev/null
+++ b/.github/workflows/test-deprecated-packages.yml
@@ -0,0 +1,52 @@
+name: Test Deprecated Packages
+
+# Disabled until we figure out how to fix the error from puppeteer
+# Runs on Travis CI for now
+#
+#on:
+# push:
+# branches:
+# - main
+# pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ concurrency:
+ group: ${{ github.head_ref }}-test-deprecated-packages
+ cancel-in-progress: true
+ timeout-minutes: 60
+
+ env:
+ PUPPETEER_DOWNLOAD_PATH: /home/runner/.npm/chromium
+
+ steps:
+ - name: Update and install dependencies
+ run: sudo apt-get update && sudo apt-get install -y libnss3 g++-12
+
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 20.15.1
+
+ - name: Cache Node.js modules
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.npm
+ .meteor
+ .babel-cache
+ dev_bundle
+ /home/runner/.npm/chromium
+ key: ${{ runner.os }}-node-${{ hashFiles('meteor', '**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-
+
+ - name: Install dependencies
+ run: npm install
+
+ - name: Run tests
+ run: ./packages/test-in-console/run.sh
\ No newline at end of file
diff --git a/guide/source/methods.md b/guide/source/methods.md
index a9689a2ef1..3db5ca7c3c 100644
--- a/guide/source/methods.md
+++ b/guide/source/methods.md
@@ -171,35 +171,35 @@ updateText.run.call({ userId: 'abcd' }, {
As you can see, this approach to calling Methods results in a better development workflow - you can more easily deal with the different parts of the Method separately and test your code without having to deal with Meteor internals. But this approach requires you to write a lot of boilerplate on the Method definition side.
-
Advanced Methods with mdg:validated-method
+Advanced Methods with jam:method
-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. Here's the same Method as above, but defined with the package:
+To alleviate some of the boilerplate that's involved in correct Method definitions, you can use a package called `jam:method` that does most of this for you. Here's the same Method as above, but defined with the package:
```js
-import { ValidatedMethod } from 'meteor/mdg:validated-method';
+import { createMethod } from 'meteor/jam:method';
-export const updateText = new ValidatedMethod({
+export const updateText = createMethod({
name: 'todos.updateText',
- validate: new SimpleSchema({
+ schema: new SimpleSchema({
todoId: { type: String },
newText: { type: String }
- }).validator(),
- run({ todoId, newText }) {
- const todo = Todos.findOne(todoId);
-
+ }),
+ async run({ todoId, newText }) {
+ const todo = await Todos.findOneAsync(todoId);
+
if (!todo.editableBy(this.userId)) {
throw new Meteor.Error('todos.updateText.unauthorized',
'Cannot edit todos in a private list that is not yours');
}
- Todos.update(todoId, {
+ Todos.updateAsync(todoId, {
$set: { text: newText }
});
}
});
```
-You call it the same way you call the advanced Method above, but the Method definition is significantly simpler. We believe this style of Method lets you clearly see the important parts - the name of the Method sent over the wire, the format of the expected arguments, and the JavaScript namespace by which the Method can be referenced. Validated methods only accept a single argument and a callback function.
+You call it the same way you call the advanced Method above, but the Method definition is significantly simpler. We believe this style of Method lets you clearly see the important parts - the name of the Method sent over the wire, the format of the expected arguments, and the JavaScript namespace by which the Method can be referenced.
Error handling
@@ -227,17 +227,13 @@ When the server was not able to complete the user's desired action because of a
When a Method call fails because the arguments are of the wrong type, it's good to throw a `ValidationError`. This works like `Meteor.Error`, but is a custom constructor that enforces a standard error format that can be read by different form and validation libraries. In particular, if you are calling this Method from a form, throwing a `ValidationError` will make it possible to display nice error messages next to particular fields in the form.
-When you use `mdg:validated-method` with `simpl-schema` as demonstrated above, this type of error is thrown for you.
-
-Read more about the error format in the [`mdg:validation-error` docs](https://atmospherejs.com/mdg/validation-error).
-
Handling errors
When you call a Method, any errors thrown by it will be returned in the callback. At this point, you should identify which error type it is and display the appropriate message to the user. In this case, it is unlikely that the Method will throw a `ValidationError` or an internal server error, so we will only handle the unauthorized error:
```js
// Call the Method
-updateText.call({
+updateText({
todoId: '12345',
newText: 'This is a todo item.'
}, (err, res) => {
@@ -261,7 +257,7 @@ We'll talk about how to handle the `ValidationError` in the section on forms bel
Errors in Method simulation
-When a Method is called, it usually runs twice---once on the client to simulate the result for Optimistic UI, and again on the server to make the actual change to the database. This means that if your Method throws an error, it will likely fail on the client _and_ the server. For this reason, `ValidatedMethod` turns on undocumented option in Meteor to avoid calling the server-side implementation if the simulation throws an error.
+When a Method is called, it usually runs twice---once on the client to simulate the result for Optimistic UI, and again on the server to make the actual change to the database. This means that if your Method throws an error, it will likely fail on the client _and_ the server. For this reason, `jam:method` turns on [an option](https://github.com/jamauro/method#options-for-meteorapplyasync) in Meteor to avoid calling the server-side implementation if the simulation throws an error.
While this behavior is good for saving server resources in cases where a Method will certainly fail, it's important to make sure that the simulation doesn't throw an error in cases where the server Method would have succeeded (for example, if you didn't load some data on the client that the Method needs to do the simulation properly). In this case, you can wrap server-side-only logic in a block that checks for a method simulation:
@@ -283,13 +279,13 @@ const amountRegEx = /^\d*\.(\d\d)?$/;
// This Method encodes the form validation requirements.
// By defining them in the Method, we do client and server-side
// validation in one place.
-export const insert = new ValidatedMethod({
+export const insert = createMethod({
name: 'Invoices.methods.insert',
- validate: new SimpleSchema({
+ schema: new SimpleSchema({
email: { type: String, regEx: emailRegEx },
description: { type: String, min: 5 },
amount: { type: String, regEx: amountRegEx }
- }).validator(),
+ }),
run(newInvoice) {
// In here, we can be sure that the newInvoice argument is
// validated.
@@ -299,7 +295,7 @@ export const insert = new ValidatedMethod({
'Must be logged in to create an invoice.');
}
- Invoices.insert(newInvoice)
+ Invoices.insertAsync(newInvoice)
}
});
```
@@ -355,7 +351,7 @@ Template.Invoices_newInvoice.events({
amount: event.target.amount.value
};
- insert.call(data, (err, res) => {
+ insert(data, (err, res) => {
if (err) {
if (err.error === 'validation-error') {
// Initialize error object
@@ -434,9 +430,9 @@ If we defined this Method in client and server code, as all Methods should be, a
The client enters a special mode where it tracks all changes made to client-side collections, so that they can be rolled back later. When this step is complete, the user of your app sees their UI update instantly with the new content of the client-side database, but the server hasn't received any data yet.
-If an exception is thrown from the Method simulation, then by default Meteor ignores it and continues to step (2). If you are using `ValidatedMethod` or pass a special `throwStubExceptions` option to `Meteor.apply`, then an exception thrown from the simulation will stop the server-side Method from running at all.
+If an exception is thrown from the Method simulation, then by default Meteor ignores it and continues to step (2). If you are using `jam:method` or pass a special `throwStubExceptions` [option](https://github.com/jamauro/method#options-for-meteorapplyasync) to `Meteor.apply`, then an exception thrown from the simulation will stop the server-side Method from running at all.
-The return value of the Method simulation is discarded, unless the `returnStubValue` option is passed when calling the Method, in which case it is returned to the Method caller. ValidatedMethod passes this option by default.
+The return value of the Method simulation is discarded, unless the `returnStubValue` option is passed when calling the Method, in which case it is returned to the Method caller. `jam:method` passes this option by default.
2. A `method` DDP message is sent to the server
diff --git a/guide/source/security.md b/guide/source/security.md
index e50420b98d..8eeef42d2a 100644
--- a/guide/source/security.md
+++ b/guide/source/security.md
@@ -80,9 +80,9 @@ Meteor.methods({
If someone comes along and passes a non-ID selector like `{}`, they will end up deleting the entire collection.
-mdg:validated-method
+jam:method
-To help you write good Methods that exhaustively validate their arguments, we've written a wrapper package for Methods that enforces argument validation. Read more about how to use it in the [Methods article](methods.html#validated-method). The rest of the code samples in this article will assume that you are using this package. If you aren't, you can still apply the same principles but the code will look a little different.
+To help you write good Methods that exhaustively validate their arguments, you can use a community package for Methods that enforces argument validation. Read more about how to use it in the [Methods article](methods.html#jam-method). The rest of the code samples in this article will assume that you are using this package. If you aren't, you can still apply the same principles but the code will look a little different.
Don't pass userId from the client
@@ -200,7 +200,8 @@ if (Meteor.isServer) {
This will make every Method only callable 5 times per second per connection. This is a rate limit that shouldn't be noticeable by the user at all, but will prevent a malicious script from totally flooding the server with requests. You will need to tune the limit parameters to match your app's needs.
-If you're using validated methods, there's an available [ddp-rate-limiter-mixin](https://github.com/nlhuykhang/ddp-rate-limiter-mixin).
+If you're using `jam:method`, it comes with built in [rate-limiting](https://github.com/jamauro/method#rate-limiting).
+
Publications
diff --git a/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json b/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json
index ebacac28ad..64d0411523 100644
--- a/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json
+++ b/packages/accounts-2fa/.npm/package/npm-shrinkwrap.json
@@ -2,9 +2,9 @@
"lockfileVersion": 4,
"dependencies": {
"@types/node": {
- "version": "22.7.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
- "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ=="
+ "version": "22.7.6",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz",
+ "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw=="
},
"@types/notp": {
"version": "2.0.5",
@@ -32,9 +32,9 @@
"integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA=="
},
"tslib": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
- "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz",
+ "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA=="
},
"undici-types": {
"version": "6.19.8",
diff --git a/packages/deprecated/http/package.js b/packages/deprecated/http/package.js
index 405387d200..b19ac4248e 100644
--- a/packages/deprecated/http/package.js
+++ b/packages/deprecated/http/package.js
@@ -1,6 +1,6 @@
Package.describe({
summary: "Make HTTP calls to remote servers",
- version: '3.0.0-beta300.7',
+ version: '3.0.0',
deprecated: 'Please use the fetch package'
});
diff --git a/packages/deprecated/stylus/.npm/plugin/compileStylusBatch/npm-shrinkwrap.json b/packages/deprecated/stylus/.npm/plugin/compileStylusBatch/npm-shrinkwrap.json
index 4bc9ce2a15..1fe92eee26 100644
--- a/packages/deprecated/stylus/.npm/plugin/compileStylusBatch/npm-shrinkwrap.json
+++ b/packages/deprecated/stylus/.npm/plugin/compileStylusBatch/npm-shrinkwrap.json
@@ -32,9 +32,9 @@
"integrity": "sha512-fKSWtyNQTclfi1A+s2KU91/r1mfANG1ZibxTdCwJGfV1J9UwcV22plFOm0wkaq4WzqW87zxiAkyp2Ho1Wn1NnA=="
},
"caniuse-db": {
- "version": "1.0.30001640",
- "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001640.tgz",
- "integrity": "sha512-K8/5iWoH/NULlqJz/iaopQJraQCHGcFGvs8dmTpAH7GyvoQu2Xq8ht3jq2c+wNck4bgQu/PHu2GN2mJfUj9qtw=="
+ "version": "1.0.30001669",
+ "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001669.tgz",
+ "integrity": "sha512-GK+G6CnRZ7IY2J2H3bcm9kshwHcJ4ZWDC5u9WaIh7DQAAHHeuxIPtaZd15GMTmGvGbDx/u1AcQs3MYur9Tem7A=="
},
"concat-map": {
"version": "0.0.1",
@@ -47,9 +47,9 @@
"integrity": "sha512-OI38lO4JQQX2GSisTqwiSFxiWNmLajXdW4tCCxAuiwGKjusHALQadSHBSxGlU8lrFp47IkLuU2AfSYz31qpETQ=="
},
"debug": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
- "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg=="
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="
},
"fs.realpath": {
"version": "1.0.0",
@@ -97,9 +97,9 @@
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="
},
"ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"multi-stage-sourcemap": {
"version": "0.2.1",
diff --git a/packages/email/.npm/package/npm-shrinkwrap.json b/packages/email/.npm/package/npm-shrinkwrap.json
index fcc8fd64c8..68404a03da 100644
--- a/packages/email/.npm/package/npm-shrinkwrap.json
+++ b/packages/email/.npm/package/npm-shrinkwrap.json
@@ -2,9 +2,9 @@
"lockfileVersion": 4,
"dependencies": {
"@types/node": {
- "version": "22.7.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
- "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ=="
+ "version": "22.7.6",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz",
+ "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw=="
},
"@types/nodemailer": {
"version": "6.4.14",
diff --git a/packages/test-helpers/async_multi.js b/packages/test-helpers/async_multi.js
index 1286508fde..c9c09ac66e 100644
--- a/packages/test-helpers/async_multi.js
+++ b/packages/test-helpers/async_multi.js
@@ -53,31 +53,31 @@ var ExpectationManager = function (test, onComplete) {
};
Object.assign(ExpectationManager.prototype, {
- expect: function (...args) {
+ expect: function (/* arguments */) {
var self = this;
- if (typeof args[0] === "function")
- var expected = args[0];
+ if (typeof arguments[0] === "function")
+ var expected = arguments[0];
else
- var expected = args;
+ var expected = Array.from(arguments);
if (self.closed)
throw new Error("Too late to add more expectations to the test");
self.outstanding++;
- return async function (...args) {
+ return async function (/* arguments */) {
if (self.dead)
return;
if (typeof expected === "function") {
try {
- await expected.apply({}, args);
+ await expected.apply({}, arguments);
} catch (e) {
if (self.cancel())
self.test.exception(e);
}
} else {
- self.test.equal(args, expected);
+ self.test.equal(Array.from(arguments), expected);
}
self.outstanding--;
@@ -115,12 +115,12 @@ testAsyncMulti = function (name, funcs, { isOnly = false } = {}) {
const addFunction = isOnly ? Tinytest.onlyAsync : Tinytest.addAsync;
addFunction(name, function (test, onComplete) {
- var remaining = Object.assign({}, funcs);
+ var remaining = [...funcs]
var context = {};
var i = 0;
var runNext = function () {
- var func = Object.values(remaining).shift();
+ var func = remaining.shift();
if (!func) {
delete test.extraDetails.asyncBlock;
onComplete();
diff --git a/packages/test-helpers/callback_logger.js b/packages/test-helpers/callback_logger.js
index 2f98cbe8de..0cac2c825c 100644
--- a/packages/test-helpers/callback_logger.js
+++ b/packages/test-helpers/callback_logger.js
@@ -1,4 +1,3 @@
-import isEmpty from 'lodash.isempty';
import isEqual from 'lodash.isequal';
// This file allows you to write tests that expect certain callbacks to be
@@ -24,11 +23,9 @@ var CallbackLogger = function (test, callbackNames) {
var self = this;
self._log = [];
self._test = test;
- self._yielded = false;
callbackNames.forEach(function (callbackName) {
- self[callbackName] = function () {
- var args = Array.from(arguments);
- self._log.push({callback: callbackName, args: args});
+ self[callbackName] = function (...args) {
+ self._log.push({ callback: callbackName, args });
};
});
};
@@ -36,7 +33,7 @@ var CallbackLogger = function (test, callbackNames) {
CallbackLogger.prototype.expectResult = async function (callbackName, args) {
var self = this;
await self._waitForLengthOrTimeout(1);
- if (isEmpty(self._log)) {
+ if (self._log.length === 0) {
self._test.fail(["Expected callback " + callbackName + " got none"]);
return;
}
@@ -78,8 +75,10 @@ CallbackLogger.prototype.expectResultUnordered = async function (list) {
await self._waitForLengthOrTimeout(list.length);
- list = [...list]; // shallow copy.
+ list = [...list];
+
var i = list.length;
+
while (i > 0) {
var found = false;
var dequeued = self._log.shift();
@@ -114,4 +113,4 @@ CallbackLogger.prototype.expectNoResult = async function (fn) {
await self._waitForLengthOrTimeout(0);
self._expectNoResultImpl();
-};
\ No newline at end of file
+};
diff --git a/packages/test-helpers/connection_server.js b/packages/test-helpers/connection_server.js
index ffb15ad5bc..255bfed03d 100644
--- a/packages/test-helpers/connection_server.js
+++ b/packages/test-helpers/connection_server.js
@@ -1,5 +1,3 @@
-import isString from 'lodash.isstring';
-
// Establish a connection from the server to the server, and wait
// until the client side of the connection has received the session
// id. On success call `succeeded` with two arguments, the client
@@ -15,7 +13,7 @@ makeTestConnection = function (test, succeeded, failed) {
// Add incoming connections to `serverConns`.
var onConnectionHandle = Meteor.onConnection(function (serverConn) {
- test.isTrue(isString(serverConn.id), "connection handle id exists and is a string");
+ test.isTrue(typeof serverConn.id === 'string', "connection handle id exists and is a string");
if (serverConns[serverConn.id]) {
test.fail("onConnection callback called multiple times for same session id");
failed();
diff --git a/packages/test-helpers/package.js b/packages/test-helpers/package.js
index bb7f296c60..8eea18c3f9 100644
--- a/packages/test-helpers/package.js
+++ b/packages/test-helpers/package.js
@@ -5,9 +5,7 @@ Package.describe({
Npm.depends({
'lodash.isequal': '4.5.0',
- 'lodash.isempty': '4.4.0',
- 'lodash.isstring': '4.0.1'
-});
+})
Package.onUse(function (api) {
api.use([
diff --git a/packages/test-helpers/try_all_permutations_test.js b/packages/test-helpers/try_all_permutations_test.js
index 4c9b451fff..91378b1bf8 100644
--- a/packages/test-helpers/try_all_permutations_test.js
+++ b/packages/test-helpers/try_all_permutations_test.js
@@ -61,7 +61,7 @@ Tinytest.add("test-helpers - try_all_permutations", function (test) {
var seen = {};
for (var i = 0; i < n; i++)
- fs.push(function (x) { seq += x + "_"; }.bind(null, i));
+ fs.push((function (x) { seq += x + "_"; }).bind(null, i));
try_all_permutations(
function () {seq = "";},
fs,
diff --git a/packages/test-in-console/package.js b/packages/test-in-console/package.js
index 810f07e1f3..04a0729eb2 100644
--- a/packages/test-in-console/package.js
+++ b/packages/test-in-console/package.js
@@ -4,7 +4,7 @@ Package.describe({
});
Package.onUse(function(api) {
- api.use(['tinytest', 'random', 'ejson', 'check']);
+ api.use(['tinytest', 'random', 'ejson', 'check', 'ecmascript']);
api.use('fetch', 'server');
api.export('TEST_STATUS', 'client');
@@ -13,9 +13,7 @@ Package.onUse(function(api) {
api.addFiles(['reporter.js'], 'server');
- // This is to be run by phantomjs, not as part of normal package code.
- api.addAssets('phantomRunner.js', 'server');
- api.addAssets('puppeteerRunner.js', 'server');
+ api.addAssets('puppeteer_runner.js', 'server');
api.export('runTests');
});
diff --git a/packages/test-in-console/phantomRunner.js b/packages/test-in-console/phantomRunner.js
deleted file mode 100644
index 43fc0b8c47..0000000000
--- a/packages/test-in-console/phantomRunner.js
+++ /dev/null
@@ -1,69 +0,0 @@
-var createPage = require('webpage').create;
-var system = require('system');
-var platform = system.args[1] || 'local';
-var platformUrl = system.env.URL + platform;
-var testUrls = [
- // Additional application URLs can be added here to re-run tests in
- // PhantomJS with different query parameter-based configurations.
- platformUrl
-];
-
-function runNextUrl() {
- var url = testUrls.shift();
- if (!url) {
- phantom.exit(0);
- return;
- }
-
- console.log('Running Meteor tests in PhantomJS... ' + url);
-
- var page = createPage();
-
- page.onConsoleMessage = function(message) {
- console.log(message);
- };
-
- page.open(url);
-
- function poll() {
- if (isDone(page)) {
- var failCount = getFailCount(page);
- if (failCount > 0) {
- phantom.exit(1);
- } else {
- page.close();
- setTimeout(runNextUrl, 1000);
- }
- } else {
- setTimeout(poll, 1000);
- }
- }
-
- poll();
-}
-
-function isDone(page) {
- return page.evaluate(function() {
- if (typeof TEST_STATUS !== 'undefined') {
- return TEST_STATUS.DONE;
- }
-
- return typeof DONE !== 'undefined' && DONE;
- });
-}
-
-function getFailCount(page) {
- return page.evaluate(function() {
- if (typeof TEST_STATUS !== 'undefined') {
- return TEST_STATUS.FAILURES;
- }
-
- if (typeof FAILURES === 'undefined') {
- return 1;
- }
-
- return 0;
- });
-}
-
-runNextUrl();
diff --git a/packages/test-in-console/puppeteerRunner.js b/packages/test-in-console/puppeteer_runner.js
similarity index 95%
rename from packages/test-in-console/puppeteerRunner.js
rename to packages/test-in-console/puppeteer_runner.js
index d0a59ae9c9..0ad644d070 100644
--- a/packages/test-in-console/puppeteerRunner.js
+++ b/packages/test-in-console/puppeteer_runner.js
@@ -5,6 +5,10 @@ let testNumber = 0;
async function runNextUrl(browser) {
const page = await browser.newPage();
+ // page.on('console', msg => {
+ // console.log('PAGE LOG:', msg.text());
+ // });
+
page.on('console', async msg => {
// this is a way to make sure the travis does not timeout
// if the test is running for too long without any output to the console (10 minutes)
@@ -58,7 +62,7 @@ async function runNextUrl(browser) {
}
}
- poll();
+ await poll();
}
/**
@@ -130,9 +134,10 @@ async function runTests() {
'--disable-setuid-sandbox',
'--disable-web-security',
],
+ headless: "new",
});
console.log(`Using version: ${await browser.version()}`);
- runNextUrl(browser);
+ await runNextUrl(browser)
}
runTests().catch((e) =>
diff --git a/packages/test-in-console/reporter.js b/packages/test-in-console/reporter.js
index 099e43a81c..7fb49b28ce 100644
--- a/packages/test-in-console/reporter.js
+++ b/packages/test-in-console/reporter.js
@@ -1,14 +1,7 @@
-// A hacky way to extract the phantom runner script from the package.
-if (process.env.WRITE_RUNNER_JS) {
- Npm.require('fs').writeFileSync(
- process.env.WRITE_RUNNER_JS, Buffer.from(Assets.getBinary('runner.js')));
-}
+let url = null;
-var url = null;
-if (Meteor.settings &&
- Meteor.settings.public &&
- Meteor.settings.public.runId &&
- Meteor.settings.public.reportTo) {
+if (Meteor.settings?.public?.runId &&
+ Meteor.settings?.public?.reportTo) {
url = Meteor.settings.public.reportTo +
"/report/" +
Meteor.settings.public.runId;
diff --git a/packages/test-in-console/run.sh b/packages/test-in-console/run.sh
index 38012a605d..9a6231d209 100755
--- a/packages/test-in-console/run.sh
+++ b/packages/test-in-console/run.sh
@@ -8,36 +8,21 @@
cd $(dirname $0)/../..
export METEOR_HOME=`pwd`
-export phantom=$phantom
-
-# only install dependencies if required
-if [ "$phantom" = true ]
-then
- # Just in case these packages haven't been installed elsewhere.
- ./meteor npm install -g phantomjs-prebuilt browserstack-webdriver
-else
- # Installs into dev_bundle/lib/node_modules/puppeteer.
- ./meteor npm install -g puppeteer@20.4.0
-fi
+# Installs into dev_bundle/lib/node_modules/puppeteer.
+./meteor npm install -g puppeteer@20.4.0
export PATH=$METEOR_HOME:$PATH
-# synchronously get the dev bundle and NPM modules if they're not there.
-./meteor --help || exit 1
export URL='http://127.0.0.1:4096/'
export METEOR_PACKAGE_DIRS='packages/deprecated'
-exec 3< <(meteor test-packages --driver-package test-in-console -p 4096 --exclude ${TEST_PACKAGES_EXCLUDE:-''} $1)
+exec 3< <(./meteor test-packages --driver-package test-in-console -p 4096 --exclude ${TEST_PACKAGES_EXCLUDE:-''} $1)
EXEC_PID=$!
+trap "pkill -TERM -P $EXEC_PID; exit 1" SIGINT
sed '/test-in-console listening$/q' <&3
-if [ "$phantom" = true ]
-then
- ./dev_bundle/bin/phantomjs "$METEOR_HOME/packages/test-in-console/phantomRunner.js"
-else
- node "$METEOR_HOME/packages/test-in-console/puppeteerRunner.js"
-fi
+node --trace-warnings "$METEOR_HOME/packages/test-in-console/puppeteer_runner.js"
STATUS=$?
diff --git a/packages/webapp/package.js b/packages/webapp/package.js
index d225d066db..9d5c36a641 100644
--- a/packages/webapp/package.js
+++ b/packages/webapp/package.js
@@ -13,7 +13,6 @@ Npm.depends({
send: "1.1.0",
"stream-to-string": "1.2.1",
qs: "6.13.0",
- 'lodash.has': '4.5.2',
"useragent-ng": "2.4.3",
"tmp": "0.2.3",
});
diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js
index 5b3ef24edf..5849c90642 100644
--- a/packages/webapp/webapp_server.js
+++ b/packages/webapp/webapp_server.js
@@ -19,7 +19,6 @@ import {
} from './socket_file.js';
import cluster from 'cluster';
import { execSync } from 'child_process';
-import has from 'lodash.has';
var SHORT_SOCKET_TIMEOUT = 5 * 1000;
var LONG_SOCKET_TIMEOUT = 120 * 1000;
@@ -622,7 +621,7 @@ WebAppInternals.staticFilesMiddleware = async function(
};
if (
- has(additionalStaticJs, pathname) &&
+ pathname in additionalStaticJs &&
!WebAppInternals.inlineScriptsAllowed()
) {
serveStaticJs(additionalStaticJs[pathname]);
diff --git a/tools/utils/utils.js b/tools/utils/utils.js
index 8ccd4f5b5a..54bbfe0b31 100644
--- a/tools/utils/utils.js
+++ b/tools/utils/utils.js
@@ -202,7 +202,7 @@ exports.sleepMs = function (ms) {
// Return a short, high entropy string without too many funny
// characters in it.
exports.randomToken = function () {
- return (Math.random() * 0x100000000 + 1).toString(36);
+ return (Math.random() * 0x100000000 + 1).toString(36).replace('.', '');
};
// Like utils.randomToken, except a legal variable name, i.e. the first