Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing with jest #8400

Open
franckyinuk opened this issue Apr 5, 2019 · 8 comments
Open

Testing with jest #8400

franckyinuk opened this issue Apr 5, 2019 · 8 comments
Labels

Comments

@franckyinuk
Copy link

Hi,

I have emscripten working nicely (using emcc 1.38.30):

  • I have c++ functions and classes exported
  • They use binding in the c++ files like this
EMSCRIPTEN_BINDINGS(MyClass)
{
    class_<MyOperation>("MYOperation");

    class_<OperationArray>("OperationArray")
        .constructor<>()
        .function<int>("GetSize", &OperationArray::GetSize)
        .function<ApiOperation*&, int>("GetAt", &OperationArray::GetAt)
        ;
}
  • Then they are compiled with those arguments
    -Oz -s WASM=1 -s INLINING_LIMIT=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s ALLOW_MEMORY_GROWTH=1 -s DISABLE_EXCEPTION_CATCHING=0 -Wno-switch -std=c++11 -c --bind -fvisibility-ms-compat
  • And they are linked with -s WASM=1 --bind -fvisibility-ms-compat
  • All my functions are getting called from some served javascript successfully

Now to the problem.
We have found that the bindings are a bit fleaky and sometime some functions become not visible from our javascript code.
So we thought we would had some jest tests to check programmatically if all our functions are being correctly exported.

So I tried 2 things.
1, I have found some tutorials showing how to test wasm files by instanciating the wasm file directly (https://hub.packtpub.com/testing-webassembly-modules-with-jest-tutorial/), but when I try to do the same I get lots of link errors like this one:
LinkError: WebAssembly Instantiation: Import #1 module="env" function="nullFunc_di" error: function import requires a callable
I get this for about 20-30 functions, and true enough those functions are all defined in the js file generated by emcc
I have tried to create all the missing functions but then the error I was getting changed:
LinkError: WebAssembly Instantiation: Import #43 module="env" function="tempDoublePtr" error: global import must be a number or WebAssembly.Global object

Why are all those functions needed by my wasm file?

2 Then I tried to load the js file generated by emcc but I get this error message
console.log ../builds/wasmMyClass/MyClass.js:4292
both async and sync fetching of the wasm failed

Any idea on this error?

Is it possible at all to test wasm file from jest?
Would there be another way to test that the exported functions are working as expected in javascript?

Any help would be appreciated,
Thanks

@kripken
Copy link
Member

kripken commented Apr 5, 2019

About 1, the wasm depends on support from JS - could be syscalls, or other things. That interface is an emscripten internal detail, basically.

If you just want to check if a function is exported, you don't need to instantiate the module, though. You can parse the wasm binary, for example you can print it using wabt or binaryen, and scan the output for the exports.

About 2, the error logging should explain how it failed (was the wasm file missing, or the browser didn't support wasm, or something else). ASSERTIONS builds may have more info.

@franckyinuk
Copy link
Author

I don't have logs to see the issue since I am not serving the js file, I am importing it inside a jest test.
So it would suggest that I can't use jest since the js file needs to be on a webserver.
What do you think?

Thank you for your help,
Franck.

@oddball
Copy link

oddball commented Jun 2, 2019

@franckyinuk Did you get any further with this? I am sitting with the same issue.

@oddball
Copy link

oddball commented Jun 3, 2019

@franckyinuk If you are interested, I got it Jest working with something like this

var QuantLibModule = require("./quantlib");
var QuantLib = null;

describe("captor/quantlib", () => {
    beforeAll(async () => {
        var loader = QuantLibModule();
        loader.ready = () =>
            // https://github.com/emscripten-core/emscripten/issues/5820
            new Promise((resolve, reject) => {
                delete loader.then;
                loader.onAbort = reject;
                loader.addOnPostRun(() => {
                    resolve(loader);
                });
            });
        QuantLib = await loader.ready();
    });

    test("Sweden Calendar", async () => {
        expect(QuantLib.Sweden.name()).toBe("Sweden");
    });
});
emcc  ... -s "EXTRA_EXPORTED_RUNTIME_METHODS=['addOnPostRun']" ...

@UnoPlatformAzureArticle
Copy link

UnoPlatformAzureArticle commented Jul 31, 2019

Jest by default uses jsdom to simulate running in a browser. This creates a Window object that the Emscripten code sees and thinks it's in a browser. I didn't debug through what happens to know exactly what the cause is (perhaps something to do with fetch and not having a web server running?)

Switching Jest to use Node.js fixed the issue on my side. Put the following at the very beginning of your JS test file to switch from jsdom to node:

/**
 * @jest-environment node
 */

@octopoulos
Copy link

Use emcc ... -s MODULARIZE=1, and then you can:

const Module = require('./test.js');

Module().then(instance => {
    // here you can do: new instance.MyClass(); if you exported a class, or instance.myFunction(); ...
});

@panuhorsmalahti
Copy link

panuhorsmalahti commented Oct 5, 2020

If you want to use jsdom to test wasm, you can mock the fetch function to return the .wasm file. I used "jest-fetch-mock" for this.

// TypeScript types don't seem to work correctly
import { enableFetchMocks } from "jest-fetch-mock";
import { readFileSync } from "fs";

enableFetchMocks();

const file = readFileSync("./src/file.wasm");

(fetch as any).mockResponse(async (request: any) => {
    if (request.url.endsWith("file.wasm")) {
        return {
            status: 200,
            body: file as any
        };
    } else {
        return {
            status: 404,
            body: "Not Found"
        };
    }
});

@stale
Copy link

stale bot commented Apr 17, 2022

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.

@stale stale bot added the wontfix label Apr 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants