Merge remote-tracking branch 'origin/release-3.0-fix-ci-tests' into release-3.0-fix-ci-tests

This commit is contained in:
denihs
2023-04-03 14:32:47 -04:00
50 changed files with 1819 additions and 2299 deletions

View File

@@ -100,7 +100,7 @@ can_disable_fibers: &can_disable_fibers
parameters:
fibers:
type: boolean
default: true
default: false # now is always off
set_fibers_env: &set_fibers_env
name: "Disable Fibers"
@@ -700,6 +700,7 @@ jobs:
path: /tmp/memuse.txt
Test Group 11:
<<: *can_disable_fibers
<<: *build_machine_environment
steps:
- run:
@@ -708,6 +709,7 @@ jobs:
<<: *run_env_change
- attach_workspace:
at: .
- run: *set_fibers_env
- run:
name: "Print environment"
command: printenv
@@ -910,6 +912,7 @@ workflows:
requires:
- Get Ready
- Test Group 11:
<<: *matrix_for_fibers
requires:
- Get Ready
- Clean Up:

View File

@@ -1,125 +1,158 @@
## v3.0, TBD
### Highlights
#### Breaking Changes
* `webapp`:
- These methods are now async:
- `WebAppInternals.reloadClientPrograms()`
- `WebAppInternals.pauseClient()`
- `WebAppInternals.generateClientProgram()`
- `WebAppInternals.generateBoilerplate()`
- `WebAppInternals.setInlineScriptsAllowed()`
- `WebAppInternals.enableSubresourceIntegrity()`
- `WebAppInternals.setBundledJsCssUrlRewriteHook()`
- `WebAppInternals.setBundledJsCssPrefix()`
- `webapp`:
* `email`:
- `Email.send` is no longer available. Use `Email.sendAsync` instead.
- These methods are now async:
- `WebAppInternals.reloadClientPrograms()`
- `WebAppInternals.pauseClient()`
- `WebAppInternals.generateClientProgram()`
- `WebAppInternals.generateBoilerplate()`
- `WebAppInternals.setInlineScriptsAllowed()`
- `WebAppInternals.enableSubresourceIntegrity()`
- `WebAppInternals.setBundledJsCssUrlRewriteHook()`
- `WebAppInternals.setBundledJsCssPrefix()`
* `accounts-2fa`:
- Some methods are now async. See below:
- `Accounts._is2faEnabledForUser`
- `(Meteor Method) - generate2faActivationQrCode`
- `(Meteor Method) - enableUser2fa`
- `(Meteor Method) - disableUser2fa`
- `(Meteor Method) - has2faEnabled`
- `email`:
* `accounts-base`:
**TODO**
- `methods.removeOtherTokens` is now async
- `Accounts.destroyToken` is now async
- `Email.send` is no longer available. Use `Email.sendAsync` instead.
* `accounts-password`:
- Some server methods are now async:
- `Accounts.sendResetPasswordEmail`
- `Accounts.sendEnrollmentEmail`
- `Accounts.sendVerificationEmail`
- `Accounts.addEmail`
- `Accounts.removeEmail`
- `Accounts.verifyEmail`
- `Accounts.createUserVerifyingEmail`
- `Accounts.createUser`
- `Accounts.generateVerificationToken`
- `Accounts.generateResetToken`
- `Accounts.forgotPassword`
- `Accounts.setPassword`
- `Accounts.changePassword`
- `Accounts.setUsername`
- `Accounts.findUserByEmail`
- `Accounts.findUserByUsername`
- `accounts-2fa`:
* `accounts-passwordless`:
- `Accounts.sendLoginTokenEmail` is now async
- Some methods are now async. See below:
- `Accounts._is2faEnabledForUser`
- `(Meteor Method) - generate2faActivationQrCode`
- `(Meteor Method) - enableUser2fa`
- `(Meteor Method) - disableUser2fa`
- `(Meteor Method) - has2faEnabled`
* `boilerplate-generator`:
- `toHTML` is no longer available (it was already deprecated). Use `toHTMLStream` instead.
- `accounts-base`:
* `ddp`:
- Added method `Meteor.isAsyncCall` that can be used to check if the current method call is async or not.
- `methods.removeOtherTokens` is now async
- `Accounts.destroyToken` is now async
* `oauth`:
- `_endOfPopupResponseTemplate` and `_endOfRedirectResponseTemplate` are no longer a property but now a function that returns a promise of the same value as before
- the following server methods are now async:
- `OAuth._renderOauthResults`
- `OAuth._endOfLoginResponse`
- `OAuth.renderEndOfLoginResponse`
- `OAuth._storePendingCredential`
- `OAuth._retrievePendingCredential`
- `ensureConfigured`
- `_cleanStaleResults`
- `accounts-password`:
* `oauth1`:
- the following server methods are now async:
- `OAuth._storeRequestToken`
- `OAuth._retrieveRequestToken`
- Some server methods are now async:
- `Accounts.sendResetPasswordEmail`
- `Accounts.sendEnrollmentEmail`
- `Accounts.sendVerificationEmail`
- `Accounts.addEmail`
- `Accounts.removeEmail`
- `Accounts.verifyEmail`
- `Accounts.createUserVerifyingEmail`
- `Accounts.createUser`
- `Accounts.generateVerificationToken`
- `Accounts.generateResetToken`
- `Accounts.forgotPassword`
- `Accounts.setPassword`
- `Accounts.changePassword`
- `Accounts.setUsername`
- `Accounts.findUserByEmail`
- `Accounts.findUserByUsername`
* `oauth2`:
- `OAuth._requestHandlers['2']` is now async.
- `accounts-passwordless`:
* `minifier-css`:
- `minifyCss` is now async.
- `Accounts.sendLoginTokenEmail` is now async
* `webapp`:
- `WebAppInternals.getBoilerplate` is now async.
- Changed engine from connect to express and changed api naming to match express. See below:
- `WebApp.connectHandlers.use(middleware)` is now `WebApp.expressHandlers.use(middleware)`
- `WebApp.rawConnectHandlers.use(middleware)` is now `WebApp.rawExpressHandlers.use(middleware)`
- `WebApp.connectApp` is now `WebApp.expressApp`
- `boilerplate-generator`:
#### Internal API changes
- `toHTML` is no longer available (it was already deprecated). Use `toHTMLStream` instead.
- `ddp`:
- Added method `Meteor.isAsyncCall` that can be used to check if the current method call is async or not.
- `oauth`:
- `_endOfPopupResponseTemplate` and `_endOfRedirectResponseTemplate` are no longer a property but now a function that returns a promise of the same value as before
- the following server methods are now async:
- `OAuth._renderOauthResults`
- `OAuth._endOfLoginResponse`
- `OAuth.renderEndOfLoginResponse`
- `OAuth._storePendingCredential`
- `OAuth._retrievePendingCredential`
- `ensureConfigured`
- `_cleanStaleResults`
- `oauth1`:
- the following server methods are now async:
- `OAuth._storeRequestToken`
- `OAuth._retrieveRequestToken`
- `oauth2`:
- `OAuth._requestHandlers['2']` is now async.
- `minifier-css`:
- `minifyCss` is now async.
- `webapp`:
- `WebAppInternals.getBoilerplate` is now async.
- Changed engine from connect to express and changed api naming to match express. See below:
- `WebApp.connectHandlers.use(middleware)` is now `WebApp.expressHandlers.use(middleware)`
- `WebApp.rawConnectHandlers.use(middleware)` is now `WebApp.rawExpressHandlers.use(middleware)`
- `WebApp.connectApp` is now `WebApp.expressApp`
* `minimongo@get-version`:
TODO: add this aswell to the minimongo docs
- `cursor.observe` now returns `isReady` and `isReadyPromise` wich indicates
if the cursor is ready and if the callbacks are have been called.
If you only use it in the `Client` or as a `LocalCollection` things have not
changed.
#### Migration Steps
#### New Public API
You can follow in [here](https://guide.meteor.com/3.0-migration.html).
- `accounts-base`: (2.9+)
- `Meteor.userAsync()`
#### Meteor Version Release
- `callback-hook`:forEachAsync
- `forEachAsync`
#### Special thanks to
- `ddp-server`: (2.8+)
- `Meteor.callAsync()`
For making this great framework even better!ifier-css`:
- `minifyCss` is now async.
- `minifier-css`: (2.9+)
- `CssTools.minifyCssAsync()`
* `webapp`:
- `WebAppInternals.getBoilerplate` is now async.
- Changed engine from connect to express and changed api naming to match express. See below:
- `WebApp.connectHandlers.use(middleware)` is now `WebApp.expressHandlers.use(middleware)`
- `WebApp.rawConnectHandlers.use(middleware)` is now `WebApp.rawExpressHandlers.use(middleware)`
- `WebApp.connectApp` is now `WebApp.expressApp`
- `mongo`:
#### Internal API changes
- `Mongo.Collection`: (2.8+)
- `createCappedCollectionAsync`
- `createIndexAsync`
- `dropCollectionAsync`
- `dropIndexAsync`
- `findOneAsync`
- `insertAsync`
- `removeAsync`
- `updateAsync`
- `upsertAsync`
- `Collection.Cursor`: (2.8+)
- `countAsync`
- `fetchAsync`
- `forEachAsync`
- `mapAsync`
- `[Symbol.asyncIterator]` so this code should work:
```js
for await (const document of collection.find(query, options)) /* ... */
```
#### Internal API changes
#### Migration Steps
`accounts-base`:
You can follow in [here](https://guide.meteor.com/3.0-migration.html).
- `_attemptLogin`
- `_loginMethod`
- `_runLoginHandlers`
#### Meteor Version Release
#### New Internal API
#### Special thanks to
`accounts-password`:
For making this great framework even better!
- `Accounts._checkPasswordAsync`

File diff suppressed because it is too large Load Diff

View File

@@ -41,7 +41,7 @@
"@babel/template": "^7.16.7",
"@babel/traverse": "^7.17.0",
"@babel/types": "^7.17.0",
"@meteorjs/reify": "https://github.com/meteor/reify/tarball/ee36898798645097948258eb9106dd0af60cec64",
"@meteorjs/reify": "https://github.com/meteor/reify/tarball/0867be73ca61e87ae9d60edef62baf26b38719ef",
"babel-preset-meteor": "^7.10.0",
"babel-preset-minify": "^0.5.1",
"convert-source-map": "^1.6.0",

View File

@@ -42,7 +42,7 @@
"no-console": "off",
"camelcase": "warn",
"consistent-return": "off",
"quotes": "warn",
"quotes": ["warn", "single", { "allowTemplateLiterals": true }],
"no-shadow": [
"error",
{

View File

@@ -94,7 +94,8 @@ BCp.processOneFileForTarget = function (inputFile, source) {
features.modernBrowsers = true;
}
features.topLevelAwait = arch.startsWith('os.') || enableClientTLA
features.topLevelAwait = inputFile.supportsTopLevelAwait &&
(arch.startsWith('os.') || enableClientTLA);
features.useNativeAsyncAwait = Meteor.isFibersDisabled;

View File

@@ -83,9 +83,7 @@ function runEagerModules(config, callback) {
var path = config.eagerModulePaths[index];
var exports = config.require(path);
// TODO[fibers]: retest the function checkAsyncModule. It looks like it's returning the wrong values
// returning false when exports is a promise
if (exports && exports.then) {
if (checkAsyncModule(exports)) {
if (path === config.mainModulePath) {
mainModuleAsync = true;
}
@@ -127,15 +125,14 @@ function runEagerModules(config, callback) {
}
function checkAsyncModule (exports) {
// Uses property descriptor to avoid running any getters
var isPromise = exports && hasOwn.call(exports, 'then') &&
typeof Object.getOwnPropertyDescriptor(exports, 'then').value === 'function';
var potentiallyAsync = exports && typeof exports === 'object' &&
hasOwn.call(exports, '__reifyAsyncModule');
if (!isPromise) {
return false;
if (!potentiallyAsync) {
return;
}
return hasOwn.call(exports, '__reifyAsyncModule');
return typeof exports.then === 'function';
}
// For this to be accurate, all linked files must be queued before calling this

View File

@@ -333,7 +333,7 @@ export default class Cursor {
}
// it means it's an id map
if (query.results?.size?.()) {
query.results.forEachAsync(handler);
query.results.forEach(handler);
}
}
@@ -361,14 +361,15 @@ export default class Cursor {
// run the observe callbacks resulting from the initial contents
// before we leave the observe.
const isReadyPromise = this.collection._observeQueue.drain();
const drainResult = this.collection._observeQueue.drain();
if (Meteor.isClient) handle.isReady = true;
else isReadyPromise.then(() => (handle.isReady = true));
handle.isReadyPromise = Meteor.isClient
? Promise.resolve()
: isReadyPromise;
if (drainResult instanceof Promise) {
handle.isReadyPromise = drainResult;
drainResult.then(() => (handle.isReady = true));
} else {
handle.isReady = true;
handle.isReadyPromise = Promise.resolve();
}
return handle;
}

View File

@@ -1651,11 +1651,8 @@ LocalCollection._observeFromObserveChanges = (cursor, observeCallbacks) => {
{ nonMutatingCallbacks: true });
// If needed, re-enable callbacks as soon as the initial batch is ready.
if (suppressed) {
handle.isReadyPromise.then(() => {
suppressed = false;
});
}
if (handle.isReady) suppressed = false;
else handle.isReadyPromise.then(() => (suppressed = false));
return handle;
};

View File

@@ -1895,12 +1895,12 @@ Tinytest.addAsync('minimongo - observe ordered with projection', async test => {
test.equal(operations.shift(), undefined);
const cursor = c.find({}, {fields: {a: 1, _id: 0}});
await test.throwsAsync(async () => {
await cursor.observeChanges({ added() {} });
});
test.throws(() => {
cursor.observe({ added() {} });
});
test.throws(() => {
cursor.observeChanges({ added() {} });
});
test.throws(() => {
cursor.observe({ added() {} });
});
// test initial inserts (and backwards sort)
handle = c.find({}, {sort: {a: -1}, fields: { a: 1 } }).observe(cbs);
@@ -3790,11 +3790,11 @@ Tinytest.add('minimongo - update should clone', test => {
Tinytest.addAsync("minimongo - fetch in observe", (test, done) => {
const coll = new LocalCollection();
let callbackInvoked = false;
coll.find().observeChanges({
async added(id, fields) {
const observe = coll.find().observeChanges({
added(id, fields) {
callbackInvoked = true;
test.equal(fields, { foo: 1 }, "equals fields");
const doc = await coll.findOneAsync({ foo: 1 });
test.equal(fields, { foo: 1 });
const doc = coll.findOne({ foo: 1 });
test.isTrue(doc);
test.equal(doc.foo, 1);
},
@@ -3812,6 +3812,22 @@ Tinytest.addAsync("minimongo - fetch in observe", (test, done) => {
});
});
Tinytest.add("minimongo - simple reactivity", (test) => {
const coll = new LocalCollection();
let runs = 0;
Tracker.autorun(() => {
runs += 1;
coll.find().fetch()
});
coll.insert({ _id: "test" });
Tracker.flush();
// runs should now be 2
test.equal(runs, 2);
});
// See #2254
Tinytest.addAsync(
"minimongo - fine-grained reactivity of observe with fields projection",

View File

@@ -2,7 +2,7 @@
"lockfileVersion": 1,
"dependencies": {
"@meteorjs/reify": {
"version": "git+https://github.com/meteor/reify.git#ee36898798645097948258eb9106dd0af60cec64"
"version": "git+https://github.com/meteor/reify.git#0867be73ca61e87ae9d60edef62baf26b38719ef"
},
"@types/estree": {
"version": "1.0.0",

View File

@@ -6,7 +6,7 @@ Package.describe({
});
Npm.depends({
"@meteorjs/reify": "git+https://github.com/meteor/reify.git#ee36898798645097948258eb9106dd0af60cec64",
"@meteorjs/reify": "git+https://github.com/meteor/reify.git#0867be73ca61e87ae9d60edef62baf26b38719ef",
"meteor-babel-helpers": "0.0.3",
});

View File

@@ -26,7 +26,7 @@ async function runNextUrl(browser) {
console.log(`
The number of tests from Test number may be different because
of the way the test is written. causing the test to fail or
to run more than once. in the console. Test number total: ${ testNumber }`);
to run more than once. in the console. Test number total: ${ testNumber }`);
console.log(`Tests complete with ${ failCount } failures`);
console.log(`Tests complete with ${ await getPassCount(page) } passes`);
if (failCount > 0) {

View File

@@ -239,6 +239,13 @@ class InputFile extends buildPluginModule.InputFile {
// accept a lazy finalizer function as a second argument, so that
// compilation can be avoided until/unless absolutely necessary.
this.supportsLazyCompilation = true;
// Communicate to compiler plugins that this version of Meteor
// is able to support top level await
// TODO: maybe this should also check if the file and package meet the
// minimum requirements to use top level await (file isn't bare, and
// package uses core-runtime and modules)
this.supportsTopLevelAwait = true;
}
getContentsAsBuffer() {

View File

@@ -410,7 +410,7 @@ const loadServerBundles = Profile("Load server bundles", async function () {
const scriptPath =
parsedSourceMaps[absoluteFilePath] ? absoluteFilePath : fileInfoOSPath;
const func = await require('vm').runInThisContext(wrapped, {
const func = require('vm').runInThisContext(wrapped, {
filename: scriptPath,
displayErrors: true
});
@@ -428,14 +428,14 @@ const loadServerBundles = Profile("Load server bundles", async function () {
});
} else {
// Allows us to use code-coverage if the debugger is not enabled
await Profile(fileInfo.path, func).apply(global, args);
Profile(fileInfo.path, func).apply(global, args);
}
}
await maybeWaitForDebuggerToAttach();
for (const info of infos) {
await info.fn.apply(global, info.args);
info.fn.apply(global, info.args);
}
if (global.Package['core-runtime']) {
return global.Package['core-runtime'].waitUntilAllLoaded();
@@ -509,5 +509,3 @@ var runMain = Profile("Run main()", async function () {
console.log(e.stack);
process.exit(1)
});

View File

@@ -150,7 +150,7 @@ selftest.define("testModule", async function () {
await s.init();
await s.createApp("app-config-mainModule", "app-config");
s.cd("app-config-mainModule");
await s.cd("app-config-mainModule");
// For meteortesting:mocha to work we must set test broswer driver
// See https://github.com/meteortesting/meteor-mocha
@@ -160,7 +160,8 @@ selftest.define("testModule", async function () {
"test",
// Not running with the --full-app option here, in order to exercise
// the normal `meteor test` behavior.
"--driver-package", "meteortesting:mocha"
/// TODO: Fibers => turn this back to meteortesthing:mocha when 3.0.0 is released
"--driver-package", "grubba:mocha" /// meteortesting:mocha"
);
run.waitSecs(60);

View File

@@ -12,3 +12,4 @@ es5-shim # ECMAScript 5 compatibility for older browsers
ecmascript # Enable ECMAScript2015+ syntax in app code
shell-server # Server-side component of the `meteor shell` command
less # Support .less files for defining CSS styles
grubba:mocha

View File

@@ -62,3 +62,4 @@ underscore@1.0.11
url@1.2.0
webapp@1.5.0
webapp-hashing@1.0.9
grubba:mocha@3.0.0

View File

@@ -1,4 +1,4 @@
jshint@0.0.1
jshint@1.1.8
linter-plugin@1.0.0
meteor@1.1.6
my-package@0.0.0

View File

@@ -0,0 +1 @@
local

View File

@@ -0,0 +1,16 @@
# Meteor packages used by this project, one per line.
# Check this file (and the other files in this directory) into your repository.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
print
meteor-base # Packages every Meteor app needs to have
ecmascript # Enable ECMAScript2015+ syntax in app code
build-plugin
webapp
sync-package
package-1
package-2
lazy-package
standard-minifier-js

View File

@@ -0,0 +1 @@
none

View File

@@ -0,0 +1,7 @@
console.log('app a.js - before');
await 0
console.log('app a.js - after');
Promise.resolve().then(() => {
console.log('app a.js - later');
});

View File

@@ -0,0 +1,7 @@
console.log('app b.js - before');
await 0
console.log('app b.js - after');
Promise.resolve().then(() => {
console.log('app b.js - later');
});

View File

@@ -0,0 +1,18 @@
import './a.js';
import './b.js';
Meteor.startup(() => {
console.log('entry - startup');
});
console.log('entry - before');
await 0
console.log('entry - after');
Promise.resolve().then(() => console.log('entry - later'));
require('meteor/lazy-package').then(({ value }) => {
console.log(`lazy package value ${value}`);
});
console.log(`package 2 value ${require('meteor/package-2').value}`);

View File

@@ -0,0 +1,20 @@
{
"name": "watch-used-files",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@babel/runtime": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
"integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
"requires": {
"regenerator-runtime": "^0.13.11"
}
},
"regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
}
}
}

View File

@@ -0,0 +1,19 @@
{
"name": "top-level-await",
"private": true,
"scripts": {
"start": "meteor run",
"test": "meteor test --once --driver-package meteortesting:mocha",
"test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
"visualize": "meteor --production --extra-packages bundle-visualizer"
},
"dependencies": {
"@babel/runtime": "^7.15.3"
},
"meteor": {
"mainModule": {
"client": "main.js",
"server": "main.js"
}
}
}

View File

@@ -0,0 +1,19 @@
Package.describe({
name: 'build-plugin',
});
Package.registerBuildPlugin({
name: 'build-plugin',
use: ['meteor', 'ecmascript'],
sources: ['plugin.js']
});
Package.registerBuildPlugin({
name: 'build-plugin-no-meteor',
use: [],
sources: ['plugin-without-meteor.js']
});
Package.onUse((api) => {
api.use('isobuild:compiler-plugin@1.0.0')
})

View File

@@ -0,0 +1 @@
console.log('plugin without Meteor');

View File

@@ -0,0 +1,7 @@
Meteor.startup(() => {
console.log('plugin - startup');
});
console.log('plugin - before');
await 0
console.log('plugin - after');
Promise.resolve().then(() => console.log('plugin - later'));

View File

@@ -0,0 +1,4 @@
console.log('lazy package');
await 0;
console.log('after lazy');
export const value = 10;

View File

@@ -0,0 +1,4 @@
Package.onUse((api) => {
api.use('ecmascript');
api.mainModule('main.js', ['client', 'server'], { lazy: true});
});

View File

@@ -0,0 +1,6 @@
console.log('package 1 - a before');
await 0;
console.log('package 1 - a after');
Promise.resolve().then(() => {
console.log('package 1 - a later');
});

View File

@@ -0,0 +1,6 @@
console.log('package 1 - b before');
await 0;
console.log('package 1 - b after');
Promise.resolve().then(() => {
console.log('package 1 - b later');
});

View File

@@ -0,0 +1,5 @@
Package.onUse((api) => {
api.use('ecmascript');
api.addFiles('b.js');
api.mainModule('a.js');
});

View File

@@ -0,0 +1,10 @@
import './b.js';
console.log('package 2 - a before');
await 0;
console.log('package 2 - a after');
Promise.resolve().then(() => {
console.log('package 2 - a later');
});
export const value = 6;

View File

@@ -0,0 +1,4 @@
console.log('package 2 - b');
Promise.resolve().then(() => {
console.log('package 2 - b later');
});

View File

@@ -0,0 +1,4 @@
Package.onUse((api) => {
api.use('ecmascript');
api.mainModule('a.js');
});

View File

@@ -0,0 +1,14 @@
// Wait for Meteor package to load
let logs = [];
let oldLog = console.log;
console.log = function (message) {
logs.push(message);
oldLog.apply(this, arguments);
}
Meteor.startup(() => {
// run after all startup hooks
setTimeout(() => {
Meteor.call('print', logs);
});
});

View File

@@ -0,0 +1,6 @@
Package.onUse((api) => {
api.use('meteor');
api.use('ddp');
api.addFiles('client.js', 'client');
api.addFiles('server.js', 'server');
});

View File

@@ -0,0 +1,8 @@
// Wait for Meteor package to load
Meteor.methods({
print(logs) {
logs.forEach(message => {
console.log('[client]', message);
});
}
});

View File

@@ -0,0 +1,4 @@
Package.onUse((api) => {
api.use('ecmascript');
api.addFiles('sync.js');
});

View File

@@ -0,0 +1,4 @@
console.log('package sync');
Promise.resolve().then(() => {
console.log('package sync - later');
});

View File

@@ -107,7 +107,7 @@ selftest.define("versioning hot code push", async function (options) {
s.set("AUTOUPDATE_VERSION", "1.0");
await s.createApp("myapp", "hot-code-push-test");
s.cd("myapp");
await s.cd("myapp");
await s.testWithAllClients(async function (run) {
await run.match("myapp");

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,7 @@ selftest.define("static-html - throws error", async () => {
await s.createApp('myapp', 'compiler-plugin-static-html-error');
s.cd('myapp');
const run = startRun(s);
const run = await startRun(s);
await run.match("Attributes on <head> not supported");
run.waitSecs(30);

View File

@@ -0,0 +1,73 @@
import * as selftest from '../tool-testing/selftest.js';
selftest.define("xxxx top level await - order", async function (options) {
const s = new selftest.Sandbox({
clients: options.clients
});
s.set('METEOR_ENABLE_CLIENT_TOP_LEVEL_AWAIT', 'true');
await s.init();
await s.createApp("myapp", "top-level-await-order");
s.cd("myapp");
await s.testWithAllClients(async (run) => {
// TODO: Startup should be the last log, but there is a bug
// where it runs too early in plugins
await run.match('plugin - startup');
await run.match('plugin - before');
await run.match('plugin - after');
await run.match('plugin - later');
await run.match('plugin without Meteor');
const lines = [
'package sync',
'package 1 - b before',
'package 2 - b',
'package 2 - a before',
'package sync - later',
'package 1 - b after',
'package 2 - b later',
'package 2 - a after',
'package 1 - b later',
'package 1 - a before',
'package 2 - a later',
'package 1 - a after',
'package 1 - a later',
'app a.js - before',
'app b.js - before',
'app a.js - after',
'app b.js - after',
'app a.js - later',
'app b.js - later',
'entry - before',
'entry - after',
'lazy package',
'package 2 value 6',
'entry - later',
'after lazy',
'lazy package value 10',
'entry - startup',
];
for(const line of lines) {
await run.match(line);
}
await run.connectClient();
for(const line of lines) {
await run.match(`[client] ${line}`);
}
await run.stop();
}, {
// concatenate js files so packages load in parallel
// otherwise, there is too much of a delay between each
// package loading
// TODO: we could instead create a custom minifier for this test that
// only concatenates, which would be faster
args: ['--production']
});
});

View File

@@ -10,21 +10,33 @@ export default class PuppeteerClient extends Client {
constructor(options) {
super(options);
enterJob(
this.name = 'Puppeteer';
this.initialized = false;
}
async init () {
await enterJob(
{
title: 'Installing Puppeteer in Meteor tool'
},
() => {
ensureDependencies(NPM_DEPENDENCIES);
return ensureDependencies(NPM_DEPENDENCIES);
}
);
this.npmPackageExports = require('puppeteer');
this.initialized = true;
}
this.name = 'Puppeteer';
_checkInitialized() {
if (!this.initialized) {
throw new Error('PuppeteerClient not initialized');
}
}
async connect() {
this._checkInitialized();
// Note for Travis and CircleCI to run sandbox must be turned off.
// From a security perspective this is not ideal, in the future would be worthwhile
// to configure to include only for CI based setups
@@ -41,7 +53,10 @@ export default class PuppeteerClient extends Client {
this.browser = null;
}
static pushClients(clients, appConfig) {
clients.push(new PuppeteerClient(appConfig));
static async pushClients(clients, appConfig) {
let client = new PuppeteerClient(appConfig);
await client.init();
clients.push(client);
}
}

View File

@@ -16,10 +16,10 @@ export default class Matcher {
});
}
write(data) {
async write(data) {
this.buf += data;
this.fullBuffer += data;
this._tryMatch();
await this._tryMatch();
}
getFullBuffer() {
@@ -64,18 +64,29 @@ export default class Matcher {
}
// Like match, but returns a Promise without calling .await().
matchAsync(pattern, {
async matchAsync(pattern, {
timeout = null,
strict = false,
matchFullBuffer = false,
}) {
if (this.matchPromise) {
return Promise.reject(new Error("already have a match pending?"));
// wait a bit to let the matcher catch up
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
await sleep(100);
this._tryMatch(); // could clear this.matchPromise
// If we still have a matchPromise, then we have a problem.
// you should check who is calling.
if (this.matchPromise) {
return Promise.reject(new Error("already have a match pending?"))
}
}
this.matchPattern = pattern;
this.matchStrict = strict;
this.matchFullBuffer = matchFullBuffer;
const mp = this.matchPromise = makeFulfillablePromise();
this.matchPromise = makeFulfillablePromise();
const mp = this.matchPromise;
this._tryMatch(); // could clear this.matchPromise
let timer = null;
@@ -92,13 +103,16 @@ export default class Matcher {
return mp;
}
return mp.then((result) => {
clearTimeout(timer);
return result;
}, (error) => {
clearTimeout(timer);
throw error;
});
return mp.then(
(result) => {
clearTimeout(timer);
return result;
},
(error) => {
clearTimeout(timer);
throw error;
}
);
}
matchBeforeEnd(pattern, timeout) {
@@ -114,12 +128,12 @@ export default class Matcher {
}
end() {
return this.endAsync().await();
return this.endAsync();
}
endAsync() {
this.resolveEndPromise();
return this._beforeEnd(() => {
return this._beforeEnd(async () => {
this.ended = true;
this._tryMatch();
return this.matchPromise;
@@ -133,7 +147,7 @@ export default class Matcher {
}
}
_tryMatch() {
async _tryMatch() {
const mp = this.matchPromise;
if (! mp) {
return;

View File

@@ -136,7 +136,7 @@ export default class Sandbox {
}
if (clientOptions.puppeteer) {
PuppeteerClient.pushClients(this.clients, appConfig);
await PuppeteerClient.pushClients(this.clients, appConfig);
}
if (clientOptions.browserstack && BrowserStackClient.prerequisitesMet()) {
@@ -272,7 +272,7 @@ export default class Sandbox {
if (callback) {
const ret = callback();
if (ret && typeof ret.then === "function") {
return ret.then(() => this.cwd = previous);
return ret.then(() => (this.cwd = previous));
} else {
this.cwd = previous;
}
@@ -516,7 +516,7 @@ async function setUpBuiltPackageTropohouse() {
}
const tropohouse = new Tropohouse(builtPackageTropohouseDir);
tropohouseLocalCatalog = newSelfTestCatalog();
tropohouseLocalCatalog = await newSelfTestCatalog();
const versions = {};
for (const packageName of tropohouseLocalCatalog.getAllNonTestPackageNames()) {
versions[packageName] =
@@ -585,16 +585,16 @@ const ROOT_PACKAGES_TO_BUILD_IN_SANDBOX = [
"typescript",
];
function newSelfTestCatalog() {
async function newSelfTestCatalog() {
if (! files.inCheckout()) {
throw Error("Only can build packages from a checkout");
}
const catalogLocal = require('../packaging/catalog/catalog-local.js');
const selfTestCatalog = new catalogLocal.LocalCatalog;
const messages = capture(
const messages = await capture(
{ title: "scanning local core packages" },
() => {
async () => {
const packagesDir =
files.pathJoin(files.getCurrentToolsDir(), 'packages');
@@ -603,7 +603,7 @@ function newSelfTestCatalog() {
// packages. One side effect of this: we really really expect them to all
// build, and we're fine with dying if they don't (there's no worries
// about needing to springboard).
selfTestCatalog.initialize({
await selfTestCatalog.initialize({
localPackageSearchDirs: [
packagesDir,
files.pathJoin(packagesDir, "non-core"),