@@ -23,10 +23,10 @@ import 'package:test_core/src/runner/plugin/environment.dart'; // ignore: implem
23
23
import 'package:test_core/src/runner/plugin/platform_helpers.dart' ; // ignore: implementation_imports
24
24
import 'package:test_core/src/runner/runner_suite.dart' ; // ignore: implementation_imports
25
25
import 'package:test_core/src/runner/suite.dart' ; // ignore: implementation_imports
26
+ import 'package:test_core/src/runner/wasm_compiler_pool.dart' ; // ignore: implementation_imports
26
27
import 'package:test_core/src/util/errors.dart' ; // ignore: implementation_imports
27
28
import 'package:test_core/src/util/io.dart' ; // ignore: implementation_imports
28
29
import 'package:test_core/src/util/package_config.dart' ; // ignore: implementation_imports
29
- import 'package:test_core/src/util/pair.dart' ; // ignore: implementation_imports
30
30
import 'package:test_core/src/util/stack_trace_mapper.dart' ; // ignore: implementation_imports
31
31
import 'package:yaml/yaml.dart' ;
32
32
@@ -40,7 +40,8 @@ class NodePlatform extends PlatformPlugin
40
40
final Configuration _config;
41
41
42
42
/// The [Dart2JsCompilerPool] managing active instances of `dart2js` .
43
- final _compilers = Dart2JsCompilerPool (['-Dnode=true' , '--server-mode' ]);
43
+ final _jsCompilers = Dart2JsCompilerPool (['-Dnode=true' , '--server-mode' ]);
44
+ final _wasmCompilers = WasmCompilerPool (['-Dnode=true' ]);
44
45
45
46
/// The temporary directory in which compiled JS is emitted.
46
47
final _compiledDir = createTempDir ();
@@ -75,15 +76,17 @@ class NodePlatform extends PlatformPlugin
75
76
@override
76
77
Future <RunnerSuite > load (String path, SuitePlatform platform,
77
78
SuiteConfiguration suiteConfig, Map <String , Object ?> message) async {
78
- if (platform.compiler != Compiler .dart2js) {
79
+ if (platform.compiler != Compiler .dart2js &&
80
+ platform.compiler != Compiler .dart2wasm) {
79
81
throw StateError (
80
82
'Unsupported compiler for the Node platform ${platform .compiler }.' );
81
83
}
82
- var pair = await _loadChannel (path, platform, suiteConfig);
84
+ var (channel, stackMapper) =
85
+ await _loadChannel (path, platform, suiteConfig);
83
86
var controller = deserializeSuite (path, platform, suiteConfig,
84
- const PluginEnvironment (), pair.first , message);
87
+ const PluginEnvironment (), channel , message);
85
88
86
- controller.channel ('test.node.mapper' ).sink.add (pair.last ? .serialize ());
89
+ controller.channel ('test.node.mapper' ).sink.add (stackMapper ? .serialize ());
87
90
88
91
return await controller.suite;
89
92
}
@@ -92,16 +95,13 @@ class NodePlatform extends PlatformPlugin
92
95
///
93
96
/// Returns that channel along with a [StackTraceMapper] representing the
94
97
/// source map for the compiled suite.
95
- Future <Pair <StreamChannel <Object ?>, StackTraceMapper ?>> _loadChannel (
96
- String path,
97
- SuitePlatform platform,
98
- SuiteConfiguration suiteConfig) async {
98
+ Future <(StreamChannel <Object ?>, StackTraceMapper ?)> _loadChannel (String path,
99
+ SuitePlatform platform, SuiteConfiguration suiteConfig) async {
99
100
final servers = await _loopback ();
100
101
101
102
try {
102
- var pair = await _spawnProcess (
103
- path, platform.runtime, suiteConfig, servers.first.port);
104
- var process = pair.first;
103
+ var (process, stackMapper) =
104
+ await _spawnProcess (path, platform, suiteConfig, servers.first.port);
105
105
106
106
// Forward Node's standard IO to the print handler so it's associated with
107
107
// the load test.
@@ -120,7 +120,7 @@ class NodePlatform extends PlatformPlugin
120
120
sink.close ();
121
121
}));
122
122
123
- return Pair (channel, pair.last );
123
+ return (channel, stackMapper );
124
124
} finally {
125
125
unawaited (Future .wait <void >(servers.map ((s) =>
126
126
s.close ().then <ServerSocket ?>((v) => v).onError ((_, __) => null ))));
@@ -131,23 +131,28 @@ class NodePlatform extends PlatformPlugin
131
131
///
132
132
/// Returns that channel along with a [StackTraceMapper] representing the
133
133
/// source map for the compiled suite.
134
- Future <Pair <Process , StackTraceMapper ?>> _spawnProcess (String path,
135
- Runtime runtime, SuiteConfiguration suiteConfig, int socketPort) async {
134
+ Future <(Process , StackTraceMapper ?)> _spawnProcess (
135
+ String path,
136
+ SuitePlatform platform,
137
+ SuiteConfiguration suiteConfig,
138
+ int socketPort) async {
136
139
if (_config.suiteDefaults.precompiledPath != null ) {
137
- return _spawnPrecompiledProcess (path, runtime, suiteConfig, socketPort ,
138
- _config.suiteDefaults.precompiledPath! );
140
+ return _spawnPrecompiledProcess (path, platform. runtime, suiteConfig,
141
+ socketPort, _config.suiteDefaults.precompiledPath! );
139
142
} else {
140
- return _spawnNormalProcess (path, runtime, suiteConfig, socketPort);
143
+ return switch (platform.compiler) {
144
+ Compiler .dart2js => _spawnNormalJsProcess (
145
+ path, platform.runtime, suiteConfig, socketPort),
146
+ Compiler .dart2wasm => _spawnNormalWasmProcess (
147
+ path, platform.runtime, suiteConfig, socketPort),
148
+ _ => throw StateError ('Unsupported compiler ${platform .compiler }' ),
149
+ };
141
150
}
142
151
}
143
152
144
- /// Compiles [testPath] with dart2js, adds the node preamble, and then spawns
145
- /// a Node.js process that loads that Dart test suite.
146
- Future <Pair <Process , StackTraceMapper ?>> _spawnNormalProcess (String testPath,
147
- Runtime runtime, SuiteConfiguration suiteConfig, int socketPort) async {
148
- var dir = Directory (_compiledDir).createTempSync ('test_' ).path;
149
- var jsPath = p.join (dir, '${p .basename (testPath )}.node_test.dart.js' );
150
- await _compilers.compile ('''
153
+ Future <String > _entrypointScriptForTest (
154
+ String testPath, SuiteConfiguration suiteConfig) async {
155
+ return '''
151
156
${suiteConfig .metadata .languageVersionComment ?? await rootPackageLanguageVersionComment }
152
157
import "package:test/src/bootstrap/node.dart";
153
158
@@ -156,7 +161,20 @@ class NodePlatform extends PlatformPlugin
156
161
void main() {
157
162
internalBootstrapNodeTest(() => test.main);
158
163
}
159
- ''' , jsPath, suiteConfig);
164
+ ''' ;
165
+ }
166
+
167
+ /// Compiles [testPath] with dart2js, adds the node preamble, and then spawns
168
+ /// a Node.js process that loads that Dart test suite.
169
+ Future <(Process , StackTraceMapper ?)> _spawnNormalJsProcess (String testPath,
170
+ Runtime runtime, SuiteConfiguration suiteConfig, int socketPort) async {
171
+ var dir = Directory (_compiledDir).createTempSync ('test_' ).path;
172
+ var jsPath = p.join (dir, '${p .basename (testPath )}.node_test.dart.js' );
173
+ await _jsCompilers.compile (
174
+ await _entrypointScriptForTest (testPath, suiteConfig),
175
+ jsPath,
176
+ suiteConfig,
177
+ );
160
178
161
179
// Add the Node.js preamble to ensure that the dart2js output is
162
180
// compatible. Use the minified version so the source map remains valid.
@@ -173,12 +191,63 @@ class NodePlatform extends PlatformPlugin
173
191
packageMap: (await currentPackageConfig).toPackageMap ());
174
192
}
175
193
176
- return Pair (await _startProcess (runtime, jsPath, socketPort), mapper);
194
+ return (await _startProcess (runtime, jsPath, socketPort), mapper);
195
+ }
196
+
197
+ /// Compiles [testPath] with dart2wasm, adds a JS entrypoint and then spawns
198
+ /// a Node.js process loading the compiled test suite.
199
+ Future <(Process , StackTraceMapper ?)> _spawnNormalWasmProcess (String testPath,
200
+ Runtime runtime, SuiteConfiguration suiteConfig, int socketPort) async {
201
+ var dir = Directory (_compiledDir).createTempSync ('test_' ).path;
202
+ // dart2wasm will emit a .wasm file and a .mjs file responsible for loading
203
+ // that file.
204
+ var wasmPath = p.join (dir, '${p .basename (testPath )}.node_test.dart.wasm' );
205
+ var loader = '${p .basename (testPath )}.node_test.dart.wasm.mjs' ;
206
+
207
+ // We need to create an additional entrypoint file loading the wasm module.
208
+ var jsPath = p.join (dir, '${p .basename (testPath )}.node_test.dart.js' );
209
+
210
+ await _wasmCompilers.compile (
211
+ await _entrypointScriptForTest (testPath, suiteConfig),
212
+ wasmPath,
213
+ suiteConfig,
214
+ );
215
+
216
+ await File (jsPath).writeAsString ('''
217
+ const { createReadStream } = require('fs');
218
+ const { once } = require('events');
219
+ const { PassThrough } = require('stream');
220
+
221
+ const main = async () => {
222
+ const { instantiate, invoke } = await import("./$loader ");
223
+
224
+ const wasmContents = createReadStream("$wasmPath .wasm");
225
+ const stream = new PassThrough();
226
+ wasmContents.pipe(stream);
227
+
228
+ await once(wasmContents, 'open');
229
+ const response = new Response(
230
+ stream,
231
+ {
232
+ headers: {
233
+ "Content-Type": "application/wasm"
234
+ }
235
+ }
236
+ );
237
+ const instancePromise = WebAssembly.compileStreaming(response);
238
+ const module = await instantiate(instancePromise, {});
239
+ invoke(module);
240
+ };
241
+
242
+ main();
243
+ ''' );
244
+
245
+ return (await _startProcess (runtime, jsPath, socketPort), null );
177
246
}
178
247
179
248
/// Spawns a Node.js process that loads the Dart test suite at [testPath]
180
249
/// under [precompiledPath] .
181
- Future <Pair < Process , StackTraceMapper ?> > _spawnPrecompiledProcess (
250
+ Future <( Process , StackTraceMapper ?) > _spawnPrecompiledProcess (
182
251
String testPath,
183
252
Runtime runtime,
184
253
SuiteConfiguration suiteConfig,
@@ -195,7 +264,7 @@ class NodePlatform extends PlatformPlugin
195
264
.toPackageMap ());
196
265
}
197
266
198
- return Pair (await _startProcess (runtime, jsPath, socketPort), mapper);
267
+ return (await _startProcess (runtime, jsPath, socketPort), mapper);
199
268
}
200
269
201
270
/// Starts the Node.js process for [runtime] with [jsPath] .
@@ -224,7 +293,8 @@ class NodePlatform extends PlatformPlugin
224
293
225
294
@override
226
295
Future <void > close () => _closeMemo.runOnce (() async {
227
- await _compilers.close ();
296
+ await _jsCompilers.close ();
297
+ await _wasmCompilers.close ();
228
298
await Directory (_compiledDir).deleteWithRetry ();
229
299
});
230
300
final _closeMemo = AsyncMemoizer <void >();
0 commit comments