mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge branch 'release-3.1.0' into leonardo/performance-optimizations
This commit is contained in:
4
.envrc
4
.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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
52
.github/workflows/test-deprecated-packages.yml
vendored
Normal file
52
.github/workflows/test-deprecated-packages.yml
vendored
Normal file
@@ -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
|
||||
@@ -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.
|
||||
|
||||
<h3 id="validated-method">Advanced Methods with mdg:validated-method</h3>
|
||||
<h3 id="jam-method">Advanced Methods with jam:method</h3>
|
||||
|
||||
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.
|
||||
|
||||
<h2 id="errors">Error handling</h2>
|
||||
|
||||
@@ -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).
|
||||
|
||||
<h3 id="handling-errors">Handling errors</h3>
|
||||
|
||||
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
|
||||
|
||||
<h3 id="throw-stub-exceptions">Errors in Method simulation</h3>
|
||||
|
||||
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.
|
||||
|
||||
<h4 id="lifecycle-ddp-message">2. A `method` DDP message is sent to the server</h4>
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
<h3 id="validated-method">mdg:validated-method</h3>
|
||||
<h3 id="jam-method">jam:method</h3>
|
||||
|
||||
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.
|
||||
|
||||
<h3 id="user-id-client">Don't pass userId from the client</h3>
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
<h2 id="publications">Publications</h2>
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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'
|
||||
});
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
6
packages/email/.npm/package/npm-shrinkwrap.json
generated
6
packages/email/.npm/package/npm-shrinkwrap.json
generated
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
@@ -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) =>
|
||||
@@ -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;
|
||||
|
||||
@@ -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=$?
|
||||
|
||||
|
||||
@@ -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",
|
||||
});
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user