|
3 | 3 | //! This module is only available when the `wasm` feature is enabled. |
4 | 4 | //! It exports JavaScript-callable functions for converting Office documents |
5 | 5 | //! to PDF in browser or Node.js environments. |
| 6 | +//! |
| 7 | +//! # Running WASM integration tests |
| 8 | +//! |
| 9 | +//! WASM integration tests use `wasm-bindgen-test` and require `wasm-pack`: |
| 10 | +//! |
| 11 | +//! ```bash |
| 12 | +//! # Install wasm-pack (one-time setup) |
| 13 | +//! cargo install wasm-pack |
| 14 | +//! |
| 15 | +//! # Run WASM tests in Node.js |
| 16 | +//! cd crates/office2pdf |
| 17 | +//! wasm-pack test --node --features wasm |
| 18 | +//! |
| 19 | +//! # Or run in a headless browser |
| 20 | +//! wasm-pack test --headless --chrome --features wasm |
| 21 | +//! ``` |
| 22 | +//! |
| 23 | +//! These tests verify end-to-end WASM conversion by building the library as |
| 24 | +//! a WASM module, loading it, and calling the exported functions. |
6 | 25 |
|
7 | 26 | use wasm_bindgen::prelude::*; |
8 | 27 |
|
@@ -252,3 +271,174 @@ mod tests { |
252 | 271 | assert!(convert_format_inner(b"bad", Format::Xlsx).is_err()); |
253 | 272 | } |
254 | 273 | } |
| 274 | + |
| 275 | +// --------------------------------------------------------------------------- |
| 276 | +// WASM integration tests (run via `wasm-pack test --node --features wasm`) |
| 277 | +// |
| 278 | +// These tests compile ONLY when targeting wasm32 and are executed inside a |
| 279 | +// real WASM runtime (Node.js or headless browser). They call the actual |
| 280 | +// `#[wasm_bindgen]`-exported functions and verify end-to-end conversion. |
| 281 | +// --------------------------------------------------------------------------- |
| 282 | +#[cfg(all(target_arch = "wasm32", test))] |
| 283 | +mod wasm_tests { |
| 284 | + use super::*; |
| 285 | + use wasm_bindgen_test::*; |
| 286 | + |
| 287 | + /// Helper: create a minimal valid DOCX via docx-rs builder. |
| 288 | + fn make_minimal_docx() -> Vec<u8> { |
| 289 | + use std::io::Cursor; |
| 290 | + let doc = docx_rs::Docx::new().add_paragraph( |
| 291 | + docx_rs::Paragraph::new().add_run(docx_rs::Run::new().add_text("Hello WASM")), |
| 292 | + ); |
| 293 | + let mut buf = Cursor::new(Vec::new()); |
| 294 | + doc.build().pack(&mut buf).unwrap(); |
| 295 | + buf.into_inner() |
| 296 | + } |
| 297 | + |
| 298 | + /// Helper: create a minimal valid PPTX. |
| 299 | + fn make_minimal_pptx() -> Vec<u8> { |
| 300 | + use std::io::{Cursor, Write}; |
| 301 | + let cursor = Cursor::new(Vec::new()); |
| 302 | + let mut zip = zip::ZipWriter::new(cursor); |
| 303 | + let options = |
| 304 | + zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated); |
| 305 | + |
| 306 | + zip.start_file("[Content_Types].xml", options).unwrap(); |
| 307 | + zip.write_all(br#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
| 308 | +<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"> |
| 309 | + <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/> |
| 310 | + <Default Extension="xml" ContentType="application/xml"/> |
| 311 | + <Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/> |
| 312 | + <Override PartName="/ppt/slides/slide1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/> |
| 313 | +</Types>"#) |
| 314 | + .unwrap(); |
| 315 | + |
| 316 | + zip.start_file("_rels/.rels", options).unwrap(); |
| 317 | + zip.write_all(br#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
| 318 | +<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> |
| 319 | + <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="ppt/presentation.xml"/> |
| 320 | +</Relationships>"#) |
| 321 | + .unwrap(); |
| 322 | + |
| 323 | + zip.start_file("ppt/presentation.xml", options).unwrap(); |
| 324 | + zip.write_all( |
| 325 | + br#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
| 326 | +<p:presentation xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" |
| 327 | + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> |
| 328 | + <p:sldSz cx="9144000" cy="6858000"/> |
| 329 | + <p:sldIdLst> |
| 330 | + <p:sldId id="256" r:id="rId2"/> |
| 331 | + </p:sldIdLst> |
| 332 | +</p:presentation>"#, |
| 333 | + ) |
| 334 | + .unwrap(); |
| 335 | + |
| 336 | + zip.start_file("ppt/_rels/presentation.xml.rels", options) |
| 337 | + .unwrap(); |
| 338 | + zip.write_all(br#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
| 339 | +<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> |
| 340 | + <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/> |
| 341 | +</Relationships>"#) |
| 342 | + .unwrap(); |
| 343 | + |
| 344 | + zip.start_file("ppt/slides/slide1.xml", options).unwrap(); |
| 345 | + zip.write_all( |
| 346 | + br#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
| 347 | +<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" |
| 348 | + xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" |
| 349 | + xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"> |
| 350 | + <p:cSld> |
| 351 | + <p:spTree> |
| 352 | + <p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr> |
| 353 | + <p:grpSpPr/> |
| 354 | + <p:sp> |
| 355 | + <p:nvSpPr><p:cNvPr id="2" name="Title"/><p:cNvSpPr/><p:nvPr/></p:nvSpPr> |
| 356 | + <p:spPr> |
| 357 | + <a:xfrm><a:off x="0" y="0"/><a:ext cx="9144000" cy="1000000"/></a:xfrm> |
| 358 | + </p:spPr> |
| 359 | + <p:txBody> |
| 360 | + <a:bodyPr/> |
| 361 | + <a:p><a:r><a:t>Hello WASM</a:t></a:r></a:p> |
| 362 | + </p:txBody> |
| 363 | + </p:sp> |
| 364 | + </p:spTree> |
| 365 | + </p:cSld> |
| 366 | +</p:sld>"#, |
| 367 | + ) |
| 368 | + .unwrap(); |
| 369 | + |
| 370 | + zip.finish().unwrap().into_inner() |
| 371 | + } |
| 372 | + |
| 373 | + /// Helper: create a minimal valid XLSX. |
| 374 | + fn make_minimal_xlsx() -> Vec<u8> { |
| 375 | + use std::io::Cursor; |
| 376 | + let mut book = umya_spreadsheet::new_file(); |
| 377 | + let sheet = book.get_sheet_mut(&0).unwrap(); |
| 378 | + sheet.get_cell_mut("A1").set_value("Hello WASM"); |
| 379 | + let mut cursor = Cursor::new(Vec::new()); |
| 380 | + umya_spreadsheet::writer::xlsx::write_writer(&book, &mut cursor).unwrap(); |
| 381 | + cursor.into_inner() |
| 382 | + } |
| 383 | + |
| 384 | + #[wasm_bindgen_test] |
| 385 | + fn wasm_convert_docx_to_pdf_produces_valid_pdf() { |
| 386 | + let docx = make_minimal_docx(); |
| 387 | + let result = convert_docx_to_pdf(&docx); |
| 388 | + assert!(result.is_ok(), "DOCX to PDF conversion failed in WASM"); |
| 389 | + let pdf = result.unwrap(); |
| 390 | + assert!( |
| 391 | + pdf.starts_with(b"%PDF"), |
| 392 | + "Output should start with %PDF magic bytes" |
| 393 | + ); |
| 394 | + assert!(pdf.len() > 100, "PDF output should have meaningful size"); |
| 395 | + } |
| 396 | + |
| 397 | + #[wasm_bindgen_test] |
| 398 | + fn wasm_convert_to_pdf_with_docx_format_string() { |
| 399 | + let docx = make_minimal_docx(); |
| 400 | + let result = convert_to_pdf(&docx, "docx"); |
| 401 | + assert!( |
| 402 | + result.is_ok(), |
| 403 | + "convert_to_pdf with 'docx' format failed in WASM" |
| 404 | + ); |
| 405 | + let pdf = result.unwrap(); |
| 406 | + assert!(pdf.starts_with(b"%PDF")); |
| 407 | + } |
| 408 | + |
| 409 | + #[wasm_bindgen_test] |
| 410 | + fn wasm_convert_pptx_to_pdf_produces_valid_pdf() { |
| 411 | + let pptx = make_minimal_pptx(); |
| 412 | + let result = convert_pptx_to_pdf(&pptx); |
| 413 | + assert!(result.is_ok(), "PPTX to PDF conversion failed in WASM"); |
| 414 | + let pdf = result.unwrap(); |
| 415 | + assert!( |
| 416 | + pdf.starts_with(b"%PDF"), |
| 417 | + "Output should start with %PDF magic bytes" |
| 418 | + ); |
| 419 | + } |
| 420 | + |
| 421 | + #[wasm_bindgen_test] |
| 422 | + fn wasm_convert_xlsx_to_pdf_produces_valid_pdf() { |
| 423 | + let xlsx = make_minimal_xlsx(); |
| 424 | + let result = convert_xlsx_to_pdf(&xlsx); |
| 425 | + assert!(result.is_ok(), "XLSX to PDF conversion failed in WASM"); |
| 426 | + let pdf = result.unwrap(); |
| 427 | + assert!( |
| 428 | + pdf.starts_with(b"%PDF"), |
| 429 | + "Output should start with %PDF magic bytes" |
| 430 | + ); |
| 431 | + } |
| 432 | + |
| 433 | + #[wasm_bindgen_test] |
| 434 | + fn wasm_convert_to_pdf_invalid_data_returns_error() { |
| 435 | + let result = convert_docx_to_pdf(b"not a valid docx"); |
| 436 | + assert!(result.is_err(), "Should fail on invalid input data"); |
| 437 | + } |
| 438 | + |
| 439 | + #[wasm_bindgen_test] |
| 440 | + fn wasm_convert_to_pdf_unsupported_format_returns_error() { |
| 441 | + let result = convert_to_pdf(b"dummy", "txt"); |
| 442 | + assert!(result.is_err(), "Should fail on unsupported format string"); |
| 443 | + } |
| 444 | +} |
0 commit comments