how to write mocha test that have timeout and async both - mocha.js

createStream need to get permission of browser's video&audio,so i have to delay this test
both createStream and destroyStream return promise
i want to test destroyStream, this just not get what i want, anyone Help?
it("my test need to be delayed, and i want to test destroyStream", function () {
setTimeout(async () => {
// i need to create stream first
const publishStream = await createStream();
expect(streamCenter.previewVideoList.length).to.equal(1);
// then destory stream
await zg.destroyStream(publishStream);
expect(streamCenter.previewVideoList.length).to.equal(0);
}, 2000); // my test need to be delayed
});

it("my test need to be delayed, and i want to test destroyStream", async function () {
this.timeout(10000); // set timeout 10s
// i need to create stream first
const publishStream = await createStream();
expect(streamCenter.previewVideoList.length).to.equal(1);
// then destory stream
await zg.destroyStream(publishStream);
expect(streamCenter.previewVideoList.length).to.equal(0);
});
this seems work if i allow the permission in time。 otherwise it will failed with Error 'Permission denied'

Related

Expecting a Promise *not* to complete, in Jest

I have the following need to test whether something does not happen.
While testing something like that may be worth a discussion (how long wait is long enough?), I hope there would exist a better way in Jest to integrate with test timeouts. So far, I haven't found one, but let's begin with the test.
test ('User information is not distributed to a project where the user is not a member', async () => {
// Write in 'userInfo' -> should NOT turn up in project 1.
//
await collection("userInfo").doc("xyz").set({ displayName: "blah", photoURL: "https://no-such.png" });
// (firebase-jest-testing 0.0.3-beta.3)
await expect( eventually("projects/1/userInfo/xyz", o => !!o, 800 /*ms*/) ).resolves.toBeUndefined();
// ideally:
//await expect(prom).not.toComplete; // ..but with cancelling such a promise
}, 9999 /*ms*/ );
The eventually returns a Promise and I'd like to check that:
within the test's normal timeout...
such a Promise does not complete (resolve or reject)
Jest provides .resolves and .rejects but nothing that would combine the two.
Can I create the anticipated .not.toComplete using some Jest extension mechanism?
Can I create a "run just before the test would time out" (with ability to make the test pass or fail) trigger?
I think the 2. suggestion might turn handy, and can create a feature request for such, but let's see what comments this gets..
Edit: There's a further complexity in that JS Promises cannot be cancelled from outside (but they can time out, from within).
I eventually solved this with a custom matcher:
/*
* test-fns/matchers/timesOut.js
*
* Usage:
* <<
* expect(prom).timesOut(500);
* <<
*/
import { expect } from '#jest/globals'
expect.extend({
async timesOut(prom, ms) { // (Promise of any, number) => { message: () => string, pass: boolean }
// Wait for either 'prom' to complete, or a timeout.
//
const [resolved,error] = await Promise.race([ prom, timeoutMs(ms) ])
.then(x => [x])
.catch(err => [undefined,err] );
const pass = (resolved === TIMED_OUT);
return pass ? {
message: () => `expected not to time out in ${ms}ms`,
pass: true
} : {
message: () => `expected to time out in ${ms}ms, but ${ error ? `rejected with ${error}`:`resolved with ${resolved}` }`,
pass: false
}
}
})
const timeoutMs = (ms) => new Promise((resolve) => { setTimeout(resolve, ms); })
.then( _ => TIMED_OUT);
const TIMED_OUT = Symbol()
source
The good side is, this can be added to any Jest project.
The down side is, one needs to separately mention the delay (and guarantee Jest's time out does not happen before).
Makes the question's code become:
await expect( eventually("projects/1/userInfo/xyz") ).timesOut(300)
Note for Firebase users:
Jest does not exit to OS level if Firestore JS SDK client listeners are still active. You can prevent it by unsubscribing to them in afterAll - but this means keeping track of which listeners are alive and which not. The firebase-jest-testing library does this for you, under the hood. Also, this will eventually ;) get fixed by Firebase.

Async/Await to simulate busy server that delay update to client browser

MERN noob here. Trying to learn Async/Await by simulating a busy server where client browser only get the update > 3 seconds later (i will manually refresh localhost:3000, after 3 seconds. I only need help on Node.js/ server side for this question)
Could you help rectify codes below? Kindly avoid proposing other ways/methods but show me how to achieve using below example. Thanks in advance.
const app = require('express')()
async function getData() {
//Purpose: to simulate a busy server that returns data back to browser, after 3 seconds delay
await setTimeout(() => {
return 'After waiting 3 seconds, return this sentense as the required data to the browser.'
}, 3000);
}
app.get('/', async (req, res) => {
try {
const data = await getData()
await res.status(200).send(`${data}`)
} catch (err) {
await res.status(400).send(`Unable to get data. Error message, "${err}"`)
}
})
app.listen(3000)
The problem here is that setTimeout doesn't return a promise so you can't use await with it. It just executes the given function after 3 seconds. You can get what you want by wrapping it in a Promise like this:
const app = require('express')()
function getData() {
//Purpose: to simulate a busy server that returns data back to browser, after 3 seconds delay
return new Promise((resolve) => {
setTimeout(() => {
resolve('After waiting 3 seconds, return this sentense as the required data to the browser.');
}, 3000);
});
}
app.get('/', async (req, res) => {
try {
const data = await getData()
await res.status(200).send(`${data}`)
} catch (err) {
await res.status(400).send(`Unable to get data. Error message, "${err}"`)
}
})
app.listen(3008)
Note that you need a return statement to return the promise inside of getData. You didn't have a return statement originally which means the function returns undefined (or if marked as async it gives a Promise that resolves to undefined).
Here we don't need to use async/await because you're not needing to use await until in the app.get. Using async/await in getData could be added but it would be redundant.
Realize that aync/await uses Promises - it's just an easy way to work with Promises. So you can't await on anything but a Promise. Note that async really just means "this function returns a Promise and we'll wrap any result in a Promise if it isn't already a Promise". So you cannot use async/await without having a Promise at some point.
But if you really want to use async/await for some reason maybe this example would help you:
async function getData() {
//Purpose: to simulate a busy server that returns data back to browser, after 3 seconds delay
const result = await new Promise((resolve) => {
setTimeout(() => {
resolve('After waiting 3 seconds, return this sentense as the required data to the browser.');
}, 3000);
});
console.log('We are done waiting 3 seconds');
return result; // <-- this returns a Promise that resolves to the result string
}

How to make jasmin test keep running until expect succeeds?

I am testing a background process API. This API call returns messages at regular intervals. I am trying to write a test that waits until it gets the specific message I am looking for.
Example:
describe('integration tests', function() {
it('expecting a specific message', async (done) => {
const callback = (message) => {
if (message === ''Hello world') {
expect(message).toEqual('Hello world');
}
};
await someApiCall(callback);
});
});
In the above example, I am passing a callback to the background process api call. The process executes the callback at regular intervals with different messages. There is no guarantee that I will get Hello World on the first execution. That's why I had to wrap expect inside if statement so that the test will not fail on message mismatch. So, I want to keep checking for some X amount of time and then fail if I did not get that specific message within that time.
Is there a better way I can test this? placing expect inside if seems bad.
When using the done function, async is not needed. I also noticed that in your example, you create a callback function but don't use it. I assume the callback to be an argument of the someApiCall function. If this is the case, you could write your test as follows.
it('expecting a specific message', () => {
const callback = (message) => null;
someApiCall(callback);
jasmine.clock().tick(10000);
expect(callback).toHaveBeenCalledWith('Hello world');
});
It could also work with the done function.
it('expecting a specific message', (done) => {
const maxCallbackInvocations = 10;
let callbackInvocations = 0;
const callback = (message) => {
callbackInvocations++;
if (message === 'Hello world') {
expect(1).toBe(1);
done();
} else if (callbackInvocations >= maxCallbackInvocations) {
fail();
}
};
someApiCall(callback);
};

Apollo server subscription not recognizing Async Iterable

I'm having an issue with Apollo GraphQL's subscription. When attempting to start the subscription I'm getting this in return:
"Subscription field must return Async Iterable. Received: { pubsub: { ee: [EventEmitter], subscriptions: {}, subIdCounter: 0 }, pullQueue: [], pushQueue: [], running: true, allSubscribed: null, eventsArray: [\"H-f_mUvS\"], return: [function return] }"
I have other subscriptions setup and are completely functional - so I can confirm the webserver is setup correctly.
I'm just curious if anyone else has ever ran onto this issue before.
Source code in PR diff (it's an open source project):
https://github.com/astronomer/houston-api/pull/165/files
error in playground
I don't think this is an issue specific to the PR you posted. I'd be surprised if any of the subscriptions were working as is.
Your subscribe function should return an AsyncIterable, as the error states. Since it returns a call to createPoller, createPoller should return an AsyncIterable. But here's what that function looks like:
export default function createPoller(
func,
pubsub,
interval = 5000, // Poll every 5 seconds
timeout = 3600000 // Kill after 1 hour
) {
// Gernate a random internal topic.
const topic = shortid.generate();
// Create an async iterator. This is what a subscription resolver expects to be returned.
const iterator = pubsub.asyncIterator(topic);
// Wrap the publish function on the pubsub object, pre-populating the topic.
const publish = bind(curry(pubsub.publish, 2)(topic), pubsub);
// Call the function once to get initial dataset.
func(publish);
// Then set up a timer to call the passed function. This is the poller.
const poll = setInterval(partial(func, publish), interval);
// If we are passed a timeout, kill subscription after that interval has passed.
const kill = setTimeout(iterator.return, timeout);
// Create a typical async iterator, but overwrite the return function
// and cancel the timer. The return function gets called by the apollo server
// when a subscription is cancelled.
return {
...iterator,
return: () => {
log.info(`Disconnecting subscription ${topic}`);
clearInterval(poll);
clearTimeout(kill);
return iterator.return();
}
};
}
So createPoller creates an AsyncIterable, but then creates a shallow copy of it and returns that. graphql-subscriptions uses iterall's isAsyncIterable for the check that's producing the error you're seeing. Because of the way isAsyncIterable works, a shallow copy won't fly. You can see this for yourself:
const { PubSub } = require('graphql-subscriptions')
const { isAsyncIterable } = require('iterall')
const pubSub = new PubSub()
const iterable = pubSub.asyncIterator('test')
const copy = { ...iterable }
console.log(isAsyncIterable(iterable)) // true
console.log(isAsyncIterable(copy)) // false
So, instead of returning a shallow copy, createPoller should just mutate the return method directly:
export default function createPoller(...) {
...
iterator.return = () => { ... }
return iterator
}

Protractor test + manage order of execution

I have a Protractor test which looks like
pageObject1.method1();
pageObject1.method2();
pageObject2.method1();
expect(pageObject2.method2());
let allDataList = pageObject2.method3();
expect(allDataList.includes('test1')).toBeTruthy();
How do I make sure that the call to pageObject2.method3() happens before the next expect call? method3() returns an array of the text of all span elements.
This case you need to use promises
Way-1:
await pageObject1.method2();
await pageObject2.method1();
expect(pageObject2.method2());
let allDataList = await pageObject2.method3();
expect(allDataList.includes('test1')).toBeTruthy();
Description On await
Way-2:
pageObject1.method2().then(function() {
pageObject2.method1().then(function() {
expect(pageObject2.method2());
pageObject2.method3().then(function(allDataList) {
expect(allDataList.includes('test1')).toBeTruthy();
});
});
});

Resources