little-cartoon-10569
06/30/2020, 1:45 AMexpect()
directly from the async function (passed as a parameter to it()
), unless there's an Output
or Promise
involved, in which case I call expect()
from within an apply()
. When everything passes, all good. And tests without apply
fail, all is good too: Test Explorer shows me my errors.
But when an expect()
inside an apply()
fails, Test Explorer shows the test as passing. I see the error message in VSCode's Output window, or in the console if that's where I running them, but Test Explorer isn't noticing that there was a failed expect()
. The failures always show up as *UnhandledPromiseRejectionWarning*s.
What am I doing wrong?it('should do stuff', function checkStuff() {
expect(stuff.apply(val => {
expect(val).to.eql("stuff");
})).not.to.throw();
});
it('should do stuff', function checkStuff() {
return new Promise(function (resolve, reject) {
try {
stuff.apply(val => {
expect(val).to.eql("stuff");
resolve();
catch (error) {
reject(error);
}
});
});
.then()
method to pulumi.Output.. if such a thing is possible...faint-table-42725
06/30/2020, 2:45 AMlittle-cartoon-10569
06/30/2020, 5:06 AMfunction promise<T>(output: pulumi.Output<T>): Promise<T | undefined> {
return (output as any).promise() as Promise<T>;
}
This allows me to write tests like this:
it('should work', async function workTest() {
expect(await promise(objectUnderTest.unappliedOutput)).to.eql("expected output");
});
This does the job. My questions (so far) are:
Where is the promise()
function defined? The one called in the return
line of the first snippet?
Can I hide the await
in that function? I haven't found a way to do that yet. I've tried making it async and returning the awaited promise. That produces the expected output on failure, but on success it always produces an error to the effect of '{} doesn't equal "expected output"`.
Can pulumi.Output
or pulumi.OutputInstance
be extended? It seems they can't because they're types not classes. I'd like to be able to make the promise()
function an extension method of Output.
If I could sort out those niggles, then I could end up with fairly elegant tests like this:
it('should work', async function workTest() {
expect(objectUnderTest.unappliedOutput.promise()).to.eventually.eql("expected output");
});
apply()
on an Output property on an Output object will resolve everything, this local promise()
function only resolves the thing being passed to it. For example, I have a VpcDhcpOptions
Output object, but I can't use expect(await promise(options.domainNameServers))
, I have to use expect(await promise((await promise(options)).domainNameServers)
...faint-table-42725
06/30/2020, 7:17 PMpromise
comes from https://github.com/pulumi/pulumi/blob/master/sdk/nodejs/output.ts#L64 which is set at https://github.com/pulumi/pulumi/blob/master/sdk/nodejs/output.ts#L188little-cartoon-10569
06/30/2020, 8:04 PMimport { expect, use as chaiWillUse } from "chai";
import * as chaiAsPromised from "chai-as-promised";
chaiWillUse(chaiAsPromised);
2) Sneakily import the needed @internal
function:
declare module '@pulumi/pulumi' {
export interface OutputInstance<T> {
promise(withUnknowns?: boolean): Promise<T>;
}
}
3) Win.
it('should work', async function workTest() {
return expect(objectUnderTest.unappliedOutput.promise()).to.eventually.eql("expected output");
});