Skip to content

Commit b4cad44

Browse files
committed
test: add wasm test
ignore emsdk temporarily remove wasi test add wasi test back --experimental-wasi-unstable-preview1 test separate wasm test run test in bash on windows fix python path
1 parent cb8bfc1 commit b4cad44

File tree

7 files changed

+306
-3
lines changed

7 files changed

+306
-3
lines changed

.github/workflows/tests.yml

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ jobs:
102102
node: 20.x
103103
name: ${{ matrix.os }} - ${{ matrix.python }} - ${{ matrix.node }}
104104
runs-on: ${{ matrix.os }}
105+
env:
106+
WASI_VERSION: '22'
107+
WASI_VERSION_FULL: '22.0'
108+
WASI_SDK_PATH: 'wasi-sdk-22.0'
109+
EM_VERSION: '3.1.52'
110+
EM_CACHE_FOLDER: 'emsdk-cache'
105111
steps:
106112
- name: Checkout Repository
107113
uses: actions/checkout@v4
@@ -115,6 +121,25 @@ jobs:
115121
python-version: ${{ matrix.python }}
116122
env:
117123
PYTHON_VERSION: ${{ matrix.python }} # Why do this?
124+
- uses: seanmiddleditch/gha-setup-ninja@v4
125+
- uses: mymindstorm/setup-emsdk@v14
126+
with:
127+
version: ${{ env.EM_VERSION }}
128+
actions-cache-folder: ${{ env.EM_CACHE_FOLDER }}
129+
- name: Install wasi-sdk (macOS or Linux)
130+
shell: bash
131+
if: ${{ !startsWith(matrix.os, 'windows') }}
132+
run: |
133+
wget -q https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/wasi-sdk-${WASI_VERSION_FULL}-${{ startsWith(matrix.os, 'macos') && 'macos' || 'linux' }}.tar.gz
134+
mkdir -p $WASI_SDK_PATH
135+
tar zxvf wasi-sdk-${WASI_VERSION_FULL}-${{ startsWith(matrix.os, 'macos') && 'macos' || 'linux' }}.tar.gz -C $WASI_SDK_PATH --strip 1
136+
- name: Install wasi-sdk (Windows)
137+
shell: pwsh
138+
if: ${{ startsWith(matrix.os, 'windows') }}
139+
run: |
140+
Start-BitsTransfer -Source https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${env:WASI_VERSION}/wasi-sdk-${env:WASI_VERSION_FULL}.m-mingw.tar.gz
141+
New-Item -ItemType Directory -Path ${env:WASI_SDK_PATH}
142+
tar -zxvf wasi-sdk-${env:WASI_VERSION_FULL}.m-mingw.tar.gz -C ${env:WASI_SDK_PATH} --strip 1
118143
- name: Install Dependencies
119144
run: |
120145
npm install
@@ -125,7 +150,7 @@ jobs:
125150
echo 'GYP_MSVS_VERSION=2015' >> $Env:GITHUB_ENV
126151
echo 'GYP_MSVS_OVERRIDE_PATH=C:\\Dummy' >> $Env:GITHUB_ENV
127152
- name: Run Python Tests
128-
run: python -m pytest
153+
run: python -m pytest --ignore=${{ env.EM_CACHE_FOLDER }}
129154
- name: Run Tests (macOS or Linux)
130155
if: "!startsWith(matrix.os, 'windows')"
131156
shell: bash
@@ -134,7 +159,7 @@ jobs:
134159
FULL_TEST: ${{ (matrix.node == '20.x' && matrix.python == '3.12') && '1' || '0' }}
135160
- name: Run Tests (Windows)
136161
if: startsWith(matrix.os, 'windows')
137-
shell: pwsh
138-
run: npm run test --python="${env:pythonLocation}\\python.exe"
162+
shell: bash # Building wasm on Windows requires using make generator, it only works in bash
163+
run: npm run test --python="${pythonLocation}\\python.exe"
139164
env:
140165
FULL_TEST: ${{ (matrix.node == '20.x' && matrix.python == '3.12') && '1' || '0' }}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,11 @@
3737
"node": "^16.14.0 || >=18.0.0"
3838
},
3939
"devDependencies": {
40+
"@emnapi/core": "^1.2.0",
41+
"@emnapi/runtime": "^1.2.0",
4042
"bindings": "^1.5.0",
4143
"cross-env": "^7.0.3",
44+
"emnapi": "^1.2.0",
4245
"mocha": "^10.2.0",
4346
"nan": "^2.14.2",
4447
"require-inject": "^1.4.4",

test/node_modules/hello_wasm/binding.gyp

Lines changed: 62 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/node_modules/hello_wasm/hello.c

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/node_modules/hello_wasm/hello.js

Lines changed: 50 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/node_modules/hello_wasm/package.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/test-wasm.js

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
'use strict'
2+
3+
const { describe, it } = require('mocha')
4+
const assert = require('assert')
5+
const path = require('path')
6+
const cp = require('child_process')
7+
const util = require('../lib/util')
8+
const { platformTimeout } = require('./common')
9+
10+
const wasmAddonPath = path.resolve(__dirname, 'node_modules', 'hello_wasm')
11+
const nodeGyp = path.resolve(__dirname, '..', 'bin', 'node-gyp.js')
12+
13+
const execFileSync = (...args) => cp.execFileSync(...args).toString().trim()
14+
15+
const execFile = async (cmd, env) => {
16+
const [err,, stderr] = await util.execFile(process.execPath, cmd, {
17+
env: {
18+
...process.env,
19+
NODE_GYP_NULL_LOGGER: undefined,
20+
...env
21+
},
22+
encoding: 'utf-8'
23+
})
24+
return [err, stderr.toString().trim().split(/\r?\n/)]
25+
}
26+
27+
function runWasm (hostProcess = process.execPath) {
28+
const testCode = "console.log(require('hello_wasm').hello())"
29+
return execFileSync(hostProcess, ['--experimental-wasi-unstable-preview1', '-e', testCode], { cwd: __dirname })
30+
}
31+
32+
function executable (name) {
33+
return name + (process.platform === 'win32' ? '.exe' : '')
34+
}
35+
36+
function getWasmEnv (target) {
37+
const env = {
38+
GYP_CROSSCOMPILE: '1',
39+
AR_host: 'ar',
40+
CC_host: 'clang',
41+
CXX_host: 'clang++'
42+
}
43+
if (target === 'emscripten') {
44+
env.AR_target = 'emar'
45+
env.CC_target = 'emcc'
46+
env.CXX_target = 'em++'
47+
} else if (target === 'wasi') {
48+
env.AR_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('ar'))
49+
env.CC_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang'))
50+
env.CXX_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang++'))
51+
} else if (target === 'wasm') {
52+
env.AR_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('ar'))
53+
env.CC_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang'))
54+
env.CXX_target = path.resolve(__dirname, '..', process.env.WASI_SDK_PATH, 'bin', executable('clang++'))
55+
env.CFLAGS = '--target=wasm32'
56+
}
57+
return env
58+
}
59+
60+
describe('wasm', function () {
61+
it('build simple node-api addon to wasm (wasm32-emscripten)', async function () {
62+
if (!process.env.EMSDK) {
63+
return this.skip('emsdk not found')
64+
}
65+
this.timeout(platformTimeout(1, { win32: 5 }))
66+
67+
const cmd = [
68+
nodeGyp,
69+
'rebuild',
70+
'-C', wasmAddonPath,
71+
'--loglevel=verbose',
72+
'--arch=wasm32',
73+
`--nodedir=${path.dirname(require.resolve('emnapi'))}`,
74+
'--', '-f', 'make'
75+
]
76+
const [err, logLines] = await execFile(cmd, getWasmEnv('emscripten'))
77+
const lastLine = logLines[logLines.length - 1]
78+
assert.strictEqual(err, null)
79+
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
80+
assert.strictEqual(runWasm(), 'world')
81+
})
82+
83+
it('build simple node-api addon to wasm (wasm32-wasip1)', async function () {
84+
if (!process.env.WASI_SDK_PATH) {
85+
return this.skip('wasi-sdk not found')
86+
}
87+
this.timeout(platformTimeout(1, { win32: 5 }))
88+
89+
const cmd = [
90+
nodeGyp,
91+
'rebuild',
92+
'-C', wasmAddonPath,
93+
'--loglevel=verbose',
94+
'--arch=wasm32',
95+
`--nodedir=${path.dirname(require.resolve('emnapi'))}`,
96+
'--', '-f', 'make'
97+
]
98+
const [err, logLines] = await execFile(cmd, getWasmEnv('wasi'))
99+
const lastLine = logLines[logLines.length - 1]
100+
assert.strictEqual(err, null)
101+
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
102+
assert.strictEqual(runWasm(), 'world')
103+
})
104+
105+
it('build simple node-api addon to wasm (wasm32-unknown-unknown)', async function () {
106+
if (!process.env.WASI_SDK_PATH) {
107+
return this.skip('wasi-sdk not found')
108+
}
109+
this.timeout(platformTimeout(1, { win32: 5 }))
110+
111+
const cmd = [
112+
nodeGyp,
113+
'rebuild',
114+
'-C', wasmAddonPath,
115+
'--loglevel=verbose',
116+
'--arch=wasm32',
117+
`--nodedir=${path.dirname(require.resolve('emnapi'))}`,
118+
'--', '-f', 'make'
119+
]
120+
const [err, logLines] = await execFile(cmd, getWasmEnv('wasm'))
121+
const lastLine = logLines[logLines.length - 1]
122+
assert.strictEqual(err, null)
123+
assert.strictEqual(lastLine, 'gyp info ok', 'should end in ok')
124+
assert.strictEqual(runWasm(), 'world')
125+
})
126+
})

0 commit comments

Comments
 (0)