browser-debugger-cli 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -6
- package/dist/__tests__/smoke/error-handling.smoke.test.js +14 -48
- package/dist/__tests__/smoke/error-handling.smoke.test.js.map +1 -1
- package/dist/__tests__/smoke/session-lifecycle.smoke.test.js +1 -1
- package/dist/__tests__/smoke/session-lifecycle.smoke.test.js.map +1 -1
- package/dist/__testutils__/testCleanup.js +1 -1
- package/dist/__testutils__/testCleanup.js.map +1 -1
- package/dist/cdp/protocol.d.ts +0 -48
- package/dist/cdp/protocol.d.ts.map +1 -1
- package/dist/cdp/protocol.js +0 -94
- package/dist/cdp/protocol.js.map +1 -1
- package/dist/commands/__tests__/cdp.contract.test.js +2 -2
- package/dist/commands/__tests__/cdp.contract.test.js.map +1 -1
- package/dist/commands/__tests__/domEval.contract.test.js +8 -4
- package/dist/commands/__tests__/domEval.contract.test.js.map +1 -1
- package/dist/commands/cdp.d.ts.map +1 -1
- package/dist/commands/cdp.js +4 -37
- package/dist/commands/cdp.js.map +1 -1
- package/dist/commands/cleanup.d.ts.map +1 -1
- package/dist/commands/cleanup.js +4 -17
- package/dist/commands/cleanup.js.map +1 -1
- package/dist/commands/console.d.ts.map +1 -1
- package/dist/commands/console.js +3 -8
- package/dist/commands/console.js.map +1 -1
- package/dist/commands/details.d.ts.map +1 -1
- package/dist/commands/details.js +1 -1
- package/dist/commands/details.js.map +1 -1
- package/dist/commands/{domEvalHelpers.d.ts → dom/evalHelpers.d.ts} +8 -5
- package/dist/commands/dom/evalHelpers.d.ts.map +1 -0
- package/dist/commands/{domEvalHelpers.js → dom/evalHelpers.js} +14 -13
- package/dist/commands/dom/evalHelpers.js.map +1 -0
- package/dist/commands/dom/formFillHelpers.d.ts +47 -0
- package/dist/commands/dom/formFillHelpers.d.ts.map +1 -0
- package/dist/commands/dom/formFillHelpers.js +185 -0
- package/dist/commands/dom/formFillHelpers.js.map +1 -0
- package/dist/commands/dom/formInteraction.d.ts +17 -0
- package/dist/commands/dom/formInteraction.d.ts.map +1 -0
- package/dist/commands/dom/formInteraction.js +239 -0
- package/dist/commands/dom/formInteraction.js.map +1 -0
- package/dist/commands/dom/formSubmitHelpers.d.ts +58 -0
- package/dist/commands/dom/formSubmitHelpers.d.ts.map +1 -0
- package/dist/commands/dom/formSubmitHelpers.js +176 -0
- package/dist/commands/dom/formSubmitHelpers.js.map +1 -0
- package/dist/commands/dom/helpers.d.ts +34 -0
- package/dist/commands/dom/helpers.d.ts.map +1 -0
- package/dist/commands/dom/helpers.js +244 -0
- package/dist/commands/dom/helpers.js.map +1 -0
- package/dist/commands/{dom.d.ts → dom/index.d.ts} +1 -1
- package/dist/commands/dom/index.d.ts.map +1 -0
- package/dist/commands/{dom.js → dom/index.js} +33 -123
- package/dist/commands/dom/index.js.map +1 -0
- package/dist/commands/dom/reactEventHelpers.d.ts +80 -0
- package/dist/commands/dom/reactEventHelpers.d.ts.map +1 -0
- package/dist/commands/dom/reactEventHelpers.js +274 -0
- package/dist/commands/dom/reactEventHelpers.js.map +1 -0
- package/dist/commands/network.js +1 -1
- package/dist/commands/network.js.map +1 -1
- package/dist/commands/peek.d.ts.map +1 -1
- package/dist/commands/peek.js +47 -52
- package/dist/commands/peek.js.map +1 -1
- package/dist/commands/shared/CommandRunner.d.ts.map +1 -1
- package/dist/commands/shared/CommandRunner.js +3 -2
- package/dist/commands/shared/CommandRunner.js.map +1 -1
- package/dist/commands/shared/commonOptions.d.ts.map +1 -1
- package/dist/commands/shared/commonOptions.js +3 -1
- package/dist/commands/shared/commonOptions.js.map +1 -1
- package/dist/commands/shared/daemonErrorHandler.d.ts +30 -0
- package/dist/commands/shared/daemonErrorHandler.d.ts.map +1 -0
- package/dist/commands/shared/daemonErrorHandler.js +32 -0
- package/dist/commands/shared/daemonErrorHandler.js.map +1 -0
- package/dist/commands/shared/{daemonSessionController.d.ts → startHelpers.d.ts} +7 -1
- package/dist/commands/shared/startHelpers.d.ts.map +1 -0
- package/dist/commands/shared/{daemonSessionController.js → startHelpers.js} +13 -5
- package/dist/commands/shared/startHelpers.js.map +1 -0
- package/dist/commands/shared/validation.d.ts +44 -0
- package/dist/commands/shared/validation.d.ts.map +1 -0
- package/dist/commands/shared/validation.js +68 -0
- package/dist/commands/shared/validation.js.map +1 -0
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +9 -25
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +6 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/stop.d.ts.map +1 -1
- package/dist/commands/stop.js +5 -16
- package/dist/commands/stop.js.map +1 -1
- package/dist/commands/tail.d.ts.map +1 -1
- package/dist/commands/tail.js +49 -44
- package/dist/commands/tail.js.map +1 -1
- package/dist/commands/types.d.ts +43 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +8 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +3 -1
- package/dist/commands.js.map +1 -1
- package/dist/connection/__tests__/cdp.contract.test.js +7 -7
- package/dist/connection/__tests__/cdp.contract.test.js.map +1 -1
- package/dist/connection/__tests__/handlers.unit.test.d.ts +11 -0
- package/dist/connection/__tests__/handlers.unit.test.d.ts.map +1 -0
- package/dist/connection/__tests__/handlers.unit.test.js +220 -0
- package/dist/connection/__tests__/handlers.unit.test.js.map +1 -0
- package/dist/connection/__tests__/pageReadiness.contract.test.d.ts +14 -0
- package/dist/connection/__tests__/pageReadiness.contract.test.d.ts.map +1 -0
- package/dist/connection/__tests__/pageReadiness.contract.test.js +382 -0
- package/dist/connection/__tests__/pageReadiness.contract.test.js.map +1 -0
- package/dist/connection/__tests__/portReservation.contract.test.d.ts +14 -0
- package/dist/connection/__tests__/portReservation.contract.test.d.ts.map +1 -0
- package/dist/connection/__tests__/portReservation.contract.test.js +250 -0
- package/dist/connection/__tests__/portReservation.contract.test.js.map +1 -0
- package/dist/connection/cdp.d.ts +34 -11
- package/dist/connection/cdp.d.ts.map +1 -1
- package/dist/connection/cdp.js +61 -45
- package/dist/connection/cdp.js.map +1 -1
- package/dist/connection/config.d.ts +63 -0
- package/dist/connection/config.d.ts.map +1 -0
- package/dist/connection/config.js +46 -0
- package/dist/connection/config.js.map +1 -0
- package/dist/connection/errors.d.ts +6 -21
- package/dist/connection/errors.d.ts.map +1 -1
- package/dist/connection/errors.js +7 -26
- package/dist/connection/errors.js.map +1 -1
- package/dist/connection/events.d.ts +30 -0
- package/dist/connection/events.d.ts.map +1 -0
- package/dist/connection/events.js +8 -0
- package/dist/connection/events.js.map +1 -0
- package/dist/connection/handlers.d.ts +3 -5
- package/dist/connection/handlers.d.ts.map +1 -1
- package/dist/connection/handlers.js +10 -12
- package/dist/connection/handlers.js.map +1 -1
- package/dist/connection/launcher/binaryResolver.d.ts +40 -0
- package/dist/connection/launcher/binaryResolver.d.ts.map +1 -0
- package/dist/connection/launcher/binaryResolver.js +78 -0
- package/dist/connection/launcher/binaryResolver.js.map +1 -0
- package/dist/connection/launcher/flagsBuilder.d.ts +64 -0
- package/dist/connection/launcher/flagsBuilder.d.ts.map +1 -0
- package/dist/connection/launcher/flagsBuilder.js +84 -0
- package/dist/connection/launcher/flagsBuilder.js.map +1 -0
- package/dist/connection/launcher/preferencesLoader.d.ts +74 -0
- package/dist/connection/launcher/preferencesLoader.d.ts.map +1 -0
- package/dist/connection/launcher/preferencesLoader.js +89 -0
- package/dist/connection/launcher/preferencesLoader.js.map +1 -0
- package/dist/connection/launcher.d.ts +24 -1
- package/dist/connection/launcher.d.ts.map +1 -1
- package/dist/connection/launcher.js +30 -205
- package/dist/connection/launcher.js.map +1 -1
- package/dist/connection/pageReadiness.d.ts +8 -8
- package/dist/connection/pageReadiness.d.ts.map +1 -1
- package/dist/connection/pageReadiness.js +36 -52
- package/dist/connection/pageReadiness.js.map +1 -1
- package/dist/connection/portReservation.d.ts +40 -0
- package/dist/connection/portReservation.d.ts.map +1 -0
- package/dist/connection/portReservation.js +55 -0
- package/dist/connection/portReservation.js.map +1 -0
- package/dist/connection/typed-cdp.d.ts +2 -1
- package/dist/connection/typed-cdp.d.ts.map +1 -1
- package/dist/connection/typed-cdp.js.map +1 -1
- package/dist/connection/types.d.ts +103 -0
- package/dist/connection/types.d.ts.map +1 -0
- package/dist/connection/types.js +8 -0
- package/dist/connection/types.js.map +1 -0
- package/dist/constants.d.ts +0 -83
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -83
- package/dist/constants.js.map +1 -1
- package/dist/daemon/__tests__/JsonlParser.unit.test.d.ts +8 -0
- package/dist/daemon/__tests__/JsonlParser.unit.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/JsonlParser.unit.test.js +140 -0
- package/dist/daemon/__tests__/JsonlParser.unit.test.js.map +1 -0
- package/dist/daemon/__tests__/PendingRequestManager.unit.test.d.ts +8 -0
- package/dist/daemon/__tests__/PendingRequestManager.unit.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/PendingRequestManager.unit.test.js +276 -0
- package/dist/daemon/__tests__/PendingRequestManager.unit.test.js.map +1 -0
- package/dist/daemon/__tests__/TelemetryStore.unit.test.d.ts +8 -0
- package/dist/daemon/__tests__/TelemetryStore.unit.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/TelemetryStore.unit.test.js +290 -0
- package/dist/daemon/__tests__/TelemetryStore.unit.test.js.map +1 -0
- package/dist/daemon/__tests__/commandRegistry.contract.test.d.ts +8 -0
- package/dist/daemon/__tests__/commandRegistry.contract.test.d.ts.map +1 -0
- package/dist/daemon/__tests__/commandRegistry.contract.test.js +384 -0
- package/dist/daemon/__tests__/commandRegistry.contract.test.js.map +1 -0
- package/dist/daemon/__tests__/ipcServer.contract.test.js +2 -1
- package/dist/daemon/__tests__/ipcServer.contract.test.js.map +1 -1
- package/dist/daemon/errors.d.ts +65 -0
- package/dist/daemon/errors.d.ts.map +1 -0
- package/dist/daemon/errors.js +82 -0
- package/dist/daemon/errors.js.map +1 -0
- package/dist/daemon/handlers/CommandHandlers.d.ts +32 -0
- package/dist/daemon/handlers/CommandHandlers.d.ts.map +1 -0
- package/dist/daemon/handlers/CommandHandlers.js +93 -0
- package/dist/daemon/handlers/CommandHandlers.js.map +1 -0
- package/dist/daemon/handlers/QueryHandlers.d.ts +35 -0
- package/dist/daemon/handlers/QueryHandlers.d.ts.map +1 -0
- package/dist/daemon/handlers/QueryHandlers.js +176 -0
- package/dist/daemon/handlers/QueryHandlers.js.map +1 -0
- package/dist/daemon/handlers/SessionHandlers.d.ts +32 -0
- package/dist/daemon/handlers/SessionHandlers.d.ts.map +1 -0
- package/dist/daemon/handlers/SessionHandlers.js +227 -0
- package/dist/daemon/handlers/SessionHandlers.js.map +1 -0
- package/dist/daemon/handlers/pendingRequests.d.ts +50 -0
- package/dist/daemon/handlers/pendingRequests.d.ts.map +1 -0
- package/dist/daemon/handlers/pendingRequests.js +57 -0
- package/dist/daemon/handlers/pendingRequests.js.map +1 -0
- package/dist/daemon/handlers/requestHandlers.d.ts +51 -0
- package/dist/daemon/handlers/requestHandlers.d.ts.map +1 -0
- package/dist/daemon/handlers/requestHandlers.js +61 -0
- package/dist/daemon/handlers/requestHandlers.js.map +1 -0
- package/dist/daemon/handlers/responseHandler.d.ts +42 -0
- package/dist/daemon/handlers/responseHandler.d.ts.map +1 -0
- package/dist/daemon/handlers/responseHandler.js +195 -0
- package/dist/daemon/handlers/responseHandler.js.map +1 -0
- package/dist/daemon/ipcServer.d.ts +19 -41
- package/dist/daemon/ipcServer.d.ts.map +1 -1
- package/dist/daemon/ipcServer.js +83 -655
- package/dist/daemon/ipcServer.js.map +1 -1
- package/dist/daemon/launcher.d.ts.map +1 -1
- package/dist/daemon/launcher.js +6 -3
- package/dist/daemon/launcher.js.map +1 -1
- package/dist/daemon/lifecycle/cdpSetup.d.ts +24 -0
- package/dist/daemon/lifecycle/cdpSetup.d.ts.map +1 -0
- package/dist/daemon/lifecycle/cdpSetup.js +59 -0
- package/dist/daemon/lifecycle/cdpSetup.js.map +1 -0
- package/dist/daemon/lifecycle/chromeConnection.d.ts +17 -0
- package/dist/daemon/lifecycle/chromeConnection.d.ts.map +1 -0
- package/dist/daemon/lifecycle/chromeConnection.js +80 -0
- package/dist/daemon/lifecycle/chromeConnection.js.map +1 -0
- package/dist/daemon/lifecycle/signalHandlers.d.ts +14 -0
- package/dist/daemon/lifecycle/signalHandlers.d.ts.map +1 -0
- package/dist/daemon/lifecycle/signalHandlers.js +35 -0
- package/dist/daemon/lifecycle/signalHandlers.js.map +1 -0
- package/dist/daemon/lifecycle/workerCleanup.d.ts +27 -0
- package/dist/daemon/lifecycle/workerCleanup.d.ts.map +1 -0
- package/dist/daemon/lifecycle/workerCleanup.js +144 -0
- package/dist/daemon/lifecycle/workerCleanup.js.map +1 -0
- package/dist/daemon/lifecycle/workerConfig.d.ts +14 -0
- package/dist/daemon/lifecycle/workerConfig.d.ts.map +1 -0
- package/dist/daemon/lifecycle/workerConfig.js +66 -0
- package/dist/daemon/lifecycle/workerConfig.js.map +1 -0
- package/dist/daemon/lifecycle/workerIpc.d.ts +14 -0
- package/dist/daemon/lifecycle/workerIpc.d.ts.map +1 -0
- package/dist/daemon/lifecycle/workerIpc.js +87 -0
- package/dist/daemon/lifecycle/workerIpc.js.map +1 -0
- package/dist/daemon/server/JsonlParser.d.ts +31 -0
- package/dist/daemon/server/JsonlParser.d.ts.map +1 -0
- package/dist/daemon/server/JsonlParser.js +57 -0
- package/dist/daemon/server/JsonlParser.js.map +1 -0
- package/dist/daemon/server/SocketServer.d.ts.map +1 -1
- package/dist/daemon/server/SocketServer.js +2 -2
- package/dist/daemon/server/SocketServer.js.map +1 -1
- package/dist/daemon/server/WorkerManager.d.ts +3 -3
- package/dist/daemon/server/WorkerManager.d.ts.map +1 -1
- package/dist/daemon/server/WorkerManager.js +10 -19
- package/dist/daemon/server/WorkerManager.js.map +1 -1
- package/dist/daemon/services/SessionService.d.ts +87 -0
- package/dist/daemon/services/SessionService.d.ts.map +1 -0
- package/dist/daemon/services/SessionService.js +45 -0
- package/dist/daemon/services/SessionService.js.map +1 -0
- package/dist/daemon/startSession.d.ts.map +1 -1
- package/dist/daemon/startSession.js +54 -31
- package/dist/daemon/startSession.js.map +1 -1
- package/dist/daemon/worker/commandRegistry.d.ts +1 -1
- package/dist/daemon/worker/commandRegistry.d.ts.map +1 -1
- package/dist/daemon/worker/commandRegistry.js +20 -215
- package/dist/daemon/worker/commandRegistry.js.map +1 -1
- package/dist/daemon/worker.d.ts +3 -12
- package/dist/daemon/worker.d.ts.map +1 -1
- package/dist/daemon/worker.js +47 -367
- package/dist/daemon/worker.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/ipc/__tests__/client.contract.test.d.ts +0 -15
- package/dist/ipc/__tests__/client.contract.test.d.ts.map +1 -1
- package/dist/ipc/__tests__/client.contract.test.js +8 -23
- package/dist/ipc/__tests__/client.contract.test.js.map +1 -1
- package/dist/ipc/__tests__/errors.unit.test.d.ts +7 -0
- package/dist/ipc/__tests__/errors.unit.test.d.ts.map +1 -0
- package/dist/ipc/__tests__/errors.unit.test.js +77 -0
- package/dist/ipc/__tests__/errors.unit.test.js.map +1 -0
- package/dist/ipc/__tests__/guards.unit.test.d.ts +7 -0
- package/dist/ipc/__tests__/guards.unit.test.d.ts.map +1 -0
- package/dist/ipc/__tests__/guards.unit.test.js +73 -0
- package/dist/ipc/__tests__/guards.unit.test.js.map +1 -0
- package/dist/ipc/__tests__/jsonl.unit.test.d.ts +7 -0
- package/dist/ipc/__tests__/jsonl.unit.test.d.ts.map +1 -0
- package/dist/ipc/__tests__/jsonl.unit.test.js +85 -0
- package/dist/ipc/__tests__/jsonl.unit.test.js.map +1 -0
- package/dist/ipc/__tests__/validation.unit.test.d.ts +7 -0
- package/dist/ipc/__tests__/validation.unit.test.d.ts.map +1 -0
- package/dist/ipc/__tests__/validation.unit.test.js +60 -0
- package/dist/ipc/__tests__/validation.unit.test.js.map +1 -0
- package/dist/ipc/client.d.ts +93 -84
- package/dist/ipc/client.d.ts.map +1 -1
- package/dist/ipc/client.js +121 -192
- package/dist/ipc/client.js.map +1 -1
- package/dist/ipc/index.d.ts +17 -0
- package/dist/ipc/index.d.ts.map +1 -0
- package/dist/ipc/index.js +23 -0
- package/dist/ipc/index.js.map +1 -0
- package/dist/ipc/protocol/commands.d.ts +144 -0
- package/dist/ipc/protocol/commands.d.ts.map +1 -0
- package/dist/ipc/protocol/commands.js +23 -0
- package/dist/ipc/protocol/commands.js.map +1 -0
- package/dist/ipc/protocol/guards.d.ts +47 -0
- package/dist/ipc/protocol/guards.d.ts.map +1 -0
- package/dist/ipc/protocol/guards.js +62 -0
- package/dist/ipc/protocol/guards.js.map +1 -0
- package/dist/ipc/protocol/index.d.ts +9 -0
- package/dist/ipc/protocol/index.d.ts.map +1 -0
- package/dist/ipc/protocol/index.js +8 -0
- package/dist/ipc/protocol/index.js.map +1 -0
- package/dist/ipc/protocol/messages.d.ts +64 -0
- package/dist/ipc/protocol/messages.d.ts.map +1 -0
- package/dist/ipc/protocol/messages.js +8 -0
- package/dist/ipc/protocol/messages.js.map +1 -0
- package/dist/ipc/session/errors.d.ts +25 -0
- package/dist/ipc/session/errors.d.ts.map +1 -0
- package/dist/ipc/{types.js → session/errors.js} +11 -6
- package/dist/ipc/session/errors.js.map +1 -0
- package/dist/ipc/session/index.d.ts +16 -0
- package/dist/ipc/session/index.d.ts.map +1 -0
- package/dist/ipc/session/index.js +7 -0
- package/dist/ipc/session/index.js.map +1 -0
- package/dist/ipc/session/lifecycle.d.ts +125 -0
- package/dist/ipc/session/lifecycle.d.ts.map +1 -0
- package/dist/ipc/session/lifecycle.js +7 -0
- package/dist/ipc/session/lifecycle.js.map +1 -0
- package/dist/ipc/session/queries.d.ts +94 -0
- package/dist/ipc/session/queries.d.ts.map +1 -0
- package/dist/ipc/session/queries.js +7 -0
- package/dist/ipc/session/queries.js.map +1 -0
- package/dist/ipc/session/types.d.ts +28 -0
- package/dist/ipc/session/types.d.ts.map +1 -0
- package/dist/ipc/session/types.js +7 -0
- package/dist/ipc/session/types.js.map +1 -0
- package/dist/ipc/transport/IPCError.d.ts +82 -0
- package/dist/ipc/transport/IPCError.d.ts.map +1 -0
- package/dist/ipc/transport/IPCError.js +109 -0
- package/dist/ipc/transport/IPCError.js.map +1 -0
- package/dist/ipc/transport/errors.d.ts +11 -0
- package/dist/ipc/transport/errors.d.ts.map +1 -0
- package/dist/ipc/transport/errors.js +28 -0
- package/dist/ipc/transport/errors.js.map +1 -0
- package/dist/ipc/transport/index.d.ts +16 -0
- package/dist/ipc/transport/index.d.ts.map +1 -0
- package/dist/ipc/transport/index.js +77 -0
- package/dist/ipc/transport/index.js.map +1 -0
- package/dist/ipc/transport/jsonl.d.ts +23 -0
- package/dist/ipc/transport/jsonl.d.ts.map +1 -0
- package/dist/ipc/transport/jsonl.js +36 -0
- package/dist/ipc/transport/jsonl.js.map +1 -0
- package/dist/ipc/transport/socket.d.ts +27 -0
- package/dist/ipc/transport/socket.d.ts.map +1 -0
- package/dist/ipc/transport/socket.js +49 -0
- package/dist/ipc/transport/socket.js.map +1 -0
- package/dist/ipc/transport/validation.d.ts +21 -0
- package/dist/ipc/transport/validation.d.ts.map +1 -0
- package/dist/ipc/transport/validation.js +23 -0
- package/dist/ipc/transport/validation.js.map +1 -0
- package/dist/ipc/utils/errors.d.ts +25 -0
- package/dist/ipc/utils/errors.d.ts.map +1 -0
- package/dist/ipc/utils/errors.js +29 -0
- package/dist/ipc/utils/errors.js.map +1 -0
- package/dist/ipc/utils/index.d.ts +12 -0
- package/dist/ipc/utils/index.d.ts.map +1 -0
- package/dist/ipc/utils/index.js +11 -0
- package/dist/ipc/utils/index.js.map +1 -0
- package/dist/ipc/utils/requestId.d.ts +23 -0
- package/dist/ipc/utils/requestId.d.ts.map +1 -0
- package/dist/ipc/utils/requestId.js +27 -0
- package/dist/ipc/utils/requestId.js.map +1 -0
- package/dist/ipc/utils/responseValidator.d.ts.map +1 -0
- package/dist/ipc/{responseValidator.js → utils/responseValidator.js} +2 -1
- package/dist/ipc/utils/responseValidator.js.map +1 -0
- package/dist/ipc/utils/session.d.ts +36 -0
- package/dist/ipc/utils/session.d.ts.map +1 -0
- package/dist/ipc/utils/session.js +37 -0
- package/dist/ipc/utils/session.js.map +1 -0
- package/dist/ipc/utils/types.d.ts +17 -0
- package/dist/ipc/utils/types.d.ts.map +1 -0
- package/dist/ipc/utils/types.js +7 -0
- package/dist/ipc/utils/types.js.map +1 -0
- package/dist/session/__tests__/chrome-cache.contract.test.d.ts +7 -0
- package/dist/session/__tests__/chrome-cache.contract.test.d.ts.map +1 -0
- package/dist/session/__tests__/chrome-cache.contract.test.js +77 -0
- package/dist/session/__tests__/chrome-cache.contract.test.js.map +1 -0
- package/dist/session/__tests__/cleanup.contract.test.d.ts +7 -0
- package/dist/session/__tests__/cleanup.contract.test.d.ts.map +1 -0
- package/dist/session/__tests__/cleanup.contract.test.js +84 -0
- package/dist/session/__tests__/cleanup.contract.test.js.map +1 -0
- package/dist/session/__tests__/lock.contract.test.d.ts +7 -0
- package/dist/session/__tests__/lock.contract.test.d.ts.map +1 -0
- package/dist/session/__tests__/lock.contract.test.js +77 -0
- package/dist/session/__tests__/lock.contract.test.js.map +1 -0
- package/dist/session/__tests__/metadata.contract.test.d.ts +7 -0
- package/dist/session/__tests__/metadata.contract.test.d.ts.map +1 -0
- package/dist/session/__tests__/metadata.contract.test.js +87 -0
- package/dist/session/__tests__/metadata.contract.test.js.map +1 -0
- package/dist/session/chrome.d.ts +20 -0
- package/dist/session/chrome.d.ts.map +1 -1
- package/dist/session/chrome.js +80 -16
- package/dist/session/chrome.js.map +1 -1
- package/dist/session/cleanup.d.ts +15 -2
- package/dist/session/cleanup.d.ts.map +1 -1
- package/dist/session/cleanup.js +100 -72
- package/dist/session/cleanup.js.map +1 -1
- package/dist/session/lock.d.ts.map +1 -1
- package/dist/session/lock.js +101 -90
- package/dist/session/lock.js.map +1 -1
- package/dist/session/metadata.d.ts +10 -3
- package/dist/session/metadata.d.ts.map +1 -1
- package/dist/session/metadata.js +24 -6
- package/dist/session/metadata.js.map +1 -1
- package/dist/session/paths.d.ts +0 -9
- package/dist/session/paths.d.ts.map +1 -1
- package/dist/session/paths.js +0 -11
- package/dist/session/paths.js.map +1 -1
- package/dist/session/pid.d.ts +15 -0
- package/dist/session/pid.d.ts.map +1 -1
- package/dist/session/pid.js +39 -21
- package/dist/session/pid.js.map +1 -1
- package/dist/session/process.d.ts +4 -41
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +4 -85
- package/dist/session/process.js.map +1 -1
- package/dist/session/statusData.d.ts +50 -0
- package/dist/session/statusData.d.ts.map +1 -0
- package/dist/session/statusData.js +51 -0
- package/dist/session/statusData.js.map +1 -0
- package/dist/telemetry/__tests__/navigation.contract.test.d.ts +8 -0
- package/dist/telemetry/__tests__/navigation.contract.test.d.ts.map +1 -0
- package/dist/telemetry/__tests__/navigation.contract.test.js +211 -0
- package/dist/telemetry/__tests__/navigation.contract.test.js.map +1 -0
- package/dist/telemetry/__tests__/network.contract.test.d.ts +0 -20
- package/dist/telemetry/__tests__/network.contract.test.d.ts.map +1 -1
- package/dist/telemetry/__tests__/network.contract.test.js +2 -64
- package/dist/telemetry/__tests__/network.contract.test.js.map +1 -1
- package/dist/telemetry/__tests__/utils.unit.test.d.ts +7 -0
- package/dist/telemetry/__tests__/utils.unit.test.d.ts.map +1 -0
- package/dist/telemetry/__tests__/utils.unit.test.js +91 -0
- package/dist/telemetry/__tests__/utils.unit.test.js.map +1 -0
- package/dist/telemetry/console.d.ts.map +1 -1
- package/dist/telemetry/console.js +19 -28
- package/dist/telemetry/console.js.map +1 -1
- package/dist/telemetry/dialogs.d.ts.map +1 -1
- package/dist/telemetry/dialogs.js +4 -8
- package/dist/telemetry/dialogs.js.map +1 -1
- package/dist/telemetry/dom.d.ts.map +1 -1
- package/dist/telemetry/dom.js +51 -59
- package/dist/telemetry/dom.js.map +1 -1
- package/dist/telemetry/filters.d.ts +5 -18
- package/dist/telemetry/filters.d.ts.map +1 -1
- package/dist/telemetry/filters.js +36 -56
- package/dist/telemetry/filters.js.map +1 -1
- package/dist/telemetry/navigation.d.ts.map +1 -1
- package/dist/telemetry/navigation.js +5 -8
- package/dist/telemetry/navigation.js.map +1 -1
- package/dist/telemetry/network.d.ts.map +1 -1
- package/dist/telemetry/network.js +105 -104
- package/dist/telemetry/network.js.map +1 -1
- package/dist/telemetry/utils.d.ts +85 -0
- package/dist/telemetry/utils.d.ts.map +1 -0
- package/dist/telemetry/utils.js +138 -0
- package/dist/telemetry/utils.js.map +1 -0
- package/dist/types/dom.d.ts +66 -0
- package/dist/types/dom.d.ts.map +1 -0
- package/dist/types/dom.js +8 -0
- package/dist/types/dom.js.map +1 -0
- package/dist/types.d.ts +15 -83
- package/dist/types.d.ts.map +1 -1
- package/dist/{commands/shared → ui}/OutputBuilder.d.ts +10 -2
- package/dist/ui/OutputBuilder.d.ts.map +1 -0
- package/dist/{commands/shared → ui}/OutputBuilder.js +8 -2
- package/dist/ui/OutputBuilder.js.map +1 -0
- package/dist/ui/errors/CommandError.d.ts +16 -2
- package/dist/ui/errors/CommandError.d.ts.map +1 -1
- package/dist/ui/errors/CommandError.js +2 -1
- package/dist/ui/errors/CommandError.js.map +1 -1
- package/dist/ui/errors/index.d.ts +2 -3
- package/dist/ui/errors/index.d.ts.map +1 -1
- package/dist/ui/errors/index.js +1 -3
- package/dist/ui/errors/index.js.map +1 -1
- package/dist/ui/errors/utils.d.ts +6 -0
- package/dist/ui/errors/utils.d.ts.map +1 -1
- package/dist/ui/errors/utils.js +8 -3
- package/dist/ui/errors/utils.js.map +1 -1
- package/dist/ui/formatters/dom.d.ts +3 -18
- package/dist/ui/formatters/dom.d.ts.map +1 -1
- package/dist/ui/formatters/dom.js +4 -27
- package/dist/ui/formatters/dom.js.map +1 -1
- package/dist/ui/formatters/preview.d.ts +8 -8
- package/dist/ui/formatters/preview.d.ts.map +1 -1
- package/dist/ui/formatters/preview.js +18 -13
- package/dist/ui/formatters/preview.js.map +1 -1
- package/dist/ui/formatters/status.d.ts +1 -1
- package/dist/ui/formatters/status.d.ts.map +1 -1
- package/dist/ui/formatters/status.js +8 -30
- package/dist/ui/formatters/status.js.map +1 -1
- package/dist/ui/formatting.d.ts +2 -270
- package/dist/ui/formatting.d.ts.map +1 -1
- package/dist/ui/formatting.js +8 -331
- package/dist/ui/formatting.js.map +1 -1
- package/dist/ui/logging/index.d.ts +1 -1
- package/dist/ui/logging/index.d.ts.map +1 -1
- package/dist/ui/logging/index.js +1 -1
- package/dist/ui/logging/index.js.map +1 -1
- package/dist/ui/logging/logger.d.ts +3 -23
- package/dist/ui/logging/logger.d.ts.map +1 -1
- package/dist/ui/logging/logger.js +2 -27
- package/dist/ui/logging/logger.js.map +1 -1
- package/dist/ui/messages/chrome.d.ts +15 -7
- package/dist/ui/messages/chrome.d.ts.map +1 -1
- package/dist/ui/messages/chrome.js +23 -32
- package/dist/ui/messages/chrome.js.map +1 -1
- package/dist/ui/messages/commands.d.ts +2 -19
- package/dist/ui/messages/commands.d.ts.map +1 -1
- package/dist/ui/messages/commands.js +5 -51
- package/dist/ui/messages/commands.js.map +1 -1
- package/dist/ui/messages/consoleMessages.d.ts +1 -1
- package/dist/ui/messages/consoleMessages.d.ts.map +1 -1
- package/dist/ui/messages/consoleMessages.js +3 -6
- package/dist/ui/messages/consoleMessages.js.map +1 -1
- package/dist/ui/messages/debug.d.ts +0 -14
- package/dist/ui/messages/debug.d.ts.map +1 -1
- package/dist/ui/messages/debug.js +0 -18
- package/dist/ui/messages/debug.js.map +1 -1
- package/dist/ui/messages/errors.d.ts +0 -34
- package/dist/ui/messages/errors.d.ts.map +1 -1
- package/dist/ui/messages/errors.js +3 -81
- package/dist/ui/messages/errors.js.map +1 -1
- package/dist/ui/messages/internal.d.ts +0 -7
- package/dist/ui/messages/internal.d.ts.map +1 -1
- package/dist/ui/messages/internal.js +0 -12
- package/dist/ui/messages/internal.js.map +1 -1
- package/dist/ui/messages/preview.d.ts +14 -1
- package/dist/ui/messages/preview.d.ts.map +1 -1
- package/dist/ui/messages/preview.js +24 -7
- package/dist/ui/messages/preview.js.map +1 -1
- package/dist/ui/messages/session.d.ts.map +1 -1
- package/dist/ui/messages/session.js +7 -23
- package/dist/ui/messages/session.js.map +1 -1
- package/dist/ui/messages/validation.d.ts.map +1 -1
- package/dist/ui/messages/validation.js +7 -8
- package/dist/ui/messages/validation.js.map +1 -1
- package/dist/utils/__tests__/atomicFile.test.d.ts +2 -0
- package/dist/utils/__tests__/atomicFile.test.d.ts.map +1 -0
- package/dist/utils/__tests__/atomicFile.test.js +43 -0
- package/dist/utils/__tests__/atomicFile.test.js.map +1 -0
- package/dist/utils/__tests__/objects.test.d.ts +2 -0
- package/dist/utils/__tests__/objects.test.d.ts.map +1 -0
- package/dist/utils/__tests__/objects.test.js +50 -0
- package/dist/utils/__tests__/objects.test.js.map +1 -0
- package/dist/utils/__tests__/session.contract.test.js +13 -3
- package/dist/utils/__tests__/session.contract.test.js.map +1 -1
- package/dist/utils/__tests__/url.test.d.ts +2 -0
- package/dist/utils/__tests__/url.test.d.ts.map +1 -0
- package/dist/utils/__tests__/url.test.js +42 -0
- package/dist/utils/__tests__/url.test.js.map +1 -0
- package/dist/utils/atomicFile.d.ts +31 -5
- package/dist/utils/atomicFile.d.ts.map +1 -1
- package/dist/utils/atomicFile.js +52 -13
- package/dist/utils/atomicFile.js.map +1 -1
- package/dist/utils/concurrency.d.ts +54 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +78 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/daemonErrors.d.ts +60 -0
- package/dist/utils/daemonErrors.d.ts.map +1 -0
- package/dist/utils/daemonErrors.js +58 -0
- package/dist/utils/daemonErrors.js.map +1 -0
- package/dist/utils/errors.d.ts +28 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +33 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/exitCodes.d.ts +41 -5
- package/dist/utils/exitCodes.d.ts.map +1 -1
- package/dist/utils/exitCodes.js +43 -9
- package/dist/utils/exitCodes.js.map +1 -1
- package/dist/utils/http.d.ts +9 -4
- package/dist/utils/http.d.ts.map +1 -1
- package/dist/utils/http.js +44 -10
- package/dist/utils/http.js.map +1 -1
- package/dist/utils/levenshtein.d.ts +45 -0
- package/dist/utils/levenshtein.d.ts.map +1 -0
- package/dist/utils/levenshtein.js +85 -0
- package/dist/utils/levenshtein.js.map +1 -0
- package/dist/utils/objects.d.ts +16 -1
- package/dist/utils/objects.d.ts.map +1 -1
- package/dist/utils/objects.js +16 -1
- package/dist/utils/objects.js.map +1 -1
- package/dist/utils/process.d.ts +45 -0
- package/dist/utils/process.d.ts.map +1 -0
- package/dist/utils/process.js +91 -0
- package/dist/utils/process.js.map +1 -0
- package/dist/utils/url.d.ts +10 -3
- package/dist/utils/url.d.ts.map +1 -1
- package/dist/utils/url.js +42 -29
- package/dist/utils/url.js.map +1 -1
- package/dist/utils/validation.d.ts +101 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +131 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +1 -1
- package/dist/commands/dom.d.ts.map +0 -1
- package/dist/commands/dom.js.map +0 -1
- package/dist/commands/domEvalHelpers.d.ts.map +0 -1
- package/dist/commands/domEvalHelpers.js.map +0 -1
- package/dist/commands/domOptionsBuilder.d.ts +0 -67
- package/dist/commands/domOptionsBuilder.d.ts.map +0 -1
- package/dist/commands/domOptionsBuilder.js +0 -86
- package/dist/commands/domOptionsBuilder.js.map +0 -1
- package/dist/commands/domSelectorParser.d.ts +0 -20
- package/dist/commands/domSelectorParser.d.ts.map +0 -1
- package/dist/commands/domSelectorParser.js +0 -20
- package/dist/commands/domSelectorParser.js.map +0 -1
- package/dist/commands/shared/OutputBuilder.d.ts.map +0 -1
- package/dist/commands/shared/OutputBuilder.js.map +0 -1
- package/dist/commands/shared/daemonSessionController.d.ts.map +0 -1
- package/dist/commands/shared/daemonSessionController.js.map +0 -1
- package/dist/commands/shared/sessionController.d.ts +0 -21
- package/dist/commands/shared/sessionController.d.ts.map +0 -1
- package/dist/commands/shared/sessionController.js +0 -54
- package/dist/commands/shared/sessionController.js.map +0 -1
- package/dist/connection/__tests__/finder.contract.test.d.ts +0 -2
- package/dist/connection/__tests__/finder.contract.test.d.ts.map +0 -1
- package/dist/connection/__tests__/finder.contract.test.js +0 -239
- package/dist/connection/__tests__/finder.contract.test.js.map +0 -1
- package/dist/connection/domOperations.d.ts +0 -48
- package/dist/connection/domOperations.d.ts.map +0 -1
- package/dist/connection/domOperations.js +0 -106
- package/dist/connection/domOperations.js.map +0 -1
- package/dist/connection/finder.d.ts +0 -12
- package/dist/connection/finder.d.ts.map +0 -1
- package/dist/connection/finder.js +0 -17
- package/dist/connection/finder.js.map +0 -1
- package/dist/ipc/commands.d.ts +0 -260
- package/dist/ipc/commands.d.ts.map +0 -1
- package/dist/ipc/commands.js +0 -77
- package/dist/ipc/commands.js.map +0 -1
- package/dist/ipc/responseValidator.d.ts.map +0 -1
- package/dist/ipc/responseValidator.js.map +0 -1
- package/dist/ipc/types.d.ts +0 -226
- package/dist/ipc/types.d.ts.map +0 -1
- package/dist/ipc/types.js.map +0 -1
- package/dist/session/fileOps.d.ts +0 -25
- package/dist/session/fileOps.d.ts.map +0 -1
- package/dist/session/fileOps.js +0 -39
- package/dist/session/fileOps.js.map +0 -1
- package/dist/session/queryCache.d.ts +0 -36
- package/dist/session/queryCache.d.ts.map +0 -1
- package/dist/session/queryCache.js +0 -66
- package/dist/session/queryCache.js.map +0 -1
- /package/dist/ipc/{responseValidator.d.ts → utils/responseValidator.d.ts} +0 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for page readiness detection
|
|
3
|
+
*
|
|
4
|
+
* Tests the contract: wait for load → network stable → DOM stable OR timeout
|
|
5
|
+
*
|
|
6
|
+
* Philosophy: Test the state machine behavior using a mock CDP connection.
|
|
7
|
+
* We don't test timing-sensitive behavior (exact ms), we test the sequence
|
|
8
|
+
* of operations and state transitions.
|
|
9
|
+
*
|
|
10
|
+
* These are contract tests because they validate the multi-phase readiness
|
|
11
|
+
* detection contract without caring about internal implementation.
|
|
12
|
+
*/
|
|
13
|
+
import assert from 'node:assert/strict';
|
|
14
|
+
import { describe, test } from 'node:test';
|
|
15
|
+
import { waitForPageReady } from '../../connection/pageReadiness.js';
|
|
16
|
+
describe('Page Readiness - Happy Path', () => {
|
|
17
|
+
test('waits through all three phases (load → network → DOM)', async () => {
|
|
18
|
+
const phases = [];
|
|
19
|
+
const mockCDP = createMockCDP({
|
|
20
|
+
onSend: (method) => {
|
|
21
|
+
phases.push(method);
|
|
22
|
+
},
|
|
23
|
+
loadEventAlreadyFired: false,
|
|
24
|
+
networkQuiet: true,
|
|
25
|
+
domStable: true,
|
|
26
|
+
});
|
|
27
|
+
await waitForPageReady(mockCDP);
|
|
28
|
+
// Contract: should enable Page and Network domains
|
|
29
|
+
assert.ok(phases.includes('Page.enable'), 'Should enable Page domain');
|
|
30
|
+
assert.ok(phases.includes('Network.enable'), 'Should enable Network domain');
|
|
31
|
+
// Contract: should check document.readyState
|
|
32
|
+
assert.ok(phases.some((p) => p.includes('Runtime.evaluate')), 'Should check document readiness');
|
|
33
|
+
});
|
|
34
|
+
test('handles page where load event already fired', async () => {
|
|
35
|
+
const mockCDP = createMockCDP({
|
|
36
|
+
loadEventAlreadyFired: true,
|
|
37
|
+
networkQuiet: true,
|
|
38
|
+
domStable: true,
|
|
39
|
+
});
|
|
40
|
+
// Contract: should not wait for load event if already complete
|
|
41
|
+
await waitForPageReady(mockCDP);
|
|
42
|
+
// Should complete without error
|
|
43
|
+
assert.ok(true, 'Should handle already-loaded page');
|
|
44
|
+
});
|
|
45
|
+
test('proceeds when network stabilizes', async () => {
|
|
46
|
+
const mockCDP = createMockCDP({
|
|
47
|
+
loadEventAlreadyFired: true,
|
|
48
|
+
networkQuiet: true,
|
|
49
|
+
domStable: true,
|
|
50
|
+
});
|
|
51
|
+
await waitForPageReady(mockCDP);
|
|
52
|
+
// Should complete network phase
|
|
53
|
+
assert.ok(true, 'Should proceed when network is stable');
|
|
54
|
+
});
|
|
55
|
+
test('proceeds when DOM stabilizes', async () => {
|
|
56
|
+
const mockCDP = createMockCDP({
|
|
57
|
+
loadEventAlreadyFired: true,
|
|
58
|
+
networkQuiet: true,
|
|
59
|
+
domStable: true,
|
|
60
|
+
});
|
|
61
|
+
await waitForPageReady(mockCDP);
|
|
62
|
+
// Should complete DOM phase
|
|
63
|
+
assert.ok(true, 'Should proceed when DOM is stable');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe('Page Readiness - Timeout Behavior', () => {
|
|
67
|
+
test('proceeds on timeout without throwing', async () => {
|
|
68
|
+
const mockCDP = createMockCDP({
|
|
69
|
+
loadEventAlreadyFired: false,
|
|
70
|
+
networkQuiet: false, // Never becomes quiet
|
|
71
|
+
domStable: false, // Never stabilizes
|
|
72
|
+
delayLoadEvent: true, // Delay to trigger timeout
|
|
73
|
+
});
|
|
74
|
+
// Contract: should NOT throw on timeout, should proceed anyway
|
|
75
|
+
await assert.doesNotReject(async () => {
|
|
76
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 100 });
|
|
77
|
+
}, 'Should not throw on timeout');
|
|
78
|
+
});
|
|
79
|
+
test('respects custom maxWaitMs option', async () => {
|
|
80
|
+
const mockCDP = createMockCDP({
|
|
81
|
+
loadEventAlreadyFired: false,
|
|
82
|
+
networkQuiet: false,
|
|
83
|
+
domStable: false,
|
|
84
|
+
delayLoadEvent: true,
|
|
85
|
+
});
|
|
86
|
+
const start = Date.now();
|
|
87
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 200 });
|
|
88
|
+
const duration = Date.now() - start;
|
|
89
|
+
// Should timeout around 200ms (with some tolerance for scheduling)
|
|
90
|
+
assert.ok(duration >= 150 && duration < 400, 'Should respect custom timeout');
|
|
91
|
+
});
|
|
92
|
+
test('uses default 5000ms timeout when not specified', async () => {
|
|
93
|
+
const mockCDP = createMockCDP({
|
|
94
|
+
loadEventAlreadyFired: true,
|
|
95
|
+
networkQuiet: true,
|
|
96
|
+
domStable: true,
|
|
97
|
+
});
|
|
98
|
+
const start = Date.now();
|
|
99
|
+
await waitForPageReady(mockCDP); // No options
|
|
100
|
+
const duration = Date.now() - start;
|
|
101
|
+
// Should complete quickly when stable (not wait full 5s)
|
|
102
|
+
assert.ok(duration < 1000, 'Should not wait unnecessarily when page is ready');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('Page Readiness - Load Event Phase', () => {
|
|
106
|
+
test('waits for Page.loadEventFired when not already loaded', async () => {
|
|
107
|
+
let loadEventFired = false;
|
|
108
|
+
const mockCDP = createMockCDP({
|
|
109
|
+
loadEventAlreadyFired: false,
|
|
110
|
+
networkQuiet: true,
|
|
111
|
+
domStable: true,
|
|
112
|
+
onEventRegistered: (event) => {
|
|
113
|
+
if (event === 'Page.loadEventFired') {
|
|
114
|
+
// Simulate load event firing after a delay
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
loadEventFired = true;
|
|
117
|
+
mockCDP.emit('Page.loadEventFired', {});
|
|
118
|
+
}, 50);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 500 });
|
|
123
|
+
assert.ok(loadEventFired, 'Should wait for and receive load event');
|
|
124
|
+
});
|
|
125
|
+
test('skips waiting for load event when document.readyState is complete', async () => {
|
|
126
|
+
const events = [];
|
|
127
|
+
const mockCDP = createMockCDP({
|
|
128
|
+
loadEventAlreadyFired: true,
|
|
129
|
+
networkQuiet: true,
|
|
130
|
+
domStable: true,
|
|
131
|
+
onEventRegistered: (event) => {
|
|
132
|
+
events.push(event);
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
await waitForPageReady(mockCDP);
|
|
136
|
+
// Contract: should not register for Page.loadEventFired if already complete
|
|
137
|
+
// (though it's okay if it does register and immediately continues)
|
|
138
|
+
assert.ok(true, 'Should handle pre-loaded page');
|
|
139
|
+
});
|
|
140
|
+
test('handles Runtime.evaluate errors gracefully', async () => {
|
|
141
|
+
const mockCDP = createMockCDP({
|
|
142
|
+
loadEventAlreadyFired: false,
|
|
143
|
+
networkQuiet: true,
|
|
144
|
+
domStable: true,
|
|
145
|
+
evaluateThrows: true,
|
|
146
|
+
});
|
|
147
|
+
// Contract: should proceed even if readyState check fails
|
|
148
|
+
await assert.doesNotReject(async () => {
|
|
149
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 200 });
|
|
150
|
+
}, 'Should handle evaluate errors gracefully');
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('Page Readiness - Network Stability Phase', () => {
|
|
154
|
+
test('detects network activity via requestWillBeSent events', async () => {
|
|
155
|
+
const events = [];
|
|
156
|
+
const mockCDP = createMockCDP({
|
|
157
|
+
loadEventAlreadyFired: true,
|
|
158
|
+
networkQuiet: false,
|
|
159
|
+
domStable: true,
|
|
160
|
+
onEventRegistered: (event) => {
|
|
161
|
+
events.push(event);
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 200 });
|
|
165
|
+
// Contract: should listen for network events
|
|
166
|
+
assert.ok(events.includes('Network.requestWillBeSent'), 'Should listen for network requests');
|
|
167
|
+
assert.ok(events.includes('Network.loadingFinished'), 'Should listen for loading finished');
|
|
168
|
+
assert.ok(events.includes('Network.loadingFailed'), 'Should listen for loading failed');
|
|
169
|
+
});
|
|
170
|
+
test('tracks active requests (requestWillBeSent increases, responses decrease)', async () => {
|
|
171
|
+
const mockCDP = createMockCDP({
|
|
172
|
+
loadEventAlreadyFired: true,
|
|
173
|
+
networkQuiet: false,
|
|
174
|
+
domStable: true,
|
|
175
|
+
onEventRegistered: (event) => {
|
|
176
|
+
if (event === 'Network.requestWillBeSent') {
|
|
177
|
+
// Simulate request/response cycle
|
|
178
|
+
setTimeout(() => {
|
|
179
|
+
mockCDP.emit('Network.requestWillBeSent', {});
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
mockCDP.emit('Network.loadingFinished', {});
|
|
182
|
+
}, 50);
|
|
183
|
+
}, 30);
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 500 });
|
|
188
|
+
// Network phase should have completed
|
|
189
|
+
assert.ok(true, 'Should track network request lifecycle');
|
|
190
|
+
});
|
|
191
|
+
test('waits for 200ms of network idle before proceeding', async () => {
|
|
192
|
+
// This test verifies the threshold concept but not exact timing
|
|
193
|
+
const mockCDP = createMockCDP({
|
|
194
|
+
loadEventAlreadyFired: true,
|
|
195
|
+
networkQuiet: true,
|
|
196
|
+
domStable: true,
|
|
197
|
+
});
|
|
198
|
+
await waitForPageReady(mockCDP);
|
|
199
|
+
// Contract: should wait for network stability (implementation uses 200ms threshold)
|
|
200
|
+
assert.ok(true, 'Should wait for network stability threshold');
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
describe('Page Readiness - DOM Stability Phase', () => {
|
|
204
|
+
test('injects MutationObserver into page', async () => {
|
|
205
|
+
const evaluations = [];
|
|
206
|
+
const mockCDP = createMockCDP({
|
|
207
|
+
loadEventAlreadyFired: true,
|
|
208
|
+
networkQuiet: true,
|
|
209
|
+
domStable: true,
|
|
210
|
+
onSend: (method, params) => {
|
|
211
|
+
if (method === 'Runtime.evaluate' && params?.['expression']) {
|
|
212
|
+
evaluations.push(params['expression']);
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
await waitForPageReady(mockCDP);
|
|
217
|
+
// Contract: should inject MutationObserver
|
|
218
|
+
const hasObserver = evaluations.some((expr) => expr.includes('MutationObserver'));
|
|
219
|
+
assert.ok(hasObserver, 'Should inject MutationObserver for DOM tracking');
|
|
220
|
+
});
|
|
221
|
+
test('cleans up MutationObserver after detection', async () => {
|
|
222
|
+
const evaluations = [];
|
|
223
|
+
const mockCDP = createMockCDP({
|
|
224
|
+
loadEventAlreadyFired: true,
|
|
225
|
+
networkQuiet: true,
|
|
226
|
+
domStable: true,
|
|
227
|
+
onSend: (method, params) => {
|
|
228
|
+
if (method === 'Runtime.evaluate' && params?.['expression']) {
|
|
229
|
+
evaluations.push(params['expression']);
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
await waitForPageReady(mockCDP);
|
|
234
|
+
// Contract: should clean up observer
|
|
235
|
+
const hasCleanup = evaluations.some((expr) => expr.includes('disconnect') || expr.includes('delete window.__bdg'));
|
|
236
|
+
assert.ok(hasCleanup, 'Should clean up MutationObserver after detection');
|
|
237
|
+
});
|
|
238
|
+
test('waits for 300ms of DOM stability before proceeding', async () => {
|
|
239
|
+
// This test verifies the threshold concept but not exact timing
|
|
240
|
+
const mockCDP = createMockCDP({
|
|
241
|
+
loadEventAlreadyFired: true,
|
|
242
|
+
networkQuiet: true,
|
|
243
|
+
domStable: true,
|
|
244
|
+
});
|
|
245
|
+
await waitForPageReady(mockCDP);
|
|
246
|
+
// Contract: should wait for DOM stability threshold (implementation uses 300ms)
|
|
247
|
+
assert.ok(true, 'Should wait for DOM stability threshold');
|
|
248
|
+
});
|
|
249
|
+
test('handles missing document.body gracefully', async () => {
|
|
250
|
+
const mockCDP = createMockCDP({
|
|
251
|
+
loadEventAlreadyFired: true,
|
|
252
|
+
networkQuiet: true,
|
|
253
|
+
domStable: true,
|
|
254
|
+
evaluateThrows: true, // Simulate errors injecting observer
|
|
255
|
+
});
|
|
256
|
+
// Contract: should handle observer injection failures
|
|
257
|
+
await assert.doesNotReject(async () => {
|
|
258
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 200 });
|
|
259
|
+
}, 'Should handle missing document.body');
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
describe('Page Readiness - Event Handler Cleanup', () => {
|
|
263
|
+
test('removes load event listener after phase completes', async () => {
|
|
264
|
+
const offCalls = [];
|
|
265
|
+
const mockCDP = createMockCDP({
|
|
266
|
+
loadEventAlreadyFired: false,
|
|
267
|
+
networkQuiet: true,
|
|
268
|
+
domStable: true,
|
|
269
|
+
onOff: (event) => {
|
|
270
|
+
offCalls.push(event);
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
// Fire load event to complete phase
|
|
274
|
+
setTimeout(() => mockCDP.emit('Page.loadEventFired', {}), 50);
|
|
275
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 500 });
|
|
276
|
+
// Contract: should clean up load event listener
|
|
277
|
+
assert.ok(offCalls.includes('Page.loadEventFired'), 'Should remove Page.loadEventFired listener');
|
|
278
|
+
});
|
|
279
|
+
test('removes network event listeners after phase completes', async () => {
|
|
280
|
+
const offCalls = [];
|
|
281
|
+
const mockCDP = createMockCDP({
|
|
282
|
+
loadEventAlreadyFired: true,
|
|
283
|
+
networkQuiet: true,
|
|
284
|
+
domStable: true,
|
|
285
|
+
onOff: (event) => {
|
|
286
|
+
offCalls.push(event);
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
await waitForPageReady(mockCDP);
|
|
290
|
+
// Contract: should clean up all network listeners
|
|
291
|
+
assert.ok(offCalls.includes('Network.requestWillBeSent'), 'Should remove requestWillBeSent listener');
|
|
292
|
+
assert.ok(offCalls.includes('Network.loadingFinished'), 'Should remove loadingFinished listener');
|
|
293
|
+
assert.ok(offCalls.includes('Network.loadingFailed'), 'Should remove loadingFailed listener');
|
|
294
|
+
});
|
|
295
|
+
test('cleans up even when timeout occurs', async () => {
|
|
296
|
+
const offCalls = [];
|
|
297
|
+
const mockCDP = createMockCDP({
|
|
298
|
+
loadEventAlreadyFired: false,
|
|
299
|
+
networkQuiet: false,
|
|
300
|
+
domStable: false,
|
|
301
|
+
delayLoadEvent: true,
|
|
302
|
+
onOff: (event) => {
|
|
303
|
+
offCalls.push(event);
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
await waitForPageReady(mockCDP, { maxWaitMs: 100 });
|
|
307
|
+
// Contract: should clean up even on timeout
|
|
308
|
+
assert.ok(offCalls.length > 0, 'Should clean up listeners even on timeout');
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
/**
|
|
312
|
+
* Create a mock CDPConnection for testing page readiness
|
|
313
|
+
*/
|
|
314
|
+
function createMockCDP(options = {}) {
|
|
315
|
+
const { loadEventAlreadyFired = false, domStable = true, delayLoadEvent = false, evaluateThrows = false, onSend, onEventRegistered, onOff, } = options;
|
|
316
|
+
const handlers = new Map();
|
|
317
|
+
let handlerId = 0;
|
|
318
|
+
const mock = {
|
|
319
|
+
send(method, params) {
|
|
320
|
+
onSend?.(method, params);
|
|
321
|
+
if (method === 'Page.enable' || method === 'Network.enable') {
|
|
322
|
+
return Promise.resolve({});
|
|
323
|
+
}
|
|
324
|
+
if (method === 'Runtime.evaluate') {
|
|
325
|
+
if (evaluateThrows) {
|
|
326
|
+
throw new Error('Evaluation failed');
|
|
327
|
+
}
|
|
328
|
+
const expression = params?.['expression'];
|
|
329
|
+
// Mock document.readyState check
|
|
330
|
+
if (expression?.includes('document.readyState')) {
|
|
331
|
+
return Promise.resolve({
|
|
332
|
+
result: {
|
|
333
|
+
value: loadEventAlreadyFired ? 'complete' : 'loading',
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
// Mock MutationObserver injection
|
|
338
|
+
if (expression?.includes('MutationObserver')) {
|
|
339
|
+
return Promise.resolve({ result: {} });
|
|
340
|
+
}
|
|
341
|
+
// Mock DOM stability check
|
|
342
|
+
if (expression?.includes('__bdg_lastMutation')) {
|
|
343
|
+
const timeSinceLastMutation = domStable ? 500 : 0; // 500ms > 300ms threshold
|
|
344
|
+
return Promise.resolve({
|
|
345
|
+
result: {
|
|
346
|
+
value: timeSinceLastMutation,
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
return Promise.resolve({ result: {} });
|
|
351
|
+
}
|
|
352
|
+
return Promise.resolve({});
|
|
353
|
+
},
|
|
354
|
+
on(event, handler) {
|
|
355
|
+
onEventRegistered?.(event);
|
|
356
|
+
if (!handlers.has(event)) {
|
|
357
|
+
handlers.set(event, new Map());
|
|
358
|
+
}
|
|
359
|
+
const id = handlerId++;
|
|
360
|
+
handlers.get(event)?.set(id, handler);
|
|
361
|
+
// Auto-fire load event if configured
|
|
362
|
+
if (event === 'Page.loadEventFired' && !delayLoadEvent) {
|
|
363
|
+
setTimeout(() => {
|
|
364
|
+
handler({});
|
|
365
|
+
}, 10);
|
|
366
|
+
}
|
|
367
|
+
return () => this.off(event, id);
|
|
368
|
+
},
|
|
369
|
+
off(event, id) {
|
|
370
|
+
onOff?.(event);
|
|
371
|
+
handlers.get(event)?.delete(id);
|
|
372
|
+
},
|
|
373
|
+
emit(event, params) {
|
|
374
|
+
const eventHandlers = handlers.get(event);
|
|
375
|
+
if (eventHandlers) {
|
|
376
|
+
eventHandlers.forEach((handler) => handler(params));
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
return mock;
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=pageReadiness.contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pageReadiness.contract.test.js","sourceRoot":"","sources":["../../../src/connection/__tests__/pageReadiness.contract.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for port reservation
|
|
3
|
+
*
|
|
4
|
+
* Tests the contract: reserve port atomically OR throw ChromeLaunchError
|
|
5
|
+
*
|
|
6
|
+
* Philosophy: Test with real network sockets to validate actual behavior.
|
|
7
|
+
* Port reservation is an I/O operation that must work correctly in production,
|
|
8
|
+
* so we use real sockets rather than mocks.
|
|
9
|
+
*
|
|
10
|
+
* These are contract tests (not unit tests) because they test the contract
|
|
11
|
+
* between reservePort() and the Node.js net module.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=portReservation.contract.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portReservation.contract.test.d.ts","sourceRoot":"","sources":["../../../src/connection/__tests__/portReservation.contract.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract tests for port reservation
|
|
3
|
+
*
|
|
4
|
+
* Tests the contract: reserve port atomically OR throw ChromeLaunchError
|
|
5
|
+
*
|
|
6
|
+
* Philosophy: Test with real network sockets to validate actual behavior.
|
|
7
|
+
* Port reservation is an I/O operation that must work correctly in production,
|
|
8
|
+
* so we use real sockets rather than mocks.
|
|
9
|
+
*
|
|
10
|
+
* These are contract tests (not unit tests) because they test the contract
|
|
11
|
+
* between reservePort() and the Node.js net module.
|
|
12
|
+
*/
|
|
13
|
+
import * as net from 'net';
|
|
14
|
+
import assert from 'node:assert/strict';
|
|
15
|
+
import { describe, test } from 'node:test';
|
|
16
|
+
import { ChromeLaunchError } from '../../connection/errors.js';
|
|
17
|
+
import { reservePort } from '../../connection/portReservation.js';
|
|
18
|
+
describe('Port Reservation - Success Cases', () => {
|
|
19
|
+
test('successfully reserves an available port', async () => {
|
|
20
|
+
const port = await findAvailablePort();
|
|
21
|
+
const reservation = await reservePort(port);
|
|
22
|
+
try {
|
|
23
|
+
// Contract: reservation should have release function
|
|
24
|
+
assert.ok(typeof reservation.release === 'function', 'Should return reservation with release()');
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
reservation.release();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
test('release() frees the port for reuse', async () => {
|
|
31
|
+
const port = await findAvailablePort();
|
|
32
|
+
const reservation1 = await reservePort(port);
|
|
33
|
+
reservation1.release();
|
|
34
|
+
// Contract: after release, port should be available again
|
|
35
|
+
const reservation2 = await reservePort(port);
|
|
36
|
+
reservation2.release();
|
|
37
|
+
// If we got here without error, port was successfully reused
|
|
38
|
+
assert.ok(true, 'Port should be available after release');
|
|
39
|
+
});
|
|
40
|
+
test('can reserve multiple different ports simultaneously', async () => {
|
|
41
|
+
const port1 = await findAvailablePort();
|
|
42
|
+
const port2 = await findAvailablePort(port1 + 1);
|
|
43
|
+
const reservation1 = await reservePort(port1);
|
|
44
|
+
const reservation2 = await reservePort(port2);
|
|
45
|
+
try {
|
|
46
|
+
assert.ok(reservation1, 'First reservation should succeed');
|
|
47
|
+
assert.ok(reservation2, 'Second reservation should succeed');
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
reservation1.release();
|
|
51
|
+
reservation2.release();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
test('release() can be called immediately after reservation', async () => {
|
|
55
|
+
const port = await findAvailablePort();
|
|
56
|
+
const reservation = await reservePort(port);
|
|
57
|
+
reservation.release(); // Immediate release
|
|
58
|
+
// Should not throw
|
|
59
|
+
assert.ok(true, 'Immediate release should be safe');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('Port Reservation - Failure Cases', () => {
|
|
63
|
+
test('throws ChromeLaunchError when port is already in use', async () => {
|
|
64
|
+
const port = await findAvailablePort();
|
|
65
|
+
// Occupy the port with a real server
|
|
66
|
+
const server = await createTestServer(port);
|
|
67
|
+
try {
|
|
68
|
+
// Contract: should throw ChromeLaunchError (not generic Error)
|
|
69
|
+
await assert.rejects(async () => {
|
|
70
|
+
await reservePort(port);
|
|
71
|
+
}, (error) => {
|
|
72
|
+
assert.ok(error instanceof ChromeLaunchError, 'Should throw ChromeLaunchError');
|
|
73
|
+
assert.ok(error.message.includes(`${port}`), 'Error message should mention port number');
|
|
74
|
+
assert.ok(error.message.includes('already in use'), 'Error message should indicate port is in use');
|
|
75
|
+
return true;
|
|
76
|
+
}, 'Should throw ChromeLaunchError when port is in use');
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await closeServer(server);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
test('fails when attempting to reserve same port twice', async () => {
|
|
83
|
+
const port = await findAvailablePort();
|
|
84
|
+
const reservation = await reservePort(port);
|
|
85
|
+
try {
|
|
86
|
+
// Contract: second reservation should fail with ChromeLaunchError
|
|
87
|
+
await assert.rejects(async () => {
|
|
88
|
+
await reservePort(port);
|
|
89
|
+
}, ChromeLaunchError, 'Should fail when port already reserved');
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
reservation.release();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
test('error message includes helpful troubleshooting steps', async () => {
|
|
96
|
+
const port = await findAvailablePort();
|
|
97
|
+
const server = await createTestServer(port);
|
|
98
|
+
try {
|
|
99
|
+
await assert.rejects(async () => {
|
|
100
|
+
await reservePort(port);
|
|
101
|
+
}, (error) => {
|
|
102
|
+
// Contract: error message should help user troubleshoot
|
|
103
|
+
assert.ok(error.message.includes('bdg cleanup'), 'Should suggest cleanup command');
|
|
104
|
+
assert.ok(error.message.includes('lsof'), 'Should suggest checking processes');
|
|
105
|
+
assert.ok(error.message.includes(`--port ${port + 1}`), 'Should suggest alternative port');
|
|
106
|
+
return true;
|
|
107
|
+
}, 'Error message should include troubleshooting steps');
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
await closeServer(server);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('Port Reservation - Release Behavior', () => {
|
|
115
|
+
test('release() closes the server immediately', async () => {
|
|
116
|
+
const port = await findAvailablePort();
|
|
117
|
+
const reservation = await reservePort(port);
|
|
118
|
+
reservation.release();
|
|
119
|
+
// Port should be immediately available (not waiting for async cleanup)
|
|
120
|
+
const testServer = net.createServer();
|
|
121
|
+
const canBind = await new Promise((resolve) => {
|
|
122
|
+
testServer.once('error', () => resolve(false));
|
|
123
|
+
testServer.listen(port, '127.0.0.1', () => {
|
|
124
|
+
testServer.close();
|
|
125
|
+
resolve(true);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
assert.ok(canBind, 'Port should be immediately available after release');
|
|
129
|
+
});
|
|
130
|
+
test('release() can be called multiple times safely', async () => {
|
|
131
|
+
const port = await findAvailablePort();
|
|
132
|
+
const reservation = await reservePort(port);
|
|
133
|
+
// Multiple releases should not throw
|
|
134
|
+
reservation.release();
|
|
135
|
+
reservation.release();
|
|
136
|
+
reservation.release();
|
|
137
|
+
assert.ok(true, 'Multiple release() calls should be safe');
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe('Port Reservation - Edge Cases', () => {
|
|
141
|
+
test('handles port number at lower boundary (1024)', async () => {
|
|
142
|
+
// Ports < 1024 require root, so we test 1024 (first non-privileged port)
|
|
143
|
+
// This may fail in environments where 1024 is in use - that's expected
|
|
144
|
+
try {
|
|
145
|
+
const reservation = await reservePort(1024);
|
|
146
|
+
reservation.release();
|
|
147
|
+
assert.ok(true, 'Should handle port 1024');
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
// If port is in use, verify it's the expected error type
|
|
151
|
+
assert.ok(error instanceof ChromeLaunchError, 'Should throw ChromeLaunchError for in-use port 1024');
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
test('handles port number at upper boundary (65535)', async () => {
|
|
155
|
+
try {
|
|
156
|
+
const reservation = await reservePort(65535);
|
|
157
|
+
reservation.release();
|
|
158
|
+
assert.ok(true, 'Should handle port 65535');
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
// If port is in use, verify it's the expected error type
|
|
162
|
+
assert.ok(error instanceof ChromeLaunchError, 'Should throw ChromeLaunchError for in-use port 65535');
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
test('binds to localhost (127.0.0.1) only, not all interfaces', async () => {
|
|
166
|
+
const port = await findAvailablePort();
|
|
167
|
+
const reservation = await reservePort(port);
|
|
168
|
+
try {
|
|
169
|
+
// Contract: should bind to 127.0.0.1, not 0.0.0.0
|
|
170
|
+
// This means we can still bind to the same port on other interfaces
|
|
171
|
+
// We verify by checking we can't bind to 127.0.0.1 but this is implicit
|
|
172
|
+
// in the reservation working at all
|
|
173
|
+
assert.ok(true, 'Reservation binds to localhost interface');
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
reservation.release();
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
describe('Port Reservation - Atomicity', () => {
|
|
181
|
+
test('reservation is atomic (prevents race conditions)', async () => {
|
|
182
|
+
const port = await findAvailablePort();
|
|
183
|
+
// Attempt two simultaneous reservations
|
|
184
|
+
const results = await Promise.allSettled([reservePort(port), reservePort(port)]);
|
|
185
|
+
// Contract: exactly one should succeed, one should fail
|
|
186
|
+
const successes = results.filter((r) => r.status === 'fulfilled');
|
|
187
|
+
const failures = results.filter((r) => r.status === 'rejected');
|
|
188
|
+
assert.equal(successes.length, 1, 'Exactly one reservation should succeed');
|
|
189
|
+
assert.equal(failures.length, 1, 'Exactly one reservation should fail');
|
|
190
|
+
// Cleanup successful reservation
|
|
191
|
+
const success = successes[0];
|
|
192
|
+
if (success?.status === 'fulfilled') {
|
|
193
|
+
success.value.release();
|
|
194
|
+
}
|
|
195
|
+
// Verify failure is ChromeLaunchError
|
|
196
|
+
const failure = failures[0];
|
|
197
|
+
if (failure?.status === 'rejected') {
|
|
198
|
+
assert.ok(failure.reason instanceof ChromeLaunchError, 'Failed reservation should throw ChromeLaunchError');
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
// Test Helpers
|
|
203
|
+
/**
|
|
204
|
+
* Find an available port starting from a base port
|
|
205
|
+
*
|
|
206
|
+
* @param startPort - Port to start searching from (default: 9000)
|
|
207
|
+
* @returns Available port number
|
|
208
|
+
*/
|
|
209
|
+
async function findAvailablePort(startPort = 9000) {
|
|
210
|
+
for (let port = startPort; port < 65535; port++) {
|
|
211
|
+
const server = net.createServer();
|
|
212
|
+
const available = await new Promise((resolve) => {
|
|
213
|
+
server.once('error', () => resolve(false));
|
|
214
|
+
server.listen(port, '127.0.0.1', () => {
|
|
215
|
+
server.close();
|
|
216
|
+
resolve(true);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
if (available) {
|
|
220
|
+
return port;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
throw new Error('No available ports found');
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Create a test server on a specific port
|
|
227
|
+
*
|
|
228
|
+
* @param port - Port to bind to
|
|
229
|
+
* @returns Server instance
|
|
230
|
+
*/
|
|
231
|
+
async function createTestServer(port) {
|
|
232
|
+
const server = net.createServer();
|
|
233
|
+
return new Promise((resolve, reject) => {
|
|
234
|
+
server.once('error', reject);
|
|
235
|
+
server.listen(port, '127.0.0.1', () => {
|
|
236
|
+
resolve(server);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Close a server gracefully
|
|
242
|
+
*
|
|
243
|
+
* @param server - Server to close
|
|
244
|
+
*/
|
|
245
|
+
async function closeServer(server) {
|
|
246
|
+
return new Promise((resolve) => {
|
|
247
|
+
server.close(() => resolve());
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=portReservation.contract.test.js.map
|