use super::*;
#[test]
fn test_setup_ts_no_duplicate_imports() {
let setup = render_setup(
"fixtures",
true,
"@sample_core/wasm",
&std::collections::BTreeMap::new(),
);
let create_require_count = setup.matches("import { createRequire }").count();
let file_url_to_path_count = setup.matches("import { fileURLToPath }").count();
let read_file_sync_count = setup.matches("readFileSync").count();
let path_imports_count = setup.matches("import { dirname, join }").count();
assert_eq!(create_require_count, 1, "createRequire should be imported exactly once");
assert_eq!(
file_url_to_path_count, 1,
"fileURLToPath should be imported exactly once"
);
assert!(read_file_sync_count >= 2, "readFileSync should be imported and used"); assert_eq!(path_imports_count, 1, "dirname, join should be imported exactly once");
let first_import = setup.find("import {").expect("should have imports");
let first_patch_comment = setup.find("// Patch CommonJS").expect("should have patch comment");
assert!(
first_import < first_patch_comment,
"all imports should come before the patch comment"
);
}
#[test]
fn test_package_json_includes_node_options_memory_cap() {
let pkg_json = render_package_json(
"@test/wasm",
"pkg",
"0.1.0",
crate::e2e::config::DependencyMode::Local,
None,
);
assert!(
pkg_json.contains("NODE_OPTIONS=--max-old-space-size=4096"),
"package.json test script must include NODE_OPTIONS memory cap; got:\n{pkg_json}"
);
assert!(
pkg_json.contains("\"test\": \"NODE_OPTIONS=--max-old-space-size=4096 vitest run\""),
"NODE_OPTIONS must be part of the test script; got:\n{pkg_json}"
);
assert!(
pkg_json.contains("\"node\": \">= 22\""),
"package.json must require Node 22 or newer; got:\n{pkg_json}"
);
}
#[test]
fn test_package_json_registry_release_uses_exact_pin() {
let pkg_json = render_package_json(
"@test/wasm",
"pkg",
"1.2.3",
crate::e2e::config::DependencyMode::Registry,
None,
);
assert!(
pkg_json.contains("\"1.2.3\""),
"registry release pin must be exact (no range operator); got:\n{pkg_json}"
);
assert!(
!pkg_json.contains("\"^1.2.3\""),
"must not add a caret range; got:\n{pkg_json}"
);
}
#[test]
fn test_package_json_local_uses_wasm_pack_nodejs_output() {
let rendered = render_package_json(
"@example/sample-wasm",
"crates/sample-wasm/pkg/nodejs",
"1.2.3",
crate::e2e::config::DependencyMode::Local,
None,
);
assert!(
rendered.contains("\"@example/sample-wasm\": \"file:crates/sample-wasm/pkg/nodejs\""),
"local dependency must point at wasm-pack's nodejs target output: {rendered}"
);
}
#[test]
fn test_package_json_registry_prerelease_uses_exact_pin() {
let pkg_json = render_package_json(
"@test/wasm",
"pkg",
"3.6.0-rc.1",
crate::e2e::config::DependencyMode::Registry,
None,
);
assert!(
pkg_json.contains("\"3.6.0-rc.1\""),
"registry pre-release pin must be exact (no range operator); got:\n{pkg_json}"
);
assert!(
!pkg_json.contains("\"^3.6.0-rc.1\""),
"must not add a caret range; got:\n{pkg_json}"
);
}
#[test]
fn test_package_json_registry_already_prefixed_passes_through() {
let pkg_json = render_package_json(
"@test/wasm",
"pkg",
"^3.6.0-rc.1",
crate::e2e::config::DependencyMode::Registry,
None,
);
assert!(
pkg_json.contains("\"^3.6.0-rc.1\""),
"already-prefixed input must pass through verbatim; got:\n{pkg_json}"
);
assert!(
!pkg_json.contains("^^"),
"must not double the `^` prefix; got:\n{pkg_json}"
);
}
#[test]
fn render_setup_emits_e2e_env_assignments_alphabetically() {
let mut env = std::collections::BTreeMap::new();
env.insert("ZEBRA".to_string(), "last_alphabetically".to_string());
env.insert("APPLE".to_string(), "first_alphabetically".to_string());
env.insert("SAMPLE_ALLOW_PRIVATE_NETWORK".to_string(), "true".to_string());
let setup = render_setup("fixtures", true, "@sample_core/wasm", &env);
assert!(
setup.contains("process.env.APPLE ??= \"first_alphabetically\";"),
"APPLE env var should be emitted, got:\n{setup}"
);
assert!(
setup.contains("process.env.SAMPLE_ALLOW_PRIVATE_NETWORK ??= \"true\";"),
"SAMPLE_ALLOW_PRIVATE_NETWORK env var should be emitted, got:\n{setup}"
);
assert!(
setup.contains("process.env.ZEBRA ??= \"last_alphabetically\";"),
"ZEBRA env var should be emitted, got:\n{setup}"
);
let apple_idx = setup.find("APPLE").expect("APPLE should be present");
let sample_idx = setup.find("SAMPLE").expect("SAMPLE should be present");
let zebra_idx = setup.find("ZEBRA").expect("ZEBRA should be present");
assert!(
apple_idx < sample_idx && sample_idx < zebra_idx,
"env vars must be sorted alphabetically; got positions: APPLE={}, SAMPLE={}, ZEBRA={}",
apple_idx,
sample_idx,
zebra_idx
);
let imports_end = setup
.find("import { dirname, join }")
.expect("imports should be present");
let env_block = setup.find("process.env.APPLE").expect("env block should be present");
let wasm_init = setup
.find("// Pre-initialize the wasm")
.expect("wasm init should be present");
assert!(
imports_end < env_block && env_block < wasm_init,
"env block must come after imports and before wasm init"
);
let empty_setup = render_setup(
"fixtures",
true,
"@sample_core/wasm",
&std::collections::BTreeMap::new(),
);
assert!(
!empty_setup.contains("process.env."),
"empty env map should not emit any env assignments, got:\n{empty_setup}"
);
}
#[test]
fn render_wasm_excluded_category_emits_named_skip_cases_with_reasons() {
let reasons = vec![
(
"visitor_skip_heading".to_string(),
"WASM visitor bridge not yet exposed via @xberg-io/html-to-markdown-wasm public API".to_string(),
),
(
"visitor_custom_output".to_string(),
"excluded for wasm e2e generation".to_string(),
),
];
let content = render_wasm_excluded_category("visitor", &reasons);
assert!(
content.contains("describe(\"visitor\""),
"must name the category:\n{content}"
);
assert!(
content.contains("it.skip(\"visitor_skip_heading\""),
"must name each excluded fixture as a skipped case:\n{content}"
);
assert!(
content.contains("it.skip(\"visitor_custom_output\""),
"must name each excluded fixture as a skipped case:\n{content}"
);
assert!(
content.contains("WASM visitor bridge not yet exposed"),
"must surface the per-fixture skip reason:\n{content}"
);
}