Merge remote-tracking branch 'origin/zodern-solution-for-async-stubs' into feature/solving-meteor-callasync-stubvaluepromise

# Conflicts:
#	packages/ddp-client/client/client_convenience.js
#	packages/ddp-client/package.js
This commit is contained in:
denihs
2023-12-19 10:56:59 -04:00
3 changed files with 271 additions and 0 deletions

View File

@@ -60,5 +60,7 @@ Package.onTest((api) => {
api.addFiles('test/livedata_tests.js');
api.addFiles('test/livedata_test_service.js');
api.addFiles('test/random_stream_tests.js');
api.addFiles('test/async_stubs/client.js', 'client');
api.addFiles('test/async_stubs/server_setup.js', 'server');
api.addFiles('test/livedata_callAsync_tests.js');
});

View File

@@ -0,0 +1,225 @@
let events = [];
Meteor.methods({
'sync-stub'() {
events.push('sync-stub');
return 'sync-stub-result'
},
async 'async-stub'() {
events.push('start async-stub');
await 0;
events.push('end async-stub');
return 'async-stub-result'
},
callAsyncFromSyncStub() {
events.push('callAsyncFromSyncStub');
Meteor.callAsync('async-stub');
},
async callSyncStubFromAsyncStub() {
events.push('start callSyncStubFromAsyncStub');
await 0
let result = Meteor.call('sync-stub');
events.push('end callSyncStubFromAsyncStub');
return result;
},
callSyncStubFromSyncStub() {
events.push('callSyncStubFromSyncStub');
return Meteor.call('sync-stub');
},
callAsyncStubFromAsyncStub() {
events.push('callAsyncStubFromAsyncStub');
return Meteor.callAsync('async-stub');
}
});
Tinytest.addAsync('applyAsync - server only', async function (test) {
let serverResolver;
let serverPromise = new Promise((resolve) => {
serverResolver = resolve;
});
let stubResult = await Meteor.applyAsync('server-only-sync', [], { returnStubValue: true }, (err, result) => {
console.log(err);
if (!err) {
serverResolver(result);
}
});
let serverResult = await serverPromise;
test.equal(stubResult, undefined);
test.equal(serverResult, 'sync-result');
});
Tinytest.addAsync('applyAsync - sync stub', async function (test) {
let serverResolver;
let serverPromise = new Promise((resolve) => {
serverResolver = resolve;
});
let stubResult = await Meteor.applyAsync('sync-stub', [], {
returnStubValue: true
}, (err, result) => {
console.log(err);
if (!err) {
serverResolver(result);
}
});
let serverResult = await serverPromise;
test.equal(stubResult, 'sync-stub-result');
test.equal(serverResult, 'sync-server-result');
});
Tinytest.addAsync('applyAsync - callAsync', async function (test) {
let serverResult = await Meteor.callAsync('async-stub');
test.equal(serverResult, 'async-server-result');
});
Tinytest.addAsync('applyAsync - callAsync twice', async function (test) {
events = [];
let promise1 = Meteor.callAsync('async-stub');
let promise2 = Meteor.callAsync('async-stub');
let results = await Promise.all([promise1, promise2]);
test.equal(events, ['start async-stub', 'end async-stub', 'start async-stub', 'end async-stub']);
test.equal(results, ['async-server-result', 'async-server-result']);
});
// Broken in Meteor 2.13: https://github.com/meteor/meteor/issues/12889#issue-1998128607
Tinytest.addAsync('applyAsync - callAsync from async stub', async function (test) {
await Meteor.callAsync('getAndResetEvents');
events = [];
let serverResolver;
let serverPromise = new Promise((resolve) => {
serverResolver = resolve;
});
let stubResult = await Meteor.applyAsync('callAsyncStubFromAsyncStub', [], { returnStubValue: true }, (err, result) => {
if (!err) {
serverResolver(result);
}
});
let serverResult = await serverPromise;
let serverEvents = await Meteor.callAsync('getAndResetEvents');
test.equal(stubResult, 'async-stub-result');
test.equal(serverResult, 'server result');
test.equal(events, ['callAsyncStubFromAsyncStub', 'start async-stub', 'end async-stub']);
test.equal(serverEvents, ['callAsyncStubFromAsyncStub']);
});
Tinytest.addAsync('applyAsync - callAsync in then', async function (test) {
await Meteor.callAsync('getAndResetEvents');
events = [];
let result = await Meteor.callAsync('async-stub').then(() => Meteor.callAsync('async-stub'));
let serverEvents = await Meteor.callAsync('getAndResetEvents');
test.equal(events, ['start async-stub', 'end async-stub', 'start async-stub', 'end async-stub']);
test.equal(serverEvents, ['async-stub', 'async-stub']);
test.equal(result, 'async-server-result');
});
Tinytest.addAsync('applyAsync - call from async stub', async function (test) {
await Meteor.callAsync('getAndResetEvents');
events = [];
let serverResolver;
let serverPromise = new Promise((resolve) => {
serverResolver = resolve;
});
let stubResult = await Meteor.applyAsync('callSyncStubFromAsyncStub', [], { returnStubValue: true }, (err, result) => {
if (!err) {
serverResolver(result);
}
});
let serverResult = await serverPromise;
let serverEvents = await Meteor.callAsync('getAndResetEvents');
test.equal(stubResult, 'sync-stub-result');
test.equal(serverResult, 'server result');
test.equal(events, ['start callSyncStubFromAsyncStub', 'sync-stub', 'end callSyncStubFromAsyncStub']);
test.equal(serverEvents, ['callSyncStubFromAsyncStub']);
});
Tinytest.addAsync('apply - call from sync stub', async function (test) {
await Meteor.callAsync('getAndResetEvents');
events = [];
let serverResolver;
let serverPromise = new Promise((resolve) => {
serverResolver = resolve;
});
let stubResult = Meteor.apply('callSyncStubFromSyncStub', [], { returnStubValue: true }, (err, result) => {
if (!err) {
serverResolver(result);
}
});
let serverResult = await serverPromise;
let serverEvents = await Meteor.callAsync('getAndResetEvents');
test.equal(stubResult, 'sync-stub-result');
test.equal(serverResult, 'server result');
test.equal(events, ['callSyncStubFromSyncStub', 'sync-stub']);
test.equal(serverEvents, ['callSyncStubFromSyncStub']);
});
Tinytest.addAsync('apply - proper order with applyAsync', async function (test) {
await Meteor.callAsync('getAndResetEvents');
events = [];
let serverResolver;
let serverPromise = new Promise((resolve) => {
serverResolver = resolve;
});
let promise1 = Meteor.callAsync('callSyncStubFromAsyncStub');
let stubResult = Meteor.apply('callSyncStubFromSyncStub', [], { returnStubValue: true }, (err, result) => {
if (!err) {
serverResolver(result);
}
});
let promise2 = Meteor.callAsync('server-only-sync');
let [
serverResult,
result1,
result2
] = await Promise.all([serverPromise, promise1, promise2]);
let serverEvents = await Meteor.callAsync('getAndResetEvents');
test.equal(stubResult, 'sync-stub-result');
test.equal(serverResult, 'server result');
test.equal(result1, 'server result');
test.equal(result2, 'sync-result');
test.equal(events, ['callSyncStubFromSyncStub', 'sync-stub', 'start callSyncStubFromAsyncStub', 'sync-stub', 'end callSyncStubFromAsyncStub']);
test.equal(serverEvents, ['callSyncStubFromAsyncStub', 'callSyncStubFromSyncStub', 'server-only-sync']);
});
Tinytest.addAsync('apply - wait', async function (test) {
await Meteor.callAsync('getAndResetEvents');
events = [];
let serverResolver;
let serverPromise = new Promise((resolve) => {
serverResolver = resolve;
});
let stubResult = Meteor.apply(
'callSyncStubFromSyncStub',
[],
{ returnStubValue: true, wait: true },
(err, result) => {
if (!err) {
serverResolver(result);
}
});
const serverResult = await serverPromise;
test.equal(stubResult, 'sync-stub-result');
test.equal(serverResult, 'server result');
});

View File

@@ -0,0 +1,44 @@
let events = [];
Meteor.methods({
getAndResetEvents() {
let oldEvents = events;
events = [];
return oldEvents;
},
'server-only-sync' () {
events.push('server-only-sync');
return 'sync-result';
},
async 'server-only-async' () {
events.push('server-only-async');
await 0
return 'server-only-async-result';
},
'sync-stub' () {
events.push('sync-stub');
return 'sync-server-result'
},
'async-stub' () {
events.push('async-stub');
return 'async-server-result'
},
'callAsyncFromSyncStub'() {
events.push('callAsyncFromSyncStub');
},
'callSyncStubFromAsyncStub'() {
events.push('callSyncStubFromAsyncStub');
return 'server result';
},
'callSyncStubFromSyncStub'() {
events.push('callSyncStubFromSyncStub');
return 'server result';
},
'callAsyncStubFromAsyncStub'() {
events.push('callAsyncStubFromAsyncStub');
return 'server result';
}
});