4242
4343import { GlobalWorkerOptions } from "pdfjs/display/worker_options.js" ;
4444import { isNodeJS } from "../../src/shared/util.js" ;
45+ import { mergeWorkerCoverageIntoWindow } from "../coverage_utils.js" ;
46+ import { MessageHandler } from "pdfjs/shared/message_handler.js" ;
47+ import { PDFWorker } from "pdfjs/display/api.js" ;
4548import { TestReporter } from "../reporter.js" ;
4649
4750async function initializePDFJS ( callback ) {
@@ -114,12 +117,66 @@ async function initializePDFJS(callback) {
114117 "The `gulp unittest` command cannot be used in Node.js environments."
115118 ) ;
116119 }
117- // Configure the worker.
118- GlobalWorkerOptions . workerSrc = "../../build/generic/build/pdf.worker.mjs" ;
120+ // Configure the worker. Point at the raw source so the webserver can
121+ // instrument it on request and the worker accumulates `__coverage__`.
122+ GlobalWorkerOptions . workerSrc = "../../src/pdf.worker.js" ;
119123
120124 callback ( ) ;
121125}
122126
127+ // Each unit-test typically spins up its own `PDFWorker`, which is destroyed
128+ // when the loading task is. Hook `destroy` so that we extract the worker-side
129+ // `__coverage__` before terminating, and merge it into the main thread's
130+ // `window.__coverage__`. Without this, anything tested through `getDocument`
131+ // → worker (most of `core/`) has its execution counts dropped on the floor.
132+ const pendingWorkerCoverage = new Set ( ) ;
133+
134+ function installWorkerCoverageHook ( ) {
135+ if ( ! window . __coverage__ ) {
136+ return ;
137+ }
138+ const originalDestroy = PDFWorker . prototype . destroy ;
139+ PDFWorker . prototype . destroy = function ( ) {
140+ if ( this . destroyed || ! this . _webWorker ) {
141+ // Already torn down, or wrapping a foreign port — defer to the original
142+ // implementation, which leaves the underlying `Worker` alone.
143+ return originalDestroy . call ( this ) ;
144+ }
145+ // Capture the underlying Worker, then run the original destroy with
146+ // `terminate` neutralized so the public `destroyed`/`port` contract is
147+ // preserved synchronously while the Worker stays alive long enough to
148+ // hand back its `__coverage__`.
149+ const webWorker = this . _webWorker ;
150+ const realTerminate = webWorker . terminate . bind ( webWorker ) ;
151+ webWorker . terminate = ( ) => { } ;
152+ try {
153+ originalDestroy . call ( this ) ;
154+ } finally {
155+ webWorker . terminate = realTerminate ;
156+ }
157+ const handler = new MessageHandler ( "main" , "worker" , webWorker ) ;
158+ const promise = handler
159+ . sendWithPromise ( "GetWorkerCoverage" , null )
160+ . then ( mergeWorkerCoverageIntoWindow )
161+ . catch ( e => {
162+ console . warn ( `Failed to collect worker coverage: ${ e } ` ) ;
163+ } )
164+ . finally ( ( ) => {
165+ handler . destroy ( ) ;
166+ realTerminate ( ) ;
167+ pendingWorkerCoverage . delete ( promise ) ;
168+ } ) ;
169+ pendingWorkerCoverage . add ( promise ) ;
170+ return undefined ;
171+ } ;
172+ }
173+
174+ async function flushPendingWorkerCoverage ( ) {
175+ while ( pendingWorkerCoverage . size > 0 ) {
176+ await Promise . allSettled ( pendingWorkerCoverage ) ;
177+ }
178+ }
179+
123180( function ( ) {
124181 window . jasmine = jasmineRequire . core ( jasmineRequire ) ;
125182
@@ -140,6 +197,13 @@ async function initializePDFJS(callback) {
140197
141198 env . addReporter ( htmlReporter ) ;
142199
200+ if ( window . __coverage__ ) {
201+ // Must run before `TestReporter`, whose `jasmineDone` triggers the
202+ // browser teardown; the worker-side counters need to be merged into
203+ // `window.__coverage__` before the page is closed.
204+ env . addReporter ( { jasmineDone : flushPendingWorkerCoverage } ) ;
205+ }
206+
143207 if ( urls . queryString . getParam ( "browser" ) ) {
144208 const testReporter = new TestReporter ( urls . queryString . getParam ( "browser" ) ) ;
145209 env . addReporter ( testReporter ) ;
@@ -157,6 +221,7 @@ async function initializePDFJS(callback) {
157221
158222 function unitTestInit ( ) {
159223 initializePDFJS ( function ( ) {
224+ installWorkerCoverageHook ( ) ;
160225 env . execute ( ) ;
161226 } ) ;
162227 }
0 commit comments