mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
Imports the tests that Webpack uses for CJS tree-shaking. One test suite
is skipped `deep-reexports`, that's because we don't support that deep
of analysis at the moment and we just bail. WIP because after landing
this stack I will work on improving this.
I did have to make some edits to the tests, a summary is below (courtesy
of Claude):
```
1. Stripped ?query request suffixes (all cases).
Webpack uses require("./x?1") / ?2 to force distinct module instances. Turbopack shares one instance across require sites and aggregates usage, so the queries were removed (require("./x")). The behavioral assertions hold on a shared instance.
2. Distinct copies where per-instance semantics are genuinely required.
A few cases actually depend on separate instances, so we replaced the query with real duplicate files:
- mutate → module-1.js / module-2.js (so mutating one import doesn't leak into the other).
- reexports → add-to-counter-1/2/3.js (the counter must increment 3×).
- reexports-define-property → add-to-counter-1/2.js.
3. Removed __resourceQuery (webpack module-query magic — undefined in turbopack).
In reexports and reexports-define-property: require("./m" + __resourceQuery) → require("./m"), and the dynamic dispatch module reexport.js (require("./" + __resourceQuery.slice(1))) was split into static reexport-direct.js / reexport-indirect.js.
4. Commented out __webpack_exports_info__ / usedExports assertions.
Webpack exposes per-export usage introspection (x.usedExports, __webpack_exports_info__.x.used) that turbopack doesn't populate for CJS. Those specific assertions were commented (the real behavioral checks kept) in: require-member-access, require-member-access-deferred, require-destructuring, this-in-exported-function(-modern), reexport-require-binding, mutate, cjs-to-esm.
5. Case-specific rewrites.
- cjs-to-esm — dropped the require.cache[require.resolve(...)].exports comparison (webpack runtime introspection).
- namespace — changed expect(await import(x)).toBe(require(x)) (object identity) to assert the observable exports (ns.abc, ns.default); turbopack's import() yields an exotic Module namespace, never the same/deep-equal object as require().
6. mjs removed entirely — built on __resourceQuery + per-query instances + .js/.mjs interop divergence; can't even evaluate in turbopack and tests behavior turbopack doesn't share.
```
All tests should be passing.
653 lines
21 KiB
Rust
653 lines
21 KiB
Rust
#![cfg(test)]
|
|
#![feature(arbitrary_self_types)]
|
|
#![feature(arbitrary_self_types_pointers)]
|
|
#![allow(clippy::needless_return)] // tokio macro-generated code doesn't respect this
|
|
|
|
mod util;
|
|
|
|
use std::{env, fs::canonicalize, path::PathBuf};
|
|
|
|
use anyhow::{Context, Result};
|
|
use bincode::{Decode, Encode};
|
|
use serde::Deserialize;
|
|
use tracing_subscriber::{Registry, layer::SubscriberExt, util::SubscriberInitExt};
|
|
use turbo_rcstr::{RcStr, rcstr};
|
|
use turbo_tasks::{
|
|
Completion, Effects, NonLocalValue, OperationVc, ReadRef, ResolvedVc, TurboTasks, Vc,
|
|
debug::ValueDebugFormat, fxindexmap, read_strongly_consistent_and_apply_effects, take_effects,
|
|
trace::TraceRawVcs,
|
|
};
|
|
use turbo_tasks_backend::{BackendOptions, TurboTasksBackend, noop_backing_storage};
|
|
use turbo_tasks_env::CommandLineProcessEnv;
|
|
use turbo_tasks_fs::{
|
|
DiskFileSystem, FileContent, FileSystem, FileSystemEntryType, FileSystemPath,
|
|
json::parse_json_with_source_context,
|
|
};
|
|
use turbo_unix_path::sys_to_unix;
|
|
use turbopack::{
|
|
ModuleAssetContext,
|
|
module_options::{EcmascriptOptionsContext, ModuleOptionsContext, TypescriptTransformOptions},
|
|
};
|
|
use turbopack_core::{
|
|
chunk::{ChunkingConfig, MangleType, MinifyType},
|
|
compile_time_defines,
|
|
compile_time_info::CompileTimeInfo,
|
|
condition::ContextCondition,
|
|
context::AssetContext,
|
|
environment::{Environment, ExecutionEnvironment, NodeJsEnvironment},
|
|
file_source::FileSource,
|
|
ident::Layer,
|
|
issue::{CollectibleIssuesExt, IssueFilter},
|
|
module_graph::{
|
|
ModuleGraph, SingleModuleGraph, binding_usage_info::compute_binding_usage_info,
|
|
},
|
|
reference_type::{InnerAssets, ReferenceType},
|
|
resolve::{
|
|
ExternalTraced, ExternalType,
|
|
options::{ImportMap, ImportMapping},
|
|
},
|
|
};
|
|
use turbopack_css::chunk::CssChunkType;
|
|
use turbopack_ecmascript::chunk::EcmascriptChunkType;
|
|
use turbopack_ecmascript_runtime::RuntimeType;
|
|
use turbopack_node::{
|
|
child_process_backend,
|
|
debug::should_debug,
|
|
evaluate::{evaluate, get_evaluate_entries},
|
|
};
|
|
use turbopack_nodejs::NodeJsChunkingContext;
|
|
use turbopack_resolve::resolve_options_context::ResolveOptionsContext;
|
|
use turbopack_test_utils::{jest::JestRunResult, snapshot::UPDATE};
|
|
use turbopack_trace_utils::{
|
|
filter_layer::FilterLayer, raw_trace::RawTraceLayer, trace_writer::TraceWriter,
|
|
tracing_presets::TRACING_TURBO_TASKS_TARGETS,
|
|
};
|
|
|
|
use crate::util::REPO_ROOT;
|
|
|
|
#[turbo_tasks::value]
|
|
struct RunTestResult {
|
|
js_result: ResolvedVc<JsResult>,
|
|
path: FileSystemPath,
|
|
}
|
|
|
|
#[turbo_tasks::value]
|
|
#[derive(Clone, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
struct JsResult {
|
|
uncaught_exceptions: Vec<String>,
|
|
unhandled_rejections: Vec<String>,
|
|
#[turbo_tasks(trace_ignore)]
|
|
jest_result: JestRunResult,
|
|
}
|
|
|
|
#[turbo_tasks::value(task_input)]
|
|
#[derive(Copy, Clone, Debug, Hash)]
|
|
enum IssueSnapshotMode {
|
|
Snapshots,
|
|
NoSnapshots,
|
|
}
|
|
|
|
// To minimize test path length and consistency with snapshot tests,
|
|
// node_modules is stored as a sibling of the test fixtures. Don't run
|
|
// it as a test.
|
|
//
|
|
// "Skip" directories named `__skipped__`, which include test directories to
|
|
// skip.
|
|
#[testing::fixture(
|
|
"tests/execution/*/*/*/input/index.js",
|
|
exclude("node_modules|__skipped__")
|
|
)]
|
|
fn test(resource: PathBuf) {
|
|
let resource = resource.parent().unwrap().parent().unwrap().to_path_buf();
|
|
let messages = get_messages(run(resource, IssueSnapshotMode::Snapshots).unwrap());
|
|
if !messages.is_empty() {
|
|
panic!(
|
|
"Failed with error(s) in the following test(s):\n\n{}",
|
|
messages.join("\n\n--\n")
|
|
)
|
|
}
|
|
}
|
|
|
|
#[testing::fixture("tests/execution/*/*/__skipped__/*/input/index.js")]
|
|
#[should_panic]
|
|
fn test_skipped_fails(resource: PathBuf) {
|
|
let resource = resource.parent().unwrap().parent().unwrap().to_path_buf();
|
|
|
|
let JsResult {
|
|
// Ignore uncaught exceptions for skipped tests.
|
|
uncaught_exceptions: _,
|
|
unhandled_rejections: _,
|
|
jest_result,
|
|
} = run(resource, IssueSnapshotMode::NoSnapshots).unwrap();
|
|
|
|
// Assert that this skipped test itself has at least one browser test which
|
|
// fails.
|
|
assert!(
|
|
// Skipped tests sometimes have errors (e.g. unsupported syntax) that prevent tests from
|
|
// running at all. Allow them to have empty results.
|
|
jest_result.test_results.is_empty()
|
|
|| jest_result
|
|
.test_results
|
|
.into_iter()
|
|
.any(|r| !r.errors.is_empty()),
|
|
"Expected an error, but the test passed?"
|
|
);
|
|
}
|
|
|
|
fn get_messages(js_results: JsResult) -> Vec<String> {
|
|
let mut messages = vec![];
|
|
|
|
if js_results.jest_result.test_results.is_empty() {
|
|
messages.push("No tests were run.".to_string());
|
|
}
|
|
|
|
for test_result in js_results.jest_result.test_results {
|
|
// It's possible to fail multiple tests across these tests,
|
|
// so collect them and fail the respective test in Rust with
|
|
// an aggregate message.
|
|
if !test_result.errors.is_empty() {
|
|
messages.push(format!(
|
|
"\"{}\":\n{}",
|
|
test_result.test_path[1..].join(" > "),
|
|
test_result.errors.join("\n")
|
|
));
|
|
}
|
|
}
|
|
|
|
for uncaught_exception in js_results.uncaught_exceptions {
|
|
messages.push(format!("Uncaught exception: {uncaught_exception}"));
|
|
}
|
|
|
|
for unhandled_rejection in js_results.unhandled_rejections {
|
|
messages.push(format!("Unhandled rejection: {unhandled_rejection}"));
|
|
}
|
|
|
|
messages
|
|
}
|
|
|
|
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
|
|
async fn run(resource: PathBuf, snapshot_mode: IssueSnapshotMode) -> Result<JsResult> {
|
|
// Clean up old output files.
|
|
let output_path = resource.join("output");
|
|
if output_path.exists() {
|
|
std::fs::remove_dir_all(&output_path)?;
|
|
}
|
|
|
|
let subscriber = Registry::default();
|
|
|
|
let trace = TRACING_TURBO_TASKS_TARGETS.join(",");
|
|
let subscriber = subscriber.with(FilterLayer::try_new(&trace).unwrap());
|
|
|
|
std::fs::create_dir_all(&output_path)
|
|
.context("Unable to create output directory")
|
|
.unwrap();
|
|
|
|
// Set up a `tracing_subscriber` for debugging -- We can only do this when using nextest, as
|
|
// `cargo test` runs all execution test cases in the same process.
|
|
//
|
|
// Configuring `tracing_subscriber` requires process-global side-effects. We can't use a
|
|
// thread-local subscriber because we're not fully single-threaded, even with the
|
|
// `current_thread` tokio executor.
|
|
//
|
|
// https://nexte.st/docs/configuration/env-vars/#environment-variables-nextest-sets
|
|
let _trace_writer_guard = if env::var_os("NEXTEST").is_some() {
|
|
let trace_file = output_path.join("trace-turbopack");
|
|
let trace_writer = std::fs::File::create(trace_file.clone()).unwrap();
|
|
let (trace_writer, trace_writer_guard) = TraceWriter::new(trace_writer);
|
|
let subscriber = subscriber.with(RawTraceLayer::new(trace_writer));
|
|
|
|
subscriber.init();
|
|
|
|
Some(trace_writer_guard)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let tt = TurboTasks::new(TurboTasksBackend::new(
|
|
BackendOptions {
|
|
storage_mode: None,
|
|
dependency_tracking: *UPDATE,
|
|
..Default::default()
|
|
},
|
|
noop_backing_storage(),
|
|
));
|
|
|
|
#[turbo_tasks::value(serialization = "skip", evict = "never")]
|
|
struct JsResultWithEffects {
|
|
result: ReadRef<JsResult>,
|
|
effects: Effects,
|
|
}
|
|
|
|
#[turbo_tasks::function(operation, root)]
|
|
async fn run_inner_operation(
|
|
resource: RcStr,
|
|
snapshot_mode: IssueSnapshotMode,
|
|
) -> Result<Vc<JsResult>> {
|
|
let prepared_test = prepare_test(resource).to_resolved().await?;
|
|
let run_result_op = run_test_operation(prepared_test);
|
|
if snapshot_mode == IssueSnapshotMode::Snapshots {
|
|
snapshot_issues(*prepared_test, run_result_op).await?;
|
|
}
|
|
|
|
let result = (*run_result_op.connect().await?.js_result.await?).clone();
|
|
|
|
Ok(result.cell())
|
|
}
|
|
|
|
/// Wrapper operation that collects all effects (including snapshot issue file writes) from
|
|
/// [`run_inner_operation`].
|
|
#[turbo_tasks::function(operation, root)]
|
|
async fn run_inner_operation_with_effects(
|
|
resource: RcStr,
|
|
snapshot_mode: IssueSnapshotMode,
|
|
) -> Result<Vc<JsResultWithEffects>> {
|
|
let op = run_inner_operation(resource, snapshot_mode);
|
|
let result = op.connect().await?.clone();
|
|
let effects = take_effects(op).await?;
|
|
Ok(JsResultWithEffects { result, effects }.cell())
|
|
}
|
|
|
|
tt.run_once(async move {
|
|
let op = run_inner_operation_with_effects(resource.to_str().unwrap().into(), snapshot_mode);
|
|
let result_with_effects =
|
|
read_strongly_consistent_and_apply_effects(op, |v| &v.effects).await?;
|
|
|
|
Ok((*result_with_effects.result).clone())
|
|
})
|
|
.await
|
|
}
|
|
|
|
#[derive(
|
|
PartialEq, Eq, Debug, Deserialize, TraceRawVcs, ValueDebugFormat, NonLocalValue, Encode, Decode,
|
|
)]
|
|
#[serde(rename_all = "camelCase", deny_unknown_fields)]
|
|
struct TestOptions {
|
|
#[serde(default = "default_true")]
|
|
follow_reexports: bool,
|
|
#[serde(default)]
|
|
module_fragments_enabled: bool,
|
|
#[serde(default = "default_true")]
|
|
remove_unused_imports: bool,
|
|
#[serde(default = "default_true")]
|
|
remove_unused_exports: bool,
|
|
#[serde(default = "default_true")]
|
|
scope_hoisting: bool,
|
|
#[serde(default)]
|
|
cjs_tree_shaking: bool,
|
|
#[serde(default)]
|
|
minify: bool,
|
|
#[serde(default)]
|
|
production_chunking: bool,
|
|
}
|
|
|
|
fn default_true() -> bool {
|
|
true
|
|
}
|
|
|
|
impl Default for TestOptions {
|
|
fn default() -> Self {
|
|
Self {
|
|
follow_reexports: default_true(),
|
|
module_fragments_enabled: false,
|
|
remove_unused_exports: default_true(),
|
|
remove_unused_imports: default_true(),
|
|
scope_hoisting: default_true(),
|
|
cjs_tree_shaking: false,
|
|
minify: false,
|
|
production_chunking: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[turbo_tasks::value]
|
|
struct PreparedTest {
|
|
path: FileSystemPath,
|
|
project_path: FileSystemPath,
|
|
tests_path: FileSystemPath,
|
|
project_root: FileSystemPath,
|
|
options: TestOptions,
|
|
}
|
|
|
|
#[turbo_tasks::function]
|
|
async fn prepare_test(resource: RcStr) -> Result<Vc<PreparedTest>> {
|
|
let resource_path = canonicalize(&resource)?;
|
|
assert!(resource_path.exists(), "{resource} does not exist");
|
|
assert!(
|
|
resource_path.is_dir(),
|
|
"{} is not a directory. Execution tests must be directories.",
|
|
resource_path.to_str().unwrap()
|
|
);
|
|
|
|
let root_fs = DiskFileSystem::new(rcstr!("workspace"), Vc::cell(REPO_ROOT.clone()));
|
|
let project_fs = DiskFileSystem::new(rcstr!("project"), Vc::cell(REPO_ROOT.clone()));
|
|
let project_root = project_fs.root().owned().await?;
|
|
|
|
let relative_path = resource_path.strip_prefix(&*REPO_ROOT).with_context(|| {
|
|
format!(
|
|
"stripping repo root {:?} from resource path {:?}",
|
|
REPO_ROOT,
|
|
resource_path.display()
|
|
)
|
|
})?;
|
|
let relative_path = RcStr::from(sys_to_unix(relative_path.to_str().unwrap()));
|
|
let path = root_fs.root().await?.join(&relative_path)?;
|
|
let project_path = project_root.join(&relative_path)?;
|
|
let tests_path = project_fs
|
|
.root()
|
|
.await?
|
|
.join("turbopack/crates/turbopack-tests")?;
|
|
|
|
let options_file = path.join("options.json")?;
|
|
|
|
let mut options = TestOptions::default();
|
|
if matches!(*options_file.get_type().await?, FileSystemEntryType::File)
|
|
&& let FileContent::Content(content) = &*options_file.read().await?
|
|
{
|
|
options =
|
|
serde_json::from_reader(content.read()).context("Unable to parse options.json")?;
|
|
}
|
|
|
|
Ok(PreparedTest {
|
|
path: path.clone(),
|
|
project_path: project_path.clone(),
|
|
tests_path: tests_path.clone(),
|
|
project_root,
|
|
options,
|
|
}
|
|
.cell())
|
|
}
|
|
|
|
#[turbo_tasks::function(operation, root)]
|
|
async fn run_test_operation(prepared_test: ResolvedVc<PreparedTest>) -> Result<Vc<RunTestResult>> {
|
|
let PreparedTest {
|
|
path,
|
|
project_path,
|
|
tests_path,
|
|
project_root,
|
|
options,
|
|
} = &*prepared_test.await?;
|
|
|
|
let jest_entry_path = tests_path.join("js/jest-entry.ts")?;
|
|
let test_path = project_path.join("input/index.js")?;
|
|
|
|
let chunk_root_path = path.join("output")?;
|
|
let static_root_path = path.join("static")?;
|
|
|
|
let chunk_root_path_in_root_path_offset = project_path
|
|
.join("output")?
|
|
.get_relative_path_to(project_root)
|
|
.context("Project path is in root path")?;
|
|
|
|
let env = Environment::new(ExecutionEnvironment::NodeJsBuildTime(
|
|
NodeJsEnvironment::default().resolved_cell(),
|
|
))
|
|
.to_resolved()
|
|
.await?;
|
|
|
|
let compile_time_info = CompileTimeInfo::builder(env)
|
|
.defines(
|
|
compile_time_defines!(
|
|
process.turbopack = true,
|
|
process.env.TURBOPACK = "1",
|
|
process.env.NODE_ENV = "production",
|
|
)
|
|
.resolved_cell(),
|
|
)
|
|
.cell()
|
|
.await?;
|
|
|
|
let mut import_map = ImportMap::empty();
|
|
import_map.insert_wildcard_alias(
|
|
rcstr!("esm-external/"),
|
|
ImportMapping::External(
|
|
Some(rcstr!("*")),
|
|
ExternalType::EcmaScriptModule,
|
|
ExternalTraced::Untraced,
|
|
)
|
|
.resolved_cell(),
|
|
);
|
|
import_map.insert_exact_alias(
|
|
rcstr!("jest-circus"),
|
|
ImportMapping::External(None, ExternalType::CommonJs, ExternalTraced::Untraced)
|
|
.resolved_cell(),
|
|
);
|
|
import_map.insert_exact_alias(
|
|
"expect",
|
|
ImportMapping::External(None, ExternalType::CommonJs, ExternalTraced::Untraced)
|
|
.resolved_cell(),
|
|
);
|
|
import_map.insert_exact_alias(
|
|
rcstr!("testGlobalExternalValue"),
|
|
ImportMapping::External(None, ExternalType::Global, ExternalTraced::Untraced)
|
|
.resolved_cell(),
|
|
);
|
|
|
|
let mut fallback_import_map = ImportMap::empty();
|
|
fallback_import_map.insert_exact_alias(
|
|
rcstr!("fallback"),
|
|
ImportMapping::External(
|
|
None,
|
|
ExternalType::EcmaScriptModule,
|
|
ExternalTraced::Untraced,
|
|
)
|
|
.resolved_cell(),
|
|
);
|
|
|
|
let asset_context: Vc<Box<dyn AssetContext>> = Vc::upcast(ModuleAssetContext::new(
|
|
Default::default(),
|
|
compile_time_info,
|
|
ModuleOptionsContext {
|
|
ecmascript: EcmascriptOptionsContext {
|
|
enable_typescript_transform: Some(
|
|
TypescriptTransformOptions::default().resolved_cell(),
|
|
),
|
|
enable_import_as_bytes: true,
|
|
import_externals: true,
|
|
enable_exports_info_inlining: true,
|
|
infer_module_side_effects: true,
|
|
cjs_tree_shaking: options.cjs_tree_shaking,
|
|
..Default::default()
|
|
},
|
|
environment: Some(env),
|
|
follow_reexports: options.follow_reexports,
|
|
module_fragments_enabled: options.module_fragments_enabled,
|
|
rules: vec![(
|
|
ContextCondition::InNodeModules,
|
|
ModuleOptionsContext {
|
|
follow_reexports: options.follow_reexports,
|
|
module_fragments_enabled: options.module_fragments_enabled,
|
|
..Default::default()
|
|
}
|
|
.resolved_cell(),
|
|
)],
|
|
..Default::default()
|
|
}
|
|
.cell(),
|
|
ResolveOptionsContext {
|
|
enable_typescript: true,
|
|
enable_node_modules: Some(project_root.clone()),
|
|
enable_node_native_modules: true,
|
|
enable_node_externals: true,
|
|
custom_conditions: vec![rcstr!("development")],
|
|
rules: vec![(
|
|
ContextCondition::InNodeModules,
|
|
ResolveOptionsContext {
|
|
enable_node_modules: Some(project_root.clone()),
|
|
custom_conditions: vec![rcstr!("development")],
|
|
browser: true,
|
|
..Default::default()
|
|
}
|
|
.resolved_cell(),
|
|
)],
|
|
browser: true,
|
|
module: true,
|
|
import_map: Some(import_map.resolved_cell()),
|
|
fallback_import_map: Some(fallback_import_map.resolved_cell()),
|
|
..Default::default()
|
|
}
|
|
.cell(),
|
|
Layer::new(rcstr!("test")),
|
|
));
|
|
|
|
let jest_entry_source = FileSource::new(jest_entry_path);
|
|
let test_source = FileSource::new(test_path);
|
|
|
|
let test_asset = asset_context
|
|
.process(
|
|
Vc::upcast(test_source),
|
|
ReferenceType::Internal(InnerAssets::empty().to_resolved().await?),
|
|
)
|
|
.module()
|
|
.to_resolved()
|
|
.await?;
|
|
|
|
let jest_entry_asset = asset_context
|
|
.process(
|
|
Vc::upcast(jest_entry_source),
|
|
ReferenceType::Internal(ResolvedVc::cell(fxindexmap! {
|
|
rcstr!("TESTS") => test_asset,
|
|
})),
|
|
)
|
|
.module();
|
|
|
|
let node_backend = child_process_backend();
|
|
|
|
let entries = get_evaluate_entries(jest_entry_asset, asset_context, node_backend, None);
|
|
|
|
let single_graph = SingleModuleGraph::new_with_entries(
|
|
entries.graph_entries().to_resolved().await?,
|
|
false,
|
|
true,
|
|
);
|
|
let mut module_graph = ModuleGraph::from_graphs(vec![single_graph], None);
|
|
|
|
let binding_usage = if options.remove_unused_imports || options.remove_unused_exports {
|
|
Some(compute_binding_usage_info(
|
|
module_graph,
|
|
options.remove_unused_imports,
|
|
))
|
|
} else {
|
|
None
|
|
};
|
|
if options.remove_unused_imports
|
|
&& let Some(binding_usage) = binding_usage
|
|
{
|
|
module_graph = ModuleGraph::from_graphs(vec![single_graph], Some(binding_usage));
|
|
}
|
|
let module_graph = module_graph.connect();
|
|
|
|
let mut builder = NodeJsChunkingContext::builder(
|
|
project_root.clone(),
|
|
chunk_root_path.clone(),
|
|
chunk_root_path_in_root_path_offset,
|
|
static_root_path.clone(),
|
|
chunk_root_path,
|
|
static_root_path,
|
|
env,
|
|
RuntimeType::Development,
|
|
)
|
|
.source_map_source_type(turbopack_core::chunk::SourceMapSourceType::RelativeUri)
|
|
.module_merging(options.scope_hoisting)
|
|
.minify_type(if options.minify {
|
|
MinifyType::Minify {
|
|
mangle: Some(MangleType::OptimalSize),
|
|
}
|
|
} else {
|
|
MinifyType::NoMinify
|
|
})
|
|
.export_usage(if options.remove_unused_exports {
|
|
Some(binding_usage.unwrap().connect().to_resolved().await?)
|
|
} else {
|
|
None
|
|
});
|
|
|
|
if options.remove_unused_imports {
|
|
builder = builder.unused_references(
|
|
binding_usage
|
|
.unwrap()
|
|
.connect()
|
|
.unused_references()
|
|
.to_resolved()
|
|
.await?,
|
|
);
|
|
}
|
|
|
|
if options.production_chunking {
|
|
builder = builder
|
|
.chunking_config(
|
|
Vc::<EcmascriptChunkType>::default().to_resolved().await?,
|
|
ChunkingConfig {
|
|
min_chunk_size: 2_000,
|
|
max_chunk_count_per_group: 40,
|
|
max_merge_chunk_size: 200_000,
|
|
..Default::default()
|
|
},
|
|
)
|
|
.chunking_config(
|
|
Vc::<CssChunkType>::default().to_resolved().await?,
|
|
ChunkingConfig {
|
|
max_merge_chunk_size: 100_000,
|
|
..Default::default()
|
|
},
|
|
)
|
|
.nested_async_availability(true);
|
|
}
|
|
let chunking_context = builder.build();
|
|
|
|
let res = evaluate(
|
|
entries,
|
|
path.clone(),
|
|
Vc::upcast(CommandLineProcessEnv::new()),
|
|
node_backend,
|
|
Vc::upcast(test_source),
|
|
Vc::upcast(chunking_context),
|
|
module_graph,
|
|
vec![],
|
|
Completion::immutable(),
|
|
should_debug("execution_test"),
|
|
)
|
|
.await?;
|
|
|
|
let Some(str) = &*res else {
|
|
return Ok(RunTestResult {
|
|
js_result: JsResult {
|
|
uncaught_exceptions: vec![],
|
|
unhandled_rejections: vec![],
|
|
jest_result: JestRunResult {
|
|
test_results: vec![],
|
|
},
|
|
}
|
|
.resolved_cell(),
|
|
path: path.clone(),
|
|
}
|
|
.cell());
|
|
};
|
|
|
|
Ok(RunTestResult {
|
|
js_result: JsResult::resolved_cell(parse_json_with_source_context(str)?),
|
|
path: path.clone(),
|
|
}
|
|
.cell())
|
|
}
|
|
|
|
#[turbo_tasks::function]
|
|
async fn snapshot_issues(
|
|
prepared_test: Vc<PreparedTest>,
|
|
run_result_op: OperationVc<RunTestResult>,
|
|
) -> Result<()> {
|
|
let PreparedTest { path, .. } = &*prepared_test.await?;
|
|
let _ = run_result_op.resolve().strongly_consistent().await;
|
|
|
|
let plain_issues = run_result_op
|
|
.peek_issues()
|
|
.get_plain_issues(&IssueFilter::everything())
|
|
.await?;
|
|
|
|
turbopack_test_utils::snapshot::snapshot_issues(plain_issues, path.join("issues")?, &REPO_ROOT)
|
|
.await
|
|
.context("Unable to handle issues")?;
|
|
|
|
Ok(())
|
|
}
|